Set Safari's default download location with Finder

Hello MacScripters. This is my first post so please be as harsh as possible. This little ditty I wrote as a Finder Plug-In (by way of the Automator menu) that lets me right-click (err… control click, yeah) on any item in the Finder and have Safari’s default download location set by way of a Rube Goldberg GUI routine that is probably painfully version specific.

I would really be thrilled if someone on here could rewrite this as a one-liner. I snooped around Safari’s preferences and they felt encrypted or otherwise inaccessible, but that could just be my newbie ignorance talking. If not, I’m sure there are ways this might be improved or otherwise stress-tested. It would also be nice to know that it’s useful to someone other than me.

If a folder is selected in the Finder, Safari’s download location will be set to that folder. If a file is selected in the Finder, the download location will be set to the folder that contains that file. So for example if you select a file on the desktop, the download location will be set to the desktop. If you select a folder on the desktop, the download location will be set to that folder.


on run
    try
        tell application "Finder" to set the_folder to POSIX path of ((item 1 of (get selection)) as alias)
        setloc(the_folder)
    on error
        display dialog "Sorry, nothing is selected in the Finder. Please try again." buttons {"OK"} default button 1 with icon 2 giving up after 5
    end try
end run
on setloc(the_folder)
    tell application "System Events" to tell process "Safari"
        tell application "Safari" to activate
        click menu item "Preferences." of menu 1 of menu bar item "Safari" of menu bar 1
        click button "General" of tool bar 1 of window 1
        tell pop up button 3 of group 1 of group 1 of window "General"
            click
            click menu item "Other." of menu 1
        end tell
        keystroke "g" using {shift down, command down}
        delay 0.5 -- if the script fails here, adjust the delay.
        tell window "Go To Folder"
            set value of text field 1 to the_folder
            click button "Go"
        end tell
        click button "Select" of sheet 1 of window "General"
    end tell
end setloc

This script runs perfectly fine as-is in the Script Editor, but I find it more useful as a Finder plug-in. Here’s how to do that:

  1. Create a new workflow in Automator
  2. Drag “Run Applescript” from Automator’s action library into your workflow
  3. delete all of the default code from the action
  4. paste this script into the action
  5. click File → “Save as Plug-In”
  6. give it a catchy name like “Download Files Here”
  7. make sure that “Plug-In for” is set to Finder
  8. click Save and you’re done!

From now on when you right-click or control-click items in the Finder you’ll see “Download Files Here” in the “Automator” item of the contextual menu.

The only thing I can find to criticise is that you’ve made some dodgy assumptions in the ‘try’ block. When I run the script, I get the “nothing is selected” message, when in fact the problem is that I don’t have GUI scripting enabled on my machine. The same message appears if the delay in setloc() is too short and needs adjusting - or for anything else that goes wrong. The various situations should be trapped separately.

on run
	tell application "Finder"
		set the_selection to the selection
		if (the_selection is {}) then my displayError("Sorry, nothing is selected in the Finder. Please try again.")
		if (class of item 1 of the_selection is not folder) then my displayError("The selected item is not a folder. Please try again.")
		set the_folder to POSIX path of ((item 1 of the_selection) as alias)
	end tell
	setloc(the_folder)
end run

on displayError(msg)
	tell application (path to frontmost application as Unicode text)
		display dialog msg buttons {"OK"} default button 1 with icon 2 giving up after 5
	end tell
	error number -128
end displayError

on setloc(the_folder)
	tell application "System Events" to tell process "Safari"
		tell application "Safari" to activate
		try
			click menu item "Preferences." of menu 1 of menu bar item "Safari" of menu bar 1
		on error
			my displayError("GUI scripting problem. It may not be enabled (or may not be available) on this machine.")
		end try
		click button "General" of tool bar 1 of window 1
		tell pop up button 3 of group 1 of group 1 of window "General"
			click
			click menu item "Other." of menu 1
		end tell
		keystroke "g" using {shift down, command down}
		delay 0.5 -- if the script fails here, adjust the delay.
		try
			tell window "Go To Folder"
				set value of text field 1 to the_folder
				click button "Go"
			end tell
		on error
			my displayError("GUI scripting problem. The delay may need to be increased in this script.")
		end try
		click button "Select" of sheet 1 of window "General"
	end tell
end setloc

It’s possible to use one ‘try’ block to cover the entire script (as you did) and to take appropriate action according to the error number, but I haven’t had time to check if the numbers are unique for each possible situation here.

Thank you for that excellent rewrite! With your permission I’d like to submit your version to MacOSXHints.com. I’ve submitted scripts there before, and they always get major revisions in the comments – which is great – but I thought perhaps I should be running these things by true AppleScript Samurai before releasing them to the teeming millions.

A few things I discovered:

  • I unwittingly wrote the script while using Safari 1.3
  • the 2.0 GUI is identical to 1.3, but 2.0 requires a longer delay
  • Safari stores the default download location in a regular plist as “NSNavLastRootDirectory”
  • the plist value appears to be read-only (when I change it, Safari just changes it back)

So anyway at the moment it appears this is the best way to accomplish this particular task. I’m quite happy with it.

Why not post your script to ScriptBuilders too? :wink:

No problem. And/or - as Ray suggested - to ScriptBuilders.

With regard to the ‘delay’ problem, a self-adjusting delay would probably be better than an error telling the user to rewrite the script! :wink:

on run
	tell application "Finder"
		set the_selection to the selection
		if (the_selection is {}) then my displayError("Sorry, nothing is selected in the Finder. Please try again.")
		if (class of item 1 of the_selection is not folder) then my displayError("The selected item is not a folder. Please try again.")
		set the_folder to POSIX path of ((item 1 of the_selection) as alias)
	end tell
	setloc(the_folder)
end run

on displayError(msg)
	tell application (path to frontmost application as Unicode text)
		display dialog msg buttons {"OK"} default button 1 with icon 2 giving up after 5
	end tell
	error number -128
end displayError

on setloc(the_folder)
	tell application "System Events" to tell process "Safari"
		tell application "Safari" to activate
		try
			click menu item "Preferences." of menu 1 of menu bar item "Safari" of menu bar 1
		on error
			my displayError("GUI scripting problem. It may not be enabled (or may not be available) on this machine.")
		end try
		click button "General" of tool bar 1 of window 1
		tell pop up button 3 of group 1 of group 1 of window "General"
			click
			click menu item "Other." of menu 1
		end tell
		keystroke "g" using {shift down, command down}
		repeat until (window "Go to Folder" exists)
			delay 0.5
		end repeat
		tell window "Go To Folder"
			set value of text field 1 to the_folder
			click button "Go"
		end tell
		click button "Select" of sheet 1 of window "General"
	end tell
end setloc

Something else to consider, in the case of a non-selection, would be to offer the user an opportunity to make the desktop the download folder…

… and, of course, in any case, to tell Safari to close window “General” at the end. :slight_smile: