1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#requires appscript
import aem, mactypes #from appscripts aem module 
from CarbonX import kAE

class FcpAe(aem.Application):
    """Communicates with Apple's Final Cut Pro using Apple Events. 
    Gets and sends XML.
    """
    
    kFCPEventClass ='KeyG'
    # event commands
    # the Open/Foreground a project file command
    kAEFCPOpenProjectFile ='ofcP'
    #the Close a project file command
    kAEFCPSaveAndCloseProjectFile = 'cfcP'
    #the XML Export command
    kKGAEGetDocumentXML = 'eXML'                
    #the XML Import command
    kAEImportXMLToDocument = 'iXML'
    #Open the item specified in the passed in UUID
    kFCPOpenItemInProject = 'fcOI'
    #Select the item specified in the passed in UUID
    kFCPSelectItemInBrowser = 'fcSI'
    # event parameters
    kXMLDataKey = 'xmlD'
    kXMLDataFileKey = 'xmlF'
    kXMLDataVersion = 'xmlV'
    kFCPProjectFileKey = 'fcpP'
    kFCPItemUUID = 'fcIU'
    kProjectFileCloseFlagsKey= 'fcCF'
    kFCPSaveAndCloseProject = 0
    kFCPDiscardAndCloseProject = 1
    kFindParameters = 'fndP'
    kFindSearchString = 'fndS'
    kFindMatchMode = 'fndM'
    kFindOmitCriteria = 'fndO'
    kFindColumnName = 'fndC'
    kFindLogicMode = 'fndL'
    kFCPFindMatchStartsWith = (1 << 0)
    kFCPFindMatchContains = (1 << 1)
    kFCPFindMatchEquals = (1 << 2)
    kFCPFindMatchEndsWith = (1 << 3)
    kFCPFindMatchLessThan = (1 << 4)
    kFCPFindMatchGreaterThan = (1 << 5)
    kFCPLogicAnd = 0
    kFCPLogicOr = 1
    
    def __init__(self):
        fcpID = 'com.apple.finalcutpro'
        fcpPath = aem.findapp.byid(fcpID)
        aem.Application.__init__(self,path=fcpPath)
        if not self.isrunning(fcpPath):
            self.launch(fcpPath)

    def commandEvent(self, fcpEvent):
        return ''.join([self.kFCPEventClass, fcpEvent])

    #fcp event commands below
    def openProject(self,unixFileStr):
        proj = mactypes.File(unixFileStr)
        eventkey = self.commandEvent(self.kAEFCPOpenProjectFile)
        res = self.event(eventkey,{self.kFCPProjectFileKey : proj}).send()
        
    def closeProject(self, unixFileStr, actionOnClose=0): # !!
        proj = mactypes.File(unixFileStr)
        eventkey = self.commandEvent(self.kAEFCPSaveAndCloseProjectFile)
        res = self.event(eventkey,{
                    self.kFCPProjectFileKey : proj,
                    self.kProjectFileCloseFlagsKey : actionOnClose}).send()
        
    def exportXML(self, projPathStr, fcpVersionXML=1.0):
        """Returns XML form of given FCP project"""
        
        proj = mactypes.File(projPathStr)
        eventkey = self.commandEvent(self.kKGAEGetDocumentXML)
        event = self.event(eventkey, {
                    self.kFCPProjectFileKey : proj,
                    self.kXMLDataVersion : fcpVersionXML})
        # note that fcp returns the XML test using kXMLDataKey 
        #instead of the usual keyAEResult
        # which is what aem expects
        # hence we use the lower level approach to wrangle the result
        # Thanks HAS!
        eventdesc = event.AEM_event
        replyeventdesc = eventdesc.AESendMessage(kAE.kAEWaitReply, 
                                                kAE.kAEDefaultTimeout)
        paramdict = aem.Codecs().unpack(replyeventdesc)
        return paramdict.get(aem.AEType('xmlD'), '')
        
    def importXML(self, xmlStr, projPathStr=None):
        """Modifies or creates FCP project based on XML supplied"""
        
        if projPathStr:
            proj = mactypes.File(projPathStr)
            aedict = {self.kFCPProjectFileKey : proj,
                      self.kXMLDataKey : xmlStr}
        else:
            aedict = {self.kXMLDataKey : xmlStr}
        eventkey = self.commandEvent(self.kAEImportXMLToDocument)
        res = self.event(eventkey, aedict).send()

    def openItem(self, projPathStr, uuid):
        proj = mactypes.File(projPathStr)
        eventkey = self.commandEvent(self.kFCPOpenItemInProject)
        return self.event(eventkey, {
                    self.kFCPProjectFileKey : proj,
                    self.kFCPItemUUID : uuid}).send()
        
    def selectItem(self, projPathStr, uuid):
        proj = mactypes.File(projPathStr)
        eventkey = self.commandEvent(self.kFCPSelectItemInBrowser)
        return self.event(eventkey, {
                    self.kFCPProjectFileKey : proj,
                    self.kFCPItemUUID : uuid}).send()
                    


# example
testxml = 'Example.xml'
testproj = 'test.fcp'
f = open(testxml,'r')
xmllist = f.readlines()
xml = ''.join(xmllist)
xmlout= ''

fcp = FcpAe()
fcp.openProject(testproj)
print fcp.exportXML(testproj, 3.0)
fcp.importXML(xml)
fcp.closeProject(testproj)