orchetect / DAWFileKit

A Swift library for reading and writing common import/export file formats between popular DAW applications.
MIT License
26 stars 2 forks source link

Final Cut Pro clipboard data read/write #26

Open orchetect opened 10 months ago

orchetect commented 10 months ago

Related to #22, out of curiosity I poked around at the clipboard content Final Cut Pro uses when copying markers from the application.

It may be possible to add methods to DAWFileKit to read/write FCP clipboard contents.

FCP uses the following UTI type:

extension NSPasteboard.PasteboardType {
    /// Final Cut Pro's pasteboard UTI type. The content is a binary plist.
    static let finalCutPro = Self("com.apple.flexo.proFFPasteboardUTI")
}

The content of the data is a binary plist. Converted to XML, this is what it looks like:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>ffpasteboardcopiedtypes</key>
    <dict>
        <key>pb_anchoredObject</key>
        <dict>
            <key>count</key>
            <integer>1</integer>
        </dict>
    </dict>
    <key>ffpasteboardobject</key>
    <data>
        <!-- base64-encoded data -->
    </data>
    <key>kffmodelobjectIDs</key>
    <array/>
</dict>

The ffpasteboardobject data blob contains a binary plist payload encoded by NSKeyedArchiver.

ffpasteboardobject

The root object is NSDictionary so it should be possible to deserialize the archive into a dictionary. It's not immediately apparent if the dictionary structure is similar to FCP XML.

ffpasteboardobject-root-obj

ffpasteboardobject-root-obj2

It definitely contains the selected markers from Final Cut Pro marker list and their details (start, duration, name).

ffpasteboardobject-marker

However, attempting to directly unarchive the data will produce errors because proprietary FCP classes are included in the archived data.

try NSKeyedUnarchiver.unarchivedObject(
    ofClasses: [NSDictionary.self, NSMutableArray.self],
    from: data
)
Error Domain=NSCocoaErrorDomain Code=4864 "*** -[NSKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class (FFAnchoredCollection) for key (NS.objects) because no class named "FFAnchoredCollection" was found; the class needs to be defined in source code or linked in from a library (ensure the class is part of the correct target).

fcp-classes

I'm not sure if Apple's ProExtension framework (which contains some FCP objects) has these classes. Worth checking out.

This means it may be necessary to manually parse the archived data, or at least selectively unarchive its children instead of attempting to unarchive the entire root dictionary. (It does not seem practical to try to model all known proprietary class types for the unarchiver to use.)

latenitefilms commented 10 months ago

You might find the CommandPost HUD's Pasteboard Editor handy for playing around with this!

image

You can also explore CommandPost's Lua to see how we use the Pasteboard data for various things.