UI consolidation:
- One Export entry (rail) opens a popup menu: Conform Timeline -> MAM and
Local Export. Retires the standalone Export & Conform / Fetch & Relink
dock buttons and the plain "Push Timeline" flow.
- Remove Import All.
- New "Upload to MAM" dock button.
Upload: reads the highlighted project-panel item(s) via the premierepro
API (best-effort, guarded) and falls back to a native file picker. Pushes
via /upload/simple (small) or chunked init/part/complete (large).
Local Export: batch-trim the timeline's hi-res clips server-side (FFMPEG),
poll trim-status, download each temp-segment-url, relink in Premiere.
Relink keys on source media path (last-wins for multi-use sources).
Conform + Local Export auto-upload any timeline sources not yet in the MAM
before proceeding (renders from the hi-res original, available post-upload).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two cooperating bugs left Export Timeline stuck at "Rendering Hi-Res"
forever:
A. worker emitted "Invalid FCP XML: no sequence element" because
Timeline.generateFcpXml produced fcpxml (FCP X schema:
<fcpxml><resources>/<library>/...) while the worker's parseFcpXml
expects xmeml (FCP 7 schema: <xmeml><sequence>...). Two completely
different formats.
Rewrite generateFcpXml to emit xmeml v5 with the structure the
parser walks:
xmeml/sequence/{name,duration,rate{timebase,ntsc},
media/video/{format/samplecharacteristics,
track[@currentExplodedTrackIndex]
/clipitem/{name,duration,rate,in,out,
start,end,file/{name,pathurl}}}}
Clipitem in/out are SOURCE frames (the underlying media in/out);
start/end are TIMELINE frames (the cut position). The worker uses
the rate timebase to parse them.
B. /api/v1/jobs/:id rejected the panel's polls with
"Invalid id — must be a UUID". The handlers below correctly parse
BullMQ-prefixed ids ("conform:42"), but router.param('id',
validateUuid('id')) ran first and 400'd everything that wasn't a
UUID. The panel's pollConform swallows the resulting fetch error
silently and polls forever.
Drop the validator. Comment in the file explains why.
Bumps panel to v2.2.2.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
getStartTime/getEndTime/getInPoint/getOutPoint can return null for
non-clip track items (gaps, transitions) that slip past the
getProjectItem check. Accessing .seconds on null threw a TypeError
that the outer catch swallowed — silently dropping every clip and
leaving clips[] empty, so the export panel never opened.
Also skip clips where all four time values resolve to 0 (filler items).