auto-editor 25.0.1__py3-none-any.whl → 25.2.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.
auto_editor/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "25.0.1"
1
+ __version__ = "25.2.0"
auto_editor/__main__.py CHANGED
@@ -259,6 +259,9 @@ def main_options(parser: ArgumentParser) -> ArgumentParser:
259
259
  metavar="CMD",
260
260
  help="Add extra options for ffmpeg. Must be in quotes",
261
261
  )
262
+ parser.add_argument(
263
+ "--config", flag=True, help="When set, look for `config.pal` and run it"
264
+ )
262
265
  parser.add_argument(
263
266
  "--no-cache", flag=True, help="Don't look for or write a cache file"
264
267
  )
auto_editor/edit.py CHANGED
@@ -15,6 +15,7 @@ from auto_editor.utils.bar import Bar
15
15
  from auto_editor.utils.chunks import Chunk, Chunks
16
16
  from auto_editor.utils.cmdkw import ParserError, parse_with_palet, pAttr, pAttrs
17
17
  from auto_editor.utils.container import Container, container_constructor
18
+ from auto_editor.utils.func import open_with_system_default
18
19
  from auto_editor.utils.log import Log
19
20
  from auto_editor.utils.types import Args
20
21
 
@@ -45,8 +46,9 @@ def set_output(
45
46
 
46
47
  ext_map = {
47
48
  "premiere": ".xml",
48
- "resolve": ".fcpxml",
49
+ "resolve-fcp7": ".xml",
49
50
  "final-cut-pro": ".fcpxml",
51
+ "resolve": ".fcpxml",
50
52
  "shotcut": ".mlt",
51
53
  "json": ".json",
52
54
  "audio": ".wav",
@@ -122,8 +124,9 @@ def parse_export(export: str, log: Log) -> dict[str, Any]:
122
124
  parsing: dict[str, pAttrs] = {
123
125
  "default": pAttrs("default"),
124
126
  "premiere": pAttrs("premiere", name_attr),
125
- "resolve": pAttrs("resolve", name_attr),
127
+ "resolve-fcp7": pAttrs("resolve-fcp7", name_attr),
126
128
  "final-cut-pro": pAttrs("final-cut-pro", name_attr),
129
+ "resolve": pAttrs("resolve", name_attr),
127
130
  "shotcut": pAttrs("shotcut"),
128
131
  "json": pAttrs("json", pAttr("api", 3, is_int)),
129
132
  "timeline": pAttrs("json", pAttr("api", 3, is_int)),
@@ -176,10 +179,11 @@ def edit_media(paths: list[str], ffmpeg: FFmpeg, args: Args, log: Log) -> None:
176
179
 
177
180
  del paths
178
181
 
179
- output, export = set_output(args.output_file, args.export, src, log)
180
- assert "export" in export
182
+ output, export_ops = set_output(args.output_file, args.export, src, log)
183
+ assert "export" in export_ops
184
+ export = export_ops["export"]
181
185
 
182
- if export["export"] == "timeline":
186
+ if export == "timeline":
183
187
  log.quiet = True
184
188
 
185
189
  if not args.preview:
@@ -203,10 +207,10 @@ def edit_media(paths: list[str], ffmpeg: FFmpeg, args: Args, log: Log) -> None:
203
207
  if tl is None:
204
208
  tl = make_timeline(sources, args, samplerate, bar, log)
205
209
 
206
- if export["export"] == "timeline":
210
+ if export == "timeline":
207
211
  from auto_editor.formats.json import make_json_timeline
208
212
 
209
- make_json_timeline(export["api"], 0, tl, log)
213
+ make_json_timeline(export_ops["api"], 0, tl, log)
210
214
  return
211
215
 
212
216
  if args.preview:
@@ -215,25 +219,27 @@ def edit_media(paths: list[str], ffmpeg: FFmpeg, args: Args, log: Log) -> None:
215
219
  preview(tl, log)
216
220
  return
217
221
 
218
- if export["export"] == "json":
222
+ if export == "json":
219
223
  from auto_editor.formats.json import make_json_timeline
220
224
 
221
- make_json_timeline(export["api"], output, tl, log)
225
+ make_json_timeline(export_ops["api"], output, tl, log)
222
226
  return
223
227
 
224
- if export["export"] == "premiere":
228
+ if export in ("premiere", "resolve-fcp7"):
225
229
  from auto_editor.formats.fcp7 import fcp7_write_xml
226
230
 
227
- fcp7_write_xml(export["name"], output, tl, log)
231
+ is_resolve = export.startswith("resolve")
232
+ fcp7_write_xml(export_ops["name"], output, is_resolve, tl, log)
228
233
  return
229
234
 
230
- if export["export"] in ("final-cut-pro", "resolve"):
235
+ if export in ("final-cut-pro", "resolve"):
231
236
  from auto_editor.formats.fcp11 import fcp11_write_xml
232
237
 
233
- fcp11_write_xml(export["name"], ffmpeg, output, export["export"], tl, log)
238
+ is_resolve = export.startswith("resolve")
239
+ fcp11_write_xml(export_ops["name"], ffmpeg, output, is_resolve, tl, log)
234
240
  return
235
241
 
236
- if export["export"] == "shotcut":
242
+ if export == "shotcut":
237
243
  from auto_editor.formats.shotcut import shotcut_write_mlt
238
244
 
239
245
  shotcut_write_mlt(output, tl)
@@ -297,7 +303,7 @@ def edit_media(paths: list[str], ffmpeg: FFmpeg, args: Args, log: Log) -> None:
297
303
  log,
298
304
  )
299
305
 
300
- if export["export"] == "clip-sequence":
306
+ if export == "clip-sequence":
301
307
  if tl.v1 is None:
302
308
  log.error("Timeline too complex to use clip-sequence export")
303
309
 
@@ -338,10 +344,8 @@ def edit_media(paths: list[str], ffmpeg: FFmpeg, args: Args, log: Log) -> None:
338
344
 
339
345
  log.stop_timer()
340
346
 
341
- if not args.no_open and export["export"] in ("default", "audio", "clip-sequence"):
347
+ if not args.no_open and export in ("default", "audio", "clip-sequence"):
342
348
  if args.player is None:
343
- from auto_editor.utils.func import open_with_system_default
344
-
345
349
  open_with_system_default(output, log)
346
350
  else:
347
351
  import subprocess
@@ -54,7 +54,7 @@ def make_name(src: FileInfo, tb: Fraction) -> str:
54
54
 
55
55
 
56
56
  def fcp11_write_xml(
57
- group_name: str, ffmpeg: FFmpeg, output: str, flavor: str, tl: v3, log: Log
57
+ group_name: str, ffmpeg: FFmpeg, output: str, resolve: bool, tl: v3, log: Log
58
58
  ) -> None:
59
59
  def fraction(val: int) -> str:
60
60
  if val == 0:
@@ -66,23 +66,22 @@ def fcp11_write_xml(
66
66
 
67
67
  proj_name = src.path.stem
68
68
  src_dur = int(src.duration * tl.tb)
69
- tl_dur = src_dur if flavor == "resolve" else tl.out_len()
69
+ tl_dur = src_dur if resolve else tl.out_len()
70
70
 
71
71
  all_srcs: list[FileInfo] = [src]
72
72
  all_refs: list[str] = ["r2"]
73
- if flavor == "resolve":
74
- if len(src.audios) > 1:
75
- fold = make_tracks_dir(src)
76
-
77
- for i in range(1, len(src.audios)):
78
- newtrack = fold / f"{i}.wav"
79
- ffmpeg.run(
80
- ["-i", f"{src.path.resolve()}", "-map", f"0:a:{i}", f"{newtrack}"]
81
- )
82
- all_srcs.append(initFileInfo(f"{newtrack}", log))
83
- all_refs.append(f"r{(i + 1) * 2}")
84
-
85
- fcpxml = Element("fcpxml", version="1.10" if flavor == "resolve" else "1.11")
73
+ if resolve and len(src.audios) > 1:
74
+ fold = make_tracks_dir(src)
75
+
76
+ for i in range(1, len(src.audios)):
77
+ newtrack = fold / f"{i}.wav"
78
+ ffmpeg.run(
79
+ ["-i", f"{src.path.resolve()}", "-map", f"0:a:{i}", f"{newtrack}"]
80
+ )
81
+ all_srcs.append(initFileInfo(f"{newtrack}", log))
82
+ all_refs.append(f"r{(i + 1) * 2}")
83
+
84
+ fcpxml = Element("fcpxml", version="1.10" if resolve else "1.11")
86
85
  resources = SubElement(fcpxml, "resources")
87
86
 
88
87
  for i, one_src in enumerate(all_srcs):
@@ -134,7 +133,7 @@ def fcp11_write_xml(
134
133
  else:
135
134
  clips = []
136
135
 
137
- def make_clip(ref: str, clip: TlVideo | TlAudio, speed_warn: bool) -> bool:
136
+ def make_clip(ref: str, clip: TlVideo | TlAudio) -> None:
138
137
  clip_properties = {
139
138
  "name": proj_name,
140
139
  "ref": ref,
@@ -148,7 +147,6 @@ def fcp11_write_xml(
148
147
  # See the "Time Maps" section.
149
148
  # https://developer.apple.com/documentation/professional_video_applications/fcpxml_reference/story_elements/timemap/
150
149
 
151
- speed_warn = True
152
150
  timemap = SubElement(asset, "timeMap")
153
151
  SubElement(timemap, "timept", time="0s", value="0s", interp="smooth2")
154
152
  SubElement(
@@ -158,19 +156,11 @@ def fcp11_write_xml(
158
156
  value=fraction(src_dur),
159
157
  interp="smooth2",
160
158
  )
161
- return speed_warn
162
159
 
163
- warn = False
164
160
  for my_ref in all_refs:
165
161
  for clip in clips:
166
- warn = make_clip(my_ref, clip, warn)
162
+ make_clip(my_ref, clip)
167
163
 
168
- if flavor == "resolve" and warn:
169
- log.warning(
170
- "DaVinci Resolve may take a very long time when importing timelines with "
171
- "speed effects. Consider switching to Premiere Pro, "
172
- "Final Cut Pro, or ShotCut (free)"
173
- )
174
164
  tree = ElementTree(fcpxml)
175
165
  indent(tree, space="\t", level=0)
176
166
  tree.write(output, xml_declaration=True, encoding="utf-8")
@@ -151,8 +151,10 @@ SUPPORTED_EFFECTS = ("timeremap",)
151
151
 
152
152
  def read_filters(clipitem: Element, log: Log) -> float:
153
153
  for effect_tag in clipitem:
154
+ if effect_tag.tag in ("enabled", "start", "end"):
155
+ continue
154
156
  if len(effect_tag) < 3:
155
- log.error("effect tag requires: <effectid> <name> and one <parameter>")
157
+ log.error("<effect> requires: <effectid> <name> and one <parameter>")
156
158
  for i, effects in enumerate(effect_tag):
157
159
  if i == 0 and effects.tag != "name":
158
160
  log.error("<effect>: <name> must be first tag")
@@ -266,9 +268,10 @@ def fcp7_read_xml(path: str, log: Log) -> v3:
266
268
  if "video" in av:
267
269
  tracks = valid.parse(av["video"], vclip_schema)
268
270
 
269
- width = tracks["format"]["samplecharacteristics"]["width"]
270
- height = tracks["format"]["samplecharacteristics"]["height"]
271
- res = width, height
271
+ if "format" in tracks:
272
+ width = tracks["format"]["samplecharacteristics"]["width"]
273
+ height = tracks["format"]["samplecharacteristics"]["height"]
274
+ res = width, height
272
275
 
273
276
  for t, track in enumerate(tracks["track"]):
274
277
  if len(track["clipitem"]) > 0:
@@ -304,7 +307,8 @@ def fcp7_read_xml(path: str, log: Log) -> v3:
304
307
 
305
308
  if "audio" in av:
306
309
  tracks = valid.parse(av["audio"], aclip_schema)
307
- sr = tracks["format"]["samplecharacteristics"]["samplerate"]
310
+ if "format" in tracks:
311
+ sr = tracks["format"]["samplecharacteristics"]["samplerate"]
308
312
 
309
313
  for t, track in enumerate(tracks["track"]):
310
314
  if len(track["clipitem"]) > 0:
@@ -344,6 +348,13 @@ def media_def(
344
348
  ET.SubElement(filedef, "name").text = src.path.stem
345
349
  ET.SubElement(filedef, "pathurl").text = url
346
350
 
351
+ timecode = ET.SubElement(filedef, "timecode")
352
+ ET.SubElement(timecode, "string").text = "00:00:00:00"
353
+ ET.SubElement(timecode, "displayformat").text = "NDF"
354
+ rate = ET.SubElement(timecode, "rate")
355
+ ET.SubElement(rate, "timebase").text = f"{tb}"
356
+ ET.SubElement(rate, "ntsc").text = ntsc
357
+
347
358
  rate = ET.SubElement(filedef, "rate")
348
359
  ET.SubElement(rate, "timebase").text = f"{tb}"
349
360
  ET.SubElement(rate, "ntsc").text = ntsc
@@ -372,87 +383,53 @@ def media_def(
372
383
  ET.SubElement(audiodef, "channelcount").text = f"{aud.channels}"
373
384
 
374
385
 
375
- def fcp7_write_xml(name: str, output: str, tl: v3, log: Log) -> None:
376
- width, height = tl.res
377
- timebase, ntsc = set_tb_ntsc(tl.tb)
378
-
379
- src_to_url: dict[FileInfo, str] = {}
380
- src_to_id: dict[FileInfo, str] = {}
381
-
382
- file_defs: set[str] = set() # Contains urls
383
-
384
- for src in set(tl.sources):
385
- the_id = f"file-{len(src_to_id)+1}"
386
- src_to_url[src] = f"{src.path.resolve()}"
387
- src_to_id[src] = the_id
388
-
389
- xmeml = ET.Element("xmeml", version="5")
390
- sequence = ET.SubElement(xmeml, "sequence", explodedTracks="true")
391
- ET.SubElement(sequence, "name").text = name
392
- ET.SubElement(sequence, "duration").text = f"{int(tl.out_len())}"
393
- rate = ET.SubElement(sequence, "rate")
394
- ET.SubElement(rate, "timebase").text = f"{timebase}"
395
- ET.SubElement(rate, "ntsc").text = ntsc
396
- media = ET.SubElement(sequence, "media")
397
- video = ET.SubElement(media, "video")
398
- vformat = ET.SubElement(video, "format")
399
- vschar = ET.SubElement(vformat, "samplecharacteristics")
400
-
401
- ET.SubElement(vschar, "width").text = f"{width}"
402
- ET.SubElement(vschar, "height").text = f"{height}"
403
- ET.SubElement(vschar, "pixelaspectratio").text = "square"
404
-
405
- rate = ET.SubElement(vschar, "rate")
406
- ET.SubElement(rate, "timebase").text = f"{timebase}"
407
- ET.SubElement(rate, "ntsc").text = ntsc
408
-
409
- if len(tl.v) > 0 and len(tl.v[0]) > 0:
410
- track = ET.SubElement(video, "track")
386
+ def resolve_write_audio(audio: Element, make_filedef, tl: v3) -> None:
387
+ for t, aclips in enumerate(tl.a):
388
+ track = ET.SubElement(audio, "track")
389
+ for j, aclip in enumerate(aclips):
390
+ src = aclip.src
411
391
 
412
- for j, clip in enumerate(tl.v[0]):
413
- assert isinstance(clip, TlVideo)
392
+ _start = f"{aclip.start}"
393
+ _end = f"{aclip.start + aclip.dur}"
394
+ _in = f"{aclip.offset}"
395
+ _out = f"{aclip.offset + aclip.dur}"
414
396
 
415
- _start = f"{clip.start}"
416
- _end = f"{clip.start + clip.dur}"
417
- _in = f"{clip.offset}"
418
- _out = f"{clip.offset + clip.dur}"
397
+ if not src.videos:
398
+ clip_item_num = j + 1
399
+ else:
400
+ clip_item_num = len(aclips) + 1 + j
419
401
 
420
- clipitem = ET.SubElement(track, "clipitem", id=f"clipitem-{j+1}")
402
+ clipitem = ET.SubElement(track, "clipitem", id=f"clipitem-{clip_item_num}")
421
403
  ET.SubElement(clipitem, "name").text = src.path.stem
422
- ET.SubElement(clipitem, "enabled").text = "TRUE"
423
404
  ET.SubElement(clipitem, "start").text = _start
424
405
  ET.SubElement(clipitem, "end").text = _end
406
+ ET.SubElement(clipitem, "enabled").text = "TRUE"
425
407
  ET.SubElement(clipitem, "in").text = _in
426
408
  ET.SubElement(clipitem, "out").text = _out
427
409
 
428
- _id = src_to_id[clip.src]
429
- filedef = ET.SubElement(clipitem, "file", id=_id)
410
+ make_filedef(clipitem, aclip.src)
430
411
 
431
- pathurl = src_to_url[clip.src]
432
- if pathurl not in file_defs:
433
- media_def(filedef, pathurl, clip.src, tl, timebase, ntsc)
434
- file_defs.add(pathurl)
435
-
436
- ET.SubElement(clipitem, "compositemode").text = "normal"
437
- if clip.speed != 1:
438
- clipitem.append(speedup(clip.speed * 100))
412
+ sourcetrack = ET.SubElement(clipitem, "sourcetrack")
413
+ ET.SubElement(sourcetrack, "mediatype").text = "audio"
414
+ ET.SubElement(sourcetrack, "trackindex").text = f"{t + 1}"
439
415
 
440
- for i in range(len(src.audios) * 2 + 1): # `2` because stereo.
416
+ if src.videos:
441
417
  link = ET.SubElement(clipitem, "link")
442
- ET.SubElement(
443
- link, "linkclipref"
444
- ).text = f"clipitem-{(i*(len(tl.v[0])))+j+1}"
445
- ET.SubElement(link, "mediatype").text = "video" if i == 0 else "audio"
446
- ET.SubElement(link, "trackindex").text = str(max(i, 1))
447
- ET.SubElement(link, "clipindex").text = str(j + 1)
418
+ ET.SubElement(link, "linkclipref").text = f"clipitem-{j + 1}"
419
+ ET.SubElement(link, "mediatype").text = "video"
420
+ link = ET.SubElement(clipitem, "link")
421
+ ET.SubElement(link, "linkclipref").text = f"clipitem-{clip_item_num}"
448
422
 
449
- # Audio definitions and clips
450
- audio = ET.SubElement(media, "audio")
423
+ if aclip.speed != 1:
424
+ clipitem.append(speedup(aclip.speed * 100))
425
+
426
+
427
+ def premiere_write_audio(audio: Element, make_filedef, src: FileInfo, tl: v3) -> None:
451
428
  ET.SubElement(audio, "numOutputChannels").text = "2"
452
429
  aformat = ET.SubElement(audio, "format")
453
430
  aschar = ET.SubElement(aformat, "samplecharacteristics")
454
431
  ET.SubElement(aschar, "depth").text = DEPTH
455
- ET.SubElement(aschar, "samplerate").text = str(tl.sr)
432
+ ET.SubElement(aschar, "samplerate").text = f"{tl.sr}"
456
433
 
457
434
  t = 0
458
435
  for aclips in tl.a:
@@ -494,11 +471,7 @@ def fcp7_write_xml(name: str, output: str, tl: v3, log: Log) -> None:
494
471
  ET.SubElement(clipitem, "in").text = _in
495
472
  ET.SubElement(clipitem, "out").text = _out
496
473
 
497
- pathurl = src_to_url[aclip.src]
498
- filedef = ET.SubElement(clipitem, "file", id=src_to_id[aclip.src])
499
- if pathurl not in file_defs:
500
- media_def(filedef, pathurl, aclip.src, tl, timebase, ntsc)
501
- file_defs.add(pathurl)
474
+ make_filedef(clipitem, aclip.src)
502
475
 
503
476
  sourcetrack = ET.SubElement(clipitem, "sourcetrack")
504
477
  ET.SubElement(sourcetrack, "mediatype").text = "audio"
@@ -511,6 +484,103 @@ def fcp7_write_xml(name: str, output: str, tl: v3, log: Log) -> None:
511
484
 
512
485
  audio.append(track)
513
486
 
487
+
488
+ def fcp7_write_xml(name: str, output: str, resolve: bool, tl: v3, log: Log) -> None:
489
+ width, height = tl.res
490
+ timebase, ntsc = set_tb_ntsc(tl.tb)
491
+
492
+ src_to_url: dict[FileInfo, str] = {}
493
+ src_to_id: dict[FileInfo, str] = {}
494
+
495
+ file_defs: set[str] = set() # Contains urls
496
+
497
+ for src in set(tl.sources):
498
+ the_id = f"file-{len(src_to_id)+1}"
499
+ src_to_url[src] = f"{src.path.resolve()}"
500
+ src_to_id[src] = the_id
501
+
502
+ def make_filedef(clipitem: Element, src: FileInfo) -> None:
503
+ pathurl = src_to_url[src]
504
+ filedef = ET.SubElement(clipitem, "file", id=src_to_id[src])
505
+ if pathurl not in file_defs:
506
+ media_def(filedef, pathurl, src, tl, timebase, ntsc)
507
+ file_defs.add(pathurl)
508
+
509
+ xmeml = ET.Element("xmeml", version="5")
510
+ if resolve:
511
+ sequence = ET.SubElement(xmeml, "sequence")
512
+ else:
513
+ sequence = ET.SubElement(xmeml, "sequence", explodedTracks="true")
514
+
515
+ ET.SubElement(sequence, "name").text = name
516
+ ET.SubElement(sequence, "duration").text = f"{int(tl.out_len())}"
517
+ rate = ET.SubElement(sequence, "rate")
518
+ ET.SubElement(rate, "timebase").text = f"{timebase}"
519
+ ET.SubElement(rate, "ntsc").text = ntsc
520
+ media = ET.SubElement(sequence, "media")
521
+ video = ET.SubElement(media, "video")
522
+ vformat = ET.SubElement(video, "format")
523
+ vschar = ET.SubElement(vformat, "samplecharacteristics")
524
+
525
+ ET.SubElement(vschar, "width").text = f"{width}"
526
+ ET.SubElement(vschar, "height").text = f"{height}"
527
+ ET.SubElement(vschar, "pixelaspectratio").text = "square"
528
+
529
+ rate = ET.SubElement(vschar, "rate")
530
+ ET.SubElement(rate, "timebase").text = f"{timebase}"
531
+ ET.SubElement(rate, "ntsc").text = ntsc
532
+
533
+ if len(tl.v) > 0 and len(tl.v[0]) > 0:
534
+ track = ET.SubElement(video, "track")
535
+
536
+ for j, clip in enumerate(tl.v[0]):
537
+ assert isinstance(clip, TlVideo)
538
+
539
+ _start = f"{clip.start}"
540
+ _end = f"{clip.start + clip.dur}"
541
+ _in = f"{clip.offset}"
542
+ _out = f"{clip.offset + clip.dur}"
543
+
544
+ this_clipid = f"clipitem-{j+1}"
545
+ clipitem = ET.SubElement(track, "clipitem", id=this_clipid)
546
+ ET.SubElement(clipitem, "name").text = src.path.stem
547
+ ET.SubElement(clipitem, "enabled").text = "TRUE"
548
+ ET.SubElement(clipitem, "start").text = _start
549
+ ET.SubElement(clipitem, "end").text = _end
550
+ ET.SubElement(clipitem, "in").text = _in
551
+ ET.SubElement(clipitem, "out").text = _out
552
+
553
+ make_filedef(clipitem, clip.src)
554
+
555
+ ET.SubElement(clipitem, "compositemode").text = "normal"
556
+ if clip.speed != 1:
557
+ clipitem.append(speedup(clip.speed * 100))
558
+
559
+ if resolve:
560
+ link = ET.SubElement(clipitem, "link")
561
+ ET.SubElement(link, "linkclipref").text = this_clipid
562
+ link = ET.SubElement(clipitem, "link")
563
+ ET.SubElement(
564
+ link, "linkclipref"
565
+ ).text = f"clipitem-{(len(tl.v[0]))+j+1}"
566
+ continue
567
+
568
+ for i in range(1 + len(src.audios) * 2): # `2` because stereo.
569
+ link = ET.SubElement(clipitem, "link")
570
+ ET.SubElement(
571
+ link, "linkclipref"
572
+ ).text = f"clipitem-{(i*(len(tl.v[0])))+j+1}"
573
+ ET.SubElement(link, "mediatype").text = "video" if i == 0 else "audio"
574
+ ET.SubElement(link, "trackindex").text = f"{max(i, 1)}"
575
+ ET.SubElement(link, "clipindex").text = f"{j + 1}"
576
+
577
+ # Audio definitions and clips
578
+ audio = ET.SubElement(media, "audio")
579
+ if resolve:
580
+ resolve_write_audio(audio, make_filedef, tl)
581
+ else:
582
+ premiere_write_audio(audio, make_filedef, src, tl)
583
+
514
584
  tree = ET.ElementTree(xmeml)
515
585
  ET.indent(tree, space=" ", level=0)
516
586
  tree.write(output, xml_declaration=True, encoding="utf-8")
@@ -0,0 +1,10 @@
1
+ from .palet import Syntax
2
+
3
+
4
+ def all() -> dict[str, object]:
5
+ return {
6
+ "get-current-env": Syntax(lambda env, node: env.data.copy()),
7
+ "proc-name": Syntax(
8
+ lambda env, node: [proc := node[1].val, env[proc].name][-1]
9
+ ),
10
+ }