auto-editor 26.3.0__py3-none-any.whl → 26.3.2__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 +37 -22
- auto_editor/analyze.py +47 -52
- auto_editor/cmds/levels.py +1 -3
- auto_editor/cmds/repl.py +2 -3
- auto_editor/cmds/test.py +336 -386
- auto_editor/edit.py +113 -28
- auto_editor/lang/palet.py +23 -27
- auto_editor/make_layers.py +28 -17
- auto_editor/preview.py +3 -2
- auto_editor/utils/bar.py +16 -10
- auto_editor/utils/log.py +1 -10
- auto_editor/utils/types.py +2 -0
- {auto_editor-26.3.0.dist-info → auto_editor-26.3.2.dist-info}/METADATA +2 -2
- {auto_editor-26.3.0.dist-info → auto_editor-26.3.2.dist-info}/RECORD +19 -19
- {auto_editor-26.3.0.dist-info → auto_editor-26.3.2.dist-info}/WHEEL +1 -1
- {auto_editor-26.3.0.dist-info → auto_editor-26.3.2.dist-info}/LICENSE +0 -0
- {auto_editor-26.3.0.dist-info → auto_editor-26.3.2.dist-info}/entry_points.txt +0 -0
- {auto_editor-26.3.0.dist-info → auto_editor-26.3.2.dist-info}/top_level.txt +0 -0
auto_editor/edit.py
CHANGED
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
3
3
|
import os
|
4
4
|
import sys
|
5
5
|
from fractions import Fraction
|
6
|
+
from heapq import heappop, heappush
|
6
7
|
from os.path import splitext
|
7
8
|
from subprocess import run
|
8
9
|
from typing import Any
|
@@ -296,7 +297,15 @@ def edit_media(paths: list[str], args: Args, log: Log) -> None:
|
|
296
297
|
def make_media(tl: v3, output_path: str) -> None:
|
297
298
|
assert src is not None
|
298
299
|
|
299
|
-
|
300
|
+
if args.fragmented and not args.no_fragmented:
|
301
|
+
log.debug("Enabling fragmented mp4/mov")
|
302
|
+
options = {
|
303
|
+
"movflags": "+default_base_moof+faststart+frag_keyframe+separate_moof",
|
304
|
+
"frag_duration": "0.2",
|
305
|
+
}
|
306
|
+
else:
|
307
|
+
options = {"movflags": "faststart"}
|
308
|
+
output = av.open(output_path, "w", options=options)
|
300
309
|
|
301
310
|
if ctr.default_sub != "none" and not args.sn:
|
302
311
|
sub_paths = make_new_subtitles(tl, log)
|
@@ -309,6 +318,13 @@ def edit_media(paths: list[str], args: Args, log: Log) -> None:
|
|
309
318
|
else:
|
310
319
|
audio_paths = []
|
311
320
|
|
321
|
+
# Setup video
|
322
|
+
if ctr.default_vid != "none" and tl.v:
|
323
|
+
vframes = render_av(output, tl, args, log)
|
324
|
+
output_stream = next(vframes)
|
325
|
+
else:
|
326
|
+
output_stream, vframes = None, iter([])
|
327
|
+
|
312
328
|
# Setup audio
|
313
329
|
if audio_paths:
|
314
330
|
try:
|
@@ -363,23 +379,16 @@ def edit_media(paths: list[str], args: Args, log: Log) -> None:
|
|
363
379
|
subtitle_streams.append(subtitle_stream)
|
364
380
|
sub_gen_frames.append(subtitle_input.demux(subtitles=0))
|
365
381
|
|
366
|
-
# Setup video
|
367
|
-
if ctr.default_vid != "none" and tl.v:
|
368
|
-
vframes = render_av(output, tl, args, log)
|
369
|
-
output_stream = next(vframes)
|
370
|
-
else:
|
371
|
-
output_stream, vframes = None, iter([])
|
372
|
-
|
373
382
|
no_color = log.no_color or log.machine
|
374
383
|
encoder_titles = []
|
375
384
|
if output_stream is not None:
|
376
385
|
name = output_stream.codec.canonical_name
|
377
386
|
encoder_titles.append(name if no_color else f"\033[95m{name}")
|
378
387
|
if audio_streams:
|
379
|
-
name = audio_streams[0].
|
388
|
+
name = audio_streams[0].codec.canonical_name
|
380
389
|
encoder_titles.append(name if no_color else f"\033[96m{name}")
|
381
390
|
if subtitle_streams:
|
382
|
-
name = subtitle_streams[0].
|
391
|
+
name = subtitle_streams[0].codec.canonical_name
|
383
392
|
encoder_titles.append(name if no_color else f"\033[32m{name}")
|
384
393
|
|
385
394
|
title = f"({os.path.splitext(output_path)[1][1:]}) "
|
@@ -389,11 +398,71 @@ def edit_media(paths: list[str], args: Args, log: Log) -> None:
|
|
389
398
|
title += "\033[0m+".join(encoder_titles) + "\033[0m"
|
390
399
|
bar.start(tl.end, title)
|
391
400
|
|
392
|
-
#
|
401
|
+
MAX_AUDIO_AHEAD = 30 # In timebase, how far audio can be ahead of video.
|
402
|
+
MAX_SUB_AHEAD = 30
|
403
|
+
|
404
|
+
class Priority:
|
405
|
+
__slots__ = ("index", "frame_type", "frame", "stream")
|
406
|
+
|
407
|
+
def __init__(self, value: int | Fraction, frame, stream):
|
408
|
+
self.frame_type: str = stream.type
|
409
|
+
assert self.frame_type in ("audio", "subtitle", "video")
|
410
|
+
if self.frame_type in {"audio", "subtitle"}:
|
411
|
+
self.index: int | float = round(value * frame.time_base * tl.tb)
|
412
|
+
else:
|
413
|
+
self.index = float("inf") if value is None else int(value)
|
414
|
+
self.frame = frame
|
415
|
+
self.stream = stream
|
416
|
+
|
417
|
+
def __lt__(self, other):
|
418
|
+
return self.index < other.index
|
419
|
+
|
420
|
+
def __eq__(self, other):
|
421
|
+
return self.index == other.index
|
422
|
+
|
423
|
+
# Priority queue for ordered frames by time_base.
|
424
|
+
frame_queue: list[Priority] = []
|
425
|
+
latest_audio_index = float("-inf")
|
426
|
+
latest_sub_index = float("-inf")
|
427
|
+
earliest_video_index = None
|
428
|
+
|
393
429
|
while True:
|
394
|
-
|
430
|
+
if earliest_video_index is None:
|
431
|
+
should_get_audio = True
|
432
|
+
should_get_sub = True
|
433
|
+
else:
|
434
|
+
for item in frame_queue:
|
435
|
+
if item.frame_type == "audio":
|
436
|
+
latest_audio_index = max(latest_audio_index, item.index)
|
437
|
+
elif item.frame_type == "subtitle":
|
438
|
+
latest_sub_index = max(latest_sub_index, item.index)
|
439
|
+
|
440
|
+
should_get_audio = (
|
441
|
+
latest_audio_index <= earliest_video_index + MAX_AUDIO_AHEAD
|
442
|
+
)
|
443
|
+
should_get_sub = (
|
444
|
+
latest_sub_index <= earliest_video_index + MAX_SUB_AHEAD
|
445
|
+
)
|
446
|
+
|
395
447
|
index, video_frame = next(vframes, (0, None))
|
396
|
-
|
448
|
+
|
449
|
+
if video_frame:
|
450
|
+
earliest_video_index = index
|
451
|
+
heappush(frame_queue, Priority(index, video_frame, output_stream))
|
452
|
+
|
453
|
+
if should_get_audio:
|
454
|
+
audio_frames = [next(frames, None) for frames in audio_gen_frames]
|
455
|
+
if output_stream is None and audio_frames and audio_frames[-1]:
|
456
|
+
assert audio_frames[-1].time is not None
|
457
|
+
index = round(audio_frames[-1].time * tl.tb)
|
458
|
+
else:
|
459
|
+
audio_frames = [None]
|
460
|
+
if should_get_sub:
|
461
|
+
subtitle_frames = [next(packet, None) for packet in sub_gen_frames]
|
462
|
+
else:
|
463
|
+
subtitle_frames = [None]
|
464
|
+
|
465
|
+
# Break if no more frames
|
397
466
|
if (
|
398
467
|
all(frame is None for frame in audio_frames)
|
399
468
|
and video_frame is None
|
@@ -401,29 +470,45 @@ def edit_media(paths: list[str], args: Args, log: Log) -> None:
|
|
401
470
|
):
|
402
471
|
break
|
403
472
|
|
404
|
-
|
405
|
-
|
473
|
+
if should_get_audio:
|
474
|
+
for audio_stream, audio_frame in zip(audio_streams, audio_frames):
|
406
475
|
for reframe in resampler.resample(audio_frame):
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
476
|
+
assert reframe.pts is not None
|
477
|
+
heappush(
|
478
|
+
frame_queue,
|
479
|
+
Priority(reframe.pts, reframe, audio_stream),
|
480
|
+
)
|
481
|
+
if should_get_sub:
|
482
|
+
for subtitle_stream, packet in zip(subtitle_streams, subtitle_frames):
|
483
|
+
if packet and packet.pts is not None:
|
484
|
+
packet.stream = subtitle_stream
|
485
|
+
heappush(
|
486
|
+
frame_queue, Priority(packet.pts, packet, subtitle_stream)
|
487
|
+
)
|
488
|
+
|
489
|
+
while frame_queue and frame_queue[0].index <= index:
|
490
|
+
item = heappop(frame_queue)
|
491
|
+
frame_type = item.frame_type
|
492
|
+
bar_index = None
|
416
493
|
try:
|
417
|
-
|
494
|
+
if frame_type in {"video", "audio"}:
|
495
|
+
if item.frame.time is not None:
|
496
|
+
bar_index = round(item.frame.time * tl.tb)
|
497
|
+
output.mux(item.stream.encode(item.frame))
|
498
|
+
elif frame_type == "subtitle":
|
499
|
+
output.mux(item.frame)
|
418
500
|
except av.error.ExternalError:
|
419
501
|
log.error(
|
420
|
-
f"Generic error for encoder: {
|
421
|
-
"
|
502
|
+
f"Generic error for encoder: {item.stream.name}\n"
|
503
|
+
f"at {item.index} time_base\nPerhaps video quality settings are too low?"
|
422
504
|
)
|
505
|
+
except av.FileNotFoundError:
|
506
|
+
log.error(f"File not found: {output_path}")
|
423
507
|
except av.FFmpegError as e:
|
424
508
|
log.error(e)
|
425
509
|
|
426
|
-
|
510
|
+
if bar_index:
|
511
|
+
bar.tick(bar_index)
|
427
512
|
|
428
513
|
# Flush streams
|
429
514
|
if output_stream is not None:
|
auto_editor/lang/palet.py
CHANGED
@@ -9,11 +9,11 @@ from dataclasses import dataclass
|
|
9
9
|
from difflib import get_close_matches
|
10
10
|
from fractions import Fraction
|
11
11
|
from io import StringIO
|
12
|
-
from typing import TYPE_CHECKING
|
12
|
+
from typing import TYPE_CHECKING, cast
|
13
13
|
|
14
14
|
import numpy as np
|
15
15
|
|
16
|
-
from auto_editor.analyze import LevelError, mut_remove_small
|
16
|
+
from auto_editor.analyze import LevelError, Levels, mut_remove_small
|
17
17
|
from auto_editor.lib.contracts import *
|
18
18
|
from auto_editor.lib.data_structs import *
|
19
19
|
from auto_editor.lib.err import MyError
|
@@ -21,7 +21,7 @@ from auto_editor.utils.func import boolop
|
|
21
21
|
|
22
22
|
if TYPE_CHECKING:
|
23
23
|
from collections.abc import Callable
|
24
|
-
from typing import Any, NoReturn
|
24
|
+
from typing import Any, NoReturn, TypeGuard
|
25
25
|
|
26
26
|
from numpy.typing import NDArray
|
27
27
|
|
@@ -510,15 +510,16 @@ def p_slice(
|
|
510
510
|
return seq[start:end:step]
|
511
511
|
|
512
512
|
|
513
|
+
def is_boolean_array(v: object) -> TypeGuard[np.ndarray]:
|
514
|
+
return isinstance(v, np.ndarray) and v.dtype.kind == "b"
|
515
|
+
|
516
|
+
|
513
517
|
is_iterable = Contract(
|
514
518
|
"iterable?",
|
515
519
|
lambda v: type(v) in {str, range, list, tuple, dict, Quoted}
|
516
520
|
or isinstance(v, np.ndarray),
|
517
521
|
)
|
518
|
-
is_boolarr = Contract(
|
519
|
-
"bool-array?",
|
520
|
-
lambda v: isinstance(v, np.ndarray) and v.dtype.kind == "b",
|
521
|
-
)
|
522
|
+
is_boolarr = Contract("bool-array?", is_boolean_array)
|
522
523
|
|
523
524
|
|
524
525
|
def raise_(msg: str | Exception) -> NoReturn:
|
@@ -568,13 +569,10 @@ def edit_audio(
|
|
568
569
|
if "@levels" not in env:
|
569
570
|
raise MyError("Can't use `audio` if there's no input media")
|
570
571
|
|
571
|
-
levels = env["@levels"]
|
572
|
-
src = levels.src
|
573
|
-
strict = levels.strict
|
574
|
-
|
572
|
+
levels = cast(Levels, env["@levels"])
|
575
573
|
stream_data: NDArray[np.bool_] | None = None
|
576
574
|
if stream == Sym("all"):
|
577
|
-
stream_range = range(0, len(
|
575
|
+
stream_range = range(0, len(levels.container.streams.audio))
|
578
576
|
else:
|
579
577
|
assert isinstance(stream, int)
|
580
578
|
stream_range = range(stream, stream + 1)
|
@@ -586,17 +584,15 @@ def edit_audio(
|
|
586
584
|
stream_data = audio_list
|
587
585
|
else:
|
588
586
|
stream_data = boolop(stream_data, audio_list, np.logical_or)
|
589
|
-
except LevelError
|
590
|
-
|
591
|
-
|
592
|
-
if stream_data is not None:
|
593
|
-
mut_remove_small(stream_data, minclip, replace=1, with_=0)
|
594
|
-
mut_remove_small(stream_data, mincut, replace=0, with_=1)
|
587
|
+
except LevelError:
|
588
|
+
return np.array([], dtype=np.bool_)
|
595
589
|
|
596
|
-
|
590
|
+
if stream_data is None:
|
591
|
+
return np.array([], dtype=np.bool_)
|
597
592
|
|
598
|
-
|
599
|
-
|
593
|
+
mut_remove_small(stream_data, minclip, replace=1, with_=0)
|
594
|
+
mut_remove_small(stream_data, mincut, replace=0, with_=1)
|
595
|
+
return stream_data
|
600
596
|
|
601
597
|
|
602
598
|
def edit_motion(
|
@@ -608,18 +604,18 @@ def edit_motion(
|
|
608
604
|
if "@levels" not in env:
|
609
605
|
raise MyError("Can't use `motion` if there's no input media")
|
610
606
|
|
611
|
-
levels = env["@levels"]
|
607
|
+
levels = cast(Levels, env["@levels"])
|
612
608
|
try:
|
613
609
|
return levels.motion(stream, blur, width) >= threshold
|
614
|
-
except LevelError
|
615
|
-
return
|
610
|
+
except LevelError:
|
611
|
+
return np.array([], dtype=np.bool_)
|
616
612
|
|
617
613
|
|
618
614
|
def edit_subtitle(pattern, stream=0, **kwargs):
|
619
615
|
if "@levels" not in env:
|
620
616
|
raise MyError("Can't use `subtitle` if there's no input media")
|
621
617
|
|
622
|
-
levels = env["@levels"]
|
618
|
+
levels = cast(Levels, env["@levels"])
|
623
619
|
if "ignore-case" not in kwargs:
|
624
620
|
kwargs["ignore-case"] = False
|
625
621
|
if "max-count" not in kwargs:
|
@@ -628,8 +624,8 @@ def edit_subtitle(pattern, stream=0, **kwargs):
|
|
628
624
|
max_count = kwargs["max-count"]
|
629
625
|
try:
|
630
626
|
return levels.subtitle(pattern, stream, ignore_case, max_count)
|
631
|
-
except LevelError
|
632
|
-
return
|
627
|
+
except LevelError:
|
628
|
+
return np.array([], dtype=np.bool_)
|
633
629
|
|
634
630
|
|
635
631
|
class StackTraceManager:
|
auto_editor/make_layers.py
CHANGED
@@ -6,9 +6,9 @@ from typing import TYPE_CHECKING, NamedTuple
|
|
6
6
|
|
7
7
|
import numpy as np
|
8
8
|
|
9
|
-
from auto_editor.analyze import
|
9
|
+
from auto_editor.analyze import initLevels
|
10
10
|
from auto_editor.ffwrapper import FileInfo
|
11
|
-
from auto_editor.lang.palet import Lexer, Parser, env, interpret,
|
11
|
+
from auto_editor.lang.palet import Lexer, Parser, env, interpret, is_boolean_array
|
12
12
|
from auto_editor.lib.data_structs import print_str
|
13
13
|
from auto_editor.lib.err import MyError
|
14
14
|
from auto_editor.timeline import ASpace, TlAudio, TlVideo, VSpace, v1, v3
|
@@ -122,7 +122,6 @@ def make_timeline(
|
|
122
122
|
|
123
123
|
has_loud = np.array([], dtype=np.bool_)
|
124
124
|
src_index = np.array([], dtype=np.int32)
|
125
|
-
concat = np.concatenate
|
126
125
|
|
127
126
|
try:
|
128
127
|
stdenv = __import__("auto_editor.lang.stdenv", fromlist=["lang"])
|
@@ -137,6 +136,7 @@ def make_timeline(
|
|
137
136
|
parser = Parser(Lexer("config.pal", file.read()))
|
138
137
|
interpret(env, parser)
|
139
138
|
|
139
|
+
results = []
|
140
140
|
for i, src in enumerate(sources):
|
141
141
|
try:
|
142
142
|
parser = Parser(Lexer("`--edit`", args.edit))
|
@@ -144,32 +144,43 @@ def make_timeline(
|
|
144
144
|
log.debug(f"edit: {parser}")
|
145
145
|
|
146
146
|
env["timebase"] = tb
|
147
|
-
env["
|
148
|
-
env["@levels"] = Levels(src, tb, bar, args.no_cache, log, len(sources) < 2)
|
147
|
+
env["@levels"] = initLevels(src, tb, bar, args.no_cache, log)
|
149
148
|
|
150
|
-
|
151
|
-
|
152
|
-
if len(results) == 0:
|
149
|
+
inter_result = interpret(env, parser)
|
150
|
+
if len(inter_result) == 0:
|
153
151
|
log.error("Expression in --edit must return a bool-array, got nothing")
|
154
152
|
|
155
|
-
result =
|
153
|
+
result = inter_result[-1]
|
156
154
|
if callable(result):
|
157
155
|
result = result()
|
158
156
|
except MyError as e:
|
159
157
|
log.error(e)
|
160
158
|
|
161
|
-
if not
|
159
|
+
if not is_boolean_array(result):
|
162
160
|
log.error(
|
163
161
|
f"Expression in --edit must return a bool-array, got {print_str(result)}"
|
164
162
|
)
|
165
|
-
assert isinstance(result, np.ndarray)
|
166
|
-
|
167
163
|
mut_margin(result, start_margin, end_margin)
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
164
|
+
results.append(result)
|
165
|
+
|
166
|
+
if all(len(result) == 0 for result in results):
|
167
|
+
if "subtitle" in args.edit:
|
168
|
+
log.error("No file(s) have the selected subtitle stream.")
|
169
|
+
if "motion" in args.edit:
|
170
|
+
log.error("No file(s) have the selected video stream.")
|
171
|
+
if "audio" in args.edit:
|
172
|
+
log.error("No file(s) have the selected audio stream.")
|
173
|
+
|
174
|
+
src_indexes = []
|
175
|
+
for i in range(0, len(results)):
|
176
|
+
if len(results[i]) == 0:
|
177
|
+
results[i] = initLevels(sources[i], tb, bar, args.no_cache, log).all()
|
178
|
+
src_indexes.append(np.full(len(results[i]), i, dtype=np.int32))
|
179
|
+
|
180
|
+
has_loud = np.concatenate(results)
|
181
|
+
src_index = np.concatenate(src_indexes)
|
182
|
+
if len(has_loud) == 0:
|
183
|
+
log.error("Empty timeline. Nothing to do.")
|
173
184
|
|
174
185
|
# Setup for handling custom speeds
|
175
186
|
speed_index = has_loud.astype(np.uint)
|
auto_editor/preview.py
CHANGED
@@ -5,7 +5,7 @@ from fractions import Fraction
|
|
5
5
|
from statistics import fmean, median
|
6
6
|
from typing import TextIO
|
7
7
|
|
8
|
-
from auto_editor.analyze import
|
8
|
+
from auto_editor.analyze import initLevels
|
9
9
|
from auto_editor.timeline import v3
|
10
10
|
from auto_editor.utils.bar import initBar
|
11
11
|
from auto_editor.utils.func import to_timecode
|
@@ -64,8 +64,9 @@ def preview(tl: v3, log: Log) -> None:
|
|
64
64
|
all_sources.add(aclip.src)
|
65
65
|
|
66
66
|
in_len = 0
|
67
|
+
bar = initBar("none")
|
67
68
|
for src in all_sources:
|
68
|
-
in_len +=
|
69
|
+
in_len += initLevels(src, tb, bar, False, log).media_length
|
69
70
|
|
70
71
|
out_len = tl.out_len()
|
71
72
|
|
auto_editor/utils/bar.py
CHANGED
@@ -89,20 +89,26 @@ class Bar:
|
|
89
89
|
percent = round(progress * 100, 1)
|
90
90
|
p_pad = " " * (4 - len(str(percent)))
|
91
91
|
columns = get_terminal_size().columns
|
92
|
-
bar_len = max(1, columns - len_title -
|
92
|
+
bar_len = max(1, columns - len_title - 35)
|
93
93
|
bar_str = self._bar_str(progress, bar_len)
|
94
94
|
|
95
|
-
bar = f" {self.icon}{title} {bar_str} {p_pad}{percent}% ETA {new_time}"
|
96
|
-
|
97
|
-
if len(bar) > columns - 2:
|
98
|
-
bar = bar[: columns - 2]
|
99
|
-
else:
|
100
|
-
bar += " " * (columns - len(bar) - 4)
|
101
|
-
|
102
|
-
sys.stdout.write(bar + "\r")
|
95
|
+
bar = f" {self.icon}{title} {bar_str} {p_pad}{percent}% ETA {new_time} \r"
|
96
|
+
sys.stdout.write(bar)
|
103
97
|
|
104
98
|
def start(self, total: float, title: str = "Please wait") -> None:
|
105
|
-
|
99
|
+
len_title = 0
|
100
|
+
in_escape = False
|
101
|
+
|
102
|
+
for char in title:
|
103
|
+
if not in_escape:
|
104
|
+
if char == "\033":
|
105
|
+
in_escape = True
|
106
|
+
else:
|
107
|
+
len_title += 1
|
108
|
+
elif char == "m":
|
109
|
+
in_escape = False
|
110
|
+
|
111
|
+
self.stack.append((title, len_title, total, time()))
|
106
112
|
|
107
113
|
try:
|
108
114
|
self.tick(0)
|
auto_editor/utils/log.py
CHANGED
@@ -1,14 +1,9 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
1
|
import sys
|
4
2
|
from datetime import timedelta
|
5
3
|
from shutil import get_terminal_size, rmtree
|
6
4
|
from tempfile import mkdtemp
|
7
5
|
from time import perf_counter, sleep
|
8
|
-
from typing import
|
9
|
-
|
10
|
-
if TYPE_CHECKING:
|
11
|
-
import av
|
6
|
+
from typing import NoReturn
|
12
7
|
|
13
8
|
|
14
9
|
class Log:
|
@@ -100,10 +95,6 @@ class Log:
|
|
100
95
|
|
101
96
|
sys.stdout.write(f"Finished. took {second_len} seconds ({minute_len})\n")
|
102
97
|
|
103
|
-
def experimental(self, codec: av.Codec) -> None:
|
104
|
-
if codec.experimental:
|
105
|
-
self.error(f"`{codec.name}` is an experimental codec")
|
106
|
-
|
107
98
|
@staticmethod
|
108
99
|
def deprecated(message: str) -> None:
|
109
100
|
sys.stderr.write(f"\033[1m\033[33m{message}\033[0m\n")
|
auto_editor/utils/types.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: auto-editor
|
3
|
-
Version: 26.3.
|
3
|
+
Version: 26.3.2
|
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.24
|
15
|
-
Requires-Dist: pyav==14.2
|
15
|
+
Requires-Dist: pyav==14.2.*
|
16
16
|
|
17
17
|
<p align="center"><img src="https://auto-editor.com/img/auto-editor-banner.webp" title="Auto-Editor" width="700"></p>
|
18
18
|
|
@@ -1,12 +1,12 @@
|
|
1
|
-
auto_editor/__init__.py,sha256=
|
2
|
-
auto_editor/__main__.py,sha256=
|
3
|
-
auto_editor/analyze.py,sha256=
|
4
|
-
auto_editor/edit.py,sha256=
|
1
|
+
auto_editor/__init__.py,sha256=bDmtpN3tJ_1R818Djb_PZ7H7ZIgSCXSdbTx5GJ009SU,23
|
2
|
+
auto_editor/__main__.py,sha256=BQRStgcJxNVUOisP4JpcaxaM_KTGFS04Qgklyy9fumc,12012
|
3
|
+
auto_editor/analyze.py,sha256=YY3Io-IDdlliawx03w-L9AW5nZSOtmbXX_la1HanYmY,12658
|
4
|
+
auto_editor/edit.py,sha256=wjs1qj13Rx8JGgf7b_dPgVEmd_vDyU-N5GDQhVGSJX8,21130
|
5
5
|
auto_editor/ffwrapper.py,sha256=1lYYfq8gVgMVkYWeAEYDPAHCwFCYbKQwy0FxYBxMzk8,4765
|
6
6
|
auto_editor/help.py,sha256=CzfDTsL4GuGu596ySHKj_wKnxGR9h8B0KUdkZpo33oE,8044
|
7
|
-
auto_editor/make_layers.py,sha256=
|
7
|
+
auto_editor/make_layers.py,sha256=Yl4xYkMHume_VvRW8Ii48hyx-ZtFr8WMmVYXJMSUmg0,9581
|
8
8
|
auto_editor/output.py,sha256=ho8Lpqz4Sv_Gw0Vj2OvG39s83xHpyZlvtRNryTPbXqc,2563
|
9
|
-
auto_editor/preview.py,sha256=
|
9
|
+
auto_editor/preview.py,sha256=cqQdozM2IB-5qXHNxeqiSrSdEIzlMfjD4SU-NX9sYZ0,3052
|
10
10
|
auto_editor/timeline.py,sha256=XfaH9cH-RB-MObOpMr5IfLcqJcjmabO1XwkUkT3_FQM,8186
|
11
11
|
auto_editor/vanparse.py,sha256=Ug5A2QaRqGiw4l55Z_h9T2QU1x0WqRibR7yY5rQ0WTk,10002
|
12
12
|
auto_editor/wavfile.py,sha256=afFfje8cK9lFjIkYoBbQHfvQIpsEPxWvspCtFhUKlAw,9499
|
@@ -14,11 +14,11 @@ auto_editor/cmds/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,
|
|
14
14
|
auto_editor/cmds/cache.py,sha256=bViYbtVXefTeEIUvSanDfA6cG35ep1N_Jvtz7ZjgIkY,1959
|
15
15
|
auto_editor/cmds/desc.py,sha256=GDrKJYiHMaeTrplZAceXl1JwoqD78XsV2_5lc0Xd7po,869
|
16
16
|
auto_editor/cmds/info.py,sha256=vYa1hYdE8kDTE8AS3kwXlnd59X6CrE2GtIEQ7UmlpRY,7010
|
17
|
-
auto_editor/cmds/levels.py,sha256=
|
17
|
+
auto_editor/cmds/levels.py,sha256=6LqXfNBca__KGeA8kJqJqH0MBR3GudaFoWU0_dnv5bI,5635
|
18
18
|
auto_editor/cmds/palet.py,sha256=ONzTqemaQq9YEfIOsDRNnwzfqnEMUMSXIQrETxyroRU,749
|
19
|
-
auto_editor/cmds/repl.py,sha256=
|
19
|
+
auto_editor/cmds/repl.py,sha256=8DgMw-XyfR5XctSmwtk4_1-zxs3ooMs72BfMRlVqLvY,3412
|
20
20
|
auto_editor/cmds/subdump.py,sha256=af_XBf7kaevqHn1A71z8C-7x8pS5WKD9FE_ugkCw6rk,665
|
21
|
-
auto_editor/cmds/test.py,sha256=
|
21
|
+
auto_editor/cmds/test.py,sha256=SzjtsEteztXFbkvLRfL9BPSgK8Qez_-yXPR5ts_tu9E,26465
|
22
22
|
auto_editor/formats/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
23
23
|
auto_editor/formats/fcp11.py,sha256=sqjC36jI47ICPLjZJYiqGwY7foOnWOiNjkPFLdgSnI4,5208
|
24
24
|
auto_editor/formats/fcp7.py,sha256=x5cagTzGCAW3i3M6m7TZC1h8gLfSmX1UK-iiDuCpdfs,20289
|
@@ -29,7 +29,7 @@ auto_editor/lang/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,
|
|
29
29
|
auto_editor/lang/json.py,sha256=D84vwyLtX5t5xl8S4r4jFXGVkbIg1L4IcexlS_a_k6w,9231
|
30
30
|
auto_editor/lang/libintrospection.py,sha256=6H1rGp0wqaCud5IPaoEmzULGnYt6ec7_0h32ATcw2oY,261
|
31
31
|
auto_editor/lang/libmath.py,sha256=z33A161Oe6vYYK7R6pgYjdZZe63dQkN38Qf36TL3prg,847
|
32
|
-
auto_editor/lang/palet.py,sha256=
|
32
|
+
auto_editor/lang/palet.py,sha256=XKMVMybHZK5c_iB368T4pFqI7Yfl5o4eDVa5XMNLEow,24082
|
33
33
|
auto_editor/lang/stdenv.py,sha256=sQyOD3bttjcieWMtTMNpE6blEZriAfHtSZHbuvC09R8,43762
|
34
34
|
auto_editor/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
35
35
|
auto_editor/lib/contracts.py,sha256=lExGQymcQUmwG5lC1lO4qm4GY8W0q_yzK_miTaAoPA4,7586
|
@@ -40,17 +40,17 @@ auto_editor/render/audio.py,sha256=_GuX0WNY1YeumgBN3bWqgwVXiuhpvx7sijABxqyO2ag,1
|
|
40
40
|
auto_editor/render/subtitle.py,sha256=jtNRKvgo1fpHTrAfGZqdkNeNgGgasw-K-4PwIKiWwfM,6231
|
41
41
|
auto_editor/render/video.py,sha256=JBVl8w-hQ6zrs97iA527LPsBZ9s601SVSJs2bSMCq88,12185
|
42
42
|
auto_editor/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
43
|
-
auto_editor/utils/bar.py,sha256=
|
43
|
+
auto_editor/utils/bar.py,sha256=Ky9JRf37JTgLyvNuIXDfucaUE8H1vBbCqKLjttmsmmo,4156
|
44
44
|
auto_editor/utils/chunks.py,sha256=J-eGKtEz68gFtRrj1kOSgH4Tj_Yz6prNQ7Xr-d9NQJw,52
|
45
45
|
auto_editor/utils/cmdkw.py,sha256=aUGBvBel2Ko1o6Rwmr4rEL-BMc5hEnzYLbyZ1GeJdcY,5729
|
46
46
|
auto_editor/utils/container.py,sha256=C_Ahh7nlMEX4DNQ2M_cITPPbYcIL68r4I_AgFy0OD6o,2487
|
47
47
|
auto_editor/utils/func.py,sha256=C8ucgsSEzPyBc-8obhsCXd_uQW0cnCdBn1KVxB7FHjU,2747
|
48
|
-
auto_editor/utils/log.py,sha256=
|
49
|
-
auto_editor/utils/types.py,sha256=
|
48
|
+
auto_editor/utils/log.py,sha256=wPNf6AabV-0cnoS_bPLv1Lh7llQBtNqPKeh07einOuc,3701
|
49
|
+
auto_editor/utils/types.py,sha256=HxFafTgmL_5HQbfR7AR_4Q6o8iHk1z-T6WT90PgQHiY,10817
|
50
50
|
docs/build.py,sha256=POy8X8QOBYe_8A8HI_yiVI_Qg9E5mLpn1z7AHQr0_vQ,1888
|
51
|
-
auto_editor-26.3.
|
52
|
-
auto_editor-26.3.
|
53
|
-
auto_editor-26.3.
|
54
|
-
auto_editor-26.3.
|
55
|
-
auto_editor-26.3.
|
56
|
-
auto_editor-26.3.
|
51
|
+
auto_editor-26.3.2.dist-info/LICENSE,sha256=yiq99pWITHfqS0pbZMp7cy2dnbreTuvBwudsU-njvIM,1210
|
52
|
+
auto_editor-26.3.2.dist-info/METADATA,sha256=lxdGmJqB_b7J1myUG1CFUnXFKo0Vt2Kr8cG7rl58xK8,6111
|
53
|
+
auto_editor-26.3.2.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
|
54
|
+
auto_editor-26.3.2.dist-info/entry_points.txt,sha256=UAsTc7qJQbnAzHd7KWg-ALo_X9Hj2yDs3M9I2DV3eyI,212
|
55
|
+
auto_editor-26.3.2.dist-info/top_level.txt,sha256=jBV5zlbWRbKOa-xaWPvTD45QL7lGExx2BDzv-Ji4dTw,17
|
56
|
+
auto_editor-26.3.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|