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 CHANGED
@@ -1 +1 @@
1
- __version__ = "28.0.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 {"B", "KiB", "MiB", "GiB", "TiB"}:
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 track, v in enumerate(src.videos):
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 track, a in enumerate(src.audios):
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 track, s_stream in enumerate(src.subtitles):
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, True)))
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)
@@ -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 do_filter and endf - startf <= 0.02:
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 i, input_file in enumerate(args.input):
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(runner: Runner, tests: list[Callable], args: TestArgs) -> None:
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(run, tests, args)
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
- assert src is not None
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 != "none" and tl.v:
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
@@ -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, Any, cast
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: TlVideo | TlAudio) -> None:
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: Sequence[TlVideo | TlAudio] = cast(Any, tl.v[0])
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:
@@ -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 TlVideo, v3
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, TlVideo)
261
+ assert isinstance(clip, Clip)
299
262
 
300
263
  _start = f"{clip.start}"
301
264
  _end = f"{clip.start + clip.dur}"
@@ -1,13 +1,9 @@
1
1
  import xml.etree.ElementTree as ET
2
- from typing import TYPE_CHECKING, Any, cast
2
+ from typing import cast
3
3
 
4
- from auto_editor.timeline import TlAudio, TlVideo, v3
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: Sequence[TlVideo | TlAudio] = cast(Any, tl.v[0])
74
+ clips = cast(list[Clip], tl.v[0])
79
75
  elif tl.a:
80
76
  clips = tl.a[0]
81
77
  else:
@@ -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, Template, TlAudio, TlVideo, VSpace, v3
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 i, clipitem in enumerate(track["clipitem"]):
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
- TlVideo(start, dur, sources[file_id], offset, speed, stream=0)
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 i, clipitem in enumerate(track["clipitem"]):
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
- TlAudio(
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)
@@ -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[TlAudio]] = []
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(TlAudio(**parse_obj(adict, audio_builder)))
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(TlVideo(c.start, c.dur, c.src, c.offset, c.speed, 0))
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(TlAudio(c.start, c.dur, c.src, c.offset, c.speed, 1, a))
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 i in range(4):
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 i in range(5): # Longest valid keyword length
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
- "filename",
70
- "text",
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 != "i" and 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 == "i":
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
 
@@ -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 | complex | Fraction
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(env: Env, node: Node) -> Any:
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),
@@ -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, complex, str, Sym):
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, complex, str, Sym)
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)
@@ -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:
@@ -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, Template, TlAudio, TlVideo, VSpace, v1, v3
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 Clip(NamedTuple):
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[Clip]:
38
- clips: list[Clip] = []
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(Clip(start, dur, offset, chunk[2], src))
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[Clip]]) -> tuple[VSpace, ASpace]:
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(TlVideo(c.start, c.dur, c.src, c.offset, c.speed, 0))
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(TlAudio(c.start, c.dur, c.src, c.offset, c.speed, 1, a))
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 i, src in enumerate(sources):
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[Clip] = []
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(Clip(start, dur, offset, chunk[3], chunk[0]))
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(TlVideo(c.start, c.dur, c.src, c.offset, c.speed, 0))
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(TlAudio(c.start, c.dur, c.src, c.offset, c.speed, 1, a))
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)]
@@ -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 TlAudio, v3
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: TlAudio, data: np.ndarray, sr: int) -> np.ndarray:
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[0]
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 c, clip in enumerate(layer):
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)
@@ -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, TlVideo
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, TlVideo):
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 TlVideo:
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
- def as_dict(self) -> dict:
50
- return {
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": "audio",
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": (TlVideo, video_builder),
158
+ "video": (Clip, video_builder),
180
159
  }
181
160
 
182
- VLayer = list[TlVideo | TlImage | TlRect]
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, TlVideo):
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, TlVideo):
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
- for i, vlayer in enumerate(self.v):
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
- a = []
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, path: Path) -> None:
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(src: FileInfo, tl: v3, log: Log) -> None:
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, path)
353
+ make_tracks_dir(fold)
366
354
  dir_exists = True
367
355
 
368
356
  newtrack = fold / f"{path.stem}_{i}.wav"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: auto-editor
3
- Version: 28.0.0
3
+ Version: 28.0.1
4
4
  Summary: Auto-Editor: Effort free video editing!
5
5
  Author-email: WyattBlue <wyattblue@auto-editor.com>
6
6
  License-Expression: Unlicense
@@ -1,44 +1,44 @@
1
- auto_editor/__init__.py,sha256=DffemEfW53YOlYaNQ9gcZ_Hf1d--6ODBrbX9JaC4Y9Y,23
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=p_UOfReMkMmdhh7b5azXBWvX99AyMKO-ZpnZBso5cj0,19257
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=8IVhZJSLx2IVqJsbR5YKDvbHOhgIOvdQmYNpMdMG_xA,9332
8
- auto_editor/make_layers.py,sha256=nSEeCHysMot2eze23q05g2HFDuskN_4Jk108xlk2Rw8,10102
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=9D-2lXIGXx2R82qQ7_4TfG77ikN4byM_fK_1QyLlPZ8,9346
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=bViYbtVXefTeEIUvSanDfA6cG35ep1N_Jvtz7ZjgIkY,1959
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=awiusgunhoiqrr3LX0AevrVwj4foNJrtRBJUbIebwyc,6589
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=ONzTqemaQq9YEfIOsDRNnwzfqnEMUMSXIQrETxyroRU,749
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=kHg8nfUi6I6VeJjEgMxupPa666qsYUh7ZEUxint7Gqo,2443
20
- auto_editor/cmds/test.py,sha256=VVU1sVDhv4jclJUw387ruWTSRFPh5m-1wfYEGW3mzBs,29624
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=3HKkTv65J3NZohAyuc08tuHk4fqgEGN8RAMQNzrNFrY,5340
23
- auto_editor/exports/fcp7.py,sha256=6ZP9EtVc8nPZu-2zZn1IZP4I5gYedzZ6TJFRM36XDWc,13480
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=J2Myi9fu37fUVqr5mzlWcfHJ9LVKu3f4Pz3tEq2onCc,4811
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=hWh78sDmMSsf7RhteDCbyz_aS8QYwY2fUg-BB-FchZg,8653
28
- auto_editor/imports/json.py,sha256=gsWtlLl26Y7BeOaIAngWH_I0innqp8bFmew0qzQWZB8,7024
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=VS_G_-czy9epsBrqUa0dhEPKWJMGaj3Q5Q49l7mp2so,24121
33
- auto_editor/lang/stdenv.py,sha256=ndxkNTFl6QbcgGdgoQtvAfjZhRiqDn6z_-Ad427bcNo,44285
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=VWLERPFmf6Lb_3yZoMeqF7pyBTWfAMChIVUVpzN9tz0,7593
36
- auto_editor/lib/data_structs.py,sha256=Hnzl5gWvo-geTU0g-lGejj6HQW3VvPv0NBEj2XoGskY,7089
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=OsvUXJD_qmv2xHivLD6skEmK8vdmPyLMhV7mBFdMLQM,17411
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=uIrYzF4bDZ3vwfX2F6TdR6F73GI4yruGssto9xEQ-AA,11999
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.0.dist-info/licenses/LICENSE,sha256=yiq99pWITHfqS0pbZMp7cy2dnbreTuvBwudsU-njvIM,1210
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.0.dist-info/METADATA,sha256=5hrS0TC7CGSbN5GyOatgqq8svTg9nWNiHw_9fSvHGms,6176
53
- auto_editor-28.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
54
- auto_editor-28.0.0.dist-info/entry_points.txt,sha256=UAsTc7qJQbnAzHd7KWg-ALo_X9Hj2yDs3M9I2DV3eyI,212
55
- auto_editor-28.0.0.dist-info/top_level.txt,sha256=jBV5zlbWRbKOa-xaWPvTD45QL7lGExx2BDzv-Ji4dTw,17
56
- auto_editor-28.0.0.dist-info/RECORD,,
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,,