Make script wait for a specific action to execute

Hello.

I’m trying to figure out how to run a script in the background that waits for a specific action, then activates, then goes back to waiting for the next time that action occurs. I have the below script that takes some annotations from a Quicktime file and places them in an .xml file and I want it to run whenever a Quicktime file is launched, then wait for the next time a Quicktime File is launched and run again.

I thought it was something simple like:

tell QuickTime Player 7
on open document
--do stuff
end open
end tell

But then I read some posts about an idle handler (which I don’t quite understand) and I’m wondering if it’s more complicated than this or if I’m just a little off in the syntax.

Any help would be greatly appreciated.

Here is the script I was referring to:

tell application "QuickTime Player 7"
	
	-- FULL NAME	
	if annotation "full name" of document 1 exists then
		set annot_fullname to full text of annotation "full name" of document 1
	else
		set annot_fullname to " "
	end if
	if first character of annot_fullname is "*" then set annot_fullname to " "
	
	-- ARTIST
	if annotation "artist" of document 1 exists then
		set annot_artist to full text of annotation "artist" of document 1
	else
		set annot_artist to " "
	end if
	if first character of annot_artist is "*" then set annot_artist to " "
	
end tell

tell application "TextEdit"
	tell (make new document)
		set every text of it to "<?xml version=\"1.0\"?>" & return & return & "<fmaStream>" & return & tab & "<data>" & return & tab & tab & "<title>" & annot_fullname & "</title>" & return & tab & tab & "<artist>" & annot_artist & "</artist>" & return & tab & "</data>" & return & "</fmaStream>"
	end tell
	
end tell

tell application "TextEdit"
	tell front document to save in "/users/bruce/desktop/testxml2.xml" as Unicode text
	tell front document to close
end tell

Thanks,

  • Bruce

An idle-handler is probably the best way to go.

An idle-handler incessantly runs in a stay-open application. So you could check every 1 second if QuickTime has a new document and if so, process that document. With the idle handler you can also write code to notify the closing of the document. (You wouldn’t want to process the same document every second or so over and over again?)

This is a simple idle handler. Save it as a Stay-Open application and launch it. See what happens.

global theCount

on run
	set theCount to 1
end run

on idle
	display dialog "This dialog has appeared " & theCount & " times to you." buttons {"Quit", "OK"} default button 2 giving up after 1
	if button returned of result is "Quit" then
		quit
	end if
	set theCount to theCount + 1
	
	return 1
end idle

Hope it helps,
ief2

Thanks for the suggestions. I think I don’t really understand how an idle handler works. I understand the concept of checking every second to see if Quicktime has a new document, but I’m not sure how the language works. I read the Applescript language guide on handlers and I think maybe I don’t know enough of the more basic stuff to understand it.

The script at the bottom is my attempt at implementing this by making a new variable based on the full name annotation of the open Quicktime document, then checking to see if it’s the same as the one taken earlier in the script. I’m not really sure what I’m repeating, though. In pseudocode, this is what I imagine happening:

1 Get annotations from the open quicktime file and assign them to variables

2 put them in an XML document

3 upload them (currently a display dialog line for simplicity - this is going to trigger an automator application that uploads the XML document)

3 wait one second

4 get only the full name annotation from the open Quicktime file and assign it to a variable

5 see if this most recent full name annotation variable is the same as the previously saved one. If it is, go to 3. If not, go to 1.

Is this close to what you’re suggesting using the idle handler?

Here’s the non-working script (it displays the dialog box when you start it, then returns the error message “The variable annot_fullname is not defined.”:

global theCount

on run
	set theCount to 1
	
	
	
	tell application "QuickTime Player 7"
		
		-- FULL NAME	
		if annotation "full name" of document 1 exists then
			set annot_fullname to full text of annotation "full name" of document 1
		else
			set annot_fullname to " "
		end if
		if first character of annot_fullname is "*" then set annot_fullname to " "
		
		-- ARTIST
		if annotation "artist" of document 1 exists then
			set annot_artist to full text of annotation "artist" of document 1
		else
			set annot_artist to " "
		end if
		if first character of annot_artist is "*" then set annot_artist to " "
		
	end tell
	
	tell application "TextEdit"
		tell (make new document)
			set every text of it to "<?xml version=\"1.0\"?>" & return & return & "<fmaStream>" & return & tab & "<data>" & return & tab & tab & "<title>" & annot_fullname & "</title>" & return & tab & tab & "<artist>" & annot_artist & "</artist>" & return & tab & "</data>" & return & "</fmaStream>"
		end tell
		
	end tell
	
	tell application "TextEdit"
		tell front document to save in "/users/brucejames/desktop/testxml2.xml" as Unicode text
		tell front document to close
	end tell
	
	display dialog "this is what happens when a new movie is opened" --this would be an upload command, but I used a dialog box to simplify things
end run

on idle
	tell application "QuickTime Player 7"
		set Annot_checking_fullname to full text of annotation "full name" of document 1
	end tell
	if (Annot_checking_fullname = annot_fullname) is false then
		set theCount to theCount + 1
	end if
	return 1
end idle

Any further ideas would be greatly appreciated.

Thanks,

  • Bruce

Is it something like the below you want?

This is what the script does:

  • At run it setups an empty list
  • The idle handler gets activated
  • The idle handler constantly repeats one action:
    ¢ Gets the annotation “full name” of document 1 (1)
    ¢ If the full name annotation is not in the Processed list
    # It adds the name to Processed list
    # It calls the saveAnnot()-handler:
    + Stores the full name and artist of the document in variables
    + Makes an XML-data string with the variables
    + Asks the user to choose a file (You can replace this by inserting the POSIX path)
    + Creates (if not exists already) the chosen file
    + Opens the file for writing access using the built in AppleScript commands
    + Writes the data and closes the file using the built in AppleScript commands
    + Display’s a dialog “Annotations Saved”
    ¢ Goes back to action (1)

Script:

global processedFullNames

on run
	set processedFullNames to {}
end run

on idle
	tell application "QuickTime Player" to set fullAnotName to full text of annotation "full name" of document 1
	if fullAnotName is not in processedFullNames then
		set end of processedFullNames to fullAnotName
		saveAnnot()
	end if
	
	return 1
end idle

(* ===== SAVE ANNOTATION ===== *)
on saveAnnot()
	tell application "QuickTime Player"
		-- FULL NAME	
		if annotation "full name" of document 1 exists then
			set annot_fullname to full text of annotation "full name" of document 1
		else
			set annot_fullname to " "
		end if
		if first character of annot_fullname is "*" then set annot_fullname to " "	
		
		-- ARTIST
		if annotation "artist" of document 1 exists then
			set annot_artist to full text of annotation "artist" of document 1
		else
			set annot_artist to " "
		end if
		if first character of annot_artist is "*" then set annot_artist to " "
	end tell
	
	
	-- WRITE DATA TO FILE
	-- get data
	set myData to "<?xml version=\"1.0\"?>" & return & return & "<fmaStream>" & return & tab & "<data>" & return & tab & tab & "<title>" & annot_fullname & "</title>" & return & tab & tab & "<artist>" & annot_artist & "</artist>" & return & tab & "</data>" & return & "</fmaStream>"
	set myData to myData as string
	
	-- make new file
	set myFile to POSIX path of (choose file name with prompt "Where do you want to save the XML?")
	makeFile(myFile, 1)
	
	-- write string
	set OA to open for access alias (my HSFWithPOSIX(myFile)) with write permission
	write myData to OA starting at 0
	close access OA
	
	display dialog "Annotations Saved" giving up after 1
end saveAnnot

(* ===== HANDLERS ===== *)
on makeFile(filename, sizeInBytes)
	try
		do shell script "mkfile " & sizeInBytes & "b " & my stringForTerminal(filename)
		return true
	on error
		return false
	end try
end makeFile

on stringForTerminal(filename)
	set tid to AppleScript's text item delimiters
	set AppleScript's text item delimiters to " "
	set allItems to every text item of filename
	set AppleScript's text item delimiters to "\\ "
	set newPath to allItems as text
	
	set AppleScript's text item delimiters to tid
	return newPath
end stringForTerminal

on HSFWithPOSIX(filename)
	set myAlias to (POSIX file filename)
	set myAlias to myAlias as string
	return myAlias
end HSFWithPOSIX

Hope it helps,
ief2

PS: This script is not tested, so there could be bugs in it.

Thanks so much!

This is really close to what I need. I modified it a little by adding the path to the file I want to always save in and took away the dialog boxes and it almost does it. It constantly updates the .xml file with the annotations from the current movie, which is great. I don’t actually need to make sure I’m not processing a movie that has already been processed, which isn’t hard to take out. What I do need to do that I can’t figure out is to trigger another application whenever a new movie is opened (regardless of whether it has been opened in the past or not).

This script works great except for the above mentioned things:

global processedFullNames

on run
	set processedFullNames to {}
end run

on idle
	tell application "QuickTime Player 7"
		if annotation "full name" of document 1 exists then
			set fullAnotName to full text of annotation "full name" of document 1
		else
			set fullAnotName to " "
		end if
	end tell
	--if fullAnotName is not in processedFullNames then
	--set end of processedFullNames to fullAnotName
	saveAnnot()
	--end if
	
	--display dialog processedFullNames as string
	return 1
end idle

(* ===== SAVE ANNOTATION ===== *)
on saveAnnot()
	tell application "QuickTime Player 7"
		-- FULL NAME	
		if annotation "full name" of document 1 exists then
			set annot_fullname to full text of annotation "full name" of document 1
		else
			set annot_fullname to " "
		end if
		if first character of annot_fullname is "*" then set annot_fullname to " "
		
		-- ARTIST
		if annotation "artist" of document 1 exists then
			set annot_artist to full text of annotation "artist" of document 1
		else
			set annot_artist to " "
		end if
		if first character of annot_artist is "*" then set annot_artist to " "
	end tell
	
	
	-- WRITE DATA TO FILE
	-- get data
	set myData to "<?xml version=\"1.0\"?>" & return & return & "<fmaStream>" & return & tab & "<data>" & return & tab & tab & "<title>" & annot_fullname & "</title>" & return & tab & tab & "<artist>" & annot_artist & "</artist>" & return & tab & "</data>" & return & "</fmaStream>"
	set myData to myData as string
	
	-- make new file
	set myFile to "/users/brucejames/desktop/testxml2.xml" as Unicode text
	--set myFile to POSIX path of (choose file name with prompt "Where do you want to save the XML?")
	--makeFile(myFile, 1)
	
	-- write string
	set OA to open for access alias (my HSFWithPOSIX(myFile)) with write permission
	write myData to OA starting at 0
	close access OA
	
	--display dialog "Annotations Saved" giving up after 1
end saveAnnot

(* ===== HANDLERS ===== *)
on makeFile(filename, sizeInBytes)
	try
		do shell script "mkfile " & sizeInBytes & "b " & my stringForTerminal(filename)
		return true
	on error
		return false
	end try
end makeFile

on stringForTerminal(filename)
	set tid to AppleScript's text item delimiters
	set AppleScript's text item delimiters to " "
	set allItems to every text item of filename
	set AppleScript's text item delimiters to "\\ "
	set newPath to allItems as text
	
	set AppleScript's text item delimiters to tid
	return newPath
end stringForTerminal

on HSFWithPOSIX(filename)
	set myAlias to (POSIX file filename)
	set myAlias to myAlias as string
	return myAlias
end HSFWithPOSIX

This is the first bit where I tried to come up with a way to check for matching between the current movie and the one played before:

global processedFullNames

on run
	set processedFullNames to {}
end run

on idle
	tell application "QuickTime Player 7"
		if annotation "full name" of document 1 exists then
			set fullAnotName to full text of annotation "full name" of document 1
		else
			set fullAnotName to " "
		end if
	end tell
	delay 3
	tell application "QuickTime Player 7"
		if document 1 exists then
			set annot_fullname to full text of annotation "full name" of document 1
		else
			set annot_fullname to " "
		end if
		if (annot_fullname = fullAnotName) is false then display dialog "it is false" --this would be if a new movie had been opened and is where I would trigger the upload application
		
		
		--if fullAnotName is not in processedFullNames then
		--set end of processedFullNames to fullAnotName
		saveAnnot()
		
	end tell
	
	--display dialog processedFullNames as string
	return 1
end idle

But when I run this bit in the full script, I get the error, “Can’t continue saveAnnot.”

Any further thoughts?

Thanks again for your help on this.

In case it’s useful, here’s the full context of what I’m doing:

I use iCal to trigger Automator applications that get a series of Quicktime movies and play them in order on a plasma screen (in a university film department). There is typically one of these applications triggered by iCal every hour all day. These are films made by students in our department.

We also capture the plasma screen (using Wirecast software) and send it as a webcast to the front page of our web site. What I’m trying to enable is live updating of the title and artist to the web site as the movies play. I used to do this all in Automator, but we kept getting all kinds of errors on various parts of the workflows. This was in 10.6. Since then, I’ve downgraded to 10.5 and still get the errors, so I thought I’d try just running the Quicktime playlists in Automator, since that’s very simple, and then using Applescript to get the names, save them in an xml, and trigger another simple Automator application to upload that xml (using Fetch) whenever a new movie is opened.

Thanks,

  • Bruce

You’ll have to declare a global variable that contains the previous doc. Then in the idle you can check if the name of the first document in quicktime matches the ones of the previous doc.

You get the error because you’ve forgotten to add the saveAnots()-handlers. (read subroutines tutorial again).

To trigger the application, you’ll have to give some more information about it. What’s is name? Does it have a scripting dictionary?

Script:

global fullNameOfLastMovie

on run
	set processedFullNames to missing value
end run

on idle
	tell application "QuickTime Player"
		if annotation "full name" of document 1 exists then
			set fullAnotName to full text of annotation "full name" of document 1
		else
			set fullAnotName to " "
		end if
	end tell
	
	if fullAnotName is not fullNameOfLastMovie then saveAnnot()
	set fullNameOfLastMovie to fullAnotName
	
	--display dialog processedFullNames as string
	return 1
end idle

(* ===== SAVE ANNOTATION ===== *)
on saveAnnot()
	tell application "QuickTime Player"
		-- FULL NAME	
		if annotation "full name" of document 1 exists then
			set annot_fullname to full text of annotation "full name" of document 1
		else
			set annot_fullname to " "
		end if
		if first character of annot_fullname is "*" then set annot_fullname to " "
		
		-- ARTIST
		if annotation "artist" of document 1 exists then
			set annot_artist to full text of annotation "artist" of document 1
		else
			set annot_artist to " "
		end if
		if first character of annot_artist is "*" then set annot_artist to " "
	end tell
	
	
	-- WRITE DATA TO FILE
	-- get data
	set myData to "<?xml version=\"1.0\"?>" & return & return & "<fmaStream>" & return & tab & "<data>" & return & tab & tab & "<title>" & annot_fullname & "</title>" & return & tab & tab & "<artist>" & annot_artist & "</artist>" & return & tab & "</data>" & return & "</fmaStream>"
	set myData to myData as string
	
	set myFile to "/users/brucejames/desktop/testxml2.xml" as Unicode text
	
	-- write string
	set OA to open for access alias (my HSFWithPOSIX(myFile)) with write permission
	write myData to OA starting at 0
	close access OA
	
	my notifyApp()
end saveAnnot

on notifyApp()
	display dialog "Procesed"
end notifyApp

Hope it helps,
ief2

Hi,

your routine to write the file can be simplified a lot.
It’s not necessary to create a file with mkfile, and the 4-times-coercion file URL > POSIX path > POSIX file > alias is also not needed. With the code below you can delete the handlers makefile() and HSFWithPOSIX()


.
-- WRITE DATA TO FILE
-- get data
set myData to "<?xml version=\"1.0\"?>" & return & return & "<fmaStream>" & return & tab & "<data>" & return & tab & tab & "<title>" & annot_fullname & "</title>" & return & tab & tab & "<artist>" & annot_artist & "</artist>" & return & tab & "</data>" & return & "</fmaStream>"

set myFile to (choose file name with prompt "Where do you want to save the XML?") as text
if myFile does not end with ".xml" then set myFile to myFile & ".xml"

-- write string
try
	set OA to open for access file myFile with write permission
	set eof OA to 0
	write myData to OA
	close access OA
on error
	close access file myFile
end try
.

Hey! Thanks, I’m learning every day :smiley:

The application I’m triggering was made in automator. Currently I’m calling it “testapplication” and this script works fine to make it run:

tell application "testapplication"
activate
end tell

This version results in the error message, “The variable fullNameOfLastMovie is not defined” every time the front movie changes. Other than that, it works. It re-writes the xml file regardless of whether the annotations of the particular movie have been written previously.

I looked through it and I can’t figure out at what point fullNameOfLastMovie is undefined. There is quite a bit in here I don’t completely follow, though, so that’s not surprising.

Any thoughts?

Thanks,

  • Bruce

My bad. Change the on run to the following: :slight_smile:

on run
   set fullNameOfLastMovie to missing value
end run

Hope it works,
ief2

That fixed that issue. Now everything works as I want it to, except that I can’t figure out how to replace the dialog box asking where I want to save the file with a path to a specific file. I tried going back to my original, less-elegant file saving method where I make a new document, then save it in a specific path:

tell application "TextEdit"
		tell (make new document)
			set every text of it to "<?xml version=\"1.0\"?>" & return & return & "<fmaStream>" & return & tab & "<data>" & return & tab & tab & "<title>" & annot_fullname & "</title>" & return & tab & tab & "<artist>" & annot_artist & "</artist>" & return & tab & "</data>" & return & "</fmaStream>"
		end tell
		
	end tell
	
	tell application "TextEdit"
		tell front document to save in "/users/brucejames/desktop/testxml2.xml" as Unicode text
		tell front document to close
	end tell

  • And this actually works fine, except that it doesn’t save the document as Unicode text, it saves in a Word 2003 format.

This is the script that’s working with the dialog box asking for the save location:

global fullNameOfLastMovie

on run
	set fullNameOfLastMovie to missing value
end run

on idle
	tell application "QuickTime Player 7"
		if annotation "full name" of document 1 exists then
			set fullAnotName to full text of annotation "full name" of document 1
		else
			set fullAnotName to " "
		end if
	end tell
	
	if fullAnotName is not fullNameOfLastMovie then saveAnnot()
	set fullNameOfLastMovie to fullAnotName
	
	--display dialog processedFullNames as string
	return 1
end idle

(* ===== SAVE ANNOTATION ===== *)
on saveAnnot()
	tell application "QuickTime Player 7"
		-- FULL NAME	
		if annotation "full name" of document 1 exists then
			set annot_fullname to full text of annotation "full name" of document 1
		else
			set annot_fullname to " "
		end if
		if first character of annot_fullname is "*" then set annot_fullname to " "
		
		-- ARTIST
		if annotation "artist" of document 1 exists then
			set annot_artist to full text of annotation "artist" of document 1
		else
			set annot_artist to " "
		end if
		if first character of annot_artist is "*" then set annot_artist to " "
	end tell
	
	tell application "TextEdit"
		tell (make new document)
			set every text of it to "<?xml version=\"1.0\"?>" & return & return & "<fmaStream>" & return & tab & "<data>" & return & tab & tab & "<title>" & annot_fullname & "</title>" & return & tab & tab & "<artist>" & annot_artist & "</artist>" & return & tab & "</data>" & return & "</fmaStream>"
		end tell
		
	end tell
	
	-- WRITE DATA TO FILE
	-- get data
	set myData to "<?xml version=\"1.0\"?>" & return & return & "<fmaStream>" & return & tab & "<data>" & return & tab & tab & "<title>" & annot_fullname & "</title>" & return & tab & tab & "<artist>" & annot_artist & "</artist>" & return & tab & "</data>" & return & "</fmaStream>"
	
	set myFile to (choose file name with prompt "Where do you want to save the XML?") as text
	if myFile does not end with ".xml" then set myFile to myFile & ".xml"
	
	-- write string
	try
		set OA to open for access file myFile with write permission
		set eof OA to 0
		write myData to OA
		close access OA
	on error
		close access file myFile
	end try
	my notifyApp()
end saveAnnot

on notifyApp()
	display dialog "Procesed"
end notifyApp

So, how can I change the location selecting dialog to a set path? Everything I’ve tried ends up with untitled text documents that don’t save anywhere.

Any final thoughts? Thanks for all your assistance on this.

  • Bruce

You’ll have to hardcode the path in HSF-form (“disk:users:yourusername:desktop:subfolder:file” → “Macintosh HD:users:yourusername:desktop:testxml2.xml”). Or use an AppleScript word like path to home folder, path to desktop folder, etc..

Script:

global fullNameOfLastMovie

on run
	set fullNameOfLastMovie to missing value
end run

on idle
	tell application "QuickTime Player"
		if annotation "full name" of document 1 exists then
			set fullAnotName to full text of annotation "full name" of document 1
		else
			set fullAnotName to " "
		end if
	end tell
	
	if fullAnotName is not fullNameOfLastMovie then saveAnnot()
	set fullNameOfLastMovie to fullAnotName
	
	--display dialog processedFullNames as string
	return 1
end idle

(* ===== SAVE ANNOTATION ===== *)
on saveAnnot()
	tell application "QuickTime Player"
		-- FULL NAME	
		if annotation "full name" of document 1 exists then
			set annot_fullname to full text of annotation "full name" of document 1
		else
			set annot_fullname to " "
		end if
		if first character of annot_fullname is "*" then set annot_fullname to " "
		
		-- ARTIST
		if annotation "artist" of document 1 exists then
			set annot_artist to full text of annotation "artist" of document 1
		else
			set annot_artist to " "
		end if
		if first character of annot_artist is "*" then set annot_artist to " "
	end tell
	
	(*tell application "TextEdit"
		tell (make new document)
			set every text of it to "<?xml version=\"1.0\"?>" & return & return & "<fmaStream>" & return & tab & "<data>" & return & tab & tab & "<title>" & annot_fullname & "</title>" & return & tab & tab & "<artist>" & annot_artist & "</artist>" & return & tab & "</data>" & return & "</fmaStream>"
		end tell
		
	end tell*)
	
	-- WRITE DATA TO FILE
	-- get data
	set myData to "<?xml version=\"1.0\"?>" & return & return & "<fmaStream>" & return & tab & "<data>" & return & tab & tab & "<title>" & annot_fullname & "</title>" & return & tab & tab & "<artist>" & annot_artist & "</artist>" & return & tab & "</data>" & return & "</fmaStream>"
	set myData to myData as string
	
	set myFile to (path to dektop as text) & "testxml2.xml"
	if myFile does not end with ".xml" then set myFile to myFile & ".xml"
	
	-- write string
	try
		set OA to open for access file myFile with write permission
		set eof OA to 0
		write myData to OA
		close access OA
	on error
		close access file myFile
	end try
	my notifyApp()
end saveAnnot

on notifyApp()
	display dialog "Procesed"
end notifyApp

Hope it works,
ief2

PS: Not gonna be able to help you, (holidays), but I’m sure the other nice people here will help you.

This works great!

Thanks so much for all of your help. I’ve gotten so much of it here on MacScripter. I hope I can give back some once I get a little better at this.

  • Bruce