A script for adding hotkeys to Final Cut Pro X

In addition to being able to add overlays and transitions with hotkeys, the script also allows you to time-scale the overlay to match the duration of the selected clip on the timeline!

Instructions:

  1. Place the script bundle scripts in “~/library/script libraries/”. See below for further instructions on script bundles.
  2. Download and install FastScripts http://www.red-sweater.com/fastscripts/
  3. Place the following script in “~/library/scripts/”
set thisPath to "~/the/path/to/a/folder"
tell script "[the name you gave your 1st script bundle without the extension]"
its createClipboardDefinitionFiles:thisPath
end tell
  1. In the above script, Substitute “~/the/path/to/a/folder” for a folder path of your choosing (the directory need not exist), also replace the text within [brackets] with the name you gave your 1st script bundle. Don’t forget to delete the [brackets]
  2. In FastScripts, go to Preferences → Script Shortcuts and choose a shortcut for your script
  3. In FCPX place an overlay element (title, generator, etc) on the timeline as a Connected Clip (not as the Primary Storyline) - or - add a transition to a clip.
  4. Making sure that the FCPX element is selected, invoke the hotkey you created in step 5. Wait until the process finishes.
  5. Go to the folder you chose in step 4 and note the name of the newly created folder
  6. Place the following script in “~/library/scripts/” and save it using the name of the newly created folder. Replace the items within [brackets] with the appropriate path and name respectively (~tildes are okay). Don’t forget to delete the [brackets]
set thisPath to "[the path to the newly created folder]"
tell script "[the name you gave your 2nd script bundle without the extension]"
its implementSimpleElement:thisPath
end tell
  1. Place another script in “~/library/scripts/” and give it an identical name except append “-Time-Scaled” to the end. Replace the two items within [brackets] with the appropriate path and name respectively (~tildes are okay). Don’t forget to delete the [brackets]
set thisPath to "[the path to the newly created folder]"
tell script "[the name you gave your 3rd script bundle without the extension]"
its implementTimeScaledElement:thisPath
end tell
  1. In FastScripts, choose hotkeys for the two new scripts. The hotkey for the script you created in step 9 places a 5 second element on the timeline. The hotkey for the script you created in step 10 only works if you have a clip on the timeline selected. When one is selected and the hotkey is invoked, it will place an overlay on the timeline matching the duration of the selected clip.
  2. Repeat steps 6 thru 11 to create additional hotkeys.

Script Bundles
Below are the script bundles (save each script as script-bundle. If you are using Mavericks click the ‘Bundle Contents’ button and check the box next to ‘AppleScript/Objective-C’)

Don’t forget to save them in “~/library/script libraries/”

Script Bundle 1 of 3: A script for creating definition files

use framework "Foundation"
use framework "AppKit"
use scripting additions


its createClipboardDefinitionFiles:thisPath

############################ (primary function) ############################

on createClipboardDefinitionFiles:thePath
	
	-- ↓ copy FCPX element to clipboard, read it as a clipboard item, and unpack the plist ↓
	set {theKey, firstValueIndex, theFCPXobject} to getFCPXitemsFromClipboard()
	
	if firstValueIndex ≠ current application's NSNotFound then
		
		-- ↓ within this conditional is everything that can be time-scaled (titles, generators, etc.) ↓
		set theFullPathObjC to createDefinitionFilesForTimescaleableElements(thePath)
	else
		
		-- ↓ within this conditional is transistions b/c they cannot be time-scaled ↓
		set theNameLocation to createDefinitionFileForSimpleElement(theKey, thePath, theFCPXobject)
		set theFullPathObjC to createDefinitionFileForSimpleElement(theKey, thePath, theFCPXobject)
	end if
	-- ↓ creates a separate file using original input from the first handler. This will be used in the simple element script ↓
	its createDefaultDurationElement(theFullPathObjC, theFCPXobject)
	
end createClipboardDefinitionFiles:

####################################################################



############################ Get FCPX Items From Clipboard ############################

on getFCPXitemsFromClipboard()
	tell application "Final Cut Pro"
		activate
	end tell
	delay 0.5
	tell application "System Events"
		key code 19 using command down -- selects the timeline
		delay 0.5
		keystroke "c" using command down
	end tell
	delay 0.5
	set theNSPasteboard to current application's NSPasteboard's generalPasteboard() -- get all clipboard data
	if (theNSPasteboard's canReadItemWithDataConformingToTypes:{"com.apple.flexo.proFFPasteboardUTI"}) as boolean then -- is there FCPX data?
		set theFCPXobject to theNSPasteboard's propertyListForType:"com.apple.flexo.proFFPasteboardUTI" -- the FCPX type
		set thePlist to current application's NSDictionary's dictionaryWithDictionary:theFCPXobject -- read it as a property list
		set theObj to thePlist's objectForKey:"ffpasteboardobject" -- this is a NSArchive object
		set {theDict, theError} to current application's NSPropertyListSerialization's propertyListWithData:theObj options:0 format:(missing value) |error|:(reference) -- unarchive it
		if theDict = missing value then
			error (theError's localizedDescription() as text) -- tell it to display error if one is present
		end if
		set theKey to theDict's objectForKey:"$objects" -- this key contains all the timecode values
	else
		set theKey to missing value
	end if
	if theKey = missing value then
		display dialog "FCPX Clipboard Data is not present"
		quit
	end if
	set firstValueIndex to theKey's indexOfObject:"__timelineContainerClip" -- this is the value immediately before the timecode value
	return {theKey, firstValueIndex, theFCPXobject}
end getFCPXitemsFromClipboard

############################ Create definition files for timescalable FCPX elements ############################

on createDefinitionFilesForTimescaleableElements(thePath)
	
	-- ↓ This will create several FCPX element files in a user-specified folder. Each file is timescaleable within a specified time-range ↓
	set {theCtrRecord, theOutputFilePath, theDirectory} to createMultibleDefinitionFiles(thePath)
	
	-- ↓ This file tells the implementation script where the placeholder timecodes are located within each corresponding element file ↓
	set theTCLocationDictionaryObjC to current application's NSDictionary's dictionaryWithDictionary:theCtrRecord
	set theOutputFilePathObjC to current application's NSString's stringWithString:theOutputFilePath
	theTCLocationDictionaryObjC's writeToFile:theOutputFilePathObjC atomically:true
	return theDirectory
end createDefinitionFilesForTimescaleableElements



on createMultibleDefinitionFiles(thePath)
	set TimeCodeArray to theTCarray()
	repeat with x from 1 to count of TimeCodeArray
		
		
		tell application "Final Cut Pro"
			activate
		end tell
		
		tell application "System Events"
			key code 19 using command down -- selects the timeline
			delay 0.1
			keystroke "d" using control down
			delay 0.1
			set FirstKeyCode to item 4 of (item x of TimeCodeArray)
			key code FirstKeyCode
			if 4 < x then
				set SecondKeyCode to item 5 of (item x of TimeCodeArray)
				key code SecondKeyCode
			end if
			delay 0.1
			if 8 < x then
				set ThirdKeyCode to item 6 of (item x of TimeCodeArray)
				key code ThirdKeyCode
			end if
			delay 0.1
			if 10 < x then
				set FourthKeyCode to item 7 of (item x of TimeCodeArray)
				key code FourthKeyCode
			end if
			delay 0.1
			key code 36
			delay 0.1
			keystroke "c" using command down
			delay 0.1
		end tell
		
		set theNSPasteboard to current application's NSPasteboard's generalPasteboard() -- get all clipboard data
		if (theNSPasteboard's canReadItemWithDataConformingToTypes:{"com.apple.flexo.proFFPasteboardUTI"}) as boolean then -- is there FCPX data?
			set theFCPXobject to (theNSPasteboard's propertyListForType:"com.apple.flexo.proFFPasteboardUTI") -- the FCPX type
			set thePlist to (current application's NSDictionary's dictionaryWithDictionary:theFCPXobject) -- read it as a property list
			set theObj to (thePlist's objectForKey:"ffpasteboardobject") -- this is a NSArchive object
			set {theDict, theError} to (current application's NSPropertyListSerialization's propertyListWithData:theObj options:0 format:(missing value) |error|:(reference)) -- unarchive it
			if theDict = missing value then
				error (theError's localizedDescription() as text) -- tell it to display error if one is present
			end if
			
			set theKey to (theDict's objectForKey:"$objects") -- this key contains all the timecode values
		else
			set theKey to missing value
		end if
		if theKey = missing value then
			display dialog "FCPX Clipboard Data is not present"
		end if
		current application's NSLog("%@", theKey)
		
		set firstValueIndex to (theKey's indexOfObject:"__timelineContainerClip")
		set theMasterTimeCode to (theKey's objectAtIndex:(firstValueIndex + 1)) -- get timecode value
		set firstTC to (getPlaceholderTCatIndex(firstValueIndex, theMasterTimeCode)) as text
		set tcInSeconds to convertToSeconds(firstTC) -- convert it from a fraction to seconds
		
		
		repeat with TheTCrange in TimeCodeArray
			set inpointInSeconds to item 1 of TheTCrange
			set outpointInSeconds to item 2 of TheTCrange
			set ElementFile to item 3 of TheTCrange
			if inpointInSeconds < tcInSeconds and tcInSeconds < outpointInSeconds then
				set theElementFile to ElementFile & ".plist"
				exit repeat
			end if
		end repeat
		
		set theFirstTClocation to (firstValueIndex + 1) as integer
		
		set TCin120000ths to (convertFraction(firstTC, 120000) as text)
		
		
		
		
		set ASkey to theKey as list
		
		set theFirstTC to (item (theFirstTClocation + 1) of ASkey) as text
		
		repeat with i from (theFirstTClocation + 3) to count of ASkey
			if (item i of ASkey) contains TCin120000ths then
				set theSecondTClocation to (i - 1)
				exit repeat
			end if
		end repeat
		
		set theSecondTC to (item (theSecondTClocation + 1) of ASkey) as text
		
		repeat with i from (theSecondTClocation + 3) to count of ASkey
			if (item i of ASkey) contains TCin120000ths then
				set theThirdTClocation to (i - 1)
				exit repeat
			end if
		end repeat
		
		set theThirdTC to (item (theThirdTClocation + 1) of ASkey) as text
		
		repeat with i from 1 to count of ASkey
			if (item i of ASkey) contains ".localized" then
				set theNameLocation to (i - 1)
				exit repeat
			end if
		end repeat
		
		set theobjectPath to (theKey's objectAtIndex:theNameLocation)
		set theobjectFile to theobjectPath's lastPathComponent()
		set thisObjectName to (theobjectFile's stringByReplacingOccurrencesOfString:".moti" withString:"")
		set thisObjectName to (thisObjectName's stringByReplacingOccurrencesOfString:".motr" withString:"")
		set thisObjectName to (thisObjectName's stringByReplacingOccurrencesOfString:".motn" withString:"")
		set pathWithTild to (current application's NSString's stringWithString:thePath)
		set extendedPath to (current application's NSString's stringWithString:theElementFile)
		set fullPath to pathWithTild's stringByExpandingTildeInPath()
		set theDirectory to (fullPath's stringByAppendingPathComponent:thisObjectName)
		set fileManager to current application's NSFileManager's defaultManager()
		if (fileManager's fileExistsAtPath:theDirectory) as boolean then
			set goodToGo to missing value
		else
			(fileManager's createDirectoryAtPath:theDirectory withIntermediateDirectories:true attributes:(missing value) |error|:(missing value))
		end if
		set theOutputFile to (theDirectory's stringByAppendingPathComponent:extendedPath)
		(theFCPXobject's writeToFile:theOutputFile atomically:true) -- write it to the appropriate folder
		
		
		### WRITE PLIST CONTROL FILE ###
		-- set labelList to {item 3 of (item x of TimeCodeArray)}
		
		if x = 1 then
			set ValueLabel to {|6 Frames|:{|1st TC in 30000ths of a second|:theFirstTClocation, |The first TC value|:theFirstTC, |2nd TC in 120000ths of a second|:theSecondTClocation, |The second TC value|:theSecondTC, |3rd TC in 120000ths of a second|:theThirdTClocation, |The third TC value|:theThirdTC, |The name location|:theNameLocation}}
		end if
		if x = 2 then
			set ValueLabel to {|7 Frames|:{|1st TC in 30000ths of a second|:theFirstTClocation, |The first TC value|:theFirstTC, |2nd TC in 120000ths of a second|:theSecondTClocation, |The second TC value|:theSecondTC, |3rd TC in 120000ths of a second|:theThirdTClocation, |The third TC value|:theThirdTC, |The name location|:theNameLocation}}
		end if
		if x = 3 then
			set ValueLabel to {|8 Frames|:{|1st TC in 30000ths of a second|:theFirstTClocation, |The first TC value|:theFirstTC, |2nd TC in 120000ths of a second|:theSecondTClocation, |The second TC value|:theSecondTC, |3rd TC in 120000ths of a second|:theThirdTClocation, |The third TC value|:theThirdTC, |The name location|:theNameLocation}}
		end if
		if x = 4 then
			set ValueLabel to {|9 Frames|:{|1st TC in 30000ths of a second|:theFirstTClocation, |The first TC value|:theFirstTC, |2nd TC in 120000ths of a second|:theSecondTClocation, |The second TC value|:theSecondTC, |3rd TC in 120000ths of a second|:theThirdTClocation, |The third TC value|:theThirdTC, |The name location|:theNameLocation}}
		end if
		if x = 5 then
			set ValueLabel to {|10 Frames|:{|1st TC in 30000ths of a second|:theFirstTClocation, |The first TC value|:theFirstTC, |2nd TC in 120000ths of a second|:theSecondTClocation, |The second TC value|:theSecondTC, |3rd TC in 120000ths of a second|:theThirdTClocation, |The third TC value|:theThirdTC, |The name location|:theNameLocation}}
		end if
		if x = 6 then
			set ValueLabel to {|11 thru 24 Frames|:{|1st TC in 30000ths of a second|:theFirstTClocation, |The first TC value|:theFirstTC, |2nd TC in 120000ths of a second|:theSecondTClocation, |The second TC value|:theSecondTC, |3rd TC in 120000ths of a second|:theThirdTClocation, |The third TC value|:theThirdTC, |The name location|:theNameLocation}}
		end if
		if x = 7 then
			set ValueLabel to {|25 Thru 99 Frames|:{|1st TC in 30000ths of a second|:theFirstTClocation, |The first TC value|:theFirstTC, |2nd TC in 120000ths of a second|:theSecondTClocation, |The second TC value|:theSecondTC, |3rd TC in 120000ths of a second|:theThirdTClocation, |The third TC value|:theThirdTC, |The name location|:theNameLocation}}
		end if
		if x = 8 then
			set ValueLabel to {|100 Thru 249 Frames|:{|1st TC in 30000ths of a second|:theFirstTClocation, |The first TC value|:theFirstTC, |2nd TC in 120000ths of a second|:theSecondTClocation, |The second TC value|:theSecondTC, |3rd TC in 120000ths of a second|:theThirdTClocation, |The third TC value|:theThirdTC, |The name location|:theNameLocation}}
		end if
		if x = 9 then
			set ValueLabel to {|250 Thru 999 Frames|:{|1st TC in 30000ths of a second|:theFirstTClocation, |The first TC value|:theFirstTC, |2nd TC in 120000ths of a second|:theSecondTClocation, |The second TC value|:theSecondTC, |3rd TC in 120000ths of a second|:theThirdTClocation, |The third TC value|:theThirdTC, |The name location|:theNameLocation}}
		end if
		if x = 10 then
			set ValueLabel to {|1000 Thru 2497 Frames|:{|1st TC in 30000ths of a second|:theFirstTClocation, |The first TC value|:theFirstTC, |2nd TC in 120000ths of a second|:theSecondTClocation, |The second TC value|:theSecondTC, |3rd TC in 120000ths of a second|:theThirdTClocation, |The third TC value|:theThirdTC, |The name location|:theNameLocation}}
		end if
		if x = 11 then
			set ValueLabel to {|2498 Thru 299700 Frames|:{|1st TC in 30000ths of a second|:theFirstTClocation, |The first TC value|:theFirstTC, |2nd TC in 120000ths of a second|:theSecondTClocation, |The second TC value|:theSecondTC, |3rd TC in 120000ths of a second|:theThirdTClocation, |The third TC value|:theThirdTC, |The name location|:theNameLocation}}
		end if
		if x = 1 then
			set theMasterArray to ValueLabel
		end if
		
		if x > 1 then
			set theMasterArray to theMasterArray & ValueLabel
		end if
		
		if x = 11 then -- once all elements are added to the record, output to plist file
			set thisObjectName to thisObjectName as text
			set thisObjectName to thisObjectName & " - TC Location Dictionary.plist"
			set thisObjectName to (current application's NSString's stringWithString:thisObjectName)
			set theOutputFilePath to (theDirectory's stringByAppendingPathComponent:thisObjectName)
			set theOutputFilePath to theOutputFilePath as text
		end if
	end repeat
	return {theMasterArray, theOutputFilePath, theDirectory}
end createMultibleDefinitionFiles

on theTCarray()
	set TimeCodeArray to ¬
		{{0.1, 0.232566666666, "6 Frames", 22}, ¬
			{0.233566666666, 0.265933333332, "7 Frames", 26}, ¬
			{0.266933333332, 0.266933333334, "8 Frames", 28}, ¬
			{0.3002, 0.3004, "9 Frames", 25}, ¬
			{0.333666666666, 0.333666666669, "10 Frames", 18, 29}, ¬
			{0.333666666668, 0.82, "11 Thru 24 Frames", 18, 23}, ¬
			{0.834166666666, 3.3034, "25 Thru 99 Frames", 19, 47}, ¬
			{3.3033, 8.3083, "100 Thru 249 Frames", 23, 47}, ¬
			{8.3083, 33.3333, "250 Thru 999 Frames", 19, 29, 47}, ¬
			{33.3333, 83.316566666667, "1000 Thru 2497 Frames", 23, 29, 47}, ¬
			{83.316566666667, 10000, "2498 Thru 299700 Frames", 18, 20, 29, 47}} -- each of these range in time require that a separate file be placed on the clipboard
	(* As you can see the above array increases in a exponential manner. The last value is incorect b/c the upper range is too high. One could add to the array for greater durations. *)
	return TimeCodeArray
end theTCarray

on getPlaceholderTCatIndex(theTClocation, thisObject)
	set theCharacterSet to current application's NSCharacterSet's characterSetWithCharactersInString:"(){}"
	set theObjectDelimitedByPunctuation to thisObject's componentsSeparatedByCharactersInSet:theCharacterSet
	set theMutableObjectDelimitedByPunctuation to current application's NSMutableArray's arrayWithArray:theObjectDelimitedByPunctuation
	theMutableObjectDelimitedByPunctuation's removeObjectIdenticalTo:""
	theMutableObjectDelimitedByPunctuation's removeObjectIdenticalTo:","
	set thePlaceholderTC to theMutableObjectDelimitedByPunctuation's lastObject()
	return thePlaceholderTC
end getPlaceholderTCatIndex

on convertToSeconds(theTC)
	set THEslash to the offset of "/" in theTC
	set numeratorEND to THEslash - 1
	set denominatorSTART to THEslash + 1
	set the_numerator to text 1 thru numeratorEND of theTC as integer
	set fraction_length to length of theTC
	set fraction_length to fraction_length
	set the_denominator to text denominatorSTART thru fraction_length of theTC as integer
	set decimal_number to (the_numerator / the_denominator)
end convertToSeconds

on convertFraction(theFraction, newDenominator)
	set theFraction to current application's NSString's stringWithString:theFraction
	set theCharacterSet to current application's NSCharacterSet's characterSetWithCharactersInString:"/"
	set theNumeratorAndDenominatorArray to theFraction's componentsSeparatedByCharactersInSet:theCharacterSet
	set theNumerator to theNumeratorAndDenominatorArray's firstObject()
	set theDenominator to theNumeratorAndDenominatorArray's lastObject()
	set newNumber to ((((theNumerator as text) as integer) / ((theDenominator as text) as integer)) * newDenominator)
	set theFormatter to current application's NSNumberFormatter's new()
	theFormatter's setNumberStyle:(current application's NSNumberFormatterNoStyle)
	set theResult to theFormatter's stringFromNumber:newNumber
	set theResult to current application's NSString's stringWithFormat_("%@/%@", theResult, newDenominator)
	return theResult
end convertFraction

############################ Create definition file for simple, non-timescaleable FCPX elements (i.e. transisitons) ############################

on createDefinitionFileForSimpleElement(theKey, thePath, theFCPXobject)
	set ASkey to theKey as list
	repeat with i from 1 to count of ASkey
		if (item i of ASkey) contains ".localized" then
			set theNameLocation to i
		else
			set theNameLocation to missing value
		end if
	end repeat
	if theNameLocation = missing value then
		set theNameLocation to 5
	end if
	set theobjectPath to theKey's objectAtIndex:(theNameLocation - 1) -- get the item containing the name of the object
	set theobjectFile to theobjectPath's lastPathComponent() -- use only the last part of the path
	set thisObjectName to theobjectFile's stringByReplacingOccurrencesOfString:".moti" withString:"" -- remove the extentions
	set thisObjectName to thisObjectName's stringByReplacingOccurrencesOfString:".motr" withString:""
	set thisObjectName to thisObjectName's stringByReplacingOccurrencesOfString:".motn" withString:""
	set pathWithTild to current application's NSString's stringWithString:thePath -- bring in our application support directory
	set fullPath to pathWithTild's stringByExpandingTildeInPath() -- expand the tild
	set theFullPath to fullPath's stringByAppendingPathComponent:thisObjectName -- create a filepath including a folder named after the object
	set fileManager to current application's NSFileManager's defaultManager()
	if (fileManager's fileExistsAtPath:theFullPath) as boolean then -- look to see if the folder already exists
		set goodToGo to missing value
	else
		fileManager's createDirectoryAtPath:theFullPath withIntermediateDirectories:false attributes:(missing value) |error|:(missing value) -- if not create one
	end if
	set plistName to current application's NSString's stringWithString:"Default duration.plist"
	set theFullPath to theFullPath's stringByAppendingPathComponent:plistName -- append the name of the object to the end of our path
	theFCPXobject's writeToFile:theFullPath atomically:true -- write it to the appropriate folder
	return theFullPath
end createDefinitionFileForSimpleElement



on createDefaultDurationElement(theFullPath, theFCPXobject)
	set plistName to current application's NSString's stringWithString:"Default duration.plist"
	set theFullPath to theFullPath's stringByAppendingPathComponent:plistName -- append the name of the object to the end of our path
	theFCPXobject's writeToFile:theFullPath atomically:true -- write it to the appropriate folder
end createDefaultDurationElement

Script Bundle 2 of 3: A script for placing simple (non-time scaled) elements on the timeline

use framework "Foundation"
use framework "AppKit"
use scripting additions


on implementSimpleElement:thePath
	set thePathObjC to expandTild(thePath)
	set theFullPathToFileObjC to thePathObjC's stringByAppendingPathComponent:"Default duration.plist"
	set OBJcDict to current application's NSDictionary's dictionaryWithContentsOfFile:theFullPathToFileObjC
	set theNSPasteboard to current application's NSPasteboard's generalPasteboard()
	theNSPasteboard's clearContents()
	theNSPasteboard's setPropertyList:OBJcDict forType:"com.apple.flexo.proFFPasteboardUTI"
	theNSPasteboard's writeObjects:OBJcDict
	tell application "Final Cut Pro"
		activate
	end tell
	tell application "System Events"
		key code 19 using command down -- select the timeline
		delay 0.1
		keystroke "v" using command down
	end tell
end implementSimpleElement:


on expandTild(thePathWithTild)
	set pathWithTild to current application's NSString's stringWithString:thePathWithTild -- bring in our application support directory
	set fullPathObjC to pathWithTild's stringByExpandingTildeInPath() -- expand the tild
	return fullPathObjC
end expandTild

Script Bundle 3 of 3: A script for placing time-scaled elements on the time-line

use framework "Foundation"
use framework "AppKit"
use scripting additions



############################ (primary function) ############################

on implementTimeScaledElement:thePath
	
	-- ↓ copy FCPX element to clipboard, read it as a clipboard item, and unpack the plist ↓
	set theKeyFromPbObjC to getFCPXitemsFromClipboard()
	
	-- ↓ read the timecode (TC) that is embeded in the plist ↓
	set {theTCinSeconds, theTCFraction} to readFCPXtcFromKey(theKeyFromPbObjC)
	
	-- ↓ Return the appropriate, time-scaleable FCPX element (another plist) for further processing ↓ 
	set {theElementKeyObjC, theElementTCName, thePathObjC, theUnmodifiedffpasteboardobject} to findTheCorrectTimeScalableFileFromElementFolder(theTCinSeconds, thePath, theTCFraction)
	
	-- ↓ Overwrite the TC values using the TC from the clipboard item ↓
	set theElementWithModifiedTC to modifyTheTCvaluesWithinTheElement(theElementKeyObjC, theElementTCName, thePathObjC, theTCFraction)
	
	-- ↓ write the modified FCPX element to the clipboard and paste it onto the timeline ↓
	its writeElementWithModifiedTCtoClipboardAndPasteIntoFCPX(theElementWithModifiedTC, theUnmodifiedffpasteboardobject)
	
end implementTimeScaledElement:

####################################################################



############################ Get FCPX Items From Clipboard ############################

on getFCPXitemsFromClipboard()
	set theNSPasteboard to current application's NSPasteboard's generalPasteboard()
	theNSPasteboard's clearContents()
	delay 0.05
	tell application "Final Cut Pro"
		activate
	end tell
	tell application "System Events"
		key code 19 using command down -- selects the timeline
		delay 0.1
		keystroke "c" using command down
	end tell
	repeat -- grab the FCPX data from the clipboard as soon as it become available
		if (theNSPasteboard's canReadItemWithDataConformingToTypes:{"com.apple.flexo.proFFPasteboardUTI"}) as boolean then 
			exit repeat
		end if
	end repeat
	set theFCPXobject to theNSPasteboard's propertyListForType:"com.apple.flexo.proFFPasteboardUTI" -- the FCPX type
	set thePlist to current application's NSDictionary's dictionaryWithDictionary:theFCPXobject -- read it as a property list
	set theObj to thePlist's objectForKey:"ffpasteboardobject" -- this is a NSArchive object
	set {theDict, theError} to current application's NSPropertyListSerialization's propertyListWithData:theObj options:0 format:(missing value) |error|:(reference) -- unarchive it
	if theDict = missing value then
		error (theError's localizedDescription() as text) -- tell it to display error if one is present
	end if
	
	set theKeyFromPbObjC to theDict's objectForKey:"$objects" -- this array contains all the timecode values	
	return theKeyFromPbObjC
end getFCPXitemsFromClipboard

############################ Read the timecode from the FCPX clipboard item ############################

on readFCPXtcFromKey(theKey)
	set firstValueIndex to theKey's indexOfObject:"__timelineContainerClip" -- this is the value immediately before the timecode value
	if firstValueIndex = current application's NSNotFound then
		display dialog "The timecode cannot be read from this item"
		return 0
	else
		set theMasterTimeCode to (theKey's objectAtIndex:(firstValueIndex + 1)) -- get timecode value
		set firstValueIndex to (firstValueIndex + 1)
		set firstTC to (getPlaceholderTCatIndex(firstValueIndex, theMasterTimeCode)) as text
		set tcInSeconds to convertToSeconds(firstTC) -- convert it from a fraction to seconds
		return {tcInSeconds, firstTC}
	end if
end readFCPXtcFromKey

on convertToSeconds(theTC)
	set THEslash to the offset of "/" in theTC
	set numeratorEND to THEslash - 1
	set denominatorSTART to THEslash + 1
	set the_numerator to text 1 thru numeratorEND of theTC as integer
	set fraction_length to length of theTC
	set fraction_length to fraction_length
	set the_denominator to text denominatorSTART thru fraction_length of theTC as integer
	set decimal_number to (the_numerator / the_denominator)
end convertToSeconds

############################ (shared function) ############################

on getPlaceholderTCatIndex(theTClocation, thisObject)
	set theCharacterSet to current application's NSCharacterSet's characterSetWithCharactersInString:"(){}"
	set theObjectDelimitedByPunctuation to thisObject's componentsSeparatedByCharactersInSet:theCharacterSet
	set theMutableObjectDelimitedByPunctuation to current application's NSMutableArray's arrayWithArray:theObjectDelimitedByPunctuation
	theMutableObjectDelimitedByPunctuation's removeObjectIdenticalTo:""
	theMutableObjectDelimitedByPunctuation's removeObjectIdenticalTo:","
	set thePlaceholderTC to theMutableObjectDelimitedByPunctuation's lastObject()
	return thePlaceholderTC
end getPlaceholderTCatIndex

############################ Return a suitable time-scaleable FCPX element ############################

on findTheCorrectTimeScalableFileFromElementFolder(theTCinSeconds, thePath)
	set timeCodeArray to theTCarray()
	repeat with TheTCrange in timeCodeArray
		set inpointInSeconds to item 1 of TheTCrange
		set outpointInSeconds to item 2 of TheTCrange
		set theElementTCName to item 3 of TheTCrange
		if inpointInSeconds < theTCinSeconds and theTCinSeconds < outpointInSeconds then
			set theElementFile to theElementTCName & ".plist"
			exit repeat
		end if
	end repeat
	set theElementFile to current application's NSString's stringWithString:theElementFile
	set thePathObjC to expandTild(thePath)
	set theFullPathToFile to thePathObjC's stringByAppendingPathComponent:theElementFile
	set thePlistObjC to current application's NSDictionary's dictionaryWithContentsOfFile:theFullPathToFile
	set {theKeyFromFileObjC, theObj} to getFCPXclipboardItemFromFile(thePlistObjC)
	return {theKeyFromFileObjC, theElementTCName, thePathObjC, theObj}
end findTheCorrectTimeScalableFileFromElementFolder

on theTCarray()
	set timeCodeArray to ¬
		{{0.1, 0.232566666666, "6 Frames", 22}, ¬
			{0.233566666666, 0.265933333332, "7 Frames", 26}, ¬
			{0.266933333332, 0.266933333334, "8 Frames", 28}, ¬
			{0.3002, 0.3004, "9 Frames", 25}, ¬
			{0.333666666666, 0.333666666669, "10 Frames", 18, 29}, ¬
			{0.333666666668, 0.82, "11 Thru 24 Frames", 18, 23}, ¬
			{0.834166666666, 3.3034, "25 Thru 99 Frames", 19, 47}, ¬
			{3.3033, 8.3083, "100 Thru 249 Frames", 23, 47}, ¬
			{8.3083, 33.3333, "250 Thru 999 Frames", 19, 29, 47}, ¬
			{33.3333, 83.316566666667, "1000 Thru 2497 Frames", 23, 29, 47}, ¬
			{83.316566666667, 10000, "2498 Thru 299700 Frames", 18, 20, 29, 47}} -- each of these range in time require that a separate file be placed on the clipboard
	(* As you can see the above array increases in a exponential manner. The last value is incorect b/c the upper range is too high. One could add to the array for greater durations. *)
	return timeCodeArray
end theTCarray

on getFCPXclipboardItemFromFile(thePlist)
	set theObj to thePlist's objectForKey:"ffpasteboardobject"
	set {theDict, theError} to current application's NSPropertyListSerialization's propertyListWithData:theObj options:0 format:(missing value) |error|:(reference)
	if theDict = missing value then
		error (theError's localizedDescription() as text)
	end if
	set theKeyObjC to theDict's valueForKey:"$objects"
	return {theKeyObjC, theDict}
end getFCPXclipboardItemFromFile

############################ (shared function) ############################

on expandTild(thePathWithTild)
	set pathWithTild to current application's NSString's stringWithString:thePathWithTild -- bring in our application support directory
	set fullPathObjC to pathWithTild's stringByExpandingTildeInPath() -- expand the tild
	return fullPathObjC
end expandTild

############################ Modify the FCPX element's timecode ############################

on modifyTheTCvaluesWithinTheElement(theElementKeyObjC, theElementTCName, thePathObjC, theTCFraction)
	set theSecondPlaceholderObjectObjC to theElementKeyObjC's objectAtIndex:10
	set theThirdPlaceholderObjectObjC to theElementKeyObjC's objectAtIndex:23
	set theSecondPlaceholderTCobjC to getPlaceholderTC(theSecondPlaceholderObjectObjC)
	set theThirdPlaceholderTCobjC to getPlaceholderTC(theThirdPlaceholderObjectObjC)
	set theFirstTimeScaledObject to current application's NSString's stringWithFormat_("{(0/1),(%@)}", theTCFraction)
	set theSecondTimeScaledObject to current application's NSString's stringWithFormat_("{(%@),(%@)}", theSecondPlaceholderTCobjC, theTCFraction)
	set theThirdTimeScaledObject to current application's NSString's stringWithFormat_("{(%@),(%@)}", theThirdPlaceholderTCobjC, theTCFraction)
	set theElementMutableKeyObjC to current application's NSMutableArray's arrayWithArray:theElementKeyObjC -- Convert the generic element to a mutable element
	theElementMutableKeyObjC's replaceObjectAtIndex:5 withObject:theFirstTimeScaledObject -- Replace all the TC objects with the new ones
	theElementMutableKeyObjC's replaceObjectAtIndex:10 withObject:theSecondTimeScaledObject
	theElementMutableKeyObjC's replaceObjectAtIndex:23 withObject:theThirdTimeScaledObject
	return theElementMutableKeyObjC -- return the object with modified TCs
end modifyTheTCvaluesWithinTheElement

on getPlaceholderTC(thisObject)
	set theCharacterSet to current application's NSCharacterSet's characterSetWithCharactersInString:"(){}"
	set theObjectDelimitedByPunctuation to thisObject's componentsSeparatedByCharactersInSet:theCharacterSet
	set theMutableObjectDelimitedByPunctuation to current application's NSMutableArray's arrayWithArray:theObjectDelimitedByPunctuation
	theMutableObjectDelimitedByPunctuation's removeObjectIdenticalTo:""
	theMutableObjectDelimitedByPunctuation's removeObjectIdenticalTo:","
	set thePlaceholderTC to theMutableObjectDelimitedByPunctuation's firstObject()
	return thePlaceholderTC
end getPlaceholderTC

on convertFraction(theFraction, newDenominator)
	set theFraction to current application's NSString's stringWithString:theFraction
	set theCharacterSet to current application's NSCharacterSet's characterSetWithCharactersInString:"/"
	set theNumeratorAndDenominatorArray to theFraction's componentsSeparatedByCharactersInSet:theCharacterSet
	set theNumerator to theNumeratorAndDenominatorArray's firstObject()
	set theDenominator to theNumeratorAndDenominatorArray's lastObject()
	set newNumber to ((((theNumerator as text) as integer) / ((theDenominator as text) as integer)) * newDenominator)
	set theFormatter to current application's NSNumberFormatter's new()
	theFormatter's setNumberStyle:(current application's NSNumberFormatterNoStyle)
	set theResult to theFormatter's stringFromNumber:newNumber
	set theResult to current application's NSString's stringWithFormat_("%@/%@", theResult, newDenominator)
	return theResult
end convertFraction

############################ Write the modifed FCPX element back to the clipboard & paste it onto the timeline ############################

on writeElementWithModifiedTCtoClipboardAndPasteIntoFCPX(theElementWithModifiedTC, theUnmodifiedffpasteboardobject)
	set |$versionValue| to theUnmodifiedffpasteboardobject's valueForKey:"$version"
	set |$archiverValue| to theUnmodifiedffpasteboardobject's valueForKey:"$archiver"
	set |$topValue| to theUnmodifiedffpasteboardobject's valueForKey:"$top"
	set newSubRecord to {|$version|:|$versionValue|, |$objects|:theElementWithModifiedTC, |$archiver|:|$archiverValue|, |$top|:|$topValue|}
	set newSubRecordObjC to current application's NSDictionary's dictionaryWithDictionary:newSubRecord
	set {theData, theError} to current application's NSPropertyListSerialization's dataWithPropertyList:newSubRecordObjC format:(current application's NSPropertyListBinaryFormat_v1_0) options:0 |error|:(reference)
	if theData = missing value then
		error (theError's localizedDescription() as text)
	end if
	set newRecord to {ffpasteboardcopiedtypes:{pb_anchoredObject:{|count|:1}}} & {ffpasteboardobject:theData} & {kffmodelobjectIDs:{}}
	set OBJcDict to current application's NSDictionary's dictionaryWithDictionary:newRecord
	set theNSPasteboard to current application's NSPasteboard's generalPasteboard()
	theNSPasteboard's clearContents()
	theNSPasteboard's setPropertyList:OBJcDict forType:"com.apple.flexo.proFFPasteboardUTI"
	theNSPasteboard's writeObjects:OBJcDict
	tell application "Final Cut Pro"
		activate
	end tell
	tell application "System Events"
		key code 19 using command down
		delay 0.1
		keystroke "v" using command down
		delay 0.5
	end tell
	
	
end writeElementWithModifiedTCtoClipboardAndPasteIntoFCPX

AMAZING. Thank you for sharing!