Using AppleScript to create a Folder Action script and then attach it

So, I have a template for a Watch Folder. Now, I want to make it so that non-AppleScript people can run a script/program, be asked a few questions, and then have my script save out a customize AppleScript that incorporates the properties that the users specify.

So, am I right to save out a file to the Folder Actions Script folder first and then attach it? Attaching an existing script to a folder doesn’t seem too hard. What I’m trying to understand is how to set up the script so that it writes a text file that can work as an applescript (line breaks and all).

Plus I want to put the variables into the result too.

This should be what you want.

on adding folder items to ThisFolder after receiving AddedList
	
	set TheDateList to {}
	set TheNameList to {}
	
	tell application "Finder"
		activate
		set TheChanges to display dialog "What are these changes called?" default answer "" buttons {"OK"} default button "OK"
		set TheWho to display dialog "Who did the changes" default answer "" buttons {"OK"} default button "OK"
	end tell
	
	repeat with TheItem in AddedList
		set TheItem to TheItem as string
		set TheInfo to info for file TheItem
		set TheName to name of TheInfo
		copy TheName to end of TheNameList
		set TheDate to short date string of modification date of TheInfo
		copy TheDate to end of TheDateList
	end repeat
	
	set TimeStamp to do shell script "date -n +%Y-%m-%d-%H-%M-%S" --File friendly time stamp
	set thepath to ((path to desktop) as string) & "Changes:"
	do shell script "mkdir -p " & (POSIX path of thepath) -- Create Changes Folder
	set TheName to "ChangesLog-" & TimeStamp & ".txt"
	set theFile to thepath & TheName
	try
		set fileref to (open for access theFile with write permission)
		set eof fileref to 0
		write text of ("Changes Are: " & (text returned of TheChanges) & return) to fileref as string
		write text of ("By: " & (text returned of TheWho) & return) to fileref as string
		write text of ("At: " & ((current date) as string) & return & return) to fileref as string
		repeat with i from 1 to (count of TheNameList)
			write text of ((item i of TheNameList) & tab & (item i of TheDateList) & return) to fileref as string
		end repeat
		write text of "End" to fileref as string
		close access fileref
	on error number x
		close access fileref
		display dialog "Error " & x
	end try
	
end adding folder items to

Any question do ask

from Bevan at www.applescript.co.nz

Ahah, I think I get it. It’s always nice to see a sample, so it guides you in the right direction. Thanks.

I don’t understand how the answer relates to what little I understand of the question. :confused:

My impression is that the query was how to create a customised Folder Action script “on the fly” and attach it to a folder. If that’s the case, then it has to be saved as a script, not as a text file.

-- Compose the script text. It should represent a script object containing the required code.
set scriptText to "script
on adding folder items to ThisFolder after receiving AddedList
beep (count AddedList)
end adding folder items to
end script"
-- Realise the script object by "running" the text.
set compiledScript to (run script scriptText)

-- Save the script object as a script in its own right in the Folder Action Scripts folder.
set scriptPath to (path to Folder Action scripts as Unicode text) & "My Script.scpt"
store script compiledScript in file scriptPath replacing ask

-- Attach the script to, say, a folder called "My Folder" on the desktop.
tell application "System Events"
	-- set folder actions enabled to true
	attach action to folder ((path to desktop as Unicode text) & "My Folder") using file scriptPath
	-- Or: attach action to folder ((path to desktop as Unicode text) & "My Folder") using "My Script.scpt"
end tell

Actually, the first response helped because it showed how I could write of the text out with the properties embedded. But as you guessed, I hit a snag because once the text was written if was a text file and not a script file (I managed to get the text of my script into a file but it wouldn’t launch, even if I put the suffix to .scpt, so I spent an hour trying to figure that part out). Now, I’ll try your method to see if it completes the picture.

Thanks.

OK, your script works to create a script, but I have a question about embedding the my properties into the final script.


tell application "Finder"
	set the source_folder to (choose folder with prompt "Select the Watch Folder:") as text
	display dialog source_folder
end tell



set scriptText to "script
on adding folder items to thisFolder after receiving theItems
	tell Application \"Finder\" 
		Display Dialog source_folder
		end tell
end adding folder items to
end script"

-- Realise the script object by "running" the text.
set compiledScript to (run script scriptText)

-- Save the script object as a script in its own right in the Folder Action Scripts folder.
set scriptPath to (path to Folder Action scripts as Unicode text) & "My Script.scpt"
store script compiledScript in file scriptPath replacing ask

-- Attach the script to, say, a folder called "My Folder" on the desktop.
tell application "System Events"
	-- set folder actions enabled to true
	attach action to folder ((path to desktop as Unicode text) & "Test") using file scriptPath
	-- Or: attach action to folder ((path to desktop as Unicode text) & "My Folder") using "My Script.scpt"
end tell

Notice the source_folder in the resulting script is gray? It literally puts “source_folder” in the script, rather than the path.

I also tried the script like this:

tell application "Finder"
	set the source_folder to (choose folder with prompt "Select the Watch Folder:") as text
	display dialog source_folder
end tell



set scriptText to "script
on adding folder items to thisFolder after receiving theItems
	tell Application \"Finder\" 
		Display Dialog" & source_folder & return & "
		end tell
end adding folder items to
end script"

-- Realise the script object by "running" the text.
set compiledScript to (run script scriptText)

-- Save the script object as a script in its own right in the Folder Action Scripts folder.
set scriptPath to (path to Folder Action scripts as Unicode text) & "My Script.scpt"
store script compiledScript in file scriptPath replacing ask

-- Attach the script to, say, a folder called "My Folder" on the desktop.
tell application "System Events"
	-- set folder actions enabled to true
	attach action to folder ((path to desktop as Unicode text) & "Test") using file scriptPath
	-- Or: attach action to folder ((path to desktop as Unicode text) & "My Folder") using "My Script.scpt"
end tell

That didn’t work either.

In need to figure out how the formating works, because the resulting watch folder script (the one I need to compile and attach) is much more complicated, it is this:



on adding folder items to thisFolder after receiving theItems
	tell application "Finder"
		
		
		repeat with f in theItems
			
		
			
			set file_name to name of (info for f)
			
			if the file_name does not contain "InProgress-" then
				--display dialog "I'm past InProgress"	
				
				
				set compressor_appfile to (application file id "com.apple.compressor.Compressor" as Unicode text)
				set theFiles to the quoted form of the POSIX path of f
				set myCluster to the ("-clustername" & space & (quoted form of "This Computer"))
				set the compressor_UNIXfile to (compressor_appfile & ":Contents:MacOS:Compressor") as alias
				set the UNIXfile_path to the quoted form of the POSIX path of the compressor_UNIXfile
				
				
				
				-- wait for the item to be all there. Since it can take a few minutes for a file to copy over.
				set Was to 0
				set isNow to 1
				repeat while isNow ≠ Was
					set Was to size of (info for f)
					delay 15 -- longer if getting the item is slow
					set isNow to size of (info for f)
				end repeat
				
				
				do shell script (UNIXfile_path & space & myCluster & space & "-jobpath" & space & theFiles & space & "-settingpath" & space & (quoted form of ("/Users/anton/Library/Application Support/Compressor/Apple ProRes 422 Interlace.setting")) & space & "-destinationpath" & space & (quoted form of ("/Users/anton/Movies/" & file_name)))
				delay 2
			end if
			
		end repeat -- get next item f in thisFolder 
		
	end tell
end adding folder items to

So, I will be replacing the UNIXfile_path, myCluster, (quoted form of (“/Users/anton/Library/Application Support/Compressor/Apple ProRes 422 Interlace.setting”), (quoted form of (“/Users/anton/Movies/” & file_name), with new values (different for every user).

The colours you see in a script are set in your own AppleScript preferences. (Script Editor → Preferences. → Formatting.) :slight_smile: But yes. ‘source_folder’ appears as a variable name in this case.

You’re on the right track with your next attempt “ to concatentate source_folder’s text value into the script text. In that context, it needs escaped quotes round it, as you’ve done with “"Finder"”

tell application "Finder"
	set the source_folder to (choose folder with prompt "Select the Watch Folder:") as text
	display dialog source_folder
end tell

set scriptText to "script
on adding folder items to thisFolder after receiving theItems
  tell Application \"Finder\"
    Display Dialog \"" & source_folder & return & "\"
    end tell
end adding folder items to
end script"

You don’t need to hard-code those. UNIXfile_path is derived from compressor_UNIXfile, which is in turn derived from compressor_appfile, which is returned by the Finder. The ‘path to’ command can provide the paths to the user’s Application Support and Movies folders.

I’m not sure what myCluster’s supposed to be. If it’s the name of the user’s computer, there’s a StandardAdditions command for that too (in Tiger, at any rate).

Unless there’s anything really awkward to customise in the script, you can use the same script for every user, which in turn means you don’t need to start with a text version of it.

on saveAndAttachScript()
	script compiledScript
		on adding folder items to thisFolder after receiving theItems
			-- Work out these paths just once, before entering the repeat.
			set settingPath to (POSIX path of (path to application support from user domain)) & "Compressor/Apple ProRes 422 Interlace.setting"
			set MoviePath to POSIX path of (path to movies folder)
			
			tell application "Finder" to set compressor_appfile to (application file id "com.apple.compressor.Compressor" as Unicode text)
			set the compressor_UNIXfile to (compressor_appfile & ":Contents:MacOS:Compressor") as alias
			set the UNIXfile_path to the quoted form of the POSIX path of the compressor_UNIXfile
			set myCluster to the ("-clustername" & space & (quoted form of computer name of (system info))) -- was . & (quoted form of "This Computer")
			
			repeat with f in theItems
				set file_name to name of (info for f)
				
				if the file_name does not contain "InProgress-" then
					--display dialog "I'm past InProgress"  
					
					set theFiles to the quoted form of the POSIX path of f
					
					-- wait for the item to be all there. Since it can take a few minutes for a file to copy over.
					set Was to 0
					set isNow to 1
					repeat while isNow ≠ Was
						set Was to size of (info for f)
						delay 15 -- longer if getting the item is slow
						set isNow to size of (info for f)
					end repeat
					
					
					do shell script (UNIXfile_path & space & myCluster & space & "-jobpath" & space & theFiles & space & "-settingpath" & space & (quoted form of settingPath) & space & "-destinationpath" & space & (quoted form of (MoviePath & file_name)))
					delay 2
				end if
				
			end repeat -- get next item f in the received items
			
		end adding folder items to
	end script
	
	-- Save the script object as a script in its own right in the Folder Action Scripts folder.
	set scriptPath to (path to Folder Action scripts as Unicode text) & "My Script.scpt"
	store script compiledScript in file scriptPath replacing ask
	
	-- Attach the script to, say, a folder called "Test" on the desktop.
	tell application "System Events"
		-- set folder actions enabled to true
		attach action to folder ((path to desktop as Unicode text) & "Test") using file scriptPath
	end tell
end saveAndAttachScript

saveAndAttachScript()

I haven’t been able to test that the saved script actually works as I don’t have Compressor, so apologies for any errors on my part. :slight_smile:

Thank you for your reply. I will digest the info and try it this evening.

Quoting your response:

You don’t need to hard-code those. UNIXfile_path is derived from compressor_UNIXfile, which is in turn derived from compressor_appfile, which is returned by the Finder. The ‘path to’ command can provide the paths to the user’s Application Support and Movies folders.

I’m not sure what myCluster’s supposed to be. If it’s the name of the user’s computer, there’s a StandardAdditions command for that too (in Tiger, at any rate).

Unless there’s anything really awkward to customise in the script, you can use the same script for every user, which in turn means you don’t need to start with a text version of it.

These values are values that exist only for my own computer and are not necessarily useful for anyone else. Let me explain:

myCluster is for the name of the Compression Cluster the user wants to send the job to (can be named anything, set up by the user who builds the cluster/render farm).

In addition, values like (quoted form of (“/Users/anton/Library/Application Support/Compressor/Apple ProRes 422 Interlace.setting”) are just examples of the type of thing that would go there. There are hundreds of settings of which Apple ProRes 422 Interlace is just one. So, the user needs to specify what setting that want to use on the video (it’s like picking different codecs in QuickTime Pro). My bigger point is that it will vary, and I need to slide in the custom values.

Sorry if I didn’t write that properly initially.

Cheers.

Nigel,

Your script works pretty well. A good start. Thank you very much.

Will try to run with it and see if I can get it the rest of the way.

Cheers,

A.

So this is my script with a bunch of stuff added into it. It seems to work, though it’s probably not the best way to write it. The Terminal session is definitely rough, but I can’t seem to get around the do shell script limitation (no response when I do the -show command). I guess I can just have them pick the Cluster by name (with the Terminal session). Haven’t decided yet. I know I have too many globals, I just haven’t cleaned that part up yet.


global target_folder, source_folder, display_quit, folder_path, error_icon, temporary_items_folder, target_cluster, settings_file, settings_path, source_POSIXpath, UNIXfile_path, settings_command_string, theFolder, theSource, settingPath

display dialog "This program will help you set up a watch folder for video codec conversions (ie. XDCAM to ProRes or DVCPRO HD)." & return & return & "Click the "Continue" button to setup this script." with title "Compressor Watch Folder Setup" buttons {"Stop", "Continue"} default button 1
if the button returned of the result is "Stop" then tell me to quit

try
	activate
	set the source_folder to (choose folder with prompt "Select the Watch Folder:")
	set theSource to the quoted form of the POSIX path of source_folder
on error
	tell me to quit
end try

try
	activate
	set the target_folder to (choose folder with prompt "Select the Destination for the Compressed Files:")
	set theFolder to the quoted form of the POSIX path of target_folder
on error
	tell me to quit
end try

set the default_folder to (((path to application support folder from user domain) as Unicode text) & "Compressor:") as alias
set the settings_file to (choose file default location default_folder without multiple selections allowed and invisibles)

set the settingPath to (POSIX path of settings_file)

-- DETERMINE CLUSTER
try
	tell application "Finder"
		set compressor_appfile to (application file id "com.apple.compressor.Compressor" as Unicode text)
	end tell
	set the compressor_UNIXfile to (compressor_appfile & ":Contents:MacOS:Compressor") as alias
	set the UNIXfile_path to the quoted form of the POSIX path of the compressor_UNIXfile
on error
	tell me to quit
end try

tell application "Terminal"
	launch
	do script with command (UNIXfile_path & space & "-show")
	tell window 1
		set background color to "black"
		set cursor color to "green"
		set normal text color to "yellow"
		set bold text color to "red"
		set title displays shell path to true
		set title displays window size to true
		set title displays device name to true
		set title displays file name to true
		set title displays custom title to true
		set custom title to "ClusterCheck"
		set number of columns to 80
		set number of rows to 40
	end tell
	set this_data to the contents of window 1
end tell
delay 3

do shell script "killall Terminal"

set the cluster_names to {}
repeat with i from 1 to the count of paragraphs of this_data
	set this_paragraph to paragraph i of this_data
	if this_paragraph contains "<cluster name" then
		set x to the offset of "\"" in this_paragraph
		set y to text from (x + 1) to -1 of this_paragraph
		set x to the offset of "\"" in y
		set the cluster_name to text 1 thru (x - 1) of y
		set the end of the cluster_names to the cluster_name
	end if
end repeat

set the target_cluster to (choose from list cluster_names with prompt "Pick the cluster node:") as Unicode text
if the target_cluster is "false" then tell me to quit

on saveAndAttachScript()
	script compiledScript
		on adding folder items to thisFolder after receiving theItems
			-- Work out these paths just once, before entering the repeat.
			--set settingPath to (POSIX path of (path to application support from user domain)) & "Compressor/Apple ProRes 422 Interlace.setting"
			set MoviePath to POSIX path of target_folder as text
			tell application "Finder" to set compressor_appfile to (application file id "com.apple.compressor.Compressor" as Unicode text)
			set the compressor_UNIXfile to (compressor_appfile & ":Contents:MacOS:Compressor") as alias
			set the UNIXfile_path to the quoted form of the POSIX path of the compressor_UNIXfile
			set myCluster to the ("-clustername" & space & (quoted form of target_cluster)) -- was . & (quoted form of "This Computer")
			
			repeat with f in theItems
				set file_name to name of (info for f)
				
				if the file_name does not contain "InProgress-" then
					--display dialog "I'm past InProgress"
					
					set theFiles to the quoted form of the POSIX path of f
					
					-- wait for the item to be all there. Since it can take a few minutes for a file to copy over.
					set Was to 0
					set isNow to 1
					repeat while isNow ≠ Was
						set Was to size of (info for f)
						delay 15 -- longer if getting the item is slow
						set isNow to size of (info for f)
					end repeat
					
					
					do shell script (UNIXfile_path & space & myCluster & space & "-jobpath" & space & theFiles & space & "-settingpath" & space & (quoted form of settingPath) & space & "-destinationpath" & space & (quoted form of (MoviePath & file_name)))
					delay 2
				end if
				
			end repeat -- get next item f in the received items
			
		end adding folder items to
	end script
	
	-- Save the script object as a script in its own right in the Folder Action Scripts folder.
	set scriptPath to (path to Folder Action scripts as Unicode text) & "My Script.scpt"
	store script compiledScript in file scriptPath replacing ask
	
	-- Attach the script to, say, a folder called "Test" on the desktop.
	tell application "System Events"
		-- set folder actions enabled to true
		attach action to source_folder using file scriptPath
	end tell
end saveAndAttachScript

saveAndAttachScript()


Maybe not elegant, but it works (at least in my preliminary tests). Now, I have to test it more.

Thanks again.

Hi, Tunaking.

I’m glad you’re having some success. Just looking quickly over your script, a couple of points you might find useful to know are:

  1. ‘tell me to quit’ is an instruction to the application running the script, not to the script itself. If you’re running the main script as an applet, the application will be the script’s own applet implementation. When it receives a ‘quit’ command, the applet will finish what it’s doing first (ie. running the script) before actually quitting. If you want to stop it dead in its tracks at the points where you’ve used ‘tell me to quit’, use ‘error number -128’ instead (the “User canceled.” error). This’ll stop the script immediately and the applet will then quit anyway, if it’s not a stay-open application.

  2. The folder action script that’s created inherits its globals and their persistent values from the main script. If it’s opened and recompiled, the values will be lost and it’ll cease to work. So any later edits will have to be made in the main script, which must then be run again to create a replacement folder action script.

Nigel,

You know, I was wondering about how the globals got the script, because I opened up the resulting watch folder script and I saw my variables in there. Are there any other scenarios besides recompiling that would delete the values? Are the values kept somewhere on the system?

Cheers

Hi, Tunaking.

The global values are stored in the script files (of both mother and child scripts, of course), independently of the source code, in the same way that they would be if they were property values. Instead of using globals, you could pass the values as parameters to the main script’s saveAndAttachScript() handler and use them to initialise properties in ‘compiledScript’.

Global and property values are updated in a script file after each run of the corresponding script, but unless they’re changed within the script itself, they’re no more likely to be altered or lost than any other data on the disk.

The AppleScript with some early versions of Tiger had a bug whereby properties and global values didn’t persist; but it wasn’t a problem before that and has been fixed in more recent versions. If in doubt, you could have the main script write the values to a separate data file “ say, in Application Support or Preferences “ and the folder action script could read them from there each time it ran.