auto-editor 25.3.0__py3-none-any.whl → 26.0.0__py3-none-any.whl
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.
- auto_editor/__init__.py +1 -1
- auto_editor/__main__.py +67 -16
- auto_editor/analyze.py +11 -14
- auto_editor/edit.py +177 -52
- auto_editor/ffwrapper.py +36 -114
- auto_editor/help.py +4 -3
- auto_editor/output.py +22 -183
- auto_editor/render/audio.py +66 -57
- auto_editor/render/subtitle.py +74 -13
- auto_editor/render/video.py +166 -180
- auto_editor/subcommands/repl.py +12 -3
- auto_editor/subcommands/test.py +47 -36
- auto_editor/utils/container.py +2 -0
- auto_editor/utils/func.py +1 -27
- auto_editor/utils/types.py +2 -15
- {auto_editor-25.3.0.dist-info → auto_editor-26.0.0.dist-info}/METADATA +2 -2
- {auto_editor-25.3.0.dist-info → auto_editor-26.0.0.dist-info}/RECORD +22 -24
- {auto_editor-25.3.0.dist-info → auto_editor-26.0.0.dist-info}/WHEEL +1 -1
- docs/build.py +1 -0
- auto_editor/utils/subtitle_tools.py +0 -29
- auto_editor/validate_input.py +0 -88
- {auto_editor-25.3.0.dist-info → auto_editor-26.0.0.dist-info}/LICENSE +0 -0
- {auto_editor-25.3.0.dist-info → auto_editor-26.0.0.dist-info}/entry_points.txt +0 -0
- {auto_editor-25.3.0.dist-info → auto_editor-26.0.0.dist-info}/top_level.txt +0 -0
auto_editor/subcommands/test.py
CHANGED
@@ -141,7 +141,10 @@ def run_tests(tests: list[Callable], args: TestArgs) -> None:
|
|
141
141
|
except Exception as e:
|
142
142
|
dur = perf_counter() - start
|
143
143
|
total_time += dur
|
144
|
-
print(
|
144
|
+
print(
|
145
|
+
f"{name:<24} ({index}/{total}) {round(dur, 2):<4} secs \033[1;31m[FAILED]\033[0m",
|
146
|
+
flush=True,
|
147
|
+
)
|
145
148
|
if args.no_fail_fast:
|
146
149
|
print(f"\n{e}")
|
147
150
|
else:
|
@@ -150,8 +153,10 @@ def run_tests(tests: list[Callable], args: TestArgs) -> None:
|
|
150
153
|
raise e
|
151
154
|
else:
|
152
155
|
passed += 1
|
153
|
-
print(
|
154
|
-
|
156
|
+
print(
|
157
|
+
f"{name:<24} ({index}/{total}) {round(dur, 2):<4} secs [\033[1;32mPASSED\033[0m]",
|
158
|
+
flush=True,
|
159
|
+
)
|
155
160
|
if outputs is not None:
|
156
161
|
if isinstance(outputs, str):
|
157
162
|
outputs = [outputs]
|
@@ -186,7 +191,7 @@ def main(sys_args: list[str] | None = None):
|
|
186
191
|
"wav/pcm-f32le.wav",
|
187
192
|
"wav/pcm-s32le.wav",
|
188
193
|
"multi-track.mov",
|
189
|
-
"
|
194
|
+
"mov_text.mp4",
|
190
195
|
"testsrc.mkv",
|
191
196
|
)
|
192
197
|
|
@@ -222,7 +227,8 @@ def main(sys_args: list[str] | None = None):
|
|
222
227
|
run.raw(["levels", "resources/new-commentary.mp3"])
|
223
228
|
|
224
229
|
def subdump():
|
225
|
-
run.raw(["subdump", "resources/
|
230
|
+
run.raw(["subdump", "resources/mov_text.mp4"])
|
231
|
+
run.raw(["subdump", "resources/webvtt.mkv"])
|
226
232
|
|
227
233
|
def desc():
|
228
234
|
run.raw(["desc", "example.mp4"])
|
@@ -233,7 +239,7 @@ def main(sys_args: list[str] | None = None):
|
|
233
239
|
video = cn.videos[0]
|
234
240
|
|
235
241
|
assert video.fps == 30
|
236
|
-
assert video.time_base == Fraction(1, 30)
|
242
|
+
# assert video.time_base == Fraction(1, 30)
|
237
243
|
assert video.width == 1280
|
238
244
|
assert video.height == 720
|
239
245
|
assert video.codec == "h264"
|
@@ -338,7 +344,10 @@ def main(sys_args: list[str] | None = None):
|
|
338
344
|
)
|
339
345
|
|
340
346
|
def track_tests():
|
341
|
-
|
347
|
+
out = run.main(["resources/multi-track.mov"], ["--keep_tracks_seperate"])
|
348
|
+
assert len(fileinfo(out).audios) == 2
|
349
|
+
|
350
|
+
return out
|
342
351
|
|
343
352
|
def export_json_tests():
|
344
353
|
out = run.main(["example.mp4"], ["--export_as_json"])
|
@@ -357,7 +366,13 @@ def main(sys_args: list[str] | None = None):
|
|
357
366
|
run.main(["example.mp4"], ["--export", 'premiere:name="Foo Bar"'])
|
358
367
|
|
359
368
|
def export_subtitles():
|
360
|
-
cn = fileinfo(run.main(["resources/
|
369
|
+
# cn = fileinfo(run.main(["resources/mov_text.mp4"], []))
|
370
|
+
|
371
|
+
# assert len(cn.videos) == 1
|
372
|
+
# assert len(cn.audios) == 1
|
373
|
+
# assert len(cn.subtitles) == 1
|
374
|
+
|
375
|
+
cn = fileinfo(run.main(["resources/webvtt.mkv"], []))
|
361
376
|
|
362
377
|
assert len(cn.videos) == 1
|
363
378
|
assert len(cn.audios) == 1
|
@@ -458,47 +473,44 @@ def main(sys_args: list[str] | None = None):
|
|
458
473
|
def frame_rate():
|
459
474
|
cn = fileinfo(run.main(["example.mp4"], ["-r", "15", "--no-seek"]))
|
460
475
|
video = cn.videos[0]
|
461
|
-
assert video.fps == 15
|
462
|
-
assert video.
|
463
|
-
assert float(video.duration) - 17.33333333333333333333333 < 3
|
476
|
+
assert video.fps == 15, video.fps
|
477
|
+
assert video.duration - 17.33333333333333333333333 < 3, video.duration
|
464
478
|
|
465
479
|
cn = fileinfo(run.main(["example.mp4"], ["-r", "20"]))
|
466
480
|
video = cn.videos[0]
|
467
|
-
assert video.fps == 20
|
468
|
-
assert video.
|
469
|
-
assert float(video.duration) - 17.33333333333333333333333 < 2
|
481
|
+
assert video.fps == 20, video.fps
|
482
|
+
assert video.duration - 17.33333333333333333333333 < 2
|
470
483
|
|
471
484
|
cn = fileinfo(out := run.main(["example.mp4"], ["-r", "60"]))
|
472
485
|
video = cn.videos[0]
|
473
486
|
|
474
|
-
assert video.fps == 60
|
475
|
-
assert video.
|
476
|
-
assert float(video.duration) - 17.33333333333333333333333 < 0.3
|
487
|
+
assert video.fps == 60, video.fps
|
488
|
+
assert video.duration - 17.33333333333333333333333 < 0.3
|
477
489
|
|
478
490
|
return out
|
479
491
|
|
480
|
-
def embedded_image():
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
492
|
+
# def embedded_image():
|
493
|
+
# out1 = run.main(["resources/embedded-image/h264-png.mp4"], [])
|
494
|
+
# cn = fileinfo(out1)
|
495
|
+
# assert cn.videos[0].codec == "h264"
|
496
|
+
# assert cn.videos[1].codec == "png"
|
485
497
|
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
498
|
+
# out2 = run.main(["resources/embedded-image/h264-mjpeg.mp4"], [])
|
499
|
+
# cn = fileinfo(out2)
|
500
|
+
# assert cn.videos[0].codec == "h264"
|
501
|
+
# assert cn.videos[1].codec == "mjpeg"
|
490
502
|
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
503
|
+
# out3 = run.main(["resources/embedded-image/h264-png.mkv"], [])
|
504
|
+
# cn = fileinfo(out3)
|
505
|
+
# assert cn.videos[0].codec == "h264"
|
506
|
+
# assert cn.videos[1].codec == "png"
|
495
507
|
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
508
|
+
# out4 = run.main(["resources/embedded-image/h264-mjpeg.mkv"], [])
|
509
|
+
# cn = fileinfo(out4)
|
510
|
+
# assert cn.videos[0].codec == "h264"
|
511
|
+
# assert cn.videos[1].codec == "mjpeg"
|
500
512
|
|
501
|
-
|
513
|
+
# return out1, out2, out3, out4
|
502
514
|
|
503
515
|
def motion():
|
504
516
|
out = run.main(
|
@@ -744,7 +756,6 @@ def main(sys_args: list[str] | None = None):
|
|
744
756
|
sr_units,
|
745
757
|
backwards_range,
|
746
758
|
cut_out,
|
747
|
-
embedded_image,
|
748
759
|
gif,
|
749
760
|
margin_tests,
|
750
761
|
input_extension,
|
auto_editor/utils/container.py
CHANGED
auto_editor/utils/func.py
CHANGED
@@ -10,8 +10,6 @@ if TYPE_CHECKING:
|
|
10
10
|
|
11
11
|
from numpy.typing import NDArray
|
12
12
|
|
13
|
-
from auto_editor.utils.log import Log
|
14
|
-
|
15
13
|
BoolList = NDArray[np.bool_]
|
16
14
|
BoolOperand = Callable[[BoolList, BoolList], BoolList]
|
17
15
|
|
@@ -43,7 +41,7 @@ def to_timecode(secs: float | Fraction, fmt: str) -> str:
|
|
43
41
|
if h == 0:
|
44
42
|
return f"{sign}{m:02d}:{s:06.3f}"
|
45
43
|
return f"{sign}{h:02d}:{m:02d}:{s:06.3f}"
|
46
|
-
if fmt == "mov_text":
|
44
|
+
if fmt == "srt" or fmt == "mov_text":
|
47
45
|
return f"{sign}{h:02d}:{m:02d}:" + f"{s:06.3f}".replace(".", ",", 1)
|
48
46
|
if fmt == "standard":
|
49
47
|
return f"{sign}{h:02d}:{m:02d}:{s:06.3f}"
|
@@ -135,30 +133,6 @@ def human_readable_time(time_in_secs: float) -> str:
|
|
135
133
|
return f"{time_in_secs} {units}"
|
136
134
|
|
137
135
|
|
138
|
-
def open_with_system_default(path: str, log: Log) -> None:
|
139
|
-
import sys
|
140
|
-
from subprocess import run
|
141
|
-
|
142
|
-
if sys.platform == "win32":
|
143
|
-
from os import startfile
|
144
|
-
|
145
|
-
try:
|
146
|
-
startfile(path)
|
147
|
-
except OSError:
|
148
|
-
log.warning("Could not find application to open file.")
|
149
|
-
else:
|
150
|
-
try: # MacOS case
|
151
|
-
run(["open", path])
|
152
|
-
except Exception:
|
153
|
-
try: # WSL2 case
|
154
|
-
run(["cmd.exe", "/C", "start", path])
|
155
|
-
except Exception:
|
156
|
-
try: # Linux case
|
157
|
-
run(["xdg-open", path])
|
158
|
-
except Exception:
|
159
|
-
log.warning("Could not open output file.")
|
160
|
-
|
161
|
-
|
162
136
|
def append_filename(path: str, val: str) -> str:
|
163
137
|
from os.path import splitext
|
164
138
|
|
auto_editor/utils/types.py
CHANGED
@@ -111,17 +111,6 @@ def sample_rate(val: str) -> int:
|
|
111
111
|
return natural(num)
|
112
112
|
|
113
113
|
|
114
|
-
def bitrate(val: str) -> str:
|
115
|
-
if val == "unset":
|
116
|
-
return val
|
117
|
-
_num, unit = _split_num_str(val)
|
118
|
-
num = int(_num) if _num.is_integer() else _num
|
119
|
-
if unit not in ("", "k", "K", "M"):
|
120
|
-
extra = f". Did you mean `{num}M`?" if unit == "m" else ""
|
121
|
-
raise CoerceError(f"`{val}` is not a valid bitrate format{extra}")
|
122
|
-
return val
|
123
|
-
|
124
|
-
|
125
114
|
def time(val: str, tb: Fraction) -> int:
|
126
115
|
if ":" in val:
|
127
116
|
boxes = val.split(":")
|
@@ -218,11 +207,9 @@ class Args:
|
|
218
207
|
yt_dlp_extras: str | None = None
|
219
208
|
video_codec: str = "auto"
|
220
209
|
audio_codec: str = "auto"
|
221
|
-
video_bitrate: str = "
|
222
|
-
audio_bitrate: str = "
|
223
|
-
video_quality_scale: str = "unset"
|
210
|
+
video_bitrate: str = "auto"
|
211
|
+
audio_bitrate: str = "auto"
|
224
212
|
scale: float = 1.0
|
225
|
-
extras: str | None = None
|
226
213
|
sn: bool = False
|
227
214
|
dn: bool = False
|
228
215
|
no_seek: bool = False
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: auto-editor
|
3
|
-
Version:
|
3
|
+
Version: 26.0.0
|
4
4
|
Summary: Auto-Editor: Effort free video editing!
|
5
5
|
Author-email: WyattBlue <wyattblue@auto-editor.com>
|
6
6
|
License: Unlicense
|
@@ -12,7 +12,7 @@ Requires-Python: <3.14,>=3.10
|
|
12
12
|
Description-Content-Type: text/markdown
|
13
13
|
License-File: LICENSE
|
14
14
|
Requires-Dist: numpy <3.0,>=1.23.0
|
15
|
-
Requires-Dist: pyav ==13.
|
15
|
+
Requires-Dist: pyav ==13.1.*
|
16
16
|
Requires-Dist: ae-ffmpeg ==1.2.*
|
17
17
|
|
18
18
|
<p align="center"><img src="https://auto-editor.com/img/auto-editor-banner.webp" title="Auto-Editor" width="700"></p>
|
@@ -1,14 +1,13 @@
|
|
1
|
-
auto_editor/__init__.py,sha256=
|
2
|
-
auto_editor/__main__.py,sha256=
|
3
|
-
auto_editor/analyze.py,sha256=
|
4
|
-
auto_editor/edit.py,sha256=
|
5
|
-
auto_editor/ffwrapper.py,sha256=
|
6
|
-
auto_editor/help.py,sha256=
|
1
|
+
auto_editor/__init__.py,sha256=WK8aO_sVSNz80fWXrArodylgnY_BkbEjGQlGWEzflks,23
|
2
|
+
auto_editor/__main__.py,sha256=ktxF22s9uR8U0rtB8TV-2Kj0hwjzyb2k7e1A1_yAJwQ,12006
|
3
|
+
auto_editor/analyze.py,sha256=uCi21659BB-lbPwZ6yxNLekS6Q3yoB2ypLNXPhmhTfg,11688
|
4
|
+
auto_editor/edit.py,sha256=DwkFnWs__F9RNz_7E_fgT93sJywAerhx75Xz4aw3Nls,16728
|
5
|
+
auto_editor/ffwrapper.py,sha256=XB-N0ex8zkIcItnr9kilC6SSf0TjUI7og-U5Q8H3BJ0,6059
|
6
|
+
auto_editor/help.py,sha256=62s3L0rlhA7nkkOjtXItRUl779EJ__A7_6E-VFH3J_E,7924
|
7
7
|
auto_editor/make_layers.py,sha256=8uFy5SvMArAP-5slYJrxa_iGAEwimQBFeM-T01VORVw,8995
|
8
|
-
auto_editor/output.py,sha256=
|
8
|
+
auto_editor/output.py,sha256=9YBBEASsXpxuBQJeGTQ5Ed8a0Fr8660DjJ85LeSrPe8,2502
|
9
9
|
auto_editor/preview.py,sha256=HUsjmV9Fx73rZ26BXrpz9z-z_e4oiui3u9e7qbbGoBY,3037
|
10
10
|
auto_editor/timeline.py,sha256=tIty8O8jD6TR2Sw2bivUtYtdnpplfuOXT7Dfc-gekr8,8174
|
11
|
-
auto_editor/validate_input.py,sha256=_9vtbNxodhVPf4PzTAH67LSj2K-HS6kShJOARmUMJdY,2904
|
12
11
|
auto_editor/vanparse.py,sha256=f0vViZ-aYtDxEyVrFHJ5X2pPTQAfqtw3N2gZgzn51kU,10002
|
13
12
|
auto_editor/wavfile.py,sha256=1HbZ4L8IBD6Fbg3pd5MQG4ZXy48YZA05t8XllSplhWk,9499
|
14
13
|
auto_editor/formats/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -28,31 +27,30 @@ auto_editor/lib/contracts.py,sha256=lExGQymcQUmwG5lC1lO4qm4GY8W0q_yzK_miTaAoPA4,
|
|
28
27
|
auto_editor/lib/data_structs.py,sha256=dcsXgsLLzbmFDUZucoirzewPALsKzoxz7z5L22_QJM8,7091
|
29
28
|
auto_editor/lib/err.py,sha256=UlszQJdzMZwkbT8x3sY4GkCV_5x9yrd6uVVUzvA8iiI,35
|
30
29
|
auto_editor/render/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
31
|
-
auto_editor/render/audio.py,sha256=
|
32
|
-
auto_editor/render/subtitle.py,sha256=
|
33
|
-
auto_editor/render/video.py,sha256=
|
30
|
+
auto_editor/render/audio.py,sha256=OWkpKtB9cdcJztTTOPe6ONgWAnvuotKD1A_28gfart4,10675
|
31
|
+
auto_editor/render/subtitle.py,sha256=TTUGO77L_iGm9Qkjq5LGERjECA2xriSV9G1fN_SQiqM,6200
|
32
|
+
auto_editor/render/video.py,sha256=l1qgnS1ArAOdq_db8vIHcvtZiMCX1jF20lqYhZHMxik,12264
|
34
33
|
auto_editor/subcommands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
35
34
|
auto_editor/subcommands/desc.py,sha256=GDrKJYiHMaeTrplZAceXl1JwoqD78XsV2_5lc0Xd7po,869
|
36
35
|
auto_editor/subcommands/info.py,sha256=t5n43HLt9hpMFSIfGV777X4zIPBAFugOKlpCfRjiKxY,6921
|
37
36
|
auto_editor/subcommands/levels.py,sha256=ChJMDTd34-jgxewqHRmmd3VNhFdy964w0DcQG0ls-hY,4079
|
38
37
|
auto_editor/subcommands/palet.py,sha256=ONzTqemaQq9YEfIOsDRNnwzfqnEMUMSXIQrETxyroRU,749
|
39
|
-
auto_editor/subcommands/repl.py,sha256=
|
38
|
+
auto_editor/subcommands/repl.py,sha256=TF_I7zsFY7-KdgidrqjafTz7o_eluVbLvgTcOBG-UWQ,3449
|
40
39
|
auto_editor/subcommands/subdump.py,sha256=af_XBf7kaevqHn1A71z8C-7x8pS5WKD9FE_ugkCw6rk,665
|
41
|
-
auto_editor/subcommands/test.py,sha256=
|
40
|
+
auto_editor/subcommands/test.py,sha256=rM6ihsmYyW745lpFVeGwWbRHLTEymLhm1pRpmm7LdAo,25776
|
42
41
|
auto_editor/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
43
42
|
auto_editor/utils/bar.py,sha256=hG_NiYeuM90TdILzAJORft-UOS5grwWN3SbRuj6upsI,3998
|
44
43
|
auto_editor/utils/chunks.py,sha256=J-eGKtEz68gFtRrj1kOSgH4Tj_Yz6prNQ7Xr-d9NQJw,52
|
45
44
|
auto_editor/utils/cmdkw.py,sha256=uW_qDGQ6UzLPRbB20HTLrCmhMlWVXSfgyQMr4MyGErU,5734
|
46
|
-
auto_editor/utils/container.py,sha256=
|
45
|
+
auto_editor/utils/container.py,sha256=ajIiMRu5ZoBxRkGgR4UZORMgsD6fwl1pT2C3aoI5FcM,2785
|
47
46
|
auto_editor/utils/encoder.py,sha256=auNYo7HXbcU4iTUCc0LE5lpwFmSvdWvBm6-5KIaRK8w,2983
|
48
|
-
auto_editor/utils/func.py,sha256=
|
47
|
+
auto_editor/utils/func.py,sha256=hASpY8zr41cBIByKY8zZUZGVqDz7B0snwV1RYODbKD8,3741
|
49
48
|
auto_editor/utils/log.py,sha256=M2QKeQHMRNLm3HMVUKedZPRprT2u5dipOStiO4miPBk,3613
|
50
|
-
auto_editor/utils/
|
51
|
-
|
52
|
-
|
53
|
-
auto_editor-
|
54
|
-
auto_editor-
|
55
|
-
auto_editor-
|
56
|
-
auto_editor-
|
57
|
-
auto_editor-
|
58
|
-
auto_editor-25.3.0.dist-info/RECORD,,
|
49
|
+
auto_editor/utils/types.py,sha256=FWa3SnOATMa_MSTjpdasl80b4WKTRIMLS0IlyYyMGxo,11043
|
50
|
+
docs/build.py,sha256=CM-ZWgQk8wSNjivx_-6wGIaG7cstrNKsX2d4TzFVivE,1642
|
51
|
+
auto_editor-26.0.0.dist-info/LICENSE,sha256=yiq99pWITHfqS0pbZMp7cy2dnbreTuvBwudsU-njvIM,1210
|
52
|
+
auto_editor-26.0.0.dist-info/METADATA,sha256=kHlPRQm-pu3oeW7_h3Ag1DIQYL_AwRvFkKx38yznj4k,6148
|
53
|
+
auto_editor-26.0.0.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
|
54
|
+
auto_editor-26.0.0.dist-info/entry_points.txt,sha256=-H7zdTw4MqnAcwrN5xTNkGIhzZtJMxS9r6lTMeR9-aA,240
|
55
|
+
auto_editor-26.0.0.dist-info/top_level.txt,sha256=jBV5zlbWRbKOa-xaWPvTD45QL7lGExx2BDzv-Ji4dTw,17
|
56
|
+
auto_editor-26.0.0.dist-info/RECORD,,
|
docs/build.py
CHANGED
@@ -1,29 +0,0 @@
|
|
1
|
-
def convert_ass_to_text(ass_text: str) -> str:
|
2
|
-
result = ""
|
3
|
-
comma_count = i = 0
|
4
|
-
|
5
|
-
while comma_count < 8 and i < len(ass_text):
|
6
|
-
if ass_text[i] == ",":
|
7
|
-
comma_count += 1
|
8
|
-
i += 1
|
9
|
-
|
10
|
-
state = False
|
11
|
-
while i < len(ass_text):
|
12
|
-
char = ass_text[i]
|
13
|
-
next_char = "" if i + 1 >= len(ass_text) else ass_text[i + 1]
|
14
|
-
|
15
|
-
if char == "\\" and next_char == "N":
|
16
|
-
result += "\n"
|
17
|
-
i += 2
|
18
|
-
continue
|
19
|
-
|
20
|
-
if not state:
|
21
|
-
if char == "{":
|
22
|
-
state = True
|
23
|
-
else:
|
24
|
-
result += ass_text[i]
|
25
|
-
elif char == "}":
|
26
|
-
state = False
|
27
|
-
i += 1
|
28
|
-
|
29
|
-
return result
|
auto_editor/validate_input.py
DELETED
@@ -1,88 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
|
-
import re
|
4
|
-
import subprocess
|
5
|
-
import sys
|
6
|
-
from os.path import exists, isdir, isfile, lexists, splitext
|
7
|
-
|
8
|
-
from auto_editor.ffwrapper import FFmpeg
|
9
|
-
from auto_editor.utils.func import get_stdout
|
10
|
-
from auto_editor.utils.log import Log
|
11
|
-
from auto_editor.utils.types import Args
|
12
|
-
|
13
|
-
|
14
|
-
def get_domain(url: str) -> str:
|
15
|
-
from urllib.parse import urlparse
|
16
|
-
|
17
|
-
t = urlparse(url).netloc
|
18
|
-
return ".".join(t.split(".")[-2:])
|
19
|
-
|
20
|
-
|
21
|
-
def download_video(my_input: str, args: Args, ffmpeg: FFmpeg, log: Log) -> str:
|
22
|
-
log.conwrite("Downloading video...")
|
23
|
-
|
24
|
-
download_format = args.download_format
|
25
|
-
|
26
|
-
if download_format is None and get_domain(my_input) == "youtube.com":
|
27
|
-
download_format = "bestvideo[ext=mp4]+bestaudio[ext=m4a]"
|
28
|
-
|
29
|
-
if args.output_format is None:
|
30
|
-
output_format = re.sub(r"\W+", "-", splitext(my_input)[0]) + ".%(ext)s"
|
31
|
-
else:
|
32
|
-
output_format = args.output_format
|
33
|
-
|
34
|
-
yt_dlp_path = args.yt_dlp_location
|
35
|
-
|
36
|
-
cmd = ["--ffmpeg-location", ffmpeg.path]
|
37
|
-
|
38
|
-
if download_format is not None:
|
39
|
-
cmd.extend(["-f", download_format])
|
40
|
-
|
41
|
-
cmd.extend(["-o", output_format, my_input])
|
42
|
-
|
43
|
-
if args.yt_dlp_extras is not None:
|
44
|
-
cmd.extend(args.yt_dlp_extras.split(" "))
|
45
|
-
|
46
|
-
try:
|
47
|
-
location = get_stdout(
|
48
|
-
[yt_dlp_path, "--get-filename", "--no-warnings"] + cmd
|
49
|
-
).strip()
|
50
|
-
except FileNotFoundError:
|
51
|
-
msg = "Could not find program 'yt-dlp' when attempting to download a URL. Install yt-dlp with "
|
52
|
-
if sys.platform == "win32":
|
53
|
-
msg += "your favorite package manager (pip, choco, winget)."
|
54
|
-
elif sys.platform == "darwin":
|
55
|
-
msg += "brew or pip and make sure it's in PATH."
|
56
|
-
else:
|
57
|
-
msg += "pip or your favorite package manager and make sure it's in PATH."
|
58
|
-
log.error(msg)
|
59
|
-
|
60
|
-
if not isfile(location):
|
61
|
-
subprocess.run([yt_dlp_path] + cmd)
|
62
|
-
|
63
|
-
if not isfile(location):
|
64
|
-
log.error(f"Download file wasn't created: {location}")
|
65
|
-
|
66
|
-
return location
|
67
|
-
|
68
|
-
|
69
|
-
def valid_input(inputs: list[str], ffmpeg: FFmpeg, args: Args, log: Log) -> list[str]:
|
70
|
-
result = []
|
71
|
-
|
72
|
-
for my_input in inputs:
|
73
|
-
if my_input.startswith("http://") or my_input.startswith("https://"):
|
74
|
-
result.append(download_video(my_input, args, ffmpeg, log))
|
75
|
-
else:
|
76
|
-
_, ext = splitext(my_input)
|
77
|
-
if ext == "":
|
78
|
-
if isdir(my_input):
|
79
|
-
log.error("Input must be a file or a URL, not a directory.")
|
80
|
-
if exists(my_input):
|
81
|
-
log.error(f"Input file must have an extension: {my_input}")
|
82
|
-
if lexists(my_input):
|
83
|
-
log.error(f"Input file is a broken symbolic link: {my_input}")
|
84
|
-
if my_input.startswith("-"):
|
85
|
-
log.error(f"Option/Input file doesn't exist: {my_input}")
|
86
|
-
result.append(my_input)
|
87
|
-
|
88
|
-
return result
|
File without changes
|
File without changes
|
File without changes
|