better-ffmpeg-progress 3.2.1__tar.gz → 3.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {better_ffmpeg_progress-3.2.1 → better_ffmpeg_progress-3.2.2}/PKG-INFO +1 -1
- {better_ffmpeg_progress-3.2.1 → better_ffmpeg_progress-3.2.2}/better_ffmpeg_progress/better_ffmpeg_progress.py +56 -113
- {better_ffmpeg_progress-3.2.1 → better_ffmpeg_progress-3.2.2}/better_ffmpeg_progress.egg-info/PKG-INFO +1 -1
- {better_ffmpeg_progress-3.2.1 → better_ffmpeg_progress-3.2.2}/setup.py +1 -1
- {better_ffmpeg_progress-3.2.1 → better_ffmpeg_progress-3.2.2}/LICENSE +0 -0
- {better_ffmpeg_progress-3.2.1 → better_ffmpeg_progress-3.2.2}/README.md +0 -0
- {better_ffmpeg_progress-3.2.1 → better_ffmpeg_progress-3.2.2}/better_ffmpeg_progress/__init__.py +0 -0
- {better_ffmpeg_progress-3.2.1 → better_ffmpeg_progress-3.2.2}/better_ffmpeg_progress/utils.py +0 -0
- {better_ffmpeg_progress-3.2.1 → better_ffmpeg_progress-3.2.2}/better_ffmpeg_progress.egg-info/SOURCES.txt +0 -0
- {better_ffmpeg_progress-3.2.1 → better_ffmpeg_progress-3.2.2}/better_ffmpeg_progress.egg-info/dependency_links.txt +0 -0
- {better_ffmpeg_progress-3.2.1 → better_ffmpeg_progress-3.2.2}/better_ffmpeg_progress.egg-info/requires.txt +0 -0
- {better_ffmpeg_progress-3.2.1 → better_ffmpeg_progress-3.2.2}/better_ffmpeg_progress.egg-info/top_level.txt +0 -0
- {better_ffmpeg_progress-3.2.1 → better_ffmpeg_progress-3.2.2}/setup.cfg +0 -0
|
@@ -5,8 +5,6 @@ import psutil
|
|
|
5
5
|
from queue import Queue
|
|
6
6
|
import shutil
|
|
7
7
|
import subprocess
|
|
8
|
-
from threading import Thread
|
|
9
|
-
from time import sleep
|
|
10
8
|
from typing import List, Optional, Union
|
|
11
9
|
|
|
12
10
|
from ffmpeg import probe
|
|
@@ -35,24 +33,6 @@ class FfmpegLogLevel(Enum):
|
|
|
35
33
|
|
|
36
34
|
|
|
37
35
|
class FfmpegProcess:
|
|
38
|
-
@staticmethod
|
|
39
|
-
def _read_pipe(pipe: subprocess.PIPE, queue: Queue, stdout: bool = False) -> None:
|
|
40
|
-
"""Read from pipe and put lines into queue."""
|
|
41
|
-
try:
|
|
42
|
-
with pipe:
|
|
43
|
-
for line in iter(pipe.readline, ""):
|
|
44
|
-
line = line.strip()
|
|
45
|
-
if line:
|
|
46
|
-
if stdout:
|
|
47
|
-
if line.startswith("out_time_ms="):
|
|
48
|
-
queue.put(line)
|
|
49
|
-
else:
|
|
50
|
-
queue.put(line)
|
|
51
|
-
except (IOError, ValueError) as e:
|
|
52
|
-
print(f"Error reading pipe: {e}")
|
|
53
|
-
finally:
|
|
54
|
-
pipe.close()
|
|
55
|
-
|
|
56
36
|
@classmethod
|
|
57
37
|
def _validate_command(cls, command: List[str]) -> bool:
|
|
58
38
|
if not shutil.which("ffmpeg"):
|
|
@@ -112,9 +92,6 @@ class FfmpegProcess:
|
|
|
112
92
|
self._print_detected_duration = print_detected_duration
|
|
113
93
|
self._print_stderr_new_line = print_stderr_new_line
|
|
114
94
|
|
|
115
|
-
with open(self._ffmpeg_log_file, "w"):
|
|
116
|
-
pass
|
|
117
|
-
|
|
118
95
|
try:
|
|
119
96
|
probe_data = probe(self._input_filepath)
|
|
120
97
|
self._duration_secs = float(probe_data["format"]["duration"])
|
|
@@ -136,18 +113,7 @@ class FfmpegProcess:
|
|
|
136
113
|
|
|
137
114
|
self.return_code = 0
|
|
138
115
|
|
|
139
|
-
def
|
|
140
|
-
if self._duration_secs is None:
|
|
141
|
-
print(stderr, end="\n" if self._print_stderr_new_line else "\r", flush=True)
|
|
142
|
-
|
|
143
|
-
try:
|
|
144
|
-
with open(self._ffmpeg_log_file, "a", encoding="utf-8") as f:
|
|
145
|
-
f.write(f"{stderr}\n")
|
|
146
|
-
except IOError as e:
|
|
147
|
-
print(f"Error writing to log file: {e}")
|
|
148
|
-
self.return_code = 1
|
|
149
|
-
|
|
150
|
-
def _use_rich(self, process, stdout_queue, stderr_queue) -> int:
|
|
116
|
+
def _use_rich(self, process) -> int:
|
|
151
117
|
with Progress(
|
|
152
118
|
SpinnerColumn(),
|
|
153
119
|
TextColumn("[progress.description]{task.description}"),
|
|
@@ -165,37 +131,32 @@ class FfmpegProcess:
|
|
|
165
131
|
total=self._duration_secs,
|
|
166
132
|
)
|
|
167
133
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
134
|
+
if task_id is not None:
|
|
135
|
+
while process.poll() is None:
|
|
136
|
+
stdout = process.stdout.readline()
|
|
137
|
+
|
|
138
|
+
if not stdout.startswith("out_time_ms"):
|
|
139
|
+
continue
|
|
140
|
+
|
|
174
141
|
try:
|
|
175
|
-
value = int(
|
|
142
|
+
value = int(stdout.split("=")[1]) / 1_000_000
|
|
143
|
+
except ValueError:
|
|
144
|
+
continue
|
|
145
|
+
else:
|
|
176
146
|
if value <= self._duration_secs:
|
|
177
147
|
progress_bar.update(task_id, completed=value)
|
|
178
|
-
except ValueError:
|
|
179
|
-
pass
|
|
180
|
-
# stderr
|
|
181
|
-
if not stderr_queue.empty():
|
|
182
|
-
self._process_stderr(stderr_queue.get())
|
|
183
|
-
|
|
184
|
-
if process.returncode == 0 and task_id is not None:
|
|
185
|
-
progress_bar.update(task_id, completed=self._duration_secs)
|
|
186
|
-
progress_bar.columns = (
|
|
187
|
-
TextColumn("[progress.description]{task.description}"),
|
|
188
|
-
BarColumn(),
|
|
189
|
-
TaskProgressColumn(),
|
|
190
|
-
)
|
|
191
|
-
progress_bar.update(
|
|
192
|
-
task_id,
|
|
193
|
-
description=f"✓ Processed {self._input_filepath.name}",
|
|
194
|
-
)
|
|
195
148
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
149
|
+
if process.returncode == 0:
|
|
150
|
+
progress_bar.update(task_id, completed=self._duration_secs)
|
|
151
|
+
progress_bar.columns = (
|
|
152
|
+
TextColumn("[progress.description]{task.description}"),
|
|
153
|
+
BarColumn(),
|
|
154
|
+
TaskProgressColumn(),
|
|
155
|
+
)
|
|
156
|
+
progress_bar.update(
|
|
157
|
+
task_id,
|
|
158
|
+
description=f"✓ Processed {self._input_filepath.name}",
|
|
159
|
+
)
|
|
199
160
|
|
|
200
161
|
if process.returncode != 0:
|
|
201
162
|
progress_bar.update(
|
|
@@ -206,12 +167,12 @@ class FfmpegProcess:
|
|
|
206
167
|
|
|
207
168
|
return 0
|
|
208
169
|
|
|
209
|
-
def _use_tqdm(self, process
|
|
210
|
-
|
|
170
|
+
def _use_tqdm(self, process) -> int:
|
|
171
|
+
progress_bar = None
|
|
211
172
|
width, _ = os.get_terminal_size()
|
|
212
173
|
|
|
213
174
|
if self._duration_secs:
|
|
214
|
-
|
|
175
|
+
progress_bar = tqdm(
|
|
215
176
|
total=self._duration_secs,
|
|
216
177
|
desc=f"Processing {self._input_filepath.name}",
|
|
217
178
|
ncols=80,
|
|
@@ -219,33 +180,27 @@ class FfmpegProcess:
|
|
|
219
180
|
bar_format="{desc} {bar} {percentage:.1f}% {elapsed} {remaining}",
|
|
220
181
|
)
|
|
221
182
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
183
|
+
if progress_bar is not None:
|
|
184
|
+
while process.poll() is None:
|
|
185
|
+
stdout = process.stdout.readline()
|
|
186
|
+
|
|
187
|
+
if not stdout.startswith("out_time_ms"):
|
|
188
|
+
continue
|
|
189
|
+
|
|
228
190
|
try:
|
|
229
|
-
value = int(
|
|
230
|
-
if value <= self._duration_secs:
|
|
231
|
-
pbar.n = value
|
|
232
|
-
pbar.refresh()
|
|
191
|
+
value = int(stdout.split("=")[1]) / 1_000_000
|
|
233
192
|
except ValueError:
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
if process.returncode == 0 and pbar:
|
|
240
|
-
pbar.n = self._duration_secs
|
|
241
|
-
pbar.set_description(f"✓ Processed {self._input_filepath.name}")
|
|
193
|
+
continue
|
|
194
|
+
else:
|
|
195
|
+
if value <= self._duration_secs:
|
|
196
|
+
progress_bar.n = value
|
|
197
|
+
progress_bar.refresh()
|
|
242
198
|
|
|
243
|
-
|
|
244
|
-
|
|
199
|
+
if process.returncode == 0:
|
|
200
|
+
progress_bar.n = self._duration_secs
|
|
201
|
+
progress_bar.set_description(f"✓ Processed {self._input_filepath.name}")
|
|
245
202
|
|
|
246
|
-
|
|
247
|
-
while not stderr_queue.empty():
|
|
248
|
-
self._process_stderr(stderr_queue.get())
|
|
203
|
+
progress_bar.close()
|
|
249
204
|
|
|
250
205
|
if process.returncode != 0:
|
|
251
206
|
print(
|
|
@@ -288,38 +243,26 @@ class FfmpegProcess:
|
|
|
288
243
|
self._ffmpeg_command = " ".join(self._ffmpeg_command)
|
|
289
244
|
|
|
290
245
|
try:
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
246
|
+
with open(self._ffmpeg_log_file, "w") as f:
|
|
247
|
+
process = subprocess.Popen(
|
|
248
|
+
self._ffmpeg_command,
|
|
249
|
+
shell=isinstance(self._ffmpeg_command, str),
|
|
250
|
+
stdout=subprocess.PIPE,
|
|
251
|
+
stderr=f,
|
|
252
|
+
text=True,
|
|
253
|
+
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP
|
|
254
|
+
if os.name == "nt"
|
|
255
|
+
else 0,
|
|
256
|
+
)
|
|
301
257
|
except Exception as e:
|
|
302
258
|
print(f"Error starting FFmpeg process: {e}")
|
|
303
259
|
return 1
|
|
304
260
|
|
|
305
|
-
stdout_queue, stderr_queue = Queue(), Queue()
|
|
306
|
-
# Start stdout and stderr pipe readers
|
|
307
|
-
Thread(
|
|
308
|
-
target=self._read_pipe,
|
|
309
|
-
args=(process.stdout, stdout_queue, True),
|
|
310
|
-
daemon=True,
|
|
311
|
-
).start()
|
|
312
|
-
Thread(
|
|
313
|
-
target=self._read_pipe,
|
|
314
|
-
args=(process.stderr, stderr_queue, False),
|
|
315
|
-
daemon=True,
|
|
316
|
-
).start()
|
|
317
|
-
|
|
318
261
|
try:
|
|
319
262
|
if use_tqdm:
|
|
320
|
-
return self._use_tqdm(process
|
|
263
|
+
return self._use_tqdm(process)
|
|
321
264
|
else:
|
|
322
|
-
return self._use_rich(process
|
|
265
|
+
return self._use_rich(process)
|
|
323
266
|
except KeyboardInterrupt:
|
|
324
267
|
try:
|
|
325
268
|
psutil.Process(process.pid).terminate()
|
|
@@ -5,7 +5,7 @@ with open("README.md", "r", encoding="utf-8") as f:
|
|
|
5
5
|
|
|
6
6
|
setuptools.setup(
|
|
7
7
|
name="better-ffmpeg-progress",
|
|
8
|
-
version="3.2.
|
|
8
|
+
version="3.2.2",
|
|
9
9
|
author="GitHub.com/CrypticSignal",
|
|
10
10
|
author_email="theaudiophile@outlook.com",
|
|
11
11
|
description="Run FFmpeg & see percentage progress + ETA.",
|
|
File without changes
|
|
File without changes
|
{better_ffmpeg_progress-3.2.1 → better_ffmpeg_progress-3.2.2}/better_ffmpeg_progress/__init__.py
RENAMED
|
File without changes
|
{better_ffmpeg_progress-3.2.1 → better_ffmpeg_progress-3.2.2}/better_ffmpeg_progress/utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|