NickVerri commited on
Commit
edb5d36
·
verified ·
1 Parent(s): 787dc44

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +48 -20
app.py CHANGED
@@ -11,8 +11,8 @@ import gc
11
  import math
12
  import uuid
13
  import re
14
- from datetime import timedelta
15
  from urllib.parse import quote
 
16
 
17
  # --- CRITICAL ENVIRONMENT FIXES ---
18
  if os.environ.get("OMP_NUM_THREADS", "").endswith("m"):
@@ -127,15 +127,21 @@ def generate_cmx_edl(edl_title, segments, source_name, fps=25):
127
  return "\n".join(edl_lines)
128
 
129
  def generate_xml(sequence_name, segments, source_name, fps=25):
130
- """Constructs a Timecode-Agnostic XML for robust Replace Edit workflows."""
131
 
132
- # UNIFIED ID: Keeps the bin clean (1 offline item)
133
- unified_file_id = "unified-source-master"
134
 
135
  # FPS Logic
136
  timebase = int(round(fps))
137
  is_ntsc = "TRUE" if fps % 1 != 0 else "FALSE"
138
 
 
 
 
 
 
 
139
  lines = []
140
  lines.append('<?xml version="1.0" encoding="UTF-8"?>')
141
  lines.append('<!DOCTYPE xmeml>')
@@ -172,10 +178,8 @@ def generate_xml(sequence_name, segments, source_name, fps=25):
172
 
173
  raw_note = seg.get('note', 'Junior Editor Selection')
174
  clip_note = (raw_note[:75] + '..') if len(raw_note) > 75 else raw_note
175
-
176
- clip_id = f"clip-v-{i}-{uuid.uuid4()}"
177
 
178
- lines.append(f'\t\t\t\t<clipitem id="{clip_id}">')
179
  lines.append(f'\t\t\t\t\t<name>{clip_note}</name>')
180
  lines.append(f'\t\t\t\t\t<duration>{duration_frames}</duration>')
181
  lines.append(f'\t\t\t\t\t<rate><timebase>{timebase}</timebase></rate>')
@@ -183,15 +187,20 @@ def generate_xml(sequence_name, segments, source_name, fps=25):
183
  lines.append(f'\t\t\t\t\t<end>{tl_end}</end>')
184
  lines.append(f'\t\t\t\t\t<in>{src_in_frames}</in>')
185
  lines.append(f'\t\t\t\t\t<out>{src_out_frames}</out>')
 
186
 
187
- # --- AGNOSTIC FILE DEFINITION ---
188
- # NO <timecode> block: Forces Premiere to use relative frame offset
189
- # NO <reel>: Prevents metadata mismatch
190
- lines.append(f'\t\t\t\t\t<file id="{unified_file_id}">')
191
  lines.append(f'\t\t\t\t\t\t<name>{source_name}</name>')
 
192
  lines.append(f'\t\t\t\t\t\t<rate><timebase>{timebase}</timebase></rate>')
193
  lines.append(f'\t\t\t\t\t\t<duration>8640000</duration>')
194
- # TIMECODE REMOVED HERE
 
 
 
 
 
195
  lines.append(f'\t\t\t\t\t\t<media>')
196
  lines.append(f'\t\t\t\t\t\t\t<video>')
197
  lines.append(f'\t\t\t\t\t\t\t\t<samplecharacteristics><width>1920</width><height>1080</height></samplecharacteristics>')
@@ -202,7 +211,7 @@ def generate_xml(sequence_name, segments, source_name, fps=25):
202
  lines.append(f'\t\t\t\t\t\t\t</audio>')
203
  lines.append(f'\t\t\t\t\t\t</media>')
204
  lines.append(f'\t\t\t\t\t</file>')
205
- # -------------------------------
206
 
207
  lines.append(f'\t\t\t\t</clipitem>')
208
 
@@ -228,10 +237,8 @@ def generate_xml(sequence_name, segments, source_name, fps=25):
228
 
229
  raw_note = seg.get('note', 'Junior Editor Selection')
230
  clip_note = (raw_note[:75] + '..') if len(raw_note) > 75 else raw_note
231
-
232
- clip_id = f"clip-a-{i}-{uuid.uuid4()}"
233
 
234
- lines.append(f'\t\t\t\t<clipitem id="{clip_id}">')
235
  lines.append(f'\t\t\t\t\t<name>{clip_note}</name>')
236
  lines.append(f'\t\t\t\t\t<duration>{duration_frames}</duration>')
237
  lines.append(f'\t\t\t\t\t<rate><timebase>{timebase}</timebase></rate>')
@@ -239,11 +246,32 @@ def generate_xml(sequence_name, segments, source_name, fps=25):
239
  lines.append(f'\t\t\t\t\t<end>{tl_end}</end>')
240
  lines.append(f'\t\t\t\t\t<in>{src_in_frames}</in>')
241
  lines.append(f'\t\t\t\t\t<out>{src_out_frames}</out>')
 
242
 
243
- # REUSE UNIFIED FILE ID
244
- lines.append(f'\t\t\t\t\t<file id="{unified_file_id}"/>')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
245
 
246
- # SOURCE TRACK MAPPING
247
  lines.append('\t\t\t\t\t<sourcetrack>')
248
  lines.append('\t\t\t\t\t\t<mediatype>audio</mediatype>')
249
  lines.append('\t\t\t\t\t\t<trackindex>1</trackindex>')
@@ -314,7 +342,7 @@ st.markdown("""
314
  * It will create an EDL or XML to import back into your editing software (Resolve, Premiere).
315
  * **For Multicam Workflows:** Use the **XML** option in the sidebar and enter the **exact name** of your Multicam Sequence.
316
  * **Resolve Users:** Uncheck "Automatically import source clips into media pool" during import.
317
- * **Premiere Users:** Import the XML. A **single** offline clip will appear in your bin. Hold **Alt (Win) / Option (Mac)** and drag your Multicam Sequence from the bin onto this **single** offline clip to link the entire timeline instantly.
318
  """)
319
 
320
  st.divider()
 
11
  import math
12
  import uuid
13
  import re
 
14
  from urllib.parse import quote
15
+ from datetime import timedelta
16
 
17
  # --- CRITICAL ENVIRONMENT FIXES ---
18
  if os.environ.get("OMP_NUM_THREADS", "").endswith("m"):
 
127
  return "\n".join(edl_lines)
128
 
129
  def generate_xml(sequence_name, segments, source_name, fps=25):
130
+ """Constructs a Robust XML for Premiere AND Resolve."""
131
 
132
+ # Static UUID ensures all cuts link to the SAME file object (Clean Bin)
133
+ master_id = "masterfile-1"
134
 
135
  # FPS Logic
136
  timebase = int(round(fps))
137
  is_ntsc = "TRUE" if fps % 1 != 0 else "FALSE"
138
 
139
+ # --- NAME & PATH LOGIC ---
140
+ # We use URL encoding but NO .mov extension.
141
+ # This allows Resolve to find it by name, and Premiere to import it as "Offline".
142
+ encoded_name = quote(source_name)
143
+ path_url = f"file://localhost/{encoded_name}"
144
+
145
  lines = []
146
  lines.append('<?xml version="1.0" encoding="UTF-8"?>')
147
  lines.append('<!DOCTYPE xmeml>')
 
178
 
179
  raw_note = seg.get('note', 'Junior Editor Selection')
180
  clip_note = (raw_note[:75] + '..') if len(raw_note) > 75 else raw_note
 
 
181
 
182
+ lines.append(f'\t\t\t\t<clipitem id="clipitem-v-{i}">')
183
  lines.append(f'\t\t\t\t\t<name>{clip_note}</name>')
184
  lines.append(f'\t\t\t\t\t<duration>{duration_frames}</duration>')
185
  lines.append(f'\t\t\t\t\t<rate><timebase>{timebase}</timebase></rate>')
 
187
  lines.append(f'\t\t\t\t\t<end>{tl_end}</end>')
188
  lines.append(f'\t\t\t\t\t<in>{src_in_frames}</in>')
189
  lines.append(f'\t\t\t\t\t<out>{src_out_frames}</out>')
190
+ lines.append(f'\t\t\t\t\t<masterclipid>{master_id}</masterclipid>')
191
 
192
+ # --- ROBUST FILE DEFINITION ---
193
+ lines.append(f'\t\t\t\t\t<file id="{master_id}">')
 
 
194
  lines.append(f'\t\t\t\t\t\t<name>{source_name}</name>')
195
+ lines.append(f'\t\t\t\t\t\t<pathurl>{path_url}</pathurl>')
196
  lines.append(f'\t\t\t\t\t\t<rate><timebase>{timebase}</timebase></rate>')
197
  lines.append(f'\t\t\t\t\t\t<duration>8640000</duration>')
198
+ lines.append(f'\t\t\t\t\t\t<timecode>')
199
+ lines.append(f'\t\t\t\t\t\t\t<rate><timebase>{timebase}</timebase></rate>')
200
+ lines.append(f'\t\t\t\t\t\t\t<string>00:00:00:00</string>')
201
+ lines.append(f'\t\t\t\t\t\t\t<frame>0</frame>')
202
+ lines.append(f'\t\t\t\t\t\t\t<displayformat>NDF</displayformat>')
203
+ lines.append(f'\t\t\t\t\t\t</timecode>')
204
  lines.append(f'\t\t\t\t\t\t<media>')
205
  lines.append(f'\t\t\t\t\t\t\t<video>')
206
  lines.append(f'\t\t\t\t\t\t\t\t<samplecharacteristics><width>1920</width><height>1080</height></samplecharacteristics>')
 
211
  lines.append(f'\t\t\t\t\t\t\t</audio>')
212
  lines.append(f'\t\t\t\t\t\t</media>')
213
  lines.append(f'\t\t\t\t\t</file>')
214
+ # -----------------------------------
215
 
216
  lines.append(f'\t\t\t\t</clipitem>')
217
 
 
237
 
238
  raw_note = seg.get('note', 'Junior Editor Selection')
239
  clip_note = (raw_note[:75] + '..') if len(raw_note) > 75 else raw_note
 
 
240
 
241
+ lines.append(f'\t\t\t\t<clipitem id="clipitem-a-{i}">')
242
  lines.append(f'\t\t\t\t\t<name>{clip_note}</name>')
243
  lines.append(f'\t\t\t\t\t<duration>{duration_frames}</duration>')
244
  lines.append(f'\t\t\t\t\t<rate><timebase>{timebase}</timebase></rate>')
 
246
  lines.append(f'\t\t\t\t\t<end>{tl_end}</end>')
247
  lines.append(f'\t\t\t\t\t<in>{src_in_frames}</in>')
248
  lines.append(f'\t\t\t\t\t<out>{src_out_frames}</out>')
249
+ lines.append(f'\t\t\t\t\t<masterclipid>{master_id}</masterclipid>')
250
 
251
+ # Reuse same file definition (Verbose)
252
+ lines.append(f'\t\t\t\t\t<file id="{master_id}">')
253
+ lines.append(f'\t\t\t\t\t\t<name>{source_name}</name>')
254
+ lines.append(f'\t\t\t\t\t\t<pathurl>{path_url}</pathurl>')
255
+ lines.append(f'\t\t\t\t\t\t<rate><timebase>{timebase}</timebase></rate>')
256
+ lines.append(f'\t\t\t\t\t\t<duration>8640000</duration>')
257
+ lines.append(f'\t\t\t\t\t\t<timecode>')
258
+ lines.append(f'\t\t\t\t\t\t\t<rate><timebase>{timebase}</timebase></rate>')
259
+ lines.append(f'\t\t\t\t\t\t\t<string>00:00:00:00</string>')
260
+ lines.append(f'\t\t\t\t\t\t\t<frame>0</frame>')
261
+ lines.append(f'\t\t\t\t\t\t\t<displayformat>NDF</displayformat>')
262
+ lines.append(f'\t\t\t\t\t\t</timecode>')
263
+ lines.append(f'\t\t\t\t\t\t<media>')
264
+ lines.append(f'\t\t\t\t\t\t\t<video>')
265
+ lines.append(f'\t\t\t\t\t\t\t\t<samplecharacteristics><width>1920</width><height>1080</height></samplecharacteristics>')
266
+ lines.append(f'\t\t\t\t\t\t\t</video>')
267
+ lines.append(f'\t\t\t\t\t\t\t<audio>')
268
+ lines.append(f'\t\t\t\t\t\t\t\t<samplecharacteristics><depth>16</depth><samplerate>48000</samplerate></samplecharacteristics>')
269
+ lines.append(f'\t\t\t\t\t\t\t\t<channelcount>2</channelcount>')
270
+ lines.append(f'\t\t\t\t\t\t\t</audio>')
271
+ lines.append(f'\t\t\t\t\t\t</media>')
272
+ lines.append(f'\t\t\t\t\t</file>')
273
 
274
+ # SOURCE TRACK MAPPING (Simple Mono)
275
  lines.append('\t\t\t\t\t<sourcetrack>')
276
  lines.append('\t\t\t\t\t\t<mediatype>audio</mediatype>')
277
  lines.append('\t\t\t\t\t\t<trackindex>1</trackindex>')
 
342
  * It will create an EDL or XML to import back into your editing software (Resolve, Premiere).
343
  * **For Multicam Workflows:** Use the **XML** option in the sidebar and enter the **exact name** of your Multicam Sequence.
344
  * **Resolve Users:** Uncheck "Automatically import source clips into media pool" during import.
345
+ * **Premiere Users:** Use the EDL option if XML conformance fails for Multicam sequences.
346
  """)
347
 
348
  st.divider()