NickVerri commited on
Commit
5fd5d2b
·
verified ·
1 Parent(s): 9d7178b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +42 -18
app.py CHANGED
@@ -11,8 +11,8 @@ import gc
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,17 +127,12 @@ 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 Robust XML for Premiere AND Resolve."""
131
-
132
- master_id = "masterfile-1"
133
 
134
  # FPS Logic
135
  timebase = int(round(fps))
136
  is_ntsc = "TRUE" if fps % 1 != 0 else "FALSE"
137
 
138
- # NOTE: We intentionally OMIT pathurl for Multicam workflows.
139
- # This forces Premiere/Resolve to match by NAME in the project bin.
140
-
141
  lines = []
142
  lines.append('<?xml version="1.0" encoding="UTF-8"?>')
143
  lines.append('<!DOCTYPE xmeml>')
@@ -173,9 +168,13 @@ def generate_xml(sequence_name, segments, source_name, fps=25):
173
  tl_end = tl_start + duration_frames
174
 
175
  raw_note = seg.get('note', 'Junior Editor Selection')
 
176
  clip_note = (raw_note[:75] + '..') if len(raw_note) > 75 else raw_note
 
 
 
177
 
178
- lines.append(f'\t\t\t\t<clipitem id="clipitem-v-{i}">')
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,12 +182,11 @@ 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
- lines.append(f'\t\t\t\t\t<masterclipid>{master_id}</masterclipid>')
187
 
188
- # --- NAME-ONLY FILE DEFINITION ---
189
- lines.append(f'\t\t\t\t\t<file id="{master_id}">')
 
190
  lines.append(f'\t\t\t\t\t\t<name>{source_name}</name>')
191
- # NO PATHURL - Forces bin search
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
  lines.append(f'\t\t\t\t\t\t<timecode>')
@@ -197,6 +195,8 @@ def generate_xml(sequence_name, segments, source_name, fps=25):
197
  lines.append(f'\t\t\t\t\t\t\t<frame>0</frame>')
198
  lines.append(f'\t\t\t\t\t\t\t<displayformat>NDF</displayformat>')
199
  lines.append(f'\t\t\t\t\t\t</timecode>')
 
 
200
  lines.append(f'\t\t\t\t\t\t<media>')
201
  lines.append(f'\t\t\t\t\t\t\t<video>')
202
  lines.append(f'\t\t\t\t\t\t\t\t<samplecharacteristics><width>1920</width><height>1080</height></samplecharacteristics>')
@@ -207,7 +207,7 @@ def generate_xml(sequence_name, segments, source_name, fps=25):
207
  lines.append(f'\t\t\t\t\t\t\t</audio>')
208
  lines.append(f'\t\t\t\t\t\t</media>')
209
  lines.append(f'\t\t\t\t\t</file>')
210
- # -----------------------------------
211
 
212
  lines.append(f'\t\t\t\t</clipitem>')
213
 
@@ -233,8 +233,11 @@ def generate_xml(sequence_name, segments, source_name, fps=25):
233
 
234
  raw_note = seg.get('note', 'Junior Editor Selection')
235
  clip_note = (raw_note[:75] + '..') if len(raw_note) > 75 else raw_note
 
 
 
236
 
237
- lines.append(f'\t\t\t\t<clipitem id="clipitem-a-{i}">')
238
  lines.append(f'\t\t\t\t\t<name>{clip_note}</name>')
239
  lines.append(f'\t\t\t\t\t<duration>{duration_frames}</duration>')
240
  lines.append(f'\t\t\t\t\t<rate><timebase>{timebase}</timebase></rate>')
@@ -242,10 +245,29 @@ def generate_xml(sequence_name, segments, source_name, fps=25):
242
  lines.append(f'\t\t\t\t\t<end>{tl_end}</end>')
243
  lines.append(f'\t\t\t\t\t<in>{src_in_frames}</in>')
244
  lines.append(f'\t\t\t\t\t<out>{src_out_frames}</out>')
245
- lines.append(f'\t\t\t\t\t<masterclipid>{master_id}</masterclipid>')
246
 
247
- # Reuse same file definition
248
- lines.append(f'\t\t\t\t\t<file id="{master_id}"/>')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
249
 
250
  # SOURCE TRACK MAPPING
251
  lines.append('\t\t\t\t\t<sourcetrack>')
@@ -316,7 +338,9 @@ st.markdown("""
316
  * Set your timeline FPS and transcription quality.
317
  * Junior Editor will transcribe and separate speakers. You can then instruct it to find engaging bits or construct a narrative.
318
  * It will create an EDL or XML to import back into your editing software (Resolve, Premiere).
319
- * **For Multicam Workflows:** Use the **XML** option in the sidebar and enter the **exact name** of your Multicam Sequence. **Uncheck "Automatically import source clips into media pool" when importing into DaVinci Resolve.**
 
 
320
  """)
321
 
322
  st.divider()
 
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
  return "\n".join(edl_lines)
128
 
129
  def generate_xml(sequence_name, segments, source_name, fps=25):
130
+ """Constructs a 'Dumb' XML that forces Premiere to respect timeline In/Outs on replace."""
 
 
131
 
132
  # FPS Logic
133
  timebase = int(round(fps))
134
  is_ntsc = "TRUE" if fps % 1 != 0 else "FALSE"
135
 
 
 
 
136
  lines = []
137
  lines.append('<?xml version="1.0" encoding="UTF-8"?>')
138
  lines.append('<!DOCTYPE xmeml>')
 
168
  tl_end = tl_start + duration_frames
169
 
170
  raw_note = seg.get('note', 'Junior Editor Selection')
171
+ # Truncate for safety
172
  clip_note = (raw_note[:75] + '..') if len(raw_note) > 75 else raw_note
173
+
174
+ # Unique ID for every single clip item to prevent "Master Clip" logic grouping
175
+ clip_id = f"clip-v-{i}-{uuid.uuid4()}"
176
 
177
+ lines.append(f'\t\t\t\t<clipitem id="{clip_id}">')
178
  lines.append(f'\t\t\t\t\t<name>{clip_note}</name>')
179
  lines.append(f'\t\t\t\t\t<duration>{duration_frames}</duration>')
180
  lines.append(f'\t\t\t\t\t<rate><timebase>{timebase}</timebase></rate>')
 
182
  lines.append(f'\t\t\t\t\t<end>{tl_end}</end>')
183
  lines.append(f'\t\t\t\t\t<in>{src_in_frames}</in>')
184
  lines.append(f'\t\t\t\t\t<out>{src_out_frames}</out>')
 
185
 
186
+ # --- DUMB FILE DEFINITION (No MasterClipID, No Path) ---
187
+ # This forces the NLE to treat it as a standalone event needing a source.
188
+ lines.append(f'\t\t\t\t\t<file id="file-v-{i}">')
189
  lines.append(f'\t\t\t\t\t\t<name>{source_name}</name>')
 
190
  lines.append(f'\t\t\t\t\t\t<rate><timebase>{timebase}</timebase></rate>')
191
  lines.append(f'\t\t\t\t\t\t<duration>8640000</duration>')
192
  lines.append(f'\t\t\t\t\t\t<timecode>')
 
195
  lines.append(f'\t\t\t\t\t\t\t<frame>0</frame>')
196
  lines.append(f'\t\t\t\t\t\t\t<displayformat>NDF</displayformat>')
197
  lines.append(f'\t\t\t\t\t\t</timecode>')
198
+ # Reel name helps Resolve link if file name fails
199
+ lines.append(f'\t\t\t\t\t\t<reel><name>{source_name}</name></reel>')
200
  lines.append(f'\t\t\t\t\t\t<media>')
201
  lines.append(f'\t\t\t\t\t\t\t<video>')
202
  lines.append(f'\t\t\t\t\t\t\t\t<samplecharacteristics><width>1920</width><height>1080</height></samplecharacteristics>')
 
207
  lines.append(f'\t\t\t\t\t\t\t</audio>')
208
  lines.append(f'\t\t\t\t\t\t</media>')
209
  lines.append(f'\t\t\t\t\t</file>')
210
+ # ----------------------------------------------
211
 
212
  lines.append(f'\t\t\t\t</clipitem>')
213
 
 
233
 
234
  raw_note = seg.get('note', 'Junior Editor Selection')
235
  clip_note = (raw_note[:75] + '..') if len(raw_note) > 75 else raw_note
236
+
237
+ # Unique ID for audio clip too
238
+ clip_id = f"clip-a-{i}-{uuid.uuid4()}"
239
 
240
+ lines.append(f'\t\t\t\t<clipitem id="{clip_id}">')
241
  lines.append(f'\t\t\t\t\t<name>{clip_note}</name>')
242
  lines.append(f'\t\t\t\t\t<duration>{duration_frames}</duration>')
243
  lines.append(f'\t\t\t\t\t<rate><timebase>{timebase}</timebase></rate>')
 
245
  lines.append(f'\t\t\t\t\t<end>{tl_end}</end>')
246
  lines.append(f'\t\t\t\t\t<in>{src_in_frames}</in>')
247
  lines.append(f'\t\t\t\t\t<out>{src_out_frames}</out>')
 
248
 
249
+ # Reuse same file definition (No Master ID)
250
+ lines.append(f'\t\t\t\t\t<file id="file-a-{i}">')
251
+ lines.append(f'\t\t\t\t\t\t<name>{source_name}</name>')
252
+ lines.append(f'\t\t\t\t\t\t<rate><timebase>{timebase}</timebase></rate>')
253
+ lines.append(f'\t\t\t\t\t\t<duration>8640000</duration>')
254
+ lines.append(f'\t\t\t\t\t\t<timecode>')
255
+ lines.append(f'\t\t\t\t\t\t\t<rate><timebase>{timebase}</timebase></rate>')
256
+ lines.append(f'\t\t\t\t\t\t\t<string>00:00:00:00</string>')
257
+ lines.append(f'\t\t\t\t\t\t\t<frame>0</frame>')
258
+ lines.append(f'\t\t\t\t\t\t\t<displayformat>NDF</displayformat>')
259
+ lines.append(f'\t\t\t\t\t\t</timecode>')
260
+ lines.append(f'\t\t\t\t\t\t<reel><name>{source_name}</name></reel>')
261
+ lines.append(f'\t\t\t\t\t\t<media>')
262
+ lines.append(f'\t\t\t\t\t\t\t<video>')
263
+ lines.append(f'\t\t\t\t\t\t\t\t<samplecharacteristics><width>1920</width><height>1080</height></samplecharacteristics>')
264
+ lines.append(f'\t\t\t\t\t\t\t</video>')
265
+ lines.append(f'\t\t\t\t\t\t\t<audio>')
266
+ lines.append(f'\t\t\t\t\t\t\t\t<samplecharacteristics><depth>16</depth><samplerate>48000</samplerate></samplecharacteristics>')
267
+ lines.append(f'\t\t\t\t\t\t\t\t<channelcount>2</channelcount>')
268
+ lines.append(f'\t\t\t\t\t\t\t</audio>')
269
+ lines.append(f'\t\t\t\t\t\t</media>')
270
+ lines.append(f'\t\t\t\t\t</file>')
271
 
272
  # SOURCE TRACK MAPPING
273
  lines.append('\t\t\t\t\t<sourcetrack>')
 
338
  * Set your timeline FPS and transcription quality.
339
  * Junior Editor will transcribe and separate speakers. You can then instruct it to find engaging bits or construct a narrative.
340
  * It will create an EDL or XML to import back into your editing software (Resolve, Premiere).
341
+ * **For Multicam Workflows:** Use the **XML** option in the sidebar and enter the **exact name** of your Multicam Sequence.
342
+ * **Resolve Users:** Uncheck "Automatically import source clips into media pool" during import.
343
+ * **Premiere Users:** Import the XML. Select all clips on the timeline. Hold **Alt (Win) / Option (Mac)** and drag your Multicam Sequence from the bin onto the selected clips to link them instantly.
344
  """)
345
 
346
  st.divider()