auto-editor 28.0.0__py3-none-any.whl → 28.0.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 +1 -1
- auto_editor/cmds/cache.py +1 -1
- auto_editor/cmds/info.py +3 -3
- auto_editor/cmds/palet.py +1 -1
- auto_editor/cmds/subdump.py +2 -4
- auto_editor/cmds/test.py +15 -12
- auto_editor/edit.py +2 -3
- auto_editor/exports/fcp11.py +5 -5
- auto_editor/exports/fcp7.py +2 -39
- auto_editor/exports/shotcut.py +3 -7
- auto_editor/imports/fcp7.py +5 -7
- auto_editor/imports/json.py +5 -6
- auto_editor/json.py +2 -2
- auto_editor/lang/palet.py +5 -42
- auto_editor/lang/stdenv.py +3 -18
- auto_editor/lib/contracts.py +3 -5
- auto_editor/lib/data_structs.py +0 -3
- auto_editor/make_layers.py +13 -13
- auto_editor/render/audio.py +8 -5
- auto_editor/render/video.py +3 -2
- auto_editor/timeline.py +28 -40
- {auto_editor-28.0.0.dist-info → auto_editor-28.0.1.dist-info}/METADATA +1 -1
- {auto_editor-28.0.0.dist-info → auto_editor-28.0.1.dist-info}/RECORD +27 -27
- {auto_editor-28.0.0.dist-info → auto_editor-28.0.1.dist-info}/WHEEL +0 -0
- {auto_editor-28.0.0.dist-info → auto_editor-28.0.1.dist-info}/entry_points.txt +0 -0
- {auto_editor-28.0.0.dist-info → auto_editor-28.0.1.dist-info}/licenses/LICENSE +0 -0
- {auto_editor-28.0.0.dist-info → auto_editor-28.0.1.dist-info}/top_level.txt +0 -0
auto_editor/__init__.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "28.0.
|
1
|
+
__version__ = "28.0.1"
|
auto_editor/cmds/cache.py
CHANGED
@@ -26,7 +26,7 @@ def main(sys_args: list[str] = sys.argv[1:]) -> None:
|
|
26
26
|
return
|
27
27
|
|
28
28
|
def format_bytes(size: float) -> str:
|
29
|
-
for unit in
|
29
|
+
for unit in ("B", "KiB", "MiB", "GiB", "TiB"):
|
30
30
|
if size < 1024:
|
31
31
|
return f"{size:.2f} {unit}"
|
32
32
|
size /= 1024
|
auto_editor/cmds/info.py
CHANGED
@@ -113,7 +113,7 @@ def main(sys_args: list[str] = sys.argv[1:]) -> None:
|
|
113
113
|
f"{recTb.numerator}/{recTb.denominator}"
|
114
114
|
)
|
115
115
|
|
116
|
-
for
|
116
|
+
for v in src.videos:
|
117
117
|
w, h = v.width, v.height
|
118
118
|
|
119
119
|
vid: VideoJson = {
|
@@ -134,7 +134,7 @@ def main(sys_args: list[str] = sys.argv[1:]) -> None:
|
|
134
134
|
}
|
135
135
|
file_info[file]["video"].append(vid)
|
136
136
|
|
137
|
-
for
|
137
|
+
for a in src.audios:
|
138
138
|
aud: AudioJson = {
|
139
139
|
"codec": a.codec,
|
140
140
|
"layout": a.layout,
|
@@ -145,7 +145,7 @@ def main(sys_args: list[str] = sys.argv[1:]) -> None:
|
|
145
145
|
}
|
146
146
|
file_info[file]["audio"].append(aud)
|
147
147
|
|
148
|
-
for
|
148
|
+
for s_stream in src.subtitles:
|
149
149
|
sub: SubtitleJson = {"codec": s_stream.codec, "lang": s_stream.lang}
|
150
150
|
file_info[file]["subtitle"].append(sub)
|
151
151
|
|
auto_editor/cmds/palet.py
CHANGED
@@ -14,7 +14,7 @@ def main(sys_args: list[str] = sys.argv[1:]) -> None:
|
|
14
14
|
|
15
15
|
env.update(make_standard_env())
|
16
16
|
try:
|
17
|
-
interpret(env, Parser(Lexer(sys_args[0], program_text
|
17
|
+
interpret(env, Parser(Lexer(sys_args[0], program_text)))
|
18
18
|
except (MyError, ZeroDivisionError) as e:
|
19
19
|
sys.stderr.write(f"error: {e}\n")
|
20
20
|
sys.exit(1)
|
auto_editor/cmds/subdump.py
CHANGED
@@ -21,8 +21,6 @@ def main(sys_args: list[str] = sys.argv[1:]) -> None:
|
|
21
21
|
parser.add_argument("--json", flag=True)
|
22
22
|
args = parser.parse_args(SubdumpArgs, sys_args)
|
23
23
|
|
24
|
-
do_filter = True
|
25
|
-
|
26
24
|
if args.json:
|
27
25
|
data = {}
|
28
26
|
for input_file in args.input:
|
@@ -46,7 +44,7 @@ def main(sys_args: list[str] = sys.argv[1:]) -> None:
|
|
46
44
|
startf = round(float(start), 3)
|
47
45
|
endf = round(float(end), 3)
|
48
46
|
|
49
|
-
if
|
47
|
+
if endf - startf <= 0.02:
|
50
48
|
continue
|
51
49
|
|
52
50
|
for sub in packet.decode():
|
@@ -60,7 +58,7 @@ def main(sys_args: list[str] = sys.argv[1:]) -> None:
|
|
60
58
|
dump(data, sys.stdout, indent=4)
|
61
59
|
return
|
62
60
|
|
63
|
-
for
|
61
|
+
for input_file in args.input:
|
64
62
|
with bv.open(input_file) as container:
|
65
63
|
for s in range(len(container.streams.subtitles)):
|
66
64
|
print(f"file: {input_file} ({s}:{container.streams.subtitles[s].name})")
|
auto_editor/cmds/test.py
CHANGED
@@ -202,6 +202,19 @@ class Runner:
|
|
202
202
|
assert audio.language == "eng"
|
203
203
|
assert audio.layout.name == "stereo"
|
204
204
|
|
205
|
+
def test_video_to_mp3(self) -> None:
|
206
|
+
out = self.main(["example.mp4"], [], output="example_ALTERED.mp3")
|
207
|
+
with bv.open(out) as container:
|
208
|
+
assert container.duration is not None
|
209
|
+
assert container.duration > 17300000 and container.duration < 2 << 24
|
210
|
+
|
211
|
+
assert len(container.streams) == 1
|
212
|
+
audio = container.streams[0]
|
213
|
+
assert isinstance(audio, bv.AudioStream)
|
214
|
+
assert audio.codec.name in ("mp3", "mp3float")
|
215
|
+
assert audio.sample_rate == 48000
|
216
|
+
assert audio.layout.name == "stereo"
|
217
|
+
|
205
218
|
def test_to_mono(self) -> None:
|
206
219
|
out = self.main(["example.mp4"], ["-layout", "mono"], output="example_mono.mp4")
|
207
220
|
with bv.open(out) as container:
|
@@ -516,9 +529,6 @@ class Runner:
|
|
516
529
|
assert output.videos[0].pix_fmt == "yuv420p"
|
517
530
|
|
518
531
|
def test_encode_hevc(self):
|
519
|
-
if os.environ.get("GITHUB_ACTIONS") == "true":
|
520
|
-
raise SkipTest()
|
521
|
-
|
522
532
|
out = self.main(["resources/testsrc.mp4"], ["-c:v", "hevc"], "out.mkv")
|
523
533
|
output = fileinfo(out)
|
524
534
|
assert output.videos[0].codec == "hevc"
|
@@ -563,15 +573,12 @@ class Runner:
|
|
563
573
|
("238.5", 238.5),
|
564
574
|
("-34", -34),
|
565
575
|
("-98.3", -98.3),
|
566
|
-
("+3i", 3j),
|
567
576
|
("3sec", 90),
|
568
577
|
("-3sec", -90),
|
569
578
|
("0.2sec", 6),
|
570
579
|
("(+ 4 3)", 7),
|
571
580
|
("(+ 4 3 2)", 9),
|
572
581
|
("(+ 10.5 3)", 13.5),
|
573
|
-
("(+ 3+4i -2-2i)", 1 + 2j),
|
574
|
-
("(+ 3+4i -2-2i 5)", 6 + 2j),
|
575
582
|
("(- 4 3)", 1),
|
576
583
|
("(- 3)", -3),
|
577
584
|
("(- 10.5 3)", 7.5),
|
@@ -580,7 +587,6 @@ class Runner:
|
|
580
587
|
("(/ 5)", 0.2),
|
581
588
|
("(/ 6 1)", 6.0),
|
582
589
|
("30/1", Fraction(30)),
|
583
|
-
("(sqrt -4)", 2j),
|
584
590
|
("(pow 2 3)", 8),
|
585
591
|
("(pow 4 0.5)", 2.0),
|
586
592
|
("(abs 1.0)", 1.0),
|
@@ -595,7 +601,6 @@ class Runner:
|
|
595
601
|
("(int? #t)", False),
|
596
602
|
("(int? #f)", False),
|
597
603
|
("(int? 4/5)", False),
|
598
|
-
("(int? 0+2i)", False),
|
599
604
|
('(int? "hello")', False),
|
600
605
|
('(int? "3")', False),
|
601
606
|
("(float? -23.4)", True),
|
@@ -609,7 +614,6 @@ class Runner:
|
|
609
614
|
('(define apple "Red Wood") apple', "Red Wood"),
|
610
615
|
("(= 1 1.0)", True),
|
611
616
|
("(= 1 2)", False),
|
612
|
-
("(= 2+3i 2+3i 2+3i)", True),
|
613
617
|
("(= 1)", True),
|
614
618
|
("(+)", 0),
|
615
619
|
("(*)", 1),
|
@@ -618,7 +622,6 @@ class Runner:
|
|
618
622
|
('(if #f mango "Hi")', "Hi"),
|
619
623
|
('{if (= [+ 3 4] 7) "yes" "no"}', "yes"),
|
620
624
|
("((if #t + -) 3 4)", 7),
|
621
|
-
("((if #t + oops) 3+3i 4-2i)", 7 + 1j),
|
622
625
|
("((if #f + -) 3 4)", -1),
|
623
626
|
("(when (positive? 3) 17)", 17),
|
624
627
|
("(string)", ""),
|
@@ -698,7 +701,7 @@ class Runner:
|
|
698
701
|
self.raw(["palet", "resources/scripts/testmath.pal"])
|
699
702
|
|
700
703
|
|
701
|
-
def run_tests(
|
704
|
+
def run_tests(tests: list[Callable], args: TestArgs) -> None:
|
702
705
|
if args.only != []:
|
703
706
|
tests = list(filter(lambda t: t.__name__ in args.only, tests))
|
704
707
|
|
@@ -797,7 +800,7 @@ def main(sys_args: list[str] | None = None) -> None:
|
|
797
800
|
]
|
798
801
|
)
|
799
802
|
try:
|
800
|
-
run_tests(
|
803
|
+
run_tests(tests, args)
|
801
804
|
except KeyboardInterrupt:
|
802
805
|
print("Testing Interrupted by User.")
|
803
806
|
shutil.rmtree(run.temp_dir)
|
auto_editor/edit.py
CHANGED
@@ -247,8 +247,7 @@ def edit_media(paths: list[str], args: Args, log: Log) -> None:
|
|
247
247
|
if export == "resolve":
|
248
248
|
from auto_editor.exports.fcp11 import fcp11_write_xml
|
249
249
|
|
250
|
-
|
251
|
-
set_stream_to_0(src, tl, log)
|
250
|
+
set_stream_to_0(tl, log)
|
252
251
|
fcp11_write_xml(export_ops["name"], 10, output, True, tl, log)
|
253
252
|
return
|
254
253
|
|
@@ -287,7 +286,7 @@ def edit_media(paths: list[str], args: Args, log: Log) -> None:
|
|
287
286
|
output = bv.open(output_path, "w", container_options=options)
|
288
287
|
|
289
288
|
# Setup video
|
290
|
-
if ctr.default_vid
|
289
|
+
if ctr.default_vid not in ("none", "png") and tl.v:
|
291
290
|
vframes = render_av(output, tl, args, log)
|
292
291
|
output_stream: bv.VideoStream | None
|
293
292
|
output_stream = next(vframes) # type: ignore
|
auto_editor/exports/fcp11.py
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import xml.etree.ElementTree as ET
|
4
|
-
from typing import TYPE_CHECKING,
|
4
|
+
from typing import TYPE_CHECKING, cast
|
5
5
|
from xml.etree.ElementTree import Element, ElementTree, SubElement, indent
|
6
6
|
|
7
|
+
from auto_editor.timeline import Clip, v3
|
8
|
+
|
7
9
|
if TYPE_CHECKING:
|
8
|
-
from collections.abc import Sequence
|
9
10
|
from fractions import Fraction
|
10
11
|
|
11
12
|
from auto_editor.ffwrapper import FileInfo
|
12
|
-
from auto_editor.timeline import TlAudio, TlVideo, v3
|
13
13
|
from auto_editor.utils.log import Log
|
14
14
|
|
15
15
|
|
@@ -121,7 +121,7 @@ def fcp11_write_xml(
|
|
121
121
|
)
|
122
122
|
spine = SubElement(sequence, "spine")
|
123
123
|
|
124
|
-
def make_clip(ref: str, clip:
|
124
|
+
def make_clip(ref: str, clip: Clip) -> None:
|
125
125
|
clip_properties = {
|
126
126
|
"name": proj_name,
|
127
127
|
"ref": ref,
|
@@ -146,7 +146,7 @@ def fcp11_write_xml(
|
|
146
146
|
)
|
147
147
|
|
148
148
|
if tl.v and tl.v[0]:
|
149
|
-
clips
|
149
|
+
clips = cast(list[Clip], tl.v[0])
|
150
150
|
elif tl.a and tl.a[0]:
|
151
151
|
clips = tl.a[0]
|
152
152
|
else:
|
auto_editor/exports/fcp7.py
CHANGED
@@ -3,14 +3,10 @@ from __future__ import annotations
|
|
3
3
|
import xml.etree.ElementTree as ET
|
4
4
|
from fractions import Fraction
|
5
5
|
from math import ceil
|
6
|
-
from typing import TYPE_CHECKING
|
7
6
|
from xml.etree.ElementTree import Element
|
8
7
|
|
9
8
|
from auto_editor.ffwrapper import FileInfo
|
10
|
-
from auto_editor.timeline import
|
11
|
-
|
12
|
-
if TYPE_CHECKING:
|
13
|
-
from auto_editor.utils.log import Log
|
9
|
+
from auto_editor.timeline import Clip, v3
|
14
10
|
|
15
11
|
"""
|
16
12
|
Premiere Pro uses the Final Cut Pro 7 XML Interchange Format
|
@@ -69,39 +65,6 @@ def speedup(speed: float) -> Element:
|
|
69
65
|
return fil
|
70
66
|
|
71
67
|
|
72
|
-
SUPPORTED_EFFECTS = ("timeremap",)
|
73
|
-
|
74
|
-
|
75
|
-
def read_filters(clipitem: Element, log: Log) -> float:
|
76
|
-
for effect_tag in clipitem:
|
77
|
-
if effect_tag.tag in {"enabled", "start", "end"}:
|
78
|
-
continue
|
79
|
-
if len(effect_tag) < 3:
|
80
|
-
log.error("<effect> requires: <effectid> <name> and one <parameter>")
|
81
|
-
for i, effects in enumerate(effect_tag):
|
82
|
-
if i == 0 and effects.tag != "name":
|
83
|
-
log.error("<effect>: <name> must be first tag")
|
84
|
-
if i == 1 and effects.tag != "effectid":
|
85
|
-
log.error("<effect>: <effectid> must be second tag")
|
86
|
-
if effects.text not in SUPPORTED_EFFECTS:
|
87
|
-
log.error(f"`{effects.text}` is not a supported effect.")
|
88
|
-
|
89
|
-
if i > 1:
|
90
|
-
for j, parms in enumerate(effects):
|
91
|
-
if j == 0:
|
92
|
-
if parms.tag != "parameterid":
|
93
|
-
log.error("<parameter>: <parameterid> must be first tag")
|
94
|
-
if parms.text != "speed":
|
95
|
-
break
|
96
|
-
|
97
|
-
if j > 0 and parms.tag == "value":
|
98
|
-
if parms.text is None:
|
99
|
-
log.error("<value>: number required")
|
100
|
-
return float(parms.text) / 100
|
101
|
-
|
102
|
-
return 1.0
|
103
|
-
|
104
|
-
|
105
68
|
def media_def(
|
106
69
|
filedef: Element, url: str, src: FileInfo, tl: v3, tb: int, ntsc: str
|
107
70
|
) -> None:
|
@@ -295,7 +258,7 @@ def fcp7_write_xml(name: str, output: str, resolve: bool, tl: v3) -> None:
|
|
295
258
|
track = ET.SubElement(video, "track")
|
296
259
|
|
297
260
|
for j, clip in enumerate(tl.v[0]):
|
298
|
-
assert isinstance(clip,
|
261
|
+
assert isinstance(clip, Clip)
|
299
262
|
|
300
263
|
_start = f"{clip.start}"
|
301
264
|
_end = f"{clip.start + clip.dur}"
|
auto_editor/exports/shotcut.py
CHANGED
@@ -1,13 +1,9 @@
|
|
1
1
|
import xml.etree.ElementTree as ET
|
2
|
-
from typing import
|
2
|
+
from typing import cast
|
3
3
|
|
4
|
-
from auto_editor.timeline import
|
4
|
+
from auto_editor.timeline import Clip, v3
|
5
5
|
from auto_editor.utils.func import aspect_ratio, to_timecode
|
6
6
|
|
7
|
-
if TYPE_CHECKING:
|
8
|
-
from collections.abc import Sequence
|
9
|
-
|
10
|
-
|
11
7
|
"""
|
12
8
|
Shotcut uses the MLT timeline format
|
13
9
|
|
@@ -75,7 +71,7 @@ def shotcut_write_mlt(output: str, tl: v3) -> None:
|
|
75
71
|
producers = 0
|
76
72
|
|
77
73
|
if tl.v:
|
78
|
-
clips
|
74
|
+
clips = cast(list[Clip], tl.v[0])
|
79
75
|
elif tl.a:
|
80
76
|
clips = tl.a[0]
|
81
77
|
else:
|
auto_editor/imports/fcp7.py
CHANGED
@@ -7,7 +7,7 @@ from urllib.parse import unquote
|
|
7
7
|
from xml.etree.ElementTree import Element
|
8
8
|
|
9
9
|
from auto_editor.ffwrapper import FileInfo
|
10
|
-
from auto_editor.timeline import ASpace,
|
10
|
+
from auto_editor.timeline import ASpace, Clip, Template, VSpace, v3
|
11
11
|
|
12
12
|
if TYPE_CHECKING:
|
13
13
|
from auto_editor.utils.log import Log
|
@@ -213,7 +213,7 @@ def fcp7_read_xml(path: str, log: Log) -> v3:
|
|
213
213
|
for t, track in enumerate(tracks["track"]):
|
214
214
|
if len(track["clipitem"]) > 0:
|
215
215
|
vobjs.append([])
|
216
|
-
for
|
216
|
+
for clipitem in track["clipitem"]:
|
217
217
|
file_id = clipitem["file"].attrib["id"]
|
218
218
|
if file_id not in sources:
|
219
219
|
fileobj = parse(clipitem["file"], {"pathurl": str})
|
@@ -239,7 +239,7 @@ def fcp7_read_xml(path: str, log: Log) -> v3:
|
|
239
239
|
offset = clipitem["in"]
|
240
240
|
|
241
241
|
vobjs[t].append(
|
242
|
-
|
242
|
+
Clip(start, dur, sources[file_id], offset, stream=0, speed=speed)
|
243
243
|
)
|
244
244
|
|
245
245
|
if "audio" in av:
|
@@ -250,7 +250,7 @@ def fcp7_read_xml(path: str, log: Log) -> v3:
|
|
250
250
|
for t, track in enumerate(tracks["track"]):
|
251
251
|
if len(track["clipitem"]) > 0:
|
252
252
|
aobjs.append([])
|
253
|
-
for
|
253
|
+
for clipitem in track["clipitem"]:
|
254
254
|
file_id = clipitem["file"].attrib["id"]
|
255
255
|
if file_id not in sources:
|
256
256
|
fileobj = parse(clipitem["file"], {"pathurl": str})
|
@@ -268,9 +268,7 @@ def fcp7_read_xml(path: str, log: Log) -> v3:
|
|
268
268
|
offset = clipitem["in"]
|
269
269
|
|
270
270
|
aobjs[t].append(
|
271
|
-
|
272
|
-
start, dur, sources[file_id], offset, speed, volume=1, stream=0
|
273
|
-
)
|
271
|
+
Clip(start, dur, sources[file_id], offset, stream=0, speed=speed)
|
274
272
|
)
|
275
273
|
|
276
274
|
T = Template.init(sources[next(iter(sources))], sr, res=res)
|
auto_editor/imports/json.py
CHANGED
@@ -9,9 +9,8 @@ from auto_editor.ffwrapper import FileInfo
|
|
9
9
|
from auto_editor.json import load
|
10
10
|
from auto_editor.lib.err import MyError
|
11
11
|
from auto_editor.timeline import (
|
12
|
+
Clip,
|
12
13
|
Template,
|
13
|
-
TlAudio,
|
14
|
-
TlVideo,
|
15
14
|
audio_builder,
|
16
15
|
v1,
|
17
16
|
v3,
|
@@ -112,7 +111,7 @@ def read_v3(tl: Any, log: Log) -> v3:
|
|
112
111
|
tb = Fraction(tl["timebase"])
|
113
112
|
|
114
113
|
v: Any = []
|
115
|
-
a: list[list[
|
114
|
+
a: list[list[Clip]] = []
|
116
115
|
|
117
116
|
for vlayers in tl["v"]:
|
118
117
|
if vlayers:
|
@@ -141,7 +140,7 @@ def read_v3(tl: Any, log: Log) -> v3:
|
|
141
140
|
log.error(f"Unknown audio object: {adict['name']}")
|
142
141
|
|
143
142
|
try:
|
144
|
-
a_out.append(
|
143
|
+
a_out.append(Clip(**parse_obj(adict, audio_builder)))
|
145
144
|
except ParserError as e:
|
146
145
|
log.error(e)
|
147
146
|
|
@@ -198,10 +197,10 @@ def read_v1(tl: Any, log: Log) -> v3:
|
|
198
197
|
if src.videos:
|
199
198
|
if len(vtl) == 0:
|
200
199
|
vtl.append([])
|
201
|
-
vtl[0].append(
|
200
|
+
vtl[0].append(Clip(c.start, c.dur, c.src, c.offset, 0, c.speed))
|
202
201
|
|
203
202
|
for a in range(len(src.audios)):
|
204
|
-
atl[a].append(
|
203
|
+
atl[a].append(Clip(c.start, c.dur, c.src, c.offset, a, c.speed))
|
205
204
|
|
206
205
|
return v3(
|
207
206
|
src.get_fps(),
|
auto_editor/json.py
CHANGED
@@ -89,7 +89,7 @@ class Lexer:
|
|
89
89
|
|
90
90
|
if self.char == "u":
|
91
91
|
buf = ""
|
92
|
-
for
|
92
|
+
for _ in range(4):
|
93
93
|
self.advance()
|
94
94
|
if self.char is None:
|
95
95
|
self.error("\\u escape sequence needs 4 hexs")
|
@@ -162,7 +162,7 @@ class Lexer:
|
|
162
162
|
return (key, None)
|
163
163
|
|
164
164
|
keyword = ""
|
165
|
-
for
|
165
|
+
for _ in range(5): # Longest valid keyword length
|
166
166
|
if self.char is None or self.char in " \t\n\r\x0b\x0c[]}{,":
|
167
167
|
break
|
168
168
|
keyword += self.char
|
auto_editor/lang/palet.py
CHANGED
@@ -65,20 +65,11 @@ class Token:
|
|
65
65
|
|
66
66
|
|
67
67
|
class Lexer:
|
68
|
-
__slots__ = (
|
69
|
-
|
70
|
-
|
71
|
-
"allow_lang_prag",
|
72
|
-
"pos",
|
73
|
-
"char",
|
74
|
-
"lineno",
|
75
|
-
"column",
|
76
|
-
)
|
77
|
-
|
78
|
-
def __init__(self, filename: str, text: str, langprag: bool = False):
|
68
|
+
__slots__ = ("filename", "text", "pos", "char", "lineno", "column")
|
69
|
+
|
70
|
+
def __init__(self, filename: str, text: str):
|
79
71
|
self.filename = filename
|
80
72
|
self.text = text
|
81
|
-
self.allow_lang_prag = langprag
|
82
73
|
self.pos: int = 0
|
83
74
|
self.lineno: int = 1
|
84
75
|
self.column: int = 1
|
@@ -157,7 +148,7 @@ class Lexer:
|
|
157
148
|
token = SEC
|
158
149
|
elif unit == "dB":
|
159
150
|
token = DB
|
160
|
-
elif unit != "
|
151
|
+
elif unit != "%":
|
161
152
|
return Token(
|
162
153
|
VAL,
|
163
154
|
Sym(result + unit, self.lineno, self.column),
|
@@ -166,9 +157,7 @@ class Lexer:
|
|
166
157
|
)
|
167
158
|
|
168
159
|
try:
|
169
|
-
if unit == "
|
170
|
-
return Token(VAL, complex(result + "j"), self.lineno, self.column)
|
171
|
-
elif unit == "%":
|
160
|
+
if unit == "%":
|
172
161
|
return Token(VAL, float(result) / 100, self.lineno, self.column)
|
173
162
|
elif "/" in result:
|
174
163
|
return Token(token, Fraction(result), self.lineno, self.column)
|
@@ -289,32 +278,6 @@ class Lexer:
|
|
289
278
|
self.advance()
|
290
279
|
if self.char is None or self.char == "\n":
|
291
280
|
continue
|
292
|
-
|
293
|
-
elif self.char == "l" and self.peek() == "a":
|
294
|
-
buf = StringIO()
|
295
|
-
while self.char_is_norm():
|
296
|
-
assert self.char is not None
|
297
|
-
buf.write(self.char)
|
298
|
-
self.advance()
|
299
|
-
|
300
|
-
result = buf.getvalue()
|
301
|
-
if result != "lang":
|
302
|
-
self.error(f"Unknown hash literal `#{result}`")
|
303
|
-
if not self.allow_lang_prag:
|
304
|
-
self.error("#lang pragma is not allowed here")
|
305
|
-
|
306
|
-
self.advance()
|
307
|
-
buf = StringIO()
|
308
|
-
while not self.is_whitespace():
|
309
|
-
assert self.char is not None
|
310
|
-
buf.write(self.char)
|
311
|
-
self.advance()
|
312
|
-
|
313
|
-
result = buf.getvalue()
|
314
|
-
if result != "palet":
|
315
|
-
self.error(f"Invalid #lang: {result}")
|
316
|
-
self.allow_lang_prag = False
|
317
|
-
continue
|
318
281
|
else:
|
319
282
|
return self.hash_literal()
|
320
283
|
|
auto_editor/lang/stdenv.py
CHANGED
@@ -19,14 +19,13 @@ if TYPE_CHECKING:
|
|
19
19
|
import numpy as np
|
20
20
|
from numpy.typing import NDArray
|
21
21
|
|
22
|
-
Number = int | float |
|
22
|
+
Number = int | float | Fraction
|
23
23
|
BoolList = NDArray[np.bool_]
|
24
24
|
Node = tuple
|
25
25
|
|
26
26
|
|
27
27
|
def make_standard_env() -> dict[str, Any]:
|
28
28
|
import os.path
|
29
|
-
from cmath import sqrt as complex_sqrt
|
30
29
|
from functools import reduce
|
31
30
|
from operator import add, ge, gt, is_, le, lt, mod, mul
|
32
31
|
from subprocess import run
|
@@ -512,7 +511,7 @@ def make_standard_env() -> dict[str, Any]:
|
|
512
511
|
for c in node[2:]:
|
513
512
|
my_eval(env, c)
|
514
513
|
|
515
|
-
def syn_quote(
|
514
|
+
def syn_quote(_: Env, node: Node) -> Any:
|
516
515
|
guard_term(node, 2, 2)
|
517
516
|
if type(node[1]) is Keyword:
|
518
517
|
return QuotedKeyword(node[1])
|
@@ -828,14 +827,6 @@ def make_standard_env() -> dict[str, Any]:
|
|
828
827
|
|
829
828
|
return reduce(lambda a, b: a // b, m, n)
|
830
829
|
|
831
|
-
def _sqrt(v: Number) -> Number:
|
832
|
-
r = complex_sqrt(v)
|
833
|
-
if r.imag == 0:
|
834
|
-
if int(r.real) == r.real:
|
835
|
-
return int(r.real)
|
836
|
-
return r.real
|
837
|
-
return r
|
838
|
-
|
839
830
|
def _xor(*vals: Any) -> bool | BoolList:
|
840
831
|
if is_boolarr(vals[0]):
|
841
832
|
check_args("xor", vals, (2, None), (is_boolarr,))
|
@@ -844,9 +835,6 @@ def make_standard_env() -> dict[str, Any]:
|
|
844
835
|
return reduce(lambda a, b: a ^ b, vals)
|
845
836
|
|
846
837
|
def number_to_string(val: Number) -> str:
|
847
|
-
if isinstance(val, complex):
|
848
|
-
join = "" if val.imag < 0 else "+"
|
849
|
-
return f"{val.real}{join}{val.imag}i"
|
850
838
|
return f"{val}"
|
851
839
|
|
852
840
|
def string_to_number(val) -> float:
|
@@ -971,6 +959,7 @@ def make_standard_env() -> dict[str, Any]:
|
|
971
959
|
# syntax
|
972
960
|
"lambda": Syntax(syn_lambda),
|
973
961
|
"λ": Syntax(syn_lambda),
|
962
|
+
"defn": Syntax(syn_define),
|
974
963
|
"define": Syntax(syn_define),
|
975
964
|
"define/c": Syntax(syn_definec),
|
976
965
|
"set!": Syntax(syn_set),
|
@@ -997,7 +986,6 @@ def make_standard_env() -> dict[str, Any]:
|
|
997
986
|
"int?": is_int,
|
998
987
|
"float?": is_float,
|
999
988
|
"frac?": is_frac,
|
1000
|
-
"complex?": Contract("complex?", lambda v: type(v) is complex),
|
1001
989
|
"nat?": is_nat,
|
1002
990
|
"nat1?": is_nat1,
|
1003
991
|
"threshold?": is_threshold,
|
@@ -1052,9 +1040,6 @@ def make_standard_env() -> dict[str, Any]:
|
|
1052
1040
|
"div": Proc("div", int_div, (2, None), is_int),
|
1053
1041
|
"add1": Proc("add1", lambda z: z + 1, (1, 1), is_num),
|
1054
1042
|
"sub1": Proc("sub1", lambda z: z - 1, (1, 1), is_num),
|
1055
|
-
"sqrt": Proc("sqrt", _sqrt, (1, 1), is_num),
|
1056
|
-
"real-part": Proc("real-part", lambda v: v.real, (1, 1), is_num),
|
1057
|
-
"imag-part": Proc("imag-part", lambda v: v.imag, (1, 1), is_num),
|
1058
1043
|
# reals
|
1059
1044
|
"pow": Proc("pow", pow, (2, 2), is_real),
|
1060
1045
|
"abs": Proc("abs", abs, (1, 1), is_real),
|
auto_editor/lib/contracts.py
CHANGED
@@ -46,7 +46,7 @@ def check_contract(c: object, val: object) -> bool:
|
|
46
46
|
return val is True
|
47
47
|
if c is False:
|
48
48
|
return val is False
|
49
|
-
if type(c) in (int, float, float64, Fraction,
|
49
|
+
if type(c) in (int, float, float64, Fraction, str, Sym):
|
50
50
|
return val == c
|
51
51
|
raise MyError(f"Invalid contract, got: {print_str(c)}")
|
52
52
|
|
@@ -164,7 +164,7 @@ def is_contract(c: object) -> bool:
|
|
164
164
|
return True
|
165
165
|
if c is True or c is False:
|
166
166
|
return True
|
167
|
-
return type(c) in (int, float, Fraction,
|
167
|
+
return type(c) in (int, float, Fraction, str, Sym)
|
168
168
|
|
169
169
|
|
170
170
|
is_bool = Contract("bool?", lambda v: type(v) is bool)
|
@@ -172,10 +172,8 @@ is_int = Contract("int?", lambda v: type(v) is int)
|
|
172
172
|
is_nat = Contract("nat?", lambda v: type(v) is int and v > -1)
|
173
173
|
is_nat1 = Contract("nat1?", lambda v: type(v) is int and v > 0)
|
174
174
|
int_not_zero = Contract("(or/c (not/c 0) int?)", lambda v: v != 0 and is_int(v))
|
175
|
-
is_num = Contract(
|
176
|
-
"number?", lambda v: type(v) in (int, float, float64, Fraction, complex)
|
177
|
-
)
|
178
175
|
is_real = Contract("real?", lambda v: type(v) in (int, float, float64, Fraction))
|
176
|
+
is_num = is_real
|
179
177
|
is_float = Contract("float?", lambda v: type(v) in (float, float64))
|
180
178
|
is_frac = Contract("frac?", lambda v: type(v) is Fraction)
|
181
179
|
is_str = Contract("string?", lambda v: type(v) is str)
|
auto_editor/lib/data_structs.py
CHANGED
@@ -182,9 +182,6 @@ def display_str(val: object) -> str:
|
|
182
182
|
return f"{val}"
|
183
183
|
if type(val) is range:
|
184
184
|
return "#<range>"
|
185
|
-
if type(val) is complex:
|
186
|
-
join = "" if val.imag < 0 else "+"
|
187
|
-
return f"{val.real}{join}{val.imag}i"
|
188
185
|
if type(val) is np.bool_:
|
189
186
|
return "1" if val else "0"
|
190
187
|
if type(val) is np.float64 or type(val) is np.float32:
|
auto_editor/make_layers.py
CHANGED
@@ -11,7 +11,7 @@ from auto_editor.ffwrapper import FileInfo
|
|
11
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
|
-
from auto_editor.timeline import ASpace,
|
14
|
+
from auto_editor.timeline import ASpace, Clip, Template, VSpace, v1, v3
|
15
15
|
from auto_editor.utils.func import mut_margin
|
16
16
|
from auto_editor.utils.types import CoerceError, time
|
17
17
|
|
@@ -26,7 +26,7 @@ if TYPE_CHECKING:
|
|
26
26
|
BoolList = NDArray[np.bool_]
|
27
27
|
|
28
28
|
|
29
|
-
class
|
29
|
+
class VirClip(NamedTuple):
|
30
30
|
start: int
|
31
31
|
dur: int
|
32
32
|
offset: int
|
@@ -34,8 +34,8 @@ class Clip(NamedTuple):
|
|
34
34
|
src: FileInfo
|
35
35
|
|
36
36
|
|
37
|
-
def clipify(chunks: Chunks, src: FileInfo, start: int = 0) -> list[
|
38
|
-
clips: list[
|
37
|
+
def clipify(chunks: Chunks, src: FileInfo, start: int = 0) -> list[VirClip]:
|
38
|
+
clips: list[VirClip] = []
|
39
39
|
i = 0
|
40
40
|
for chunk in chunks:
|
41
41
|
if chunk[2] > 0 and chunk[2] < 99999.0:
|
@@ -46,14 +46,14 @@ def clipify(chunks: Chunks, src: FileInfo, start: int = 0) -> list[Clip]:
|
|
46
46
|
offset = int(chunk[0] / chunk[2])
|
47
47
|
|
48
48
|
if not (clips and clips[-1].start == round(start)):
|
49
|
-
clips.append(
|
49
|
+
clips.append(VirClip(start, dur, offset, chunk[2], src))
|
50
50
|
start += dur
|
51
51
|
i += 1
|
52
52
|
|
53
53
|
return clips
|
54
54
|
|
55
55
|
|
56
|
-
def make_av(src: FileInfo, all_clips: list[list[
|
56
|
+
def make_av(src: FileInfo, all_clips: list[list[VirClip]]) -> tuple[VSpace, ASpace]:
|
57
57
|
assert type(src) is FileInfo
|
58
58
|
vtl: VSpace = []
|
59
59
|
atl: ASpace = [[] for _ in range(len(src.audios))]
|
@@ -63,11 +63,11 @@ def make_av(src: FileInfo, all_clips: list[list[Clip]]) -> tuple[VSpace, ASpace]
|
|
63
63
|
if src.videos:
|
64
64
|
if len(vtl) == 0:
|
65
65
|
vtl.append([])
|
66
|
-
vtl[0].append(
|
66
|
+
vtl[0].append(Clip(c.start, c.dur, c.src, c.offset, 0, c.speed))
|
67
67
|
|
68
68
|
for c in clips:
|
69
69
|
for a in range(len(src.audios)):
|
70
|
-
atl[a].append(
|
70
|
+
atl[a].append(Clip(c.start, c.dur, c.src, c.offset, a, c.speed))
|
71
71
|
|
72
72
|
return vtl, atl
|
73
73
|
|
@@ -139,7 +139,7 @@ def make_timeline(
|
|
139
139
|
interpret(env, parser)
|
140
140
|
|
141
141
|
results = []
|
142
|
-
for
|
142
|
+
for src in sources:
|
143
143
|
try:
|
144
144
|
parser = Parser(Lexer("`--edit`", args.edit))
|
145
145
|
if log.is_debug:
|
@@ -247,7 +247,7 @@ def make_timeline(
|
|
247
247
|
check_monotonic = len(sources) == 1
|
248
248
|
last_i = 0
|
249
249
|
|
250
|
-
clips: list[
|
250
|
+
clips: list[VirClip] = []
|
251
251
|
start = 0
|
252
252
|
|
253
253
|
for chunk in echunk(speed_index, src_index):
|
@@ -265,7 +265,7 @@ def make_timeline(
|
|
265
265
|
raise ValueError("not monotonic", sources, this_i, last_i)
|
266
266
|
last_i = this_i
|
267
267
|
|
268
|
-
clips.append(
|
268
|
+
clips.append(VirClip(start, dur, offset, chunk[3], chunk[0]))
|
269
269
|
|
270
270
|
start += dur
|
271
271
|
|
@@ -275,13 +275,13 @@ def make_timeline(
|
|
275
275
|
if c.src.videos:
|
276
276
|
if len(vtl) == 0:
|
277
277
|
vtl.append([])
|
278
|
-
vtl[0].append(
|
278
|
+
vtl[0].append(Clip(c.start, c.dur, c.src, c.offset, 0, c.speed))
|
279
279
|
|
280
280
|
for c in clips:
|
281
281
|
for a in range(len(c.src.audios)):
|
282
282
|
if a >= len(atl):
|
283
283
|
atl.append([])
|
284
|
-
atl[a].append(
|
284
|
+
atl[a].append(Clip(c.start, c.dur, c.src, c.offset, a, c.speed))
|
285
285
|
|
286
286
|
# Turn long silent/loud array to formatted chunk list.
|
287
287
|
# Example: [1, 1, 1, 2, 2], {1: 1.0, 2: 1.5} => [(0, 3, 1.0), (3, 5, 1.5)]
|
auto_editor/render/audio.py
CHANGED
@@ -15,7 +15,7 @@ from auto_editor.json import load
|
|
15
15
|
from auto_editor.lang.palet import env
|
16
16
|
from auto_editor.lib.contracts import andc, between_c, is_int_or_float
|
17
17
|
from auto_editor.lib.err import MyError
|
18
|
-
from auto_editor.timeline import
|
18
|
+
from auto_editor.timeline import Clip, v3
|
19
19
|
from auto_editor.utils.cmdkw import ParserError, parse_with_palet, pAttr, pAttrs
|
20
20
|
from auto_editor.utils.func import parse_bitrate
|
21
21
|
from auto_editor.utils.log import Log
|
@@ -155,7 +155,7 @@ def apply_audio_normalization(
|
|
155
155
|
output_file.close()
|
156
156
|
|
157
157
|
|
158
|
-
def process_audio_clip(clip:
|
158
|
+
def process_audio_clip(clip: Clip, data: np.ndarray, sr: int, log: Log) -> np.ndarray:
|
159
159
|
to_s16 = bv.AudioResampler(format="s16", layout="stereo", rate=sr)
|
160
160
|
input_buffer = BytesIO()
|
161
161
|
|
@@ -217,6 +217,9 @@ def process_audio_clip(clip: TlAudio, data: np.ndarray, sr: int) -> np.ndarray:
|
|
217
217
|
except (bv.BlockingIOError, bv.EOFError):
|
218
218
|
break
|
219
219
|
|
220
|
+
if not all_frames:
|
221
|
+
log.debug(f"No audio frames at {clip=}")
|
222
|
+
return np.zeros_like(data)
|
220
223
|
return np.concatenate(all_frames, axis=1)
|
221
224
|
|
222
225
|
|
@@ -383,7 +386,7 @@ class Getter:
|
|
383
386
|
|
384
387
|
def __init__(self, path: Path, stream: int, rate: int):
|
385
388
|
self.container = bv.open(path)
|
386
|
-
self.stream = self.container.streams.audio[
|
389
|
+
self.stream = self.container.streams.audio[stream]
|
387
390
|
self.rate = rate
|
388
391
|
|
389
392
|
def get(self, start: int, end: int) -> np.ndarray:
|
@@ -454,7 +457,7 @@ def _make_new_audio(tl: v3, fmt: bv.AudioFormat, args: Args, log: Log) -> list[A
|
|
454
457
|
arr: np.ndarray | None = None
|
455
458
|
use_iter = False
|
456
459
|
|
457
|
-
for
|
460
|
+
for clip in layer:
|
458
461
|
if (clip.src, clip.stream) not in samples:
|
459
462
|
samples[(clip.src, clip.stream)] = Getter(
|
460
463
|
clip.src.path, clip.stream, sr
|
@@ -473,7 +476,7 @@ def _make_new_audio(tl: v3, fmt: bv.AudioFormat, args: Args, log: Log) -> list[A
|
|
473
476
|
|
474
477
|
if clip.speed != 1 or clip.volume != 1:
|
475
478
|
clip_arr = process_audio_clip(
|
476
|
-
clip, getter.get(samp_start, samp_end), sr
|
479
|
+
clip, getter.get(samp_start, samp_end), sr, log
|
477
480
|
)
|
478
481
|
else:
|
479
482
|
clip_arr = getter.get(samp_start, samp_end)
|
auto_editor/render/video.py
CHANGED
@@ -6,7 +6,7 @@ from typing import TYPE_CHECKING
|
|
6
6
|
import bv
|
7
7
|
import numpy as np
|
8
8
|
|
9
|
-
from auto_editor.timeline import TlImage, TlRect
|
9
|
+
from auto_editor.timeline import Clip, TlImage, TlRect
|
10
10
|
from auto_editor.utils.func import parse_bitrate
|
11
11
|
|
12
12
|
if TYPE_CHECKING:
|
@@ -120,6 +120,7 @@ def render_av(
|
|
120
120
|
|
121
121
|
del codec
|
122
122
|
output_stream = output.add_stream(args.video_codec, rate=target_fps)
|
123
|
+
output_stream.options = {"x265-params": "log-level=error"} # type: ignore
|
123
124
|
|
124
125
|
cc = output_stream.codec_context
|
125
126
|
if args.vprofile is not None:
|
@@ -193,7 +194,7 @@ def render_av(
|
|
193
194
|
obj_list: list[VideoFrame | TlRect | TlImage] = []
|
194
195
|
for layer in tl.v:
|
195
196
|
for lobj in layer:
|
196
|
-
if isinstance(lobj,
|
197
|
+
if isinstance(lobj, Clip):
|
197
198
|
if index >= lobj.start and index < (lobj.start + lobj.dur):
|
198
199
|
_i = round((lobj.offset + index - lobj.start) * lobj.speed)
|
199
200
|
obj_list.append(VideoFrame(_i, lobj.src))
|
auto_editor/timeline.py
CHANGED
@@ -38,45 +38,24 @@ class v1:
|
|
38
38
|
|
39
39
|
|
40
40
|
@dataclass(slots=True)
|
41
|
-
class
|
41
|
+
class Clip:
|
42
42
|
start: int
|
43
43
|
dur: int
|
44
44
|
src: FileInfo
|
45
45
|
offset: int
|
46
|
-
speed: float
|
47
46
|
stream: int
|
48
47
|
|
49
|
-
|
50
|
-
|
51
|
-
"name": "video",
|
52
|
-
"src": self.src,
|
53
|
-
"start": self.start,
|
54
|
-
"dur": self.dur,
|
55
|
-
"offset": self.offset,
|
56
|
-
"speed": self.speed,
|
57
|
-
"stream": self.stream,
|
58
|
-
}
|
59
|
-
|
60
|
-
|
61
|
-
@dataclass(slots=True)
|
62
|
-
class TlAudio:
|
63
|
-
start: int
|
64
|
-
dur: int
|
65
|
-
src: FileInfo
|
66
|
-
offset: int
|
67
|
-
speed: float
|
68
|
-
volume: float
|
69
|
-
stream: int
|
48
|
+
speed: float = 1.0
|
49
|
+
volume: float = 1.0
|
70
50
|
|
71
51
|
def as_dict(self) -> dict:
|
72
52
|
return {
|
73
|
-
"name": "
|
53
|
+
"name": "video",
|
74
54
|
"src": self.src,
|
75
55
|
"start": self.start,
|
76
56
|
"dur": self.dur,
|
77
57
|
"offset": self.offset,
|
78
58
|
"speed": self.speed,
|
79
|
-
"volume": self.volume,
|
80
59
|
"stream": self.stream,
|
81
60
|
}
|
82
61
|
|
@@ -176,14 +155,12 @@ rect_builder = pAttrs(
|
|
176
155
|
visual_objects = {
|
177
156
|
"rect": (TlRect, rect_builder),
|
178
157
|
"image": (TlImage, img_builder),
|
179
|
-
"video": (
|
158
|
+
"video": (Clip, video_builder),
|
180
159
|
}
|
181
160
|
|
182
|
-
VLayer = list[
|
161
|
+
VLayer = list[Clip | TlImage | TlRect]
|
183
162
|
VSpace = list[VLayer]
|
184
|
-
|
185
|
-
ALayer = list[TlAudio]
|
186
|
-
ASpace = list[ALayer]
|
163
|
+
ASpace = list[list[Clip]]
|
187
164
|
|
188
165
|
|
189
166
|
@dataclass(slots=True)
|
@@ -248,7 +225,7 @@ video\n"""
|
|
248
225
|
for i, layer in enumerate(self.v):
|
249
226
|
result += f" v{i} "
|
250
227
|
for obj in layer:
|
251
|
-
if isinstance(obj,
|
228
|
+
if isinstance(obj, Clip):
|
252
229
|
result += (
|
253
230
|
f"[#:start {obj.start} #:dur {obj.dur} #:off {obj.offset}] "
|
254
231
|
)
|
@@ -283,7 +260,7 @@ video\n"""
|
|
283
260
|
def sources(self) -> Iterator[FileInfo]:
|
284
261
|
for vclips in self.v:
|
285
262
|
for v in vclips:
|
286
|
-
if isinstance(v,
|
263
|
+
if isinstance(v, Clip):
|
287
264
|
yield v.src
|
288
265
|
for aclips in self.a:
|
289
266
|
for a in aclips:
|
@@ -306,15 +283,26 @@ video\n"""
|
|
306
283
|
return result
|
307
284
|
|
308
285
|
def as_dict(self) -> dict:
|
286
|
+
def aclip_to_dict(self: Clip) -> dict:
|
287
|
+
return {
|
288
|
+
"name": "audio",
|
289
|
+
"src": self.src,
|
290
|
+
"start": self.start,
|
291
|
+
"dur": self.dur,
|
292
|
+
"offset": self.offset,
|
293
|
+
"speed": self.speed,
|
294
|
+
"volume": self.volume,
|
295
|
+
"stream": self.stream,
|
296
|
+
}
|
297
|
+
|
309
298
|
v = []
|
310
|
-
|
299
|
+
a = []
|
300
|
+
for vlayer in self.v:
|
311
301
|
vb = [vobj.as_dict() for vobj in vlayer]
|
312
302
|
if vb:
|
313
303
|
v.append(vb)
|
314
|
-
|
315
|
-
|
316
|
-
for i, alayer in enumerate(self.a):
|
317
|
-
ab = [aobj.as_dict() for aobj in alayer]
|
304
|
+
for layer in self.a:
|
305
|
+
ab = [aclip_to_dict(clip) for clip in layer]
|
318
306
|
if ab:
|
319
307
|
a.append(ab)
|
320
308
|
|
@@ -342,7 +330,7 @@ video\n"""
|
|
342
330
|
return self.T.sr
|
343
331
|
|
344
332
|
|
345
|
-
def make_tracks_dir(tracks_dir: Path
|
333
|
+
def make_tracks_dir(tracks_dir: Path) -> None:
|
346
334
|
from os import mkdir
|
347
335
|
from shutil import rmtree
|
348
336
|
|
@@ -353,7 +341,7 @@ def make_tracks_dir(tracks_dir: Path, path: Path) -> None:
|
|
353
341
|
mkdir(tracks_dir)
|
354
342
|
|
355
343
|
|
356
|
-
def set_stream_to_0(
|
344
|
+
def set_stream_to_0(tl: v3, log: Log) -> None:
|
357
345
|
dir_exists = False
|
358
346
|
cache: dict[Path, FileInfo] = {}
|
359
347
|
|
@@ -362,7 +350,7 @@ def set_stream_to_0(src: FileInfo, tl: v3, log: Log) -> None:
|
|
362
350
|
|
363
351
|
fold = path.parent / f"{path.stem}_tracks"
|
364
352
|
if not dir_exists:
|
365
|
-
make_tracks_dir(fold
|
353
|
+
make_tracks_dir(fold)
|
366
354
|
dir_exists = True
|
367
355
|
|
368
356
|
newtrack = fold / f"{path.stem}_{i}.wav"
|
@@ -1,44 +1,44 @@
|
|
1
|
-
auto_editor/__init__.py,sha256=
|
1
|
+
auto_editor/__init__.py,sha256=qvc7djhJkqlXmlxcWZWLvK6JKBp01_I3fJuFV5euTBg,23
|
2
2
|
auto_editor/__main__.py,sha256=t5Um7M9ess9xYRfmn6iDvJoBqj_KRQLhlkpFdfhx3MU,15478
|
3
3
|
auto_editor/analyze.py,sha256=CeJG0LI9wXZk1R-QPrNGPS4za-_Avd8y7H-D437DqLg,12300
|
4
|
-
auto_editor/edit.py,sha256=
|
4
|
+
auto_editor/edit.py,sha256=GhOfKIe_FdbBGDQ_WH02CJl7Oi-AwaaSSh73F81h_kA,19234
|
5
5
|
auto_editor/ffwrapper.py,sha256=ueYdN7-cBAdJBJbv5yT05iuQP_BPFIrR5hFeMkk5c3U,5040
|
6
6
|
auto_editor/help.py,sha256=8Kkos7Bpcn-3YN7ngv0fZp-8a8Qw6b70ZZKerL8SEQ4,7901
|
7
|
-
auto_editor/json.py,sha256=
|
8
|
-
auto_editor/make_layers.py,sha256=
|
7
|
+
auto_editor/json.py,sha256=g6ZsrSOXtjQj-8Otea3TIY2G-HZ6g-IXUblwukgTO1g,9332
|
8
|
+
auto_editor/make_layers.py,sha256=Udxn7Vw0Jz9HOarLeswQ-WwTu87PWcsyduBdtFwSOyc,10079
|
9
9
|
auto_editor/preview.py,sha256=yYn5jJLQ3TiJiNC6JffaggLVPQfBU558zJeRQz7nCDY,3046
|
10
|
-
auto_editor/timeline.py,sha256=
|
10
|
+
auto_editor/timeline.py,sha256=ebnEX23HubNm444SIB2QNPkNdZcxHGhci1BpAeVDwcQ,9186
|
11
11
|
auto_editor/vanparse.py,sha256=Ug5A2QaRqGiw4l55Z_h9T2QU1x0WqRibR7yY5rQ0WTk,10002
|
12
12
|
auto_editor/cmds/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
13
|
-
auto_editor/cmds/cache.py,sha256=
|
13
|
+
auto_editor/cmds/cache.py,sha256=rK06dX3Z1pDAK0t5rqR7S2cMEpnT_Tv17t3Q5qPQKLI,1959
|
14
14
|
auto_editor/cmds/desc.py,sha256=kdRJfabdde5thuFOoTXlW3J3G8F0ZvbsJoOkUn7E3GA,805
|
15
|
-
auto_editor/cmds/info.py,sha256=
|
15
|
+
auto_editor/cmds/info.py,sha256=NwzZu6l6IIdK0ajZdn8WX_iiJwlsMrGIZ2vffDRu3gc,6535
|
16
16
|
auto_editor/cmds/levels.py,sha256=2Hbvoy6wMbRRoHdZf25PMqq1uvhRKyPcITNPMpZFo7s,5632
|
17
|
-
auto_editor/cmds/palet.py,sha256=
|
17
|
+
auto_editor/cmds/palet.py,sha256=t2O_xM82PXUjnSgcHxyt9OG24gwQS4ksR2sKiQ1SvUA,743
|
18
18
|
auto_editor/cmds/repl.py,sha256=HSUTDaVykPb5Bd-v_jz_8R7HvFmKOcT_ZVmP-d0AbUY,3247
|
19
|
-
auto_editor/cmds/subdump.py,sha256=
|
20
|
-
auto_editor/cmds/test.py,sha256=
|
19
|
+
auto_editor/cmds/subdump.py,sha256=Zxs9X0gEaQYA5F1EqccJmVUYfI1o3J7ltyc9bvy1tA4,2393
|
20
|
+
auto_editor/cmds/test.py,sha256=p7z2cojsiyWnRN_UVeT4iYakkGlsQTjt_dRZ4cSvIQg,29835
|
21
21
|
auto_editor/exports/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
22
|
-
auto_editor/exports/fcp11.py,sha256=
|
23
|
-
auto_editor/exports/fcp7.py,sha256=
|
22
|
+
auto_editor/exports/fcp11.py,sha256=LiWHtA-jgwzbiSoBzNBUaTjOEuqnvr3dYBQmdlw7m3Y,5244
|
23
|
+
auto_editor/exports/fcp7.py,sha256=shZtn5i66hqGVrpR1PP1hiwKiZirr1cRUxATzbW-BOo,12069
|
24
24
|
auto_editor/exports/json.py,sha256=Z7RKtD5-OB3saOtWG9qfI9OrLtylhU9VyfpnVRNcuU8,768
|
25
|
-
auto_editor/exports/shotcut.py,sha256=
|
25
|
+
auto_editor/exports/shotcut.py,sha256=MpzYqDO_XSnd-bKCKQjJFqOf_mSdR9QOWi8_Y1Y_BwY,4696
|
26
26
|
auto_editor/imports/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
27
|
-
auto_editor/imports/fcp7.py,sha256=
|
28
|
-
auto_editor/imports/json.py,sha256=
|
27
|
+
auto_editor/imports/fcp7.py,sha256=Vep1syViRZOrtZBlF6Ek_eRy0rLINpTso5nrh3uY3zk,8563
|
28
|
+
auto_editor/imports/json.py,sha256=5c_vKoS8FzxAWagCetrwATHdnZ2beWQ77g8JYKVM0i8,6993
|
29
29
|
auto_editor/lang/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
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=
|
33
|
-
auto_editor/lang/stdenv.py,sha256=
|
32
|
+
auto_editor/lang/palet.py,sha256=bsuEWNEefTb0-69Dc4lq4aotqu7aarH1okETK8ab-Gw,22794
|
33
|
+
auto_editor/lang/stdenv.py,sha256=munuKA5rkg_5krQ_km92JhoNY6Vio9wo5E79YWlD2eg,43654
|
34
34
|
auto_editor/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
35
|
-
auto_editor/lib/contracts.py,sha256=
|
36
|
-
auto_editor/lib/data_structs.py,sha256=
|
35
|
+
auto_editor/lib/contracts.py,sha256=bADXnFXyq_-Tku59saxwDOlvexfS3wMAMdrKNL-Ql2w,7494
|
36
|
+
auto_editor/lib/data_structs.py,sha256=2SxsOXKiY0H95wRIFOrQBjv1ykJUQar0Vr5dK9zZOiQ,6971
|
37
37
|
auto_editor/lib/err.py,sha256=UlszQJdzMZwkbT8x3sY4GkCV_5x9yrd6uVVUzvA8iiI,35
|
38
38
|
auto_editor/render/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
39
|
-
auto_editor/render/audio.py,sha256=
|
39
|
+
auto_editor/render/audio.py,sha256=08Leg9R66ROz8meZyY03e7yfUd5otxdd6DdNO9vX5ys,17518
|
40
40
|
auto_editor/render/subtitle.py,sha256=F27T8OsAojUIGTGBWqTdH36h0BnHXSExxIqzOtqyZoE,6129
|
41
|
-
auto_editor/render/video.py,sha256=
|
41
|
+
auto_editor/render/video.py,sha256=8somlAxtbGMSRREab8psTdIlaETZQ2s2gY20PWY9sww,12072
|
42
42
|
auto_editor/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
43
43
|
auto_editor/utils/bar.py,sha256=Ky9JRf37JTgLyvNuIXDfucaUE8H1vBbCqKLjttmsmmo,4156
|
44
44
|
auto_editor/utils/chunks.py,sha256=J-eGKtEz68gFtRrj1kOSgH4Tj_Yz6prNQ7Xr-d9NQJw,52
|
@@ -47,10 +47,10 @@ auto_editor/utils/container.py,sha256=CNHChHbhzIrjmDdWw6UzMqscrr9u7A-ZqKWejGjJwY
|
|
47
47
|
auto_editor/utils/func.py,sha256=ODyjXnzSDatEu08w398K8_xBKYdXMY3IPHiJpGRZDyQ,3250
|
48
48
|
auto_editor/utils/log.py,sha256=wPNf6AabV-0cnoS_bPLv1Lh7llQBtNqPKeh07einOuc,3701
|
49
49
|
auto_editor/utils/types.py,sha256=j2hd4zMQ9EftDy41Ji2_PFru_7HEZObd9yKA0BJxFaY,7616
|
50
|
-
auto_editor-28.0.
|
50
|
+
auto_editor-28.0.1.dist-info/licenses/LICENSE,sha256=yiq99pWITHfqS0pbZMp7cy2dnbreTuvBwudsU-njvIM,1210
|
51
51
|
docs/build.py,sha256=g1uc1H9T_naGaermUiVMMwUpbT0IWElRhjgT0fvCh8w,1914
|
52
|
-
auto_editor-28.0.
|
53
|
-
auto_editor-28.0.
|
54
|
-
auto_editor-28.0.
|
55
|
-
auto_editor-28.0.
|
56
|
-
auto_editor-28.0.
|
52
|
+
auto_editor-28.0.1.dist-info/METADATA,sha256=DqTFmUbe3CYS0CefGlNadtwH80JaemOw0MOCXtDGCsg,6176
|
53
|
+
auto_editor-28.0.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
54
|
+
auto_editor-28.0.1.dist-info/entry_points.txt,sha256=UAsTc7qJQbnAzHd7KWg-ALo_X9Hj2yDs3M9I2DV3eyI,212
|
55
|
+
auto_editor-28.0.1.dist-info/top_level.txt,sha256=jBV5zlbWRbKOa-xaWPvTD45QL7lGExx2BDzv-Ji4dTw,17
|
56
|
+
auto_editor-28.0.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|