Skip to content

Import FCPXML bundles - #24

Merged
FedyaLight merged 4 commits into
mainfrom
feat/fcpxml-bundles
Nov 12, 2026
Merged

FedyaLight merged 4 commits into
mainfrom
feat/fcpxml-bundles

Conversation

@FedyaLight

Copy link
Copy Markdown
Owner

Stacked on fix/camera-xml-sidecars, whose timeline recognition this
extends.

Final Cut Pro 10.6 and later export FCPXML as a .fcpxmld bundle: a
directory whose Info.fcpxml is the document. Align did not recognize the
extension, and input expansion scanned the bundle as a folder of media, so
adding one ended in "No readable audio or video media was found."

Reading:

  • A .fcpxmld directory is a timeline. Reading it and listing its sequences
    use its Info.fcpxml. Errors (ImportError::naming), warnings and the
    draft's source name the bundle the user added, not Info.fcpxml.
  • FCPXML media URLs relative to the document now resolve against its folder,
    which for a bundle is the bundle root, and are percent-decoded. Before,
    they resolved against the working directory (for plain .fcpxml files
    too), so a bundle carrying ./Media/… found no media.
  • Input expansion treats a bundle as one timeline; an explicit timeline input
    may be a bundle directory. Folder scans do not enter bundles, so media
    inside one are not loose clips.

Repaired copies (Path Fixer, align-cli fixed copies):

  • A .fcpxmld destination is written as a bundle: a copy of the source
    bundle (symbolic links kept as links on Unix, folder permissions kept) with
    its document rewritten. It is built in a temporary folder beside the
    destination. An existing destination must itself be a bundle; it is moved
    aside, the new bundle takes its place, and the old one is moved back if
    that fails, so no failure loses either. This also avoids renaming a
    directory onto an existing path, which Windows does not allow.
  • The destination may neither lie inside the source (its document or a
    nested bundle) nor contain it, compared as resolved paths.
  • Copying checks cancellation per entry and before the swap.
  • Relative media URLs that would no longer resolve from the copy's location
    become absolute file URLs; those pointing into a bundle that is copied
    along stay relative (Relocation in rewrite_media_paths).
  • A .fcpxml destination receives the repaired document alone.
  • docs/formats.md lists bundle import.

Tests, each checked by removing the corresponding fix:

  • fcpxml_bundles_are_read_through_their_document
  • bundle_media_resolve_against_the_bundle,
    fcpxml_media_may_be_relative_to_the_document (core)
  • repaired_bundle_copies_keep_the_bundle (copied files, replaced stale
    bundle, unchanged source, no leftovers beside it)
  • repaired_copies_keep_relative_media_resolving
  • repaired_bundles_never_overwrite_the_source_or_other_folders (document
    inside the source, nested bundle, source inside the destination, a
    non-bundle folder)
  • a_cancelled_bundle_copy_leaves_the_destination
  • bundle_copies_keep_symbolic_links (Unix)
  • fcpxml_bundles_beside_media_are_imported_as_timelines,
    folder_scans_do_not_enter_fcpxml_bundles

Not changed: an FCPXML document without a sequence still reports "No FCP 7
XML sequence was found" (the existing wording for both XML formats), and the
Path Fixer still appends a missing extension after the save panel returns.

Validation:

  • cargo fmt --all -- --check
  • cargo clippy --locked --workspace --all-targets -- -D warnings
  • cargo test --locked --workspace: 386 passed, 1 ignored

Every .xml path was imported as a timeline. Canon writes clip metadata as
XML beside each clip, so selecting a clip together with its XML, or two
clips' XML files, stopped the whole run with "No FCP 7 XML sequence was
found" or "Add one timeline at a time". Folder imports already skipped
these files.

An XML file is now a timeline only when its root element is FCP 7 xmeml
or fcpxml; recognizing that reads at most 16 KiB. A UTF-16 file is decoded
to find its root, so a UTF-16 project is still reported as unreadable
instead of skipped. Files that cannot be read or parsed still count as
timelines, so their import reports why. The app recognizes timeline
inputs once, when they are added, and rendering no longer reads files.

The timeline import error also lost its doubled final period.
Final Cut Pro 10.6 and later export FCPXML as a .fcpxmld bundle: a
directory whose Info.fcpxml is the document. Align did not recognize the
extension, and expanding inputs scanned the bundle as a folder of media, so
adding one gave "No readable audio or video media was found."

A .fcpxmld bundle is now a timeline: it is read through its Info.fcpxml,
and errors and warnings name the bundle. Folder scans do not enter bundles.
FCPXML media URLs relative to the document now resolve against its folder
(the bundle root) and are percent-decoded; they used to resolve against the
working directory.

A repaired copy saved as .fcpxmld is a bundle again: the source bundle is
copied, links and folder permissions kept, with its document rewritten.
It is built beside the destination and swapped in; an existing destination
must be a bundle, is moved aside and moved back if the swap fails. The
destination may neither lie inside the source nor contain it, and copying
can be cancelled. Relative media that would no longer resolve from the
copy's location become absolute file URLs.
On Windows the copied bundle follows links, and the unused file type
failed clippy.
@FedyaLight
FedyaLight changed the base branch from fix/camera-xml-sidecars to main November 12, 2026 07:29
Windows refuses to rename a folder that holds an open file, so every
repaired bundle failed there with "Access is denied."
@FedyaLight
FedyaLight merged commit ab1de32 into main Nov 12, 2026
14 checks passed
@FedyaLight
FedyaLight deleted the feat/fcpxml-bundles branch November 12, 2026 07:41
@FedyaLight FedyaLight mentioned this pull request Nov 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant