Script 3 of 4. Annotations to movie credits

My problem: I have a growing collection of videos that I’ve acquired over the years. My problem is that I have so many now that it’s difficult to remember what they all are, what they’re about, who is in each etc.

The solution: I developed a workflow of 4 applescripts to accomplish my task. The workflow ultimately places the information about each video in the video file, such that I can open a video and instantly see the data or use Spotlight to search on the data. A more detailed explanation of what each script does is explained inside each applescript.

This is script 3 of 4. Annotations to movie credits:
This script works on a folder full of videos which have their annotations set using script 2. It creates a text track from the annotations, adds the text track to the video, and places the text track at the beginning of the video. This one is really cool. It is also nondestructive to the video.

The 4 scripts are here:
http://bbs.applescript.net/viewtopic.php?pid=82570#p82570
http://bbs.applescript.net/viewtopic.php?pid=82571#p82571
http://bbs.applescript.net/viewtopic.php?pid=82572#p82572
http://bbs.applescript.net/viewtopic.php?pid=82573#p82573

(* This script works on a folder full of video files that have information in their annotations. The purpose is to add some descriptive text to the beginning of the movie. It is designed to work with my "imdb to annotations" script which adds movie data from the imdb database to the annoations of a movie. This script uses those annotations to create the text for the movie. The text is added as a text track (called Opening Credits Track) to the movie and is presented as rolling credits in the beginning of the movie. The default is set such that the text will overlay the opening seconds of the movie. *)

(* Note: Set the property "credits_overlay" to false if you want the rolling credits placed before the movie instead of over the beginning of the movie. *)
(* Note: this is a non-destructive technique. It does not write over any part of the movie. To undo the rolling credits simply disable or delete the "Opening Credits Track" from the movie. *)

property credits_overlay : true -- true means credits overlay the movie, false places them before movie

-- this is a list of annotations, ordered in the order they are displayed on screen
-- note the format: a list of lists. Each list contains the official annotation name. Some of them contain a second name. This second name is the name of the credit when it is displayed on screen, in other words the second word in the list takes the place of the first word when displayed on screen. If there isn't a second name then the annotation name is displayed as is.
set ann_order to {{"Full Name", "Title"}, {"Copyright", "Release Date"}, {"Special Playback Requirements", "MPAA Rating"}, {"Warning", "User Rating"}, {"Description"}, {"Performers", "Actors"}, {"Genre"}}

property title_font : "Baskerville"
property title_style : "{bold}{italic}{dropShadow: on}{dropShadowOffset: 3, 4}"
property title_minSize : 10

property annName_font : "Geneva"
property annName_style : "{italic}"
property annName_font_minSize : 8
property annValue_font : "Geneva"
property annValue_style : "{plain}"
property annValue_font_minSize : 10

property end_duration : 0.5 -- in seconds, the amount of time before the movie starts after the credits end

-- choose the source folder and get all of its files
set source_folder to choose folder with prompt "Choose the folder of movie files:"
set source_folder to source_folder as string
tell application "Finder" to set source_movies to every file of folder source_folder

tell application "QuickTime Player"
	launch
	my supressAutoPlay(true) -- make sure movies set to auto play do not do that
	repeat with i from 1 to count of source_movies
		set aMovie to item i of source_movies as string
		try
			open aMovie
			rewind
			select none
			if saveable of movie 1 is true then
				if not (exists track "Opening Credits Track" of movie 1) then
					set movie_name to name of front movie
					set movie_path to original file of movie movie_name
					
					set nmExt to my getName_andExtension(movie_path)
					set movie_title to item 1 of nmExt
					
					tell movie movie_name
						set time_scale to time scale
						copy natural dimensions to {movie_width, movie_height}
					end tell
					
					-- get the movie annotations
					set all_anns to my get_allAnns(movie_name)
					
					-- order the annotations so the credits appear properly and make sure that a title appears in the list
					set ordered_credits to my orderCredits(ann_order, all_anns)
					if item 1 of (item 1 of ordered_credits) is not "Title" then
						set beginning of ordered_credits to {"Title", movie_title}
					end if
					
					-- setup the header text for the credits file
					set the credits_text to ""
					set the credits_text to the the credits_text & "{QTtext}" & return
					set the credits_text to the the credits_text & "{font:Geneva}"
					set the credits_text to the the credits_text & "{plain}"
					set the credits_text to the the credits_text & "{size:16}" & return
					if credits_overlay then
						set the credits_text to the the credits_text & "{textColor: 65535, 65535, 65535}" & return
						set the credits_text to the the credits_text & "{backColor: 0, 0, 0}" & return
					else
						set the credits_text to the the credits_text & "{textColor: 0, 0, 0}" & return
						set the credits_text to the the credits_text & "{backColor: 44461,52428,44204}" & return
					end if
					set the credits_text to the the credits_text & "{anti-alias:on}" & return
					set the credits_text to the the credits_text & "{justify:center}" & return
					set the credits_text to the the credits_text & "{timeScale:" & time_scale & "}" & return
					set the credits_text to the the credits_text & "{width:" & (movie_width as string) & "}" & return
					set the credits_text to the the credits_text & "{height:" & (movie_height as string) & "}" & return
					set the credits_text to the the credits_text & "{timeStamps:relative}" & return
					set the credits_text to the the credits_text & "{language:0}" & return
					set the credits_text to the the credits_text & "{textEncoding:0}" & return
					set the credits_text to the the credits_text & "{scrollIn:off}" & return
					set the credits_text to the the credits_text & "{scrollOut:off}" & return
					if credits_overlay then
						set the credits_text to the the credits_text & "{keyedText:on}" & return & return
					else
						set the credits_text to the the credits_text & "{keyedText:off}" & return & return
					end if
					set the credits_text to the the credits_text & "[00:00:00.000]" & return
					
					-- calculate text sizes and other info for the credits
					set title_size to movie_width div 12
					if title_size is less than title_minSize then set title_size to title_minSize
					
					set spacer_size to movie_width div 68
					if spacer_size is greater than 12 then set spacer_size to 12
					set spacer_line to "{font:" & annName_font & "}{plain}{size:" & spacer_size & "} " & return
					
					set annName_size to movie_width div 34
					if annName_size is less than annName_font_minSize then set annName_size to annName_font_minSize
					
					set annValue_size to movie_width div 22
					if annValue_size is less than annValue_font_minSize then set annValue_size to annValue_font_minSize
					
					set title_duration to 4
					set title_timecode to my time2timecode((title_duration * time_scale), time_scale)
					
					set credits_duration to ((count of ordered_credits) - 2) * 3
					set credits_timecode to my time2timecode((credits_duration * time_scale), time_scale)
					
					-- add the ordered credits to the text file
					repeat with i from 1 to (count of ordered_credits)
						if i is 1 then
							-- remove the year from the title of the movie if it has one
							set this_title to (item 2 of (item i of ordered_credits))
							set this_title to my stripYear(this_title)
							set title_credit to "{font:" & title_font & "}{size:" & title_size & "}" & title_style & this_title & return
							set credits_text to credits_text & return & return & return & return & title_credit & spacer_line
							
						else if i is 2 then
							set item_name to (item 1 of (item i of ordered_credits))
							set item_value to (item 2 of (item i of ordered_credits))
							set this_credit to ¬
								"{font:" & annName_font & "}{size:" & annName_size & "}" & annName_style & item_name & return & ¬
								"{font:" & annValue_font & "}{size:" & annValue_size & "}" & annValue_style & item_value & return
							set credits_text to credits_text & this_credit & title_timecode & return & "{dropShadow: off}{scrollIn:on}{scrollOut:on}" & return
							
						else
							set item_name to (item 1 of (item i of ordered_credits))
							set item_value to (item 2 of (item i of ordered_credits))
							if item_name is "Actors" then set item_value to my parseActors(item_value)
							set this_credit to ¬
								"{font:" & annName_font & "}{size:" & annName_size & "}" & annName_style & item_name & return & ¬
								"{font:" & annValue_font & "}{size:" & annValue_size & "}" & annValue_style & item_value & return & return & return
							set credits_text to credits_text & this_credit
						end if
					end repeat
					
					-- set the time code for the credit
					set credits_text to credits_text & credits_timecode & return
					
					-- set the ending line time code
					set end_time to end_duration * time_scale
					set ending_timecode to my time2timecode(end_time, time_scale)
					set end_credit to "{font:" & annName_font & "}{plain}{size:" & annName_size & "} " & return & ending_timecode & return
					set credits_text to credits_text & end_credit
					
					-- write the credits file
					set target_file to ((path to temporary items folder as text) & "CREDITS_TEMP.TXT")
					my writeTo(credits_text, target_file, false, string)
					
					-- open the credits file in quicktime
					set new_movie_status to open movie in new player
					set open movie in new player to true
					open file target_file
					set open movie in new player to new_movie_status
					
					-- insert the credits in the movie as defined by the property credits_overlay
					tell movie 1
						tell track 1 to set name to "Opening Credits Track"
						rewind
						select all
						copy
						select none
						close saving no
					end tell
					
					tell movie movie_name
						select none
						rewind
						if credits_overlay then
							add
						else
							paste
						end if
						select none
						rewind
						select at 0 to 0
					end tell
					
					-- save and close the movie
					close movie 1 saving yes
				else
					close movie 1 saving no
				end if
			else
				display dialog "This movie has previously been set so that it cannot be copied, edited, or saved." & return & return & "Would you like to close this movie and continue processing the rest of the movies or stop the script?" buttons {"Close and Continue", "Stop"} default button 2
				set button_entered to button returned of result
				if button_entered is "Stop" then
					return
				else
					close movie 1 saving no
				end if
			end if
		on error
			tell application "QuickTime Player" to if exists movie 1 then close every movie saving no
			tell application "Finder" to tell file aMovie to set label index to 2
		end try
	end repeat
end tell

(*==================== SUBROUTINES ======================*)
on getName_andExtension(F)
	set F to F as string
	set {name:Nm, name extension:Ex} to info for file F
	if Ex is missing value then set Ex to ""
	if Ex is not "" then
		set Nm to text 1 thru ((count Nm) - (count Ex) - 1) of Nm
		set Ex to "." & Ex
	end if
	return {Nm, Ex}
end getName_andExtension

on supressAutoPlay(status_flag)
	tell application "QuickTime Player"
		set ignore auto play to the status_flag
		set ignore auto present to the status_flag
	end tell
end supressAutoPlay

on get_allAnns(movie_name) -- get all the annotations from the movie
	set all_anns to {}
	tell application "QuickTime Player" to tell movie movie_name
		set annNames to name of annotations
		set annValues to full text of annotations
		repeat with i from 1 to count of annNames
			set end of all_anns to {item i of annNames, item i of annValues}
		end repeat
	end tell
	return all_anns
end get_allAnns

on orderCredits(ann_order, all_anns) -- order the annotations as defined in the script property ann_order
	set ordered_credits to {}
	repeat with i from 1 to count of ann_order
		set this_ann to (item i of ann_order)
		set ann_name to (item 1 of this_ann)
		if (count of this_ann) > 1 then
			set credit_name to item 2 of this_ann
		else
			set credit_name to item 1 of this_ann
		end if
		repeat with j from 1 to count of all_anns
			set this_all_ann to (item j of all_anns)
			set this_ann_name to item 1 of this_all_ann
			set this_ann_value to item 2 of this_all_ann
			if ann_name is this_ann_name then
				set end of ordered_credits to {credit_name, this_ann_value}
				exit repeat
			end if
		end repeat
	end repeat
	return ordered_credits
end orderCredits

on writeTo(this_data, target_file, append_data, mode) -- append_data is true or false, mode is string etc. (no quotes around either)
	try
		set target_file to target_file as Unicode text
		if target_file does not contain ":" then set target_file to POSIX file target_file as Unicode text
		set the open_target_file to open for access file target_file with write permission
		if append_data is false then set eof of the open_target_file to 0
		write this_data to the open_target_file starting at eof as mode
		close access the open_target_file
		return true
	on error
		try
			close access file target_file
		end try
		return false
	end try
end writeTo

on time2timecode(this_time, movie_scale)
	set the_secs to this_time / movie_scale
	set sub_mins to the_secs div 60
	set secs to the_secs mod 60
	set hrs to sub_mins div 60
	set mins to sub_mins mod 60
	set hrs to (text -2 thru -1 of ("00" & hrs)) as string
	set mins to (text -2 thru -1 of ("00" & mins)) as string
	set decimal_offset to offset of "." in ("00" & secs)
	if decimal_offset is 0 then
		set secs to (text -6 thru -1 of ("00" & secs & ".000")) as string
	else
		set secs to text (decimal_offset - 2) thru (decimal_offset + 3) of ("00" & secs & "000") as string
	end if
	return "[" & hrs & ":" & mins & ":" & secs & "]"
end time2timecode

on stripYear(movie_title)
	if movie_title contains "(" then
		set x to offset of "(" in movie_title
		if character (x + 5) of movie_title is ")" then
			if length of movie_title > (x + 5) then
				if character (x - 1) of movie_title is space then
					set movie_title to (characters 1 thru (x - 2) of movie_title & characters (x + 6) thru -1 of movie_title) as string
				else
					set movie_title to (characters 1 thru (x - 1) of movie_title & characters (x + 6) thru -1 of movie_title) as string
				end if
			else
				if character (x - 1) of movie_title is space then
					set movie_title to (characters 1 thru (x - 2) of movie_title) as string
				else
					set movie_title to (characters 1 thru (x - 1) of movie_title) as string
				end if
			end if
		end if
	end if
	return movie_title
end stripYear

on parseActors(actors_value)
	set text item delimiters to ", "
	set b to text items of actors_value
	set text item delimiters to return
	set actors_value to b as string
	set text item delimiters to ""
	return actors_value
end parseActors