auto-editor 24.27.1__py3-none-any.whl → 24.30.1__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 +2 -2
- auto_editor/analyze.py +159 -218
- auto_editor/edit.py +14 -21
- auto_editor/lang/palet.py +29 -9
- auto_editor/lib/contracts.py +12 -6
- auto_editor/make_layers.py +4 -25
- auto_editor/output.py +4 -4
- auto_editor/preview.py +2 -3
- auto_editor/render/subtitle.py +1 -1
- auto_editor/render/video.py +8 -18
- auto_editor/subcommands/levels.py +52 -37
- auto_editor/subcommands/repl.py +4 -13
- auto_editor/subcommands/subdump.py +5 -8
- auto_editor/utils/container.py +71 -313
- {auto_editor-24.27.1.dist-info → auto_editor-24.30.1.dist-info}/METADATA +3 -6
- {auto_editor-24.27.1.dist-info → auto_editor-24.30.1.dist-info}/RECORD +20 -23
- {auto_editor-24.27.1.dist-info → auto_editor-24.30.1.dist-info}/WHEEL +1 -1
- {auto_editor-24.27.1.dist-info → auto_editor-24.30.1.dist-info}/top_level.txt +0 -1
- ae-ffmpeg/ae_ffmpeg/__init__.py +0 -16
- ae-ffmpeg/ae_ffmpeg/py.typed +0 -0
- ae-ffmpeg/setup.py +0 -65
- {auto_editor-24.27.1.dist-info → auto_editor-24.30.1.dist-info}/LICENSE +0 -0
- {auto_editor-24.27.1.dist-info → auto_editor-24.30.1.dist-info}/entry_points.txt +0 -0
auto_editor/lib/contracts.py
CHANGED
@@ -5,6 +5,8 @@ from dataclasses import dataclass
|
|
5
5
|
from fractions import Fraction
|
6
6
|
from typing import Any
|
7
7
|
|
8
|
+
from numpy import float64
|
9
|
+
|
8
10
|
from .data_structs import Sym, print_str
|
9
11
|
from .err import MyError
|
10
12
|
|
@@ -41,7 +43,7 @@ def check_contract(c: object, val: object) -> bool:
|
|
41
43
|
return val is True
|
42
44
|
if c is False:
|
43
45
|
return val is False
|
44
|
-
if type(c) in (int, float, Fraction, complex, str, Sym):
|
46
|
+
if type(c) in (int, float, float64, Fraction, complex, str, Sym):
|
45
47
|
return val == c
|
46
48
|
raise MyError(f"Invalid contract, got: {print_str(c)}")
|
47
49
|
|
@@ -163,17 +165,21 @@ is_int = Contract("int?", lambda v: type(v) is int)
|
|
163
165
|
is_nat = Contract("nat?", lambda v: type(v) is int and v > -1)
|
164
166
|
is_nat1 = Contract("nat1?", lambda v: type(v) is int and v > 0)
|
165
167
|
int_not_zero = Contract("(or/c (not/c 0) int?)", lambda v: v != 0 and is_int(v))
|
166
|
-
is_num = Contract(
|
167
|
-
|
168
|
-
|
168
|
+
is_num = Contract(
|
169
|
+
"number?", lambda v: type(v) in (int, float, float64, Fraction, complex)
|
170
|
+
)
|
171
|
+
is_real = Contract("real?", lambda v: type(v) in (int, float, float64, Fraction))
|
172
|
+
is_float = Contract("float?", lambda v: type(v) in (float, float64))
|
169
173
|
is_frac = Contract("frac?", lambda v: type(v) is Fraction)
|
170
174
|
is_str = Contract("string?", lambda v: type(v) is str)
|
171
175
|
any_p = Contract("any", lambda v: True)
|
172
176
|
is_void = Contract("void?", lambda v: v is None)
|
173
|
-
is_int_or_float = Contract(
|
177
|
+
is_int_or_float = Contract(
|
178
|
+
"(or/c int? float?)", lambda v: type(v) in (int, float, float64)
|
179
|
+
)
|
174
180
|
is_threshold = Contract(
|
175
181
|
"threshold?",
|
176
|
-
lambda v: type(v) in (int, float) and v >= 0 and v <= 1, # type: ignore
|
182
|
+
lambda v: type(v) in (int, float, float64) and v >= 0 and v <= 1, # type: ignore
|
177
183
|
)
|
178
184
|
is_proc = Contract("procedure?", lambda v: isinstance(v, Proc | Contract))
|
179
185
|
|
auto_editor/make_layers.py
CHANGED
@@ -18,7 +18,6 @@ from auto_editor.utils.types import Args, CoerceError, time
|
|
18
18
|
if TYPE_CHECKING:
|
19
19
|
from numpy.typing import NDArray
|
20
20
|
|
21
|
-
from auto_editor.output import Ensure
|
22
21
|
from auto_editor.utils.bar import Bar
|
23
22
|
from auto_editor.utils.chunks import Chunks
|
24
23
|
from auto_editor.utils.log import Log
|
@@ -75,7 +74,6 @@ def make_av(src: FileInfo, all_clips: list[list[Clip]]) -> tuple[VSpace, ASpace]
|
|
75
74
|
def run_interpreter_for_edit_option(
|
76
75
|
text: str, filesetup: FileSetup
|
77
76
|
) -> NDArray[np.bool_]:
|
78
|
-
ensure = filesetup.ensure
|
79
77
|
src = filesetup.src
|
80
78
|
tb = filesetup.tb
|
81
79
|
bar = filesetup.bar
|
@@ -87,8 +85,8 @@ def run_interpreter_for_edit_option(
|
|
87
85
|
if log.is_debug:
|
88
86
|
log.debug(f"edit: {parser}")
|
89
87
|
|
90
|
-
env["timebase"] =
|
91
|
-
env["@levels"] = Levels(
|
88
|
+
env["timebase"] = tb
|
89
|
+
env["@levels"] = Levels(src, tb, bar, temp, log)
|
92
90
|
env["@filesetup"] = filesetup
|
93
91
|
|
94
92
|
results = interpret(env, parser)
|
@@ -139,7 +137,6 @@ def parse_time(val: str, arr: NDArray, tb: Fraction) -> int: # raises: `CoerceE
|
|
139
137
|
|
140
138
|
def make_timeline(
|
141
139
|
sources: list[FileInfo],
|
142
|
-
ensure: Ensure,
|
143
140
|
args: Args,
|
144
141
|
sr: int,
|
145
142
|
bar: Bar,
|
@@ -169,7 +166,7 @@ def make_timeline(
|
|
169
166
|
concat = np.concatenate
|
170
167
|
|
171
168
|
for i, src in enumerate(sources):
|
172
|
-
filesetup = FileSetup(src,
|
169
|
+
filesetup = FileSetup(src, len(sources) < 2, tb, bar, temp, log)
|
173
170
|
|
174
171
|
edit_result = run_interpreter_for_edit_option(method, filesetup)
|
175
172
|
mut_margin(edit_result, start_margin, end_margin)
|
@@ -296,22 +293,4 @@ def make_timeline(
|
|
296
293
|
else:
|
297
294
|
v1_compatiable = None
|
298
295
|
|
299
|
-
|
300
|
-
|
301
|
-
# Additional monotonic check, o(n^2) time complexity so disable by default.
|
302
|
-
|
303
|
-
# if len(sources) != 1:
|
304
|
-
# return tl
|
305
|
-
|
306
|
-
# last_i = 0
|
307
|
-
# for index in range(tl.end):
|
308
|
-
# for layer in tl.v:
|
309
|
-
# for lobj in layer:
|
310
|
-
# if index >= lobj.start and index < (lobj.start + lobj.dur):
|
311
|
-
# _i = round((lobj.offset + index - lobj.start) * lobj.speed)
|
312
|
-
# if (_i < last_i):
|
313
|
-
# print(_i, last_i)
|
314
|
-
# raise ValueError("not monotonic")
|
315
|
-
# last_i = _i
|
316
|
-
|
317
|
-
return tl
|
296
|
+
return v3(inp, tb, sr, res, args.background, vtl, atl, v1_compatiable)
|
auto_editor/output.py
CHANGED
@@ -57,7 +57,7 @@ class Ensure:
|
|
57
57
|
output_astream = out_container.add_stream("pcm_s16le", rate=sample_rate)
|
58
58
|
assert isinstance(output_astream, av.audio.stream.AudioStream)
|
59
59
|
|
60
|
-
resampler = AudioResampler(format="s16", layout="stereo", rate=sample_rate)
|
60
|
+
resampler = AudioResampler(format="s16", layout="stereo", rate=sample_rate)
|
61
61
|
for i, frame in enumerate(in_container.decode(astream)):
|
62
62
|
if i % 1500 == 0:
|
63
63
|
bar.tick(0 if frame.time is None else frame.time)
|
@@ -99,7 +99,7 @@ def _ffset(option: str, value: str | None) -> list[str]:
|
|
99
99
|
return [option] + [value]
|
100
100
|
|
101
101
|
|
102
|
-
def video_quality(args: Args
|
102
|
+
def video_quality(args: Args) -> list[str]:
|
103
103
|
return (
|
104
104
|
_ffset("-b:v", args.video_bitrate)
|
105
105
|
+ ["-c:v", args.video_codec]
|
@@ -174,7 +174,7 @@ def mux_quality_media(
|
|
174
174
|
for is_video, path in visual_output:
|
175
175
|
if is_video:
|
176
176
|
if apply_v:
|
177
|
-
cmd += video_quality(args
|
177
|
+
cmd += video_quality(args)
|
178
178
|
else:
|
179
179
|
# Real video is only allowed on track 0
|
180
180
|
cmd += ["-c:v:0", "copy"]
|
@@ -211,7 +211,7 @@ def mux_quality_media(
|
|
211
211
|
cmd.extend(["-c:s", scodec])
|
212
212
|
elif ctr.scodecs is not None:
|
213
213
|
if scodec not in ctr.scodecs:
|
214
|
-
scodec = ctr.
|
214
|
+
scodec = ctr.default_sub
|
215
215
|
cmd.extend(["-c:s", scodec])
|
216
216
|
|
217
217
|
if a_tracks > 0:
|
auto_editor/preview.py
CHANGED
@@ -6,7 +6,6 @@ from statistics import fmean, median
|
|
6
6
|
from typing import TextIO
|
7
7
|
|
8
8
|
from auto_editor.analyze import Levels
|
9
|
-
from auto_editor.output import Ensure
|
10
9
|
from auto_editor.timeline import v3
|
11
10
|
from auto_editor.utils.bar import Bar
|
12
11
|
from auto_editor.utils.func import to_timecode
|
@@ -49,7 +48,7 @@ def all_cuts(tl: v3, in_len: int) -> list[int]:
|
|
49
48
|
return cut_lens
|
50
49
|
|
51
50
|
|
52
|
-
def preview(
|
51
|
+
def preview(tl: v3, temp: str, log: Log) -> None:
|
53
52
|
log.conwrite("")
|
54
53
|
tb = tl.tb
|
55
54
|
|
@@ -66,7 +65,7 @@ def preview(ensure: Ensure, tl: v3, temp: str, log: Log) -> None:
|
|
66
65
|
|
67
66
|
in_len = 0
|
68
67
|
for src in all_sources:
|
69
|
-
in_len += Levels(
|
68
|
+
in_len += Levels(src, tb, Bar("none"), temp, log).media_length
|
70
69
|
|
71
70
|
out_len = tl.out_len()
|
72
71
|
|
auto_editor/render/subtitle.py
CHANGED
@@ -49,7 +49,7 @@ class SubtitleParser:
|
|
49
49
|
self.codec = codec
|
50
50
|
self.contents = []
|
51
51
|
|
52
|
-
if codec == "ass":
|
52
|
+
if codec == "ass" or codec == "ssa":
|
53
53
|
time_code = re.compile(r"(.*)(\d+:\d+:[\d.]+)(.*)(\d+:\d+:[\d.]+)(.*)")
|
54
54
|
elif codec == "webvtt":
|
55
55
|
time_code = re.compile(r"()(\d+:[\d.]+)( --> )(\d+:[\d.]+)(\n.*)")
|
auto_editor/render/video.py
CHANGED
@@ -17,8 +17,6 @@ from auto_editor.utils.types import color
|
|
17
17
|
if TYPE_CHECKING:
|
18
18
|
from collections.abc import Iterator
|
19
19
|
|
20
|
-
from av.filter import FilterContext
|
21
|
-
|
22
20
|
from auto_editor.ffwrapper import FFmpeg, FileInfo
|
23
21
|
from auto_editor.timeline import v3
|
24
22
|
from auto_editor.utils.bar import Bar
|
@@ -33,11 +31,6 @@ class VideoFrame:
|
|
33
31
|
src: FileInfo
|
34
32
|
|
35
33
|
|
36
|
-
def link_nodes(*nodes: FilterContext) -> None:
|
37
|
-
for c, n in zip(nodes, nodes[1:]):
|
38
|
-
c.link_to(n)
|
39
|
-
|
40
|
-
|
41
34
|
# From: github.com/PyAV-Org/PyAV/blob/main/av/video/frame.pyx
|
42
35
|
allowed_pix_fmt = {
|
43
36
|
"yuv420p",
|
@@ -98,12 +91,11 @@ def make_image_cache(tl: v3) -> dict[tuple[FileInfo, int], np.ndarray]:
|
|
98
91
|
for frame in cn.decode(my_stream):
|
99
92
|
if obj.width != 0:
|
100
93
|
graph = av.filter.Graph()
|
101
|
-
link_nodes(
|
94
|
+
graph.link_nodes(
|
102
95
|
graph.add_buffer(template=my_stream),
|
103
96
|
graph.add("scale", f"{obj.width}:-1"),
|
104
97
|
graph.add("buffersink"),
|
105
|
-
)
|
106
|
-
graph.vpush(frame)
|
98
|
+
).vpush(frame)
|
107
99
|
frame = graph.vpull()
|
108
100
|
img_cache[(obj.src, obj.width)] = frame.to_ndarray(
|
109
101
|
format="rgb24"
|
@@ -177,7 +169,7 @@ def render_av(
|
|
177
169
|
target_width = max(round(tl.res[0] * args.scale), 2)
|
178
170
|
target_height = max(round(tl.res[1] * args.scale), 2)
|
179
171
|
scale_graph = av.filter.Graph()
|
180
|
-
link_nodes(
|
172
|
+
scale_graph.link_nodes(
|
181
173
|
scale_graph.add(
|
182
174
|
"buffer", video_size="1x1", time_base="1/1", pix_fmt=target_pix_fmt
|
183
175
|
),
|
@@ -213,7 +205,7 @@ def render_av(
|
|
213
205
|
if apply_video_later:
|
214
206
|
cmd += ["-c:v", "mpeg4", "-qscale:v", "1"]
|
215
207
|
else:
|
216
|
-
cmd += video_quality(args
|
208
|
+
cmd += video_quality(args)
|
217
209
|
|
218
210
|
# Setting SAR requires re-encoding so we do it here.
|
219
211
|
if src is not None and src.videos and (sar := src.videos[0].sar) is not None:
|
@@ -293,7 +285,7 @@ def render_av(
|
|
293
285
|
if (frame.width, frame.height) != tl.res:
|
294
286
|
width, height = tl.res
|
295
287
|
graph = av.filter.Graph()
|
296
|
-
link_nodes(
|
288
|
+
graph.link_nodes(
|
297
289
|
graph.add_buffer(template=my_stream),
|
298
290
|
graph.add(
|
299
291
|
"scale",
|
@@ -301,21 +293,19 @@ def render_av(
|
|
301
293
|
),
|
302
294
|
graph.add("pad", f"{width}:{height}:-1:-1:color={bg}"),
|
303
295
|
graph.add("buffersink"),
|
304
|
-
)
|
305
|
-
graph.vpush(frame)
|
296
|
+
).vpush(frame)
|
306
297
|
frame = graph.vpull()
|
307
298
|
elif isinstance(obj, TlRect):
|
308
299
|
graph = av.filter.Graph()
|
309
300
|
x, y = apply_anchor(obj.x, obj.y, obj.width, obj.height, obj.anchor)
|
310
|
-
link_nodes(
|
301
|
+
graph.link_nodes(
|
311
302
|
graph.add_buffer(template=my_stream),
|
312
303
|
graph.add(
|
313
304
|
"drawbox",
|
314
305
|
f"x={x}:y={y}:w={obj.width}:h={obj.height}:color={obj.fill}:t=fill",
|
315
306
|
),
|
316
307
|
graph.add("buffersink"),
|
317
|
-
)
|
318
|
-
graph.vpush(frame)
|
308
|
+
).vpush(frame)
|
319
309
|
frame = graph.vpull()
|
320
310
|
elif isinstance(obj, TlImage):
|
321
311
|
img = img_cache[(obj.src, obj.width)]
|
@@ -2,22 +2,30 @@ from __future__ import annotations
|
|
2
2
|
|
3
3
|
import sys
|
4
4
|
from dataclasses import dataclass, field
|
5
|
+
from fractions import Fraction
|
5
6
|
from typing import TYPE_CHECKING
|
6
7
|
|
7
8
|
import numpy as np
|
8
9
|
|
9
|
-
from auto_editor.analyze import LevelError, Levels,
|
10
|
-
from auto_editor.ffwrapper import
|
10
|
+
from auto_editor.analyze import LevelError, Levels, iter_audio, iter_motion
|
11
|
+
from auto_editor.ffwrapper import initFileInfo
|
11
12
|
from auto_editor.lang.palet import env
|
12
|
-
from auto_editor.
|
13
|
+
from auto_editor.lib.contracts import is_bool, is_nat, is_nat1, is_str, is_void, orc
|
13
14
|
from auto_editor.utils.bar import Bar
|
14
|
-
from auto_editor.utils.cmdkw import
|
15
|
+
from auto_editor.utils.cmdkw import (
|
16
|
+
ParserError,
|
17
|
+
Required,
|
18
|
+
parse_with_palet,
|
19
|
+
pAttr,
|
20
|
+
pAttrs,
|
21
|
+
)
|
15
22
|
from auto_editor.utils.func import setup_tempdir
|
16
23
|
from auto_editor.utils.log import Log
|
17
24
|
from auto_editor.utils.types import frame_rate
|
18
25
|
from auto_editor.vanparse import ArgumentParser
|
19
26
|
|
20
27
|
if TYPE_CHECKING:
|
28
|
+
from collections.abc import Iterator
|
21
29
|
from fractions import Fraction
|
22
30
|
|
23
31
|
from numpy.typing import NDArray
|
@@ -28,8 +36,6 @@ class LevelArgs:
|
|
28
36
|
input: list[str] = field(default_factory=list)
|
29
37
|
edit: str = "audio"
|
30
38
|
timebase: Fraction | None = None
|
31
|
-
ffmpeg_location: str | None = None
|
32
|
-
my_ffmpeg: bool = False
|
33
39
|
help: bool = False
|
34
40
|
|
35
41
|
|
@@ -47,16 +53,12 @@ def levels_options(parser: ArgumentParser) -> ArgumentParser:
|
|
47
53
|
type=frame_rate,
|
48
54
|
help="Set custom timebase",
|
49
55
|
)
|
50
|
-
parser.add_argument("--ffmpeg-location", help="Point to your custom ffmpeg file")
|
51
|
-
parser.add_argument(
|
52
|
-
"--my-ffmpeg",
|
53
|
-
flag=True,
|
54
|
-
help="Use the ffmpeg on your PATH instead of the one packaged",
|
55
|
-
)
|
56
56
|
return parser
|
57
57
|
|
58
58
|
|
59
59
|
def print_arr(arr: NDArray) -> None:
|
60
|
+
print("")
|
61
|
+
print("@start")
|
60
62
|
if arr.dtype == np.float64:
|
61
63
|
for a in arr:
|
62
64
|
sys.stdout.write(f"{a:.20f}\n")
|
@@ -66,14 +68,25 @@ def print_arr(arr: NDArray) -> None:
|
|
66
68
|
else:
|
67
69
|
for a in arr:
|
68
70
|
sys.stdout.write(f"{a}\n")
|
71
|
+
sys.stdout.flush()
|
72
|
+
print("")
|
73
|
+
|
74
|
+
|
75
|
+
def print_arr_gen(arr: Iterator[int | float]) -> None:
|
76
|
+
print("")
|
77
|
+
print("@start")
|
78
|
+
for a in arr:
|
79
|
+
if isinstance(a, float):
|
80
|
+
print(f"{a:.20f}")
|
81
|
+
else:
|
82
|
+
print(a)
|
83
|
+
print("")
|
69
84
|
|
70
85
|
|
71
86
|
def main(sys_args: list[str] = sys.argv[1:]) -> None:
|
72
87
|
parser = levels_options(ArgumentParser("levels"))
|
73
88
|
args = parser.parse_args(LevelArgs, sys_args)
|
74
89
|
|
75
|
-
ffmpeg = FFmpeg(args.ffmpeg_location, args.my_ffmpeg)
|
76
|
-
|
77
90
|
bar = Bar("none")
|
78
91
|
temp = setup_tempdir(None, Log())
|
79
92
|
log = Log(quiet=True, temp=temp)
|
@@ -85,44 +98,48 @@ def main(sys_args: list[str] = sys.argv[1:]) -> None:
|
|
85
98
|
src = sources[0]
|
86
99
|
|
87
100
|
tb = src.get_fps() if args.timebase is None else args.timebase
|
88
|
-
ensure = Ensure(ffmpeg, bar, src.get_sr(), temp, log)
|
89
101
|
|
90
102
|
if ":" in args.edit:
|
91
103
|
method, attrs = args.edit.split(":", 1)
|
92
104
|
else:
|
93
105
|
method, attrs = args.edit, ""
|
94
106
|
|
95
|
-
|
96
|
-
|
97
|
-
|
107
|
+
audio_builder = pAttrs("audio", pAttr("stream", 0, is_nat))
|
108
|
+
motion_builder = pAttrs(
|
109
|
+
"motion",
|
110
|
+
pAttr("stream", 0, is_nat),
|
111
|
+
pAttr("blur", 9, is_nat),
|
112
|
+
pAttr("width", 400, is_nat1),
|
113
|
+
)
|
114
|
+
subtitle_builder = pAttrs(
|
115
|
+
"subtitle",
|
116
|
+
pAttr("pattern", Required, is_str),
|
117
|
+
pAttr("stream", 0, is_nat),
|
118
|
+
pAttr("ignore-case", False, is_bool),
|
119
|
+
pAttr("max-count", None, orc(is_nat, is_void)),
|
120
|
+
)
|
98
121
|
|
99
|
-
|
122
|
+
builder_map = {
|
123
|
+
"audio": audio_builder,
|
124
|
+
"motion": motion_builder,
|
125
|
+
"subtitle": subtitle_builder,
|
126
|
+
}
|
100
127
|
|
128
|
+
for src in sources:
|
101
129
|
if method in builder_map:
|
102
|
-
builder = builder_map[method]
|
103
|
-
|
104
130
|
try:
|
105
|
-
obj = parse_with_palet(attrs,
|
131
|
+
obj = parse_with_palet(attrs, builder_map[method], env)
|
106
132
|
except ParserError as e:
|
107
133
|
log.error(e)
|
108
134
|
|
109
|
-
|
110
|
-
del obj["threshold"]
|
111
|
-
|
135
|
+
levels = Levels(src, tb, bar, temp, log)
|
112
136
|
try:
|
113
137
|
if method == "audio":
|
114
|
-
|
138
|
+
print_arr_gen(iter_audio(src, tb, **obj))
|
115
139
|
elif method == "motion":
|
116
|
-
|
140
|
+
print_arr_gen(iter_motion(src, tb, **obj))
|
117
141
|
elif method == "subtitle":
|
118
|
-
print_arr(
|
119
|
-
levels.subtitle(
|
120
|
-
obj["pattern"],
|
121
|
-
obj["stream"],
|
122
|
-
obj["ignore_case"],
|
123
|
-
obj["max_count"],
|
124
|
-
)
|
125
|
-
)
|
142
|
+
print_arr(levels.subtitle(**obj))
|
126
143
|
elif method == "none":
|
127
144
|
print_arr(levels.none())
|
128
145
|
elif method == "all/e":
|
@@ -132,8 +149,6 @@ def main(sys_args: list[str] = sys.argv[1:]) -> None:
|
|
132
149
|
except LevelError as e:
|
133
150
|
log.error(e)
|
134
151
|
|
135
|
-
sys.stdout.flush()
|
136
|
-
print("")
|
137
152
|
log.cleanup()
|
138
153
|
|
139
154
|
|
auto_editor/subcommands/repl.py
CHANGED
@@ -6,11 +6,10 @@ from fractions import Fraction
|
|
6
6
|
|
7
7
|
import auto_editor
|
8
8
|
from auto_editor.analyze import FileSetup, Levels
|
9
|
-
from auto_editor.ffwrapper import
|
9
|
+
from auto_editor.ffwrapper import initFileInfo
|
10
10
|
from auto_editor.lang.palet import ClosingError, Lexer, Parser, env, interpret
|
11
11
|
from auto_editor.lib.data_structs import print_str
|
12
12
|
from auto_editor.lib.err import MyError
|
13
|
-
from auto_editor.output import Ensure
|
14
13
|
from auto_editor.utils.bar import Bar
|
15
14
|
from auto_editor.utils.func import setup_tempdir
|
16
15
|
from auto_editor.utils.log import Log
|
@@ -48,12 +47,6 @@ def repl_options(parser: ArgumentParser) -> ArgumentParser:
|
|
48
47
|
type=frame_rate,
|
49
48
|
help="Set custom timebase",
|
50
49
|
)
|
51
|
-
parser.add_argument("--ffmpeg-location", help="Point to your custom ffmpeg file")
|
52
|
-
parser.add_argument(
|
53
|
-
"--my-ffmpeg",
|
54
|
-
flag=True,
|
55
|
-
help="Use the ffmpeg on your PATH instead of the one packaged",
|
56
|
-
)
|
57
50
|
parser.add_argument(
|
58
51
|
"--temp-dir",
|
59
52
|
metavar="PATH",
|
@@ -68,16 +61,14 @@ def main(sys_args: list[str] = sys.argv[1:]) -> None:
|
|
68
61
|
if args.input:
|
69
62
|
temp = setup_tempdir(args.temp_dir, Log())
|
70
63
|
log = Log(quiet=True, temp=temp)
|
71
|
-
ffmpeg = FFmpeg(args.ffmpeg_location, args.my_ffmpeg, False)
|
72
64
|
strict = len(args.input) < 2
|
73
65
|
sources = [initFileInfo(path, log) for path in args.input]
|
74
66
|
src = sources[0]
|
75
67
|
tb = src.get_fps() if args.timebase is None else args.timebase
|
76
|
-
bar = Bar("
|
77
|
-
ensure = Ensure(ffmpeg, bar, src.get_sr(), temp, log)
|
68
|
+
bar = Bar("modern")
|
78
69
|
env["timebase"] = tb
|
79
|
-
env["@levels"] = Levels(
|
80
|
-
env["@filesetup"] = FileSetup(src,
|
70
|
+
env["@levels"] = Levels(src, tb, bar, temp, log)
|
71
|
+
env["@filesetup"] = FileSetup(src, strict, tb, bar, temp, log)
|
81
72
|
|
82
73
|
print(f"Auto-Editor {auto_editor.version} ({auto_editor.__version__})")
|
83
74
|
text = None
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import sys
|
2
2
|
|
3
3
|
import av
|
4
|
-
from av.subtitles.subtitle import AssSubtitle
|
4
|
+
from av.subtitles.subtitle import AssSubtitle
|
5
5
|
|
6
6
|
|
7
7
|
def main(sys_args: list[str] = sys.argv[1:]) -> None:
|
@@ -9,13 +9,10 @@ def main(sys_args: list[str] = sys.argv[1:]) -> None:
|
|
9
9
|
with av.open(input_file) as container:
|
10
10
|
for s in range(len(container.streams.subtitles)):
|
11
11
|
print(f"file: {input_file} ({s}:{container.streams.subtitles[s].name})")
|
12
|
-
for
|
13
|
-
for
|
14
|
-
|
15
|
-
|
16
|
-
print(sub.ass.decode("utf-8", errors="ignore"))
|
17
|
-
elif isinstance(sub, TextSubtitle):
|
18
|
-
print(sub.text.decode("utf-8", errors="ignore"))
|
12
|
+
for subset in container.decode(subtitles=s):
|
13
|
+
for sub in subset:
|
14
|
+
if isinstance(sub, AssSubtitle):
|
15
|
+
print(sub.ass.decode("utf-8", errors="ignore"))
|
19
16
|
print("------")
|
20
17
|
|
21
18
|
|