auto-editor 28.0.1__py3-none-any.whl → 28.0.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
auto_editor/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "28.0.1"
1
+ __version__ = "28.0.2"
@@ -36,6 +36,7 @@ class LevelArgs:
36
36
  input: list[str] = field(default_factory=list)
37
37
  edit: str = "audio"
38
38
  timebase: Fraction | None = None
39
+ no_cache: bool = False
39
40
  help: bool = False
40
41
 
41
42
 
@@ -53,16 +54,14 @@ def levels_options(parser: ArgumentParser) -> ArgumentParser:
53
54
  type=frame_rate,
54
55
  help="Set custom timebase",
55
56
  )
57
+ parser.add_argument("--no-cache", flag=True)
56
58
  return parser
57
59
 
58
60
 
59
61
  def print_arr(arr: NDArray) -> None:
60
62
  print("")
61
63
  print("@start")
62
- if arr.dtype in {np.float64, np.float32, np.float16}:
63
- for a in arr:
64
- sys.stdout.write(f"{a:.20f}\n")
65
- elif arr.dtype == np.bool_:
64
+ if arr.dtype == np.bool_:
66
65
  for a in arr:
67
66
  sys.stdout.write(f"{1 if a else 0}\n")
68
67
  else:
@@ -76,7 +75,7 @@ def print_arr_gen(arr: Iterator[float | np.float32]) -> None:
76
75
  print("")
77
76
  print("@start")
78
77
  for a in arr:
79
- print(f"{a:.20f}")
78
+ print(f"{a}")
80
79
  print("")
81
80
 
82
81
 
@@ -131,7 +130,11 @@ def main(sys_args: list[str] = sys.argv[1:]) -> None:
131
130
  levels = initLevels(src, tb, bar, False, log)
132
131
  try:
133
132
  if method == "audio":
134
- if (arr := levels.read_cache("audio", (obj["stream"],))) is not None:
133
+ if (
134
+ not args.no_cache
135
+ and (arr := levels.read_cache("audio", (obj["stream"],)))
136
+ is not None
137
+ ):
135
138
  print_arr(arr)
136
139
  else:
137
140
  container = bv.open(src.path, "r")
@@ -148,11 +151,15 @@ def main(sys_args: list[str] = sys.argv[1:]) -> None:
148
151
  container.close()
149
152
 
150
153
  cache_array = np.array(values, dtype=np.float32)
151
- levels.cache(cache_array, "audio", (obj["stream"],))
154
+ if not args.no_cache:
155
+ levels.cache(cache_array, "audio", (obj["stream"],))
152
156
 
153
157
  elif method == "motion":
154
158
  mobj = (obj["stream"], obj["width"], obj["blur"])
155
- if (arr := levels.read_cache("motion", mobj)) is not None:
159
+ if (
160
+ not args.no_cache
161
+ and (arr := levels.read_cache("motion", mobj)) is not None
162
+ ):
156
163
  print_arr(arr)
157
164
  else:
158
165
  container = bv.open(src.path, "r")
@@ -171,7 +178,8 @@ def main(sys_args: list[str] = sys.argv[1:]) -> None:
171
178
  container.close()
172
179
 
173
180
  cache_array = np.array(values, dtype=np.float32)
174
- levels.cache(cache_array, "motion", mobj)
181
+ if not args.no_cache:
182
+ levels.cache(cache_array, "motion", mobj)
175
183
 
176
184
  elif method == "subtitle":
177
185
  print_arr(levels.subtitle(**obj))
auto_editor/edit.py CHANGED
@@ -29,8 +29,8 @@ if TYPE_CHECKING:
29
29
 
30
30
 
31
31
  def set_output(
32
- out: str | None, _export: str | None, path: Path | None, log: Log
33
- ) -> tuple[str, dict[str, Any]]:
32
+ out: str | None, export: str | None, path: Path | None, log: Log
33
+ ) -> tuple[str, str]:
34
34
  if out is None or out == "-":
35
35
  if path is None:
36
36
  log.error("`--output` must be set.") # When a timeline file is the input.
@@ -42,33 +42,33 @@ def set_output(
42
42
  # Use `mp4` as the default, because it is most compatible.
43
43
  ext = ".mp4" if path is None else path.suffix
44
44
 
45
- if _export is None:
45
+ if export is None:
46
46
  match ext:
47
47
  case ".xml":
48
- export: dict[str, Any] = {"export": "premiere"}
48
+ export = "premiere"
49
49
  case ".fcpxml":
50
- export = {"export": "final-cut-pro"}
50
+ export = "final-cut-pro"
51
51
  case ".mlt":
52
- export = {"export": "shotcut"}
52
+ export = "shotcut"
53
53
  case ".json" | ".v1":
54
- export = {"export": "v1"}
54
+ export = "v1"
55
55
  case ".v3":
56
- export = {"export": "v3"}
56
+ export = "v3"
57
57
  case _:
58
- export = {"export": "default"}
59
- else:
60
- export = parse_export(_export, log)
61
-
62
- ext_map = {
63
- "premiere": ".xml",
64
- "resolve-fcp7": ".xml",
65
- "final-cut-pro": ".fcpxml",
66
- "resolve": ".fcpxml",
67
- "shotcut": ".mlt",
68
- "json": ".json",
69
- }
70
- if export["export"] in ext_map:
71
- ext = ext_map[export["export"]]
58
+ export = "default"
59
+
60
+ match export:
61
+ case "premiere" | "resolve-fcp7":
62
+ ext = ".xml"
63
+ case "final-cut-pro" | "resolve":
64
+ ext = ".fcpxml"
65
+ case "shotcut":
66
+ ext = ".mlt"
67
+ case "v1":
68
+ if ext != ".json":
69
+ ext = ".v1"
70
+ case "v3":
71
+ ext = ".v3"
72
72
 
73
73
  if out == "-":
74
74
  return "-", export
@@ -184,9 +184,13 @@ def edit_media(paths: list[str], args: Args, log: Log) -> None:
184
184
  src = sources[0]
185
185
  use_path = src.path
186
186
 
187
- output, export_ops = set_output(args.output, args.export, use_path, log)
188
- assert "export" in export_ops
189
- export = export_ops["export"]
187
+ if args.export is None:
188
+ output, export = set_output(args.output, args.export, use_path, log)
189
+ export_ops: dict[str, Any] = {"export": export}
190
+ else:
191
+ export_ops = parse_export(args.export, log)
192
+ export = export_ops["export"]
193
+ output, _ = set_output(args.output, export, use_path, log)
190
194
 
191
195
  if output == "-":
192
196
  # When printing to stdout, silence all logs.
@@ -1,17 +1,10 @@
1
- from __future__ import annotations
2
-
3
1
  import xml.etree.ElementTree as ET
4
- from typing import TYPE_CHECKING, cast
2
+ from fractions import Fraction
5
3
  from xml.etree.ElementTree import Element, ElementTree, SubElement, indent
6
4
 
5
+ from auto_editor.ffwrapper import FileInfo
7
6
  from auto_editor.timeline import Clip, v3
8
-
9
- if TYPE_CHECKING:
10
- from fractions import Fraction
11
-
12
- from auto_editor.ffwrapper import FileInfo
13
- from auto_editor.utils.log import Log
14
-
7
+ from auto_editor.utils.log import Log
15
8
 
16
9
  """
17
10
  Export a FCPXML 11 file readable with Final Cut Pro 10.6.8 or later.
@@ -52,6 +45,35 @@ def make_name(src: FileInfo, tb: Fraction) -> str:
52
45
  return "FFVideoFormatRateUndefined"
53
46
 
54
47
 
48
+ def parseSMPTE(val: str, fps: Fraction, log: Log) -> int:
49
+ if len(val) == 0:
50
+ return 0
51
+ try:
52
+ parts = val.split(":")
53
+ if len(parts) != 4:
54
+ raise ValueError(f"Invalid SMPTE format: {val}")
55
+
56
+ hours, minutes, seconds, frames = map(int, parts)
57
+
58
+ if (
59
+ hours < 0
60
+ or minutes < 0
61
+ or minutes >= 60
62
+ or seconds < 0
63
+ or seconds >= 60
64
+ or frames < 0
65
+ ):
66
+ raise ValueError(f"Invalid SMPTE values: {val}")
67
+
68
+ if frames >= fps:
69
+ raise ValueError(f"Frame count {frames} exceeds fps {fps}")
70
+
71
+ total_frames = (hours * 3600 + minutes * 60 + seconds) * fps + frames
72
+ return int(round(total_frames))
73
+ except (ValueError, ZeroDivisionError) as e:
74
+ log.error(f"Cannot parse SMPTE timecode '{val}': {e}")
75
+
76
+
55
77
  def fcp11_write_xml(
56
78
  group_name: str, version: int, output: str, resolve: bool, tl: v3, log: Log
57
79
  ) -> None:
@@ -90,12 +112,14 @@ def fcp11_write_xml(
90
112
  height=f"{tl.res[1]}",
91
113
  colorSpace=get_colorspace(one_src),
92
114
  )
115
+
116
+ startPoint = parseSMPTE(one_src.timecode, tl.tb, log)
93
117
  r2 = SubElement(
94
118
  resources,
95
119
  "asset",
96
120
  id=f"r{i * 2 + 2}",
97
121
  name=one_src.path.stem,
98
- start="0s",
122
+ start=fraction(startPoint),
99
123
  hasVideo="1" if one_src.videos else "0",
100
124
  format=f"r{i * 2 + 1}",
101
125
  hasAudio="1" if one_src.audios else "0",
@@ -122,12 +146,14 @@ def fcp11_write_xml(
122
146
  spine = SubElement(sequence, "spine")
123
147
 
124
148
  def make_clip(ref: str, clip: Clip) -> None:
149
+ startPoint = parseSMPTE(clip.src.timecode, tl.tb, log)
150
+
125
151
  clip_properties = {
126
152
  "name": proj_name,
127
153
  "ref": ref,
128
- "offset": fraction(clip.start),
154
+ "offset": fraction(clip.start + startPoint),
129
155
  "duration": fraction(clip.dur),
130
- "start": fraction(clip.offset),
156
+ "start": fraction(clip.offset + startPoint),
131
157
  "tcFormat": "NDF",
132
158
  }
133
159
  asset = SubElement(spine, "asset-clip", clip_properties)
@@ -146,7 +172,7 @@ def fcp11_write_xml(
146
172
  )
147
173
 
148
174
  if tl.v and tl.v[0]:
149
- clips = cast(list[Clip], tl.v[0])
175
+ clips = [clip for clip in tl.v[0] if isinstance(clip, Clip)]
150
176
  elif tl.a and tl.a[0]:
151
177
  clips = tl.a[0]
152
178
  else:
@@ -1,13 +1,44 @@
1
- from __future__ import annotations
2
-
3
1
  import sys
4
- from typing import TYPE_CHECKING
5
2
 
6
3
  from auto_editor.json import dump
7
- from auto_editor.timeline import v3
8
-
9
- if TYPE_CHECKING:
10
- from auto_editor.utils.log import Log
4
+ from auto_editor.timeline import Clip, v3
5
+ from auto_editor.utils.log import Log
6
+
7
+
8
+ def as_dict(self: v3) -> dict:
9
+ def aclip_to_dict(self: Clip) -> dict:
10
+ return {
11
+ "name": "audio",
12
+ "src": self.src,
13
+ "start": self.start,
14
+ "dur": self.dur,
15
+ "offset": self.offset,
16
+ "speed": self.speed,
17
+ "volume": self.volume,
18
+ "stream": self.stream,
19
+ }
20
+
21
+ v = []
22
+ a = []
23
+ for vlayer in self.v:
24
+ vb = [vobj.as_dict() for vobj in vlayer]
25
+ if vb:
26
+ v.append(vb)
27
+ for layer in self.a:
28
+ ab = [aclip_to_dict(clip) for clip in layer]
29
+ if ab:
30
+ a.append(ab)
31
+
32
+ return {
33
+ "version": "3",
34
+ "timebase": f"{self.tb.numerator}/{self.tb.denominator}",
35
+ "background": self.background,
36
+ "resolution": self.T.res,
37
+ "samplerate": self.T.sr,
38
+ "layout": self.T.layout,
39
+ "v": v,
40
+ "a": a,
41
+ }
11
42
 
12
43
 
13
44
  def make_json_timeline(ver: str, out: str, tl: v3, log: Log) -> None:
@@ -20,7 +51,7 @@ def make_json_timeline(ver: str, out: str, tl: v3, log: Log) -> None:
20
51
  outfile = open(out, "w")
21
52
 
22
53
  if ver == "v3":
23
- dump(tl.as_dict(), outfile, indent=2)
54
+ dump(as_dict(tl), outfile, indent=2)
24
55
  else:
25
56
  if tl.v1 is None:
26
57
  log.error("Timeline can't be converted to v1 format")
@@ -1,5 +1,4 @@
1
1
  import xml.etree.ElementTree as ET
2
- from typing import cast
3
2
 
4
3
  from auto_editor.timeline import Clip, v3
5
4
  from auto_editor.utils.func import aspect_ratio, to_timecode
@@ -71,7 +70,7 @@ def shotcut_write_mlt(output: str, tl: v3) -> None:
71
70
  producers = 0
72
71
 
73
72
  if tl.v:
74
- clips = cast(list[Clip], tl.v[0])
73
+ clips = [clip for clip in tl.v[0] if isinstance(clip, Clip)]
75
74
  elif tl.a:
76
75
  clips = tl.a[0]
77
76
  else:
auto_editor/ffwrapper.py CHANGED
@@ -66,6 +66,7 @@ class FileInfo:
66
66
  path: Path
67
67
  bitrate: int
68
68
  duration: float
69
+ timecode: str # in SMPTE
69
70
  videos: tuple[VideoStream, ...]
70
71
  audios: tuple[AudioStream, ...]
71
72
  subtitles: tuple[SubtitleStream, ...]
@@ -165,12 +166,22 @@ class FileInfo:
165
166
  ext = sub_exts.get(codec, "vtt")
166
167
  subtitles += (SubtitleStream(codec, ext, s.language),)
167
168
 
169
+ def get_timecode() -> str:
170
+ for d in cont.streams.data:
171
+ if (result := d.metadata.get("timecode")) is not None:
172
+ return result
173
+ for v in cont.streams.video:
174
+ if (result := v.metadata.get("timecode")) is not None:
175
+ return result
176
+ return "00:00:00:00"
177
+
178
+ timecode = get_timecode()
168
179
  bitrate = 0 if cont.bit_rate is None else cont.bit_rate
169
180
  dur = 0 if cont.duration is None else cont.duration / bv.time_base
170
181
 
171
182
  cont.close()
172
183
 
173
- return FileInfo(Path(path), bitrate, dur, videos, audios, subtitles)
184
+ return FileInfo(Path(path), bitrate, dur, timecode, videos, audios, subtitles)
174
185
 
175
186
  def __repr__(self) -> str:
176
187
  return f"@{self.path.name}"
auto_editor/preview.py CHANGED
@@ -28,23 +28,24 @@ def time_frame(
28
28
  def all_cuts(tl: v3, in_len: int) -> list[int]:
29
29
  # Calculate cuts
30
30
  tb = tl.tb
31
- oe: list[tuple[int, int]] = []
31
+ clip_spans: list[tuple[int, int]] = []
32
32
 
33
33
  for clip in tl.a[0]:
34
34
  old_offset = clip.offset * clip.speed
35
- oe.append((round(old_offset * clip.speed), round(old_offset + clip.dur)))
35
+ clip_spans.append((round(old_offset), round(old_offset + clip.dur)))
36
36
 
37
37
  cut_lens = []
38
38
  i = 0
39
- while i < len(oe) - 1:
40
- if i == 0 and oe[i][0] != 0:
41
- cut_lens.append(oe[i][1])
39
+ while i < len(clip_spans) - 1:
40
+ if i == 0 and clip_spans[i][0] != 0:
41
+ cut_lens.append(clip_spans[i][0])
42
42
 
43
- cut_lens.append(oe[i + 1][0] - oe[i][1])
43
+ cut_lens.append(clip_spans[i + 1][0] - clip_spans[i][1])
44
44
  i += 1
45
45
 
46
- if len(oe) > 0 and oe[-1][1] < round(in_len * tb):
47
- cut_lens.append(in_len - oe[-1][1])
46
+ if len(clip_spans) > 0 and clip_spans[-1][1] < round(in_len / tb):
47
+ cut_lens.append(in_len - clip_spans[-1][1])
48
+
48
49
  return cut_lens
49
50
 
50
51
 
@@ -53,19 +54,9 @@ def preview(tl: v3, log: Log) -> None:
53
54
  tb = tl.tb
54
55
 
55
56
  # Calculate input videos length
56
- all_sources = set()
57
- for vlayer in tl.v:
58
- for vclip in vlayer:
59
- if hasattr(vclip, "src"):
60
- all_sources.add(vclip.src)
61
- for alayer in tl.a:
62
- for aclip in alayer:
63
- if hasattr(aclip, "src"):
64
- all_sources.add(aclip.src)
65
-
66
57
  in_len = 0
67
58
  bar = initBar("none")
68
- for src in all_sources:
59
+ for src in tl.unique_sources():
69
60
  in_len += initLevels(src, tb, bar, False, log).media_length
70
61
 
71
62
  out_len = len(tl)
@@ -77,7 +68,7 @@ def preview(tl: v3, log: Log) -> None:
77
68
  time_frame(fp, "output", out_len, tb, f"{round((out_len / in_len) * 100, 2)}%")
78
69
  time_frame(fp, "diff", diff, tb, f"{round((diff / in_len) * 100, 2)}%")
79
70
 
80
- clip_lens = [clip.dur / clip.speed for clip in tl.a[0]]
71
+ clip_lens = [clip.dur for clip in tl.a[0]]
81
72
  log.debug(clip_lens)
82
73
 
83
74
  fp.write(f"clips:\n - amount: {len(clip_lens)}\n")
@@ -90,7 +81,7 @@ def preview(tl: v3, log: Log) -> None:
90
81
 
91
82
  cut_lens = all_cuts(tl, in_len)
92
83
  log.debug(cut_lens)
93
- fp.write(f"cuts:\n - amount: {len(clip_lens)}\n")
84
+ fp.write(f"cuts:\n - amount: {len(cut_lens)}\n")
94
85
  if len(cut_lens) > 0:
95
86
  time_frame(fp, "smallest", min(cut_lens), tb)
96
87
  time_frame(fp, "largest", max(cut_lens), tb)
auto_editor/timeline.py CHANGED
@@ -282,41 +282,6 @@ video\n"""
282
282
 
283
283
  return result
284
284
 
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
-
298
- v = []
299
- a = []
300
- for vlayer in self.v:
301
- vb = [vobj.as_dict() for vobj in vlayer]
302
- if vb:
303
- v.append(vb)
304
- for layer in self.a:
305
- ab = [aclip_to_dict(clip) for clip in layer]
306
- if ab:
307
- a.append(ab)
308
-
309
- return {
310
- "version": "3",
311
- "timebase": f"{self.tb.numerator}/{self.tb.denominator}",
312
- "background": self.background,
313
- "resolution": self.T.res,
314
- "samplerate": self.T.sr,
315
- "layout": self.T.layout,
316
- "v": v,
317
- "a": a,
318
- }
319
-
320
285
  @property
321
286
  def T(self) -> Template:
322
287
  return self.template
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: auto-editor
3
- Version: 28.0.1
3
+ Version: 28.0.2
4
4
  Summary: Auto-Editor: Effort free video editing!
5
5
  Author-email: WyattBlue <wyattblue@auto-editor.com>
6
6
  License-Expression: Unlicense
@@ -1,28 +1,28 @@
1
- auto_editor/__init__.py,sha256=qvc7djhJkqlXmlxcWZWLvK6JKBp01_I3fJuFV5euTBg,23
1
+ auto_editor/__init__.py,sha256=6apXf8Vs7EJRS3EJg55T29rrBLN_XnKO63TMnymWMvI,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=GhOfKIe_FdbBGDQ_WH02CJl7Oi-AwaaSSh73F81h_kA,19234
5
- auto_editor/ffwrapper.py,sha256=ueYdN7-cBAdJBJbv5yT05iuQP_BPFIrR5hFeMkk5c3U,5040
4
+ auto_editor/edit.py,sha256=sNvS2A7Aknzx-kDGDkdiIenCeIVCIxqj5NXnnhfeWpQ,19311
5
+ auto_editor/ffwrapper.py,sha256=dSrONV1QyPzPhK0g6lOM5pPDITz7qblyjLpRV_VRH_Y,5474
6
6
  auto_editor/help.py,sha256=8Kkos7Bpcn-3YN7ngv0fZp-8a8Qw6b70ZZKerL8SEQ4,7901
7
7
  auto_editor/json.py,sha256=g6ZsrSOXtjQj-8Otea3TIY2G-HZ6g-IXUblwukgTO1g,9332
8
8
  auto_editor/make_layers.py,sha256=Udxn7Vw0Jz9HOarLeswQ-WwTu87PWcsyduBdtFwSOyc,10079
9
- auto_editor/preview.py,sha256=yYn5jJLQ3TiJiNC6JffaggLVPQfBU558zJeRQz7nCDY,3046
10
- auto_editor/timeline.py,sha256=ebnEX23HubNm444SIB2QNPkNdZcxHGhci1BpAeVDwcQ,9186
9
+ auto_editor/preview.py,sha256=pBCw21wTORG0-Zs4Zf2anCecTNlnfiCq50tINeOcFmg,2815
10
+ auto_editor/timeline.py,sha256=84k-sSK3c2kTZ28atPoIaWgSecZvO-fOGfsXFlmifP4,8165
11
11
  auto_editor/vanparse.py,sha256=Ug5A2QaRqGiw4l55Z_h9T2QU1x0WqRibR7yY5rQ0WTk,10002
12
12
  auto_editor/cmds/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
13
  auto_editor/cmds/cache.py,sha256=rK06dX3Z1pDAK0t5rqR7S2cMEpnT_Tv17t3Q5qPQKLI,1959
14
14
  auto_editor/cmds/desc.py,sha256=kdRJfabdde5thuFOoTXlW3J3G8F0ZvbsJoOkUn7E3GA,805
15
15
  auto_editor/cmds/info.py,sha256=NwzZu6l6IIdK0ajZdn8WX_iiJwlsMrGIZ2vffDRu3gc,6535
16
- auto_editor/cmds/levels.py,sha256=2Hbvoy6wMbRRoHdZf25PMqq1uvhRKyPcITNPMpZFo7s,5632
16
+ auto_editor/cmds/levels.py,sha256=zR9Sd7wDO36rEI-Tu_pdsAwNiwQxg62CQ04RG5mZeC0,5853
17
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
19
  auto_editor/cmds/subdump.py,sha256=Zxs9X0gEaQYA5F1EqccJmVUYfI1o3J7ltyc9bvy1tA4,2393
20
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=LiWHtA-jgwzbiSoBzNBUaTjOEuqnvr3dYBQmdlw7m3Y,5244
22
+ auto_editor/exports/fcp11.py,sha256=uOonQPBoSQSfUpdi58vqDgpZdmN6Jevm2YNPo9m9nI0,6195
23
23
  auto_editor/exports/fcp7.py,sha256=shZtn5i66hqGVrpR1PP1hiwKiZirr1cRUxATzbW-BOo,12069
24
- auto_editor/exports/json.py,sha256=Z7RKtD5-OB3saOtWG9qfI9OrLtylhU9VyfpnVRNcuU8,768
25
- auto_editor/exports/shotcut.py,sha256=MpzYqDO_XSnd-bKCKQjJFqOf_mSdR9QOWi8_Y1Y_BwY,4696
24
+ auto_editor/exports/json.py,sha256=Q176-MtctEyPVenxbjuhMx_j8oVx-_G4Zwa-PJ3f7oQ,1579
25
+ auto_editor/exports/shotcut.py,sha256=miIOvzM73tUJcHFCe7fUu66YZxEvlDSkV1PHxv8ED8k,4699
26
26
  auto_editor/imports/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
27
  auto_editor/imports/fcp7.py,sha256=Vep1syViRZOrtZBlF6Ek_eRy0rLINpTso5nrh3uY3zk,8563
28
28
  auto_editor/imports/json.py,sha256=5c_vKoS8FzxAWagCetrwATHdnZ2beWQ77g8JYKVM0i8,6993
@@ -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.1.dist-info/licenses/LICENSE,sha256=yiq99pWITHfqS0pbZMp7cy2dnbreTuvBwudsU-njvIM,1210
50
+ auto_editor-28.0.2.dist-info/licenses/LICENSE,sha256=yiq99pWITHfqS0pbZMp7cy2dnbreTuvBwudsU-njvIM,1210
51
51
  docs/build.py,sha256=g1uc1H9T_naGaermUiVMMwUpbT0IWElRhjgT0fvCh8w,1914
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,,
52
+ auto_editor-28.0.2.dist-info/METADATA,sha256=E8DfZMV3tmFRZCJ9vjb-MMe8nHHPRssbhWyzWFm5XZA,6176
53
+ auto_editor-28.0.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
54
+ auto_editor-28.0.2.dist-info/entry_points.txt,sha256=UAsTc7qJQbnAzHd7KWg-ALo_X9Hj2yDs3M9I2DV3eyI,212
55
+ auto_editor-28.0.2.dist-info/top_level.txt,sha256=jBV5zlbWRbKOa-xaWPvTD45QL7lGExx2BDzv-Ji4dTw,17
56
+ auto_editor-28.0.2.dist-info/RECORD,,