better-ffmpeg-progress 2.3.0__tar.gz → 2.4.0__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-2.3.0 → better_ffmpeg_progress-2.4.0}/PKG-INFO +6 -1
- {better_ffmpeg_progress-2.3.0 → better_ffmpeg_progress-2.4.0}/README.md +5 -1
- {better_ffmpeg_progress-2.3.0 → better_ffmpeg_progress-2.4.0}/better_ffmpeg_progress/better_ffmpeg_progress.py +70 -43
- {better_ffmpeg_progress-2.3.0 → better_ffmpeg_progress-2.4.0}/better_ffmpeg_progress.egg-info/PKG-INFO +6 -1
- {better_ffmpeg_progress-2.3.0 → better_ffmpeg_progress-2.4.0}/better_ffmpeg_progress.egg-info/requires.txt +1 -0
- {better_ffmpeg_progress-2.3.0 → better_ffmpeg_progress-2.4.0}/setup.py +2 -2
- {better_ffmpeg_progress-2.3.0 → better_ffmpeg_progress-2.4.0}/LICENSE +0 -0
- {better_ffmpeg_progress-2.3.0 → better_ffmpeg_progress-2.4.0}/better_ffmpeg_progress/__init__.py +0 -0
- {better_ffmpeg_progress-2.3.0 → better_ffmpeg_progress-2.4.0}/better_ffmpeg_progress.egg-info/SOURCES.txt +0 -0
- {better_ffmpeg_progress-2.3.0 → better_ffmpeg_progress-2.4.0}/better_ffmpeg_progress.egg-info/dependency_links.txt +0 -0
- {better_ffmpeg_progress-2.3.0 → better_ffmpeg_progress-2.4.0}/better_ffmpeg_progress.egg-info/top_level.txt +0 -0
- {better_ffmpeg_progress-2.3.0 → better_ffmpeg_progress-2.4.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: better-ffmpeg-progress
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4.0
|
|
4
4
|
Summary: Run FFmpeg & see percentage progress + ETA.
|
|
5
5
|
Home-page: https://github.com/CrypticSignal/better-ffmpeg-progress
|
|
6
6
|
Author: GitHub.com/CrypticSignal
|
|
@@ -13,6 +13,7 @@ Requires-Python: >=3.7
|
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
14
|
License-File: LICENSE
|
|
15
15
|
Requires-Dist: ffmpeg-python
|
|
16
|
+
Requires-Dist: psutil
|
|
16
17
|
Requires-Dist: rich
|
|
17
18
|
|
|
18
19
|
<div align="center">
|
|
@@ -166,3 +167,7 @@ The `run` method takes the following **optional** arguments:
|
|
|
166
167
|
|
|
167
168
|
[29/10/2024]
|
|
168
169
|
- [v2.3.0] Set `shell=True` to support piping.
|
|
170
|
+
- [v2.3.1] Kill FFmpeg process(es) on KeyboardInterrupt
|
|
171
|
+
|
|
172
|
+
[31/10/2024]
|
|
173
|
+
- [v2.4.0] Print FFmpeg stderr if better progress information cannot be shown.
|
|
@@ -148,4 +148,8 @@ The `run` method takes the following **optional** arguments:
|
|
|
148
148
|
- [v2.2.2] Make printing the detected duration of the input file optional.
|
|
149
149
|
|
|
150
150
|
[29/10/2024]
|
|
151
|
-
- [v2.3.0] Set `shell=True` to support piping.
|
|
151
|
+
- [v2.3.0] Set `shell=True` to support piping.
|
|
152
|
+
- [v2.3.1] Kill FFmpeg process(es) on KeyboardInterrupt
|
|
153
|
+
|
|
154
|
+
[31/10/2024]
|
|
155
|
+
- [v2.4.0] Print FFmpeg stderr if better progress information cannot be shown.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from dataclasses import dataclass
|
|
2
|
+
import os
|
|
2
3
|
from pathlib import Path
|
|
3
4
|
from queue import Empty, Queue
|
|
4
5
|
import subprocess
|
|
@@ -7,6 +8,7 @@ from threading import Thread
|
|
|
7
8
|
from typing import Callable, List, Optional, Union
|
|
8
9
|
|
|
9
10
|
from ffmpeg import probe
|
|
11
|
+
import psutil
|
|
10
12
|
from rich.progress import (
|
|
11
13
|
Progress,
|
|
12
14
|
TextColumn,
|
|
@@ -77,15 +79,11 @@ class FfmpegProcess:
|
|
|
77
79
|
)
|
|
78
80
|
|
|
79
81
|
# -progress pipe:1 sends progress metrics to stdout AND -stats_period sets the period at which encoding progress/statistics are updated
|
|
80
|
-
|
|
81
|
-
self._ffmpeg_args.extend(
|
|
82
|
-
["-progress", "pipe:1", "-stats_period", "0.1", "-nostats"]
|
|
83
|
-
)
|
|
82
|
+
self._ffmpeg_args.extend(["-progress", "pipe:1", "-stats_period", "0.1"])
|
|
84
83
|
except Exception:
|
|
85
84
|
print(
|
|
86
|
-
f"Could not detect the duration of {self._input_filepath.name}. Percentage progress, ETA and estimated filesize will be unavailable
|
|
85
|
+
f"Could not detect the duration of '{self._input_filepath.name}'. Percentage progress, ETA and estimated filesize will be unavailable.\n",
|
|
87
86
|
)
|
|
88
|
-
self._duration_secs = None
|
|
89
87
|
|
|
90
88
|
def _check_output_exists(self) -> bool:
|
|
91
89
|
"""Check if output file exists and handle overwrite prompt."""
|
|
@@ -163,7 +161,9 @@ class FfmpegProcess:
|
|
|
163
161
|
if is_error:
|
|
164
162
|
return
|
|
165
163
|
|
|
166
|
-
print(
|
|
164
|
+
print(
|
|
165
|
+
f"{"\n\n" if self._duration_secs is None else ""}FFmpeg log filename: {log_file}"
|
|
166
|
+
)
|
|
167
167
|
|
|
168
168
|
def _start_process(
|
|
169
169
|
self,
|
|
@@ -171,12 +171,15 @@ class FfmpegProcess:
|
|
|
171
171
|
task_id: Optional[int],
|
|
172
172
|
progress_handler: Optional[Callable],
|
|
173
173
|
) -> None:
|
|
174
|
+
creationflags = subprocess.CREATE_NEW_PROCESS_GROUP if os.name == "nt" else 0
|
|
175
|
+
|
|
174
176
|
process = subprocess.Popen(
|
|
175
177
|
self._ffmpeg_args,
|
|
176
178
|
stdout=subprocess.PIPE,
|
|
177
179
|
stderr=subprocess.PIPE,
|
|
178
180
|
text=True,
|
|
179
181
|
shell=True,
|
|
182
|
+
creationflags=creationflags,
|
|
180
183
|
)
|
|
181
184
|
|
|
182
185
|
stdout_queue, stderr_queue = Queue(), Queue()
|
|
@@ -187,40 +190,50 @@ class FfmpegProcess:
|
|
|
187
190
|
target=self._handle_pipe, args=(process.stderr, stderr_queue), daemon=True
|
|
188
191
|
).start()
|
|
189
192
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
193
|
+
try:
|
|
194
|
+
while process.poll() is None:
|
|
195
|
+
if self._duration_secs is not None:
|
|
196
|
+
try:
|
|
197
|
+
stdout = stdout_queue.get_nowait()
|
|
198
|
+
|
|
199
|
+
if stdout:
|
|
200
|
+
metric, value = stdout.split("=")
|
|
201
|
+
|
|
202
|
+
if (
|
|
203
|
+
metric in self.WANTED_METRICS
|
|
204
|
+
and value
|
|
205
|
+
and "N/A" not in value
|
|
206
|
+
):
|
|
207
|
+
self._update_metrics(
|
|
208
|
+
stdout, metric, value, progress_handler
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
if (
|
|
212
|
+
metric == "out_time_ms"
|
|
213
|
+
and progress_bar
|
|
214
|
+
and task_id is not None
|
|
215
|
+
):
|
|
216
|
+
progress_bar.update(
|
|
217
|
+
task_id,
|
|
218
|
+
completed=self._metrics.seconds_processed,
|
|
219
|
+
speed=self._metrics.speed,
|
|
220
|
+
)
|
|
221
|
+
except Empty:
|
|
222
|
+
pass
|
|
223
|
+
|
|
224
|
+
try:
|
|
225
|
+
stderr = stderr_queue.get_nowait()
|
|
226
|
+
|
|
227
|
+
if self._duration_secs is None:
|
|
228
|
+
print(stderr, end="\r")
|
|
229
|
+
|
|
230
|
+
self._ffmpeg_stderr.append(stderr)
|
|
231
|
+
except Empty:
|
|
232
|
+
pass
|
|
233
|
+
|
|
234
|
+
except KeyboardInterrupt:
|
|
235
|
+
self._kill_process_and_children(process.pid)
|
|
236
|
+
sys.exit("[KeyboardInterrupt] FFmpeg process(es) killed.")
|
|
224
237
|
|
|
225
238
|
return process.returncode
|
|
226
239
|
|
|
@@ -243,7 +256,9 @@ class FfmpegProcess:
|
|
|
243
256
|
if not self._check_output_exists():
|
|
244
257
|
return
|
|
245
258
|
|
|
246
|
-
print(
|
|
259
|
+
print(
|
|
260
|
+
f"Executing: {' '.join(self._ffmpeg_args)}{"\n" if self._duration_secs is None else ""}"
|
|
261
|
+
)
|
|
247
262
|
|
|
248
263
|
if self._duration_secs and not progress_handler:
|
|
249
264
|
with Progress(
|
|
@@ -299,4 +314,16 @@ class FfmpegProcess:
|
|
|
299
314
|
if success_handler:
|
|
300
315
|
success_handler()
|
|
301
316
|
else:
|
|
302
|
-
print(
|
|
317
|
+
print(
|
|
318
|
+
f"{"\n" if self._duration_secs is None else ""}FFmpeg process completed."
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
def _kill_process_and_children(self, proc_pid):
|
|
322
|
+
try:
|
|
323
|
+
process = psutil.Process(proc_pid)
|
|
324
|
+
for child in process.children(recursive=True):
|
|
325
|
+
child.terminate()
|
|
326
|
+
# Terminate the main process
|
|
327
|
+
process.terminate()
|
|
328
|
+
except psutil.NoSuchProcess:
|
|
329
|
+
pass
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: better-ffmpeg-progress
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4.0
|
|
4
4
|
Summary: Run FFmpeg & see percentage progress + ETA.
|
|
5
5
|
Home-page: https://github.com/CrypticSignal/better-ffmpeg-progress
|
|
6
6
|
Author: GitHub.com/CrypticSignal
|
|
@@ -13,6 +13,7 @@ Requires-Python: >=3.7
|
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
14
|
License-File: LICENSE
|
|
15
15
|
Requires-Dist: ffmpeg-python
|
|
16
|
+
Requires-Dist: psutil
|
|
16
17
|
Requires-Dist: rich
|
|
17
18
|
|
|
18
19
|
<div align="center">
|
|
@@ -166,3 +167,7 @@ The `run` method takes the following **optional** arguments:
|
|
|
166
167
|
|
|
167
168
|
[29/10/2024]
|
|
168
169
|
- [v2.3.0] Set `shell=True` to support piping.
|
|
170
|
+
- [v2.3.1] Kill FFmpeg process(es) on KeyboardInterrupt
|
|
171
|
+
|
|
172
|
+
[31/10/2024]
|
|
173
|
+
- [v2.4.0] Print FFmpeg stderr if better progress information cannot be shown.
|
|
@@ -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="2.
|
|
8
|
+
version="2.4.0",
|
|
9
9
|
author="GitHub.com/CrypticSignal",
|
|
10
10
|
author_email="theaudiophile@outlook.com",
|
|
11
11
|
description="Run FFmpeg & see percentage progress + ETA.",
|
|
@@ -13,7 +13,7 @@ setuptools.setup(
|
|
|
13
13
|
long_description_content_type="text/markdown",
|
|
14
14
|
url="https://github.com/CrypticSignal/better-ffmpeg-progress",
|
|
15
15
|
packages=["better_ffmpeg_progress"],
|
|
16
|
-
install_requires=["ffmpeg-python", "rich"],
|
|
16
|
+
install_requires=["ffmpeg-python", "psutil", "rich"],
|
|
17
17
|
python_requires=">=3.7",
|
|
18
18
|
keywords=["ffmpeg", "progress"],
|
|
19
19
|
classifiers=[
|
|
File without changes
|
{better_ffmpeg_progress-2.3.0 → better_ffmpeg_progress-2.4.0}/better_ffmpeg_progress/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|