auto-editor 28.1.0__py3-none-any.whl → 29.0.0__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.
Files changed (59) hide show
  1. {auto_editor-28.1.0.dist-info → auto_editor-29.0.0.dist-info}/METADATA +4 -3
  2. auto_editor-29.0.0.dist-info/RECORD +5 -0
  3. auto_editor-29.0.0.dist-info/top_level.txt +1 -0
  4. auto_editor/__init__.py +0 -1
  5. auto_editor/__main__.py +0 -504
  6. auto_editor/analyze.py +0 -393
  7. auto_editor/cmds/__init__.py +0 -0
  8. auto_editor/cmds/cache.py +0 -69
  9. auto_editor/cmds/desc.py +0 -32
  10. auto_editor/cmds/info.py +0 -213
  11. auto_editor/cmds/levels.py +0 -199
  12. auto_editor/cmds/palet.py +0 -29
  13. auto_editor/cmds/repl.py +0 -113
  14. auto_editor/cmds/subdump.py +0 -72
  15. auto_editor/cmds/test.py +0 -816
  16. auto_editor/edit.py +0 -560
  17. auto_editor/exports/__init__.py +0 -0
  18. auto_editor/exports/fcp11.py +0 -195
  19. auto_editor/exports/fcp7.py +0 -313
  20. auto_editor/exports/json.py +0 -63
  21. auto_editor/exports/kdenlive.py +0 -322
  22. auto_editor/exports/shotcut.py +0 -147
  23. auto_editor/ffwrapper.py +0 -187
  24. auto_editor/help.py +0 -224
  25. auto_editor/imports/__init__.py +0 -0
  26. auto_editor/imports/fcp7.py +0 -275
  27. auto_editor/imports/json.py +0 -234
  28. auto_editor/json.py +0 -297
  29. auto_editor/lang/__init__.py +0 -0
  30. auto_editor/lang/libintrospection.py +0 -10
  31. auto_editor/lang/libmath.py +0 -23
  32. auto_editor/lang/palet.py +0 -724
  33. auto_editor/lang/stdenv.py +0 -1179
  34. auto_editor/lib/__init__.py +0 -0
  35. auto_editor/lib/contracts.py +0 -235
  36. auto_editor/lib/data_structs.py +0 -278
  37. auto_editor/lib/err.py +0 -2
  38. auto_editor/make_layers.py +0 -315
  39. auto_editor/preview.py +0 -93
  40. auto_editor/render/__init__.py +0 -0
  41. auto_editor/render/audio.py +0 -517
  42. auto_editor/render/subtitle.py +0 -205
  43. auto_editor/render/video.py +0 -307
  44. auto_editor/timeline.py +0 -331
  45. auto_editor/utils/__init__.py +0 -0
  46. auto_editor/utils/bar.py +0 -142
  47. auto_editor/utils/chunks.py +0 -2
  48. auto_editor/utils/cmdkw.py +0 -206
  49. auto_editor/utils/container.py +0 -101
  50. auto_editor/utils/func.py +0 -128
  51. auto_editor/utils/log.py +0 -126
  52. auto_editor/utils/types.py +0 -277
  53. auto_editor/vanparse.py +0 -313
  54. auto_editor-28.1.0.dist-info/RECORD +0 -57
  55. auto_editor-28.1.0.dist-info/entry_points.txt +0 -6
  56. auto_editor-28.1.0.dist-info/top_level.txt +0 -2
  57. docs/build.py +0 -70
  58. {auto_editor-28.1.0.dist-info → auto_editor-29.0.0.dist-info}/WHEEL +0 -0
  59. {auto_editor-28.1.0.dist-info → auto_editor-29.0.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,195 +0,0 @@
1
- import xml.etree.ElementTree as ET
2
- from fractions import Fraction
3
- from xml.etree.ElementTree import Element, ElementTree, SubElement, indent
4
-
5
- from auto_editor.ffwrapper import FileInfo
6
- from auto_editor.timeline import Clip, v3
7
- from auto_editor.utils.log import Log
8
-
9
- """
10
- Export a FCPXML 11 file readable with Final Cut Pro 10.6.8 or later.
11
-
12
- See docs here:
13
- https://developer.apple.com/documentation/professional_video_applications/fcpxml_reference
14
-
15
- """
16
-
17
-
18
- def get_colorspace(src: FileInfo) -> str:
19
- # See: https://developer.apple.com/documentation/professional_video_applications/fcpxml_reference/asset#3686496
20
-
21
- if not src.videos:
22
- return "1-1-1 (Rec. 709)"
23
-
24
- s = src.videos[0]
25
- if s.pix_fmt == "rgb24":
26
- return "sRGB IEC61966-2.1"
27
- if s.color_space == 5: # "bt470bg"
28
- return "5-1-6 (Rec. 601 PAL)"
29
- if s.color_space == 6: # "smpte170m"
30
- return "6-1-6 (Rec. 601 NTSC)"
31
- if s.color_primaries == 9: # "bt2020"
32
- # See: https://video.stackexchange.com/questions/22059/how-to-identify-hdr-video
33
- if s.color_transfer in {16, 18}: # "smpte2084" "arib-std-b67"
34
- return "9-18-9 (Rec. 2020 HLG)"
35
- return "9-1-9 (Rec. 2020)"
36
-
37
- return "1-1-1 (Rec. 709)"
38
-
39
-
40
- def make_name(src: FileInfo, tb: Fraction) -> str:
41
- if src.get_res()[1] == 720 and tb == 30:
42
- return "FFVideoFormat720p30"
43
- if src.get_res()[1] == 720 and tb == 25:
44
- return "FFVideoFormat720p25"
45
- return "FFVideoFormatRateUndefined"
46
-
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
-
77
- def fcp11_write_xml(
78
- group_name: str, version: int, output: str, resolve: bool, tl: v3, log: Log
79
- ) -> None:
80
- def fraction(val: int) -> str:
81
- if val == 0:
82
- return "0s"
83
- return f"{val * tl.tb.denominator}/{tl.tb.numerator}s"
84
-
85
- if version == 11:
86
- ver_str = "1.11"
87
- elif version == 10:
88
- ver_str = "1.10"
89
- else:
90
- log.error(f"Unknown final cut pro version: {version}")
91
-
92
- fcpxml = Element("fcpxml", version=ver_str)
93
- resources = SubElement(fcpxml, "resources")
94
-
95
- src_dur = 0
96
- tl_dur = 0 if resolve else len(tl)
97
-
98
- for i, one_src in enumerate(tl.unique_sources()):
99
- if i == 0:
100
- proj_name = one_src.path.stem
101
- src_dur = int(one_src.duration * tl.tb)
102
- if resolve:
103
- tl_dur = src_dur
104
-
105
- SubElement(
106
- resources,
107
- "format",
108
- id=f"r{i * 2 + 1}",
109
- name=make_name(one_src, tl.tb),
110
- frameDuration=fraction(1),
111
- width=f"{tl.res[0]}",
112
- height=f"{tl.res[1]}",
113
- colorSpace=get_colorspace(one_src),
114
- )
115
-
116
- startPoint = parseSMPTE(one_src.timecode, tl.tb, log)
117
- r2 = SubElement(
118
- resources,
119
- "asset",
120
- id=f"r{i * 2 + 2}",
121
- name=one_src.path.stem,
122
- start=fraction(startPoint),
123
- hasVideo="1" if one_src.videos else "0",
124
- format=f"r{i * 2 + 1}",
125
- hasAudio="1" if one_src.audios else "0",
126
- audioSources="1",
127
- audioChannels=f"{2 if not one_src.audios else one_src.audios[0].channels}",
128
- duration=fraction(tl_dur),
129
- )
130
- SubElement(
131
- r2, "media-rep", kind="original-media", src=one_src.path.resolve().as_uri()
132
- )
133
-
134
- lib = SubElement(fcpxml, "library")
135
- evt = SubElement(lib, "event", name=group_name)
136
- proj = SubElement(evt, "project", name=proj_name)
137
- sequence = SubElement(
138
- proj,
139
- "sequence",
140
- format="r1",
141
- tcStart="0s",
142
- tcFormat="NDF",
143
- audioLayout=tl.T.layout,
144
- audioRate="44.1k" if tl.sr == 44100 else "48k",
145
- )
146
- spine = SubElement(sequence, "spine")
147
-
148
- def make_clip(ref: str, clip: Clip) -> None:
149
- startPoint = parseSMPTE(clip.src.timecode, tl.tb, log)
150
-
151
- clip_properties = {
152
- "name": proj_name,
153
- "ref": ref,
154
- "offset": fraction(clip.start + startPoint),
155
- "duration": fraction(clip.dur),
156
- "start": fraction(clip.offset + startPoint),
157
- "tcFormat": "NDF",
158
- }
159
- asset = SubElement(spine, "asset-clip", clip_properties)
160
- if clip.speed != 1:
161
- # See the "Time Maps" section.
162
- # https://developer.apple.com/documentation/professional_video_applications/fcpxml_reference/story_elements/timemap/
163
-
164
- timemap = SubElement(asset, "timeMap")
165
- SubElement(timemap, "timept", time="0s", value="0s", interp="smooth2")
166
- SubElement(
167
- timemap,
168
- "timept",
169
- time=fraction(int(src_dur // clip.speed)),
170
- value=fraction(src_dur),
171
- interp="smooth2",
172
- )
173
-
174
- if tl.v and tl.v[0]:
175
- clips = [clip for clip in tl.v[0] if isinstance(clip, Clip)]
176
- elif tl.a and tl.a[0]:
177
- clips = tl.a[0]
178
- else:
179
- clips = []
180
-
181
- all_refs: list[str] = ["r2"]
182
- if resolve:
183
- for i in range(1, len(tl.a)):
184
- all_refs.append(f"r{(i + 1) * 2}")
185
-
186
- for my_ref in reversed(all_refs):
187
- for clip in clips:
188
- make_clip(my_ref, clip)
189
-
190
- tree = ElementTree(fcpxml)
191
- indent(tree, space="\t", level=0)
192
- if output == "-":
193
- print(ET.tostring(fcpxml, encoding="unicode"))
194
- else:
195
- tree.write(output, xml_declaration=True, encoding="utf-8")
@@ -1,313 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import xml.etree.ElementTree as ET
4
- from fractions import Fraction
5
- from math import ceil
6
- from xml.etree.ElementTree import Element
7
-
8
- from auto_editor.ffwrapper import FileInfo
9
- from auto_editor.timeline import Clip, v3
10
-
11
- """
12
- Premiere Pro uses the Final Cut Pro 7 XML Interchange Format
13
-
14
- See docs here:
15
- https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/FinalCutPro_XML/Elements/Elements.html
16
-
17
- Also, Premiere itself will happily output subtlety incorrect XML files that don't
18
- come back the way they started.
19
- """
20
-
21
- DEPTH = "16"
22
-
23
-
24
- def set_tb_ntsc(tb: Fraction) -> tuple[int, str]:
25
- # See chart: https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/FinalCutPro_XML/FrameRate/FrameRate.html#//apple_ref/doc/uid/TP30001158-TPXREF103
26
- if tb == Fraction(24000, 1001):
27
- return 24, "TRUE"
28
- if tb == Fraction(30000, 1001):
29
- return 30, "TRUE"
30
- if tb == Fraction(60000, 1001):
31
- return 60, "TRUE"
32
-
33
- ctb = ceil(tb)
34
- if ctb not in {24, 30, 60} and ctb * Fraction(999, 1000) == tb:
35
- return ctb, "TRUE"
36
-
37
- return int(tb), "FALSE"
38
-
39
-
40
- def speedup(speed: float) -> Element:
41
- fil = Element("filter")
42
- effect = ET.SubElement(fil, "effect")
43
- ET.SubElement(effect, "name").text = "Time Remap"
44
- ET.SubElement(effect, "effectid").text = "timeremap"
45
-
46
- para = ET.SubElement(effect, "parameter", authoringApp="PremierePro")
47
- ET.SubElement(para, "parameterid").text = "variablespeed"
48
- ET.SubElement(para, "name").text = "variablespeed"
49
- ET.SubElement(para, "valuemin").text = "0"
50
- ET.SubElement(para, "valuemax").text = "1"
51
- ET.SubElement(para, "value").text = "0"
52
-
53
- para2 = ET.SubElement(effect, "parameter", authoringApp="PremierePro")
54
- ET.SubElement(para2, "parameterid").text = "speed"
55
- ET.SubElement(para2, "name").text = "speed"
56
- ET.SubElement(para2, "valuemin").text = "-100000"
57
- ET.SubElement(para2, "valuemax").text = "100000"
58
- ET.SubElement(para2, "value").text = str(speed)
59
-
60
- para3 = ET.SubElement(effect, "parameter", authoringApp="PremierePro")
61
- ET.SubElement(para3, "parameterid").text = "frameblending"
62
- ET.SubElement(para3, "name").text = "frameblending"
63
- ET.SubElement(para3, "value").text = "FALSE"
64
-
65
- return fil
66
-
67
-
68
- def media_def(
69
- filedef: Element, url: str, src: FileInfo, tl: v3, tb: int, ntsc: str
70
- ) -> None:
71
- ET.SubElement(filedef, "name").text = src.path.stem
72
- ET.SubElement(filedef, "pathurl").text = url
73
-
74
- timecode = ET.SubElement(filedef, "timecode")
75
- ET.SubElement(timecode, "string").text = "00:00:00:00"
76
- ET.SubElement(timecode, "displayformat").text = "NDF"
77
- rate = ET.SubElement(timecode, "rate")
78
- ET.SubElement(rate, "timebase").text = f"{tb}"
79
- ET.SubElement(rate, "ntsc").text = ntsc
80
-
81
- rate = ET.SubElement(filedef, "rate")
82
- ET.SubElement(rate, "timebase").text = f"{tb}"
83
- ET.SubElement(rate, "ntsc").text = ntsc
84
-
85
- # DaVinci Resolve needs this tag even though it's blank
86
- ET.SubElement(filedef, "duration").text = ""
87
-
88
- mediadef = ET.SubElement(filedef, "media")
89
-
90
- if len(src.videos) > 0:
91
- videodef = ET.SubElement(mediadef, "video")
92
-
93
- vschar = ET.SubElement(videodef, "samplecharacteristics")
94
- rate = ET.SubElement(vschar, "rate")
95
- ET.SubElement(rate, "timebase").text = f"{tb}"
96
- ET.SubElement(rate, "ntsc").text = ntsc
97
- ET.SubElement(vschar, "width").text = f"{tl.res[0]}"
98
- ET.SubElement(vschar, "height").text = f"{tl.res[1]}"
99
- ET.SubElement(vschar, "pixelaspectratio").text = "square"
100
-
101
- for aud in src.audios:
102
- audiodef = ET.SubElement(mediadef, "audio")
103
- aschar = ET.SubElement(audiodef, "samplecharacteristics")
104
- ET.SubElement(aschar, "depth").text = DEPTH
105
- ET.SubElement(aschar, "samplerate").text = f"{tl.sr}"
106
- ET.SubElement(audiodef, "channelcount").text = f"{aud.channels}"
107
-
108
-
109
- def resolve_write_audio(audio: Element, make_filedef, tl: v3) -> None:
110
- for t, aclips in enumerate(tl.a):
111
- track = ET.SubElement(audio, "track")
112
- for j, aclip in enumerate(aclips):
113
- src = aclip.src
114
-
115
- _start = f"{aclip.start}"
116
- _end = f"{aclip.start + aclip.dur}"
117
- _in = f"{aclip.offset}"
118
- _out = f"{aclip.offset + aclip.dur}"
119
-
120
- if not src.videos:
121
- clip_item_num = j + 1
122
- else:
123
- clip_item_num = len(aclips) + 1 + j
124
-
125
- clipitem = ET.SubElement(track, "clipitem", id=f"clipitem-{clip_item_num}")
126
- ET.SubElement(clipitem, "name").text = src.path.stem
127
- ET.SubElement(clipitem, "start").text = _start
128
- ET.SubElement(clipitem, "end").text = _end
129
- ET.SubElement(clipitem, "enabled").text = "TRUE"
130
- ET.SubElement(clipitem, "in").text = _in
131
- ET.SubElement(clipitem, "out").text = _out
132
-
133
- make_filedef(clipitem, aclip.src)
134
-
135
- sourcetrack = ET.SubElement(clipitem, "sourcetrack")
136
- ET.SubElement(sourcetrack, "mediatype").text = "audio"
137
- ET.SubElement(sourcetrack, "trackindex").text = f"{t + 1}"
138
-
139
- if src.videos:
140
- link = ET.SubElement(clipitem, "link")
141
- ET.SubElement(link, "linkclipref").text = f"clipitem-{j + 1}"
142
- ET.SubElement(link, "mediatype").text = "video"
143
- link = ET.SubElement(clipitem, "link")
144
- ET.SubElement(link, "linkclipref").text = f"clipitem-{clip_item_num}"
145
-
146
- if aclip.speed != 1:
147
- clipitem.append(speedup(aclip.speed * 100))
148
-
149
-
150
- def premiere_write_audio(audio: Element, make_filedef, tl: v3) -> None:
151
- ET.SubElement(audio, "numOutputChannels").text = "2"
152
- aformat = ET.SubElement(audio, "format")
153
- aschar = ET.SubElement(aformat, "samplecharacteristics")
154
- ET.SubElement(aschar, "depth").text = DEPTH
155
- ET.SubElement(aschar, "samplerate").text = f"{tl.sr}"
156
-
157
- has_video = tl.v and tl.v[0]
158
- t = 0
159
- for aclips in tl.a:
160
- for channelcount in range(0, 2): # Because "stereo" is hardcoded.
161
- t += 1
162
- track = ET.Element(
163
- "track",
164
- currentExplodedTrackIndex=f"{channelcount}",
165
- totalExplodedTrackCount="2", # Because "stereo" is hardcoded.
166
- premiereTrackType="Stereo",
167
- )
168
-
169
- if has_video:
170
- ET.SubElement(track, "outputchannelindex").text = f"{channelcount + 1}"
171
-
172
- for j, aclip in enumerate(aclips):
173
- src = aclip.src
174
-
175
- _start = f"{aclip.start}"
176
- _end = f"{aclip.start + aclip.dur}"
177
- _in = f"{aclip.offset}"
178
- _out = f"{aclip.offset + aclip.dur}"
179
-
180
- if not has_video:
181
- clip_item_num = j + 1
182
- else:
183
- clip_item_num = len(aclips) + 1 + j + (t * len(aclips))
184
-
185
- clipitem = ET.SubElement(
186
- track,
187
- "clipitem",
188
- id=f"clipitem-{clip_item_num}",
189
- premiereChannelType="stereo",
190
- )
191
- ET.SubElement(clipitem, "name").text = src.path.stem
192
- ET.SubElement(clipitem, "enabled").text = "TRUE"
193
- ET.SubElement(clipitem, "start").text = _start
194
- ET.SubElement(clipitem, "end").text = _end
195
- ET.SubElement(clipitem, "in").text = _in
196
- ET.SubElement(clipitem, "out").text = _out
197
-
198
- make_filedef(clipitem, aclip.src)
199
-
200
- sourcetrack = ET.SubElement(clipitem, "sourcetrack")
201
- ET.SubElement(sourcetrack, "mediatype").text = "audio"
202
- ET.SubElement(sourcetrack, "trackindex").text = f"{t}"
203
- labels = ET.SubElement(clipitem, "labels")
204
- ET.SubElement(labels, "label2").text = "Iris"
205
-
206
- if aclip.speed != 1:
207
- clipitem.append(speedup(aclip.speed * 100))
208
-
209
- audio.append(track)
210
-
211
-
212
- def fcp7_write_xml(name: str, output: str, resolve: bool, tl: v3) -> None:
213
- width, height = tl.res
214
- timebase, ntsc = set_tb_ntsc(tl.tb)
215
-
216
- src_to_url: dict[FileInfo, str] = {}
217
- src_to_id: dict[FileInfo, str] = {}
218
-
219
- file_defs: set[str] = set() # Contains urls
220
-
221
- for src in set(tl.sources):
222
- the_id = f"file-{len(src_to_id) + 1}"
223
- src_to_url[src] = f"{src.path.resolve()}"
224
- src_to_id[src] = the_id
225
-
226
- def make_filedef(clipitem: Element, src: FileInfo) -> None:
227
- pathurl = src_to_url[src]
228
- filedef = ET.SubElement(clipitem, "file", id=src_to_id[src])
229
- if pathurl not in file_defs:
230
- media_def(filedef, pathurl, src, tl, timebase, ntsc)
231
- file_defs.add(pathurl)
232
-
233
- xmeml = ET.Element("xmeml", version="5")
234
- if resolve:
235
- sequence = ET.SubElement(xmeml, "sequence")
236
- else:
237
- sequence = ET.SubElement(xmeml, "sequence", explodedTracks="true")
238
-
239
- ET.SubElement(sequence, "name").text = name
240
- ET.SubElement(sequence, "duration").text = f"{len(tl)}"
241
- rate = ET.SubElement(sequence, "rate")
242
- ET.SubElement(rate, "timebase").text = f"{timebase}"
243
- ET.SubElement(rate, "ntsc").text = ntsc
244
- media = ET.SubElement(sequence, "media")
245
- video = ET.SubElement(media, "video")
246
- vformat = ET.SubElement(video, "format")
247
- vschar = ET.SubElement(vformat, "samplecharacteristics")
248
-
249
- ET.SubElement(vschar, "width").text = f"{width}"
250
- ET.SubElement(vschar, "height").text = f"{height}"
251
- ET.SubElement(vschar, "pixelaspectratio").text = "square"
252
-
253
- rate = ET.SubElement(vschar, "rate")
254
- ET.SubElement(rate, "timebase").text = f"{timebase}"
255
- ET.SubElement(rate, "ntsc").text = ntsc
256
-
257
- if len(tl.v) > 0 and len(tl.v[0]) > 0:
258
- track = ET.SubElement(video, "track")
259
-
260
- for j, clip in enumerate(tl.v[0]):
261
- assert isinstance(clip, Clip)
262
-
263
- _start = f"{clip.start}"
264
- _end = f"{clip.start + clip.dur}"
265
- _in = f"{clip.offset}"
266
- _out = f"{clip.offset + clip.dur}"
267
-
268
- this_clipid = f"clipitem-{j + 1}"
269
- clipitem = ET.SubElement(track, "clipitem", id=this_clipid)
270
- ET.SubElement(clipitem, "name").text = src.path.stem
271
- ET.SubElement(clipitem, "enabled").text = "TRUE"
272
- ET.SubElement(clipitem, "start").text = _start
273
- ET.SubElement(clipitem, "end").text = _end
274
- ET.SubElement(clipitem, "in").text = _in
275
- ET.SubElement(clipitem, "out").text = _out
276
-
277
- make_filedef(clipitem, clip.src)
278
-
279
- ET.SubElement(clipitem, "compositemode").text = "normal"
280
- if clip.speed != 1:
281
- clipitem.append(speedup(clip.speed * 100))
282
-
283
- if resolve:
284
- link = ET.SubElement(clipitem, "link")
285
- ET.SubElement(link, "linkclipref").text = this_clipid
286
- link = ET.SubElement(clipitem, "link")
287
- ET.SubElement(
288
- link, "linkclipref"
289
- ).text = f"clipitem-{(len(tl.v[0])) + j + 1}"
290
- continue
291
-
292
- for i in range(1 + len(src.audios) * 2): # `2` because stereo.
293
- link = ET.SubElement(clipitem, "link")
294
- ET.SubElement(
295
- link, "linkclipref"
296
- ).text = f"clipitem-{(i * (len(tl.v[0]))) + j + 1}"
297
- ET.SubElement(link, "mediatype").text = "video" if i == 0 else "audio"
298
- ET.SubElement(link, "trackindex").text = f"{max(i, 1)}"
299
- ET.SubElement(link, "clipindex").text = f"{j + 1}"
300
-
301
- # Audio definitions and clips
302
- audio = ET.SubElement(media, "audio")
303
- if resolve:
304
- resolve_write_audio(audio, make_filedef, tl)
305
- else:
306
- premiere_write_audio(audio, make_filedef, tl)
307
-
308
- tree = ET.ElementTree(xmeml)
309
- ET.indent(tree, space=" ", level=0)
310
- if output == "-":
311
- print(ET.tostring(xmeml, encoding="unicode"))
312
- else:
313
- tree.write(output, xml_declaration=True, encoding="utf-8")
@@ -1,63 +0,0 @@
1
- import sys
2
-
3
- from auto_editor.json import dump
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
- }
42
-
43
-
44
- def make_json_timeline(ver: str, out: str, tl: v3, log: Log) -> None:
45
- if ver not in {"v1", "v3"}:
46
- log.error(f"Unknown timeline version: {ver}")
47
-
48
- if out == "-":
49
- outfile = sys.stdout
50
- else:
51
- outfile = open(out, "w")
52
-
53
- if ver == "v3":
54
- dump(as_dict(tl), outfile, indent=2)
55
- else:
56
- if tl.v1 is None:
57
- log.error("Timeline can't be converted to v1 format")
58
- dump(tl.v1.as_dict(), outfile, indent=2)
59
-
60
- if out == "-":
61
- print("") # Flush stdout
62
- else:
63
- outfile.close()