A 'Copy Public Link' Menu Item for iDisk
Author: Drew McCormack
Web Site: www.macflashcards.com
I’ve been using Dropbox now for a month or so, and I’ve found it a very useful tool for syncing and sharing files. It’s free, so give it a shot.
One of my favorite features is an obscure contextual menu: if you right click on a file in the Public folder of your Dropbox, there is an item called ‘Copy public link’. This makes it trivially easy to share a file with anyone. You just copy the file to the Public folder, use the contextual menu to copy the link, and paste the link in an email. This very simple piece of functionality makes my life so much easier.
Apple seem to have cottoned on to it too, because yesterday they announced a new feature which allows you to generate a public link for a file on your iDisk. While this is welcome, it still requires you to open the MobileMe web app, which is one step too many in my view. So I guess we have to wait for Snow Leopard to see the feature supported in Finder…or do we?
There really is no reason you can’t generate public links for iDisk via Finder to mimic the way Dropbox does it. All you need to do is convert the local file path into the appropriate URL for the file online. It’s not rocket science, so I took a shot at it using Automator. The rest of this post will be about how you can install the Automator workflow I came up in order to make use of the ‘Copy Public Link’ menu item. I’ll also delve into the code a little to show you how it works.
Installing the Workflow
First, download the workflow and unpack the zip file. You’ll need to open the workflow in Automator, and change one variable: the MobileMe user name. I couldn’t figure out how to determine the MobileMe user name automatically, but it’s not a big deal; set it once, and you’re done. Here’s how: Locate the second stage of the pipeline on the right side of the window.

Now change the following line, inserting your MobileMe user name between the quotation marks.
mobileMeUser = '<enter mobile me user name>'
If your MobileMe email address is davedook12345@me.com, enter ‘davedook12345’ as the user name. Save and quit Automator.
To install the workflow so that it appears in Finder, drag it into this directory
~/Library/Workflows/Applications/Finder
You’ll probably need to create this directory yourself, as well as any ancestors that don’t already exist.
With the workflow installed, you should be able to select a file in the Public folder of your iDisk, right click on it, drill down through the More and Automator sub-menus, and select ‘Copy Public Link’. This should put the public link on the clipboard for pasting into emails or other documents.
How Does it Work?
The workflow is quite straightforward. The first stage simply gets the selected files from the Finder. The second stage is a Python script that takes the first file passed in and converts that to a URL corresponding to the file on the iDisk.
#!/usr/bin/python
import string, sys, urllib, os
mobileMeUser = '<enter mobile me user name>'
# Define local directory of file relative to Public folder
# Ie., strip /Volumes/<username>/Public
components = string.split(sys.argv[1], os.sep)
localDir = string.join( components[4:], os.sep )
# Percent escape file path
localDir = urllib.quote(localDir)
# Construct url
remoteURL = 'http://idisk.mac.com/%s-Public/%s' % ( mobileMeUser, localDir )
# Put on pasteboard
os.system( "echo '%s' | pbcopy" % (remoteURL) )
You could do this type of path massaging with any number of tools, including straight up bash scripting, but I prefer the simplicity and power of Python.
The script begins by stripping off the components of the file path in the local file system that lead up to the Public directory. It then takes the remainder of the path, processes it with the urllib module to add percent escapes for spaces and other characters not allowed in URLs, and finally appends this path to the end of the root iDisk address for the user’s public directory. The last line uses the command pbcopy to put this URL string on the pasteboard.



Comments
Updated version--also copies/zips the file
I have made an updated version of Drew's script which will also copy the file to your public folder on iDisk before generating the URL. If the file is a folder, the script will zip it as well. I'm not much of python scripter (I STRONGLY prefer Perl and shell scripting) but I kept it in python to maintain consistency. Due to my limited python skills, there may well be a better way to accomplish what I have done. Updates are certainly welcome.
One caveat is that the script doesn't seem to be working on files with spaces in their names. I never use spaces in filenames (a bag of hurt, in my opinion), so I may not get around to figuring out how to fix it in python. If someone knows how, by all means please post an update.
Cheers
The lines below the code "if os.path.isdir(localFile) == False:" and "else:" should be indented to follow with python syntax. I can't seem to get it to format properly above.
Brilliant
Just what I wanted.
Missing bits?
First of all, here's how you get rid of spaces:
remoteURL = 'http://public.me.com/%s/%s' % ( mobileMeUser, localFile.replace(" ","%20" ) )
Note that I replaced the mac.com by me.com, and "-Public" has gone. The MobileMe preference pane said that that's how I had to access the iDisk.
But I'm still not there: the actual file is not showing up. And that does not depend on how I make that remoteURL.
The console log shows:
2/16/09 6:00:07 AM Automator Runner[6619] CFPropertyListCreateFromXMLData(): Old-style plist parser: missing semicolon in dictionary.
which I don't understand.
Anyone any suggestions?
Victor.
Applescript version
I've created an applescript version.
The first part of the script asks you to select a file, the next part uses a shell script to compresses it to a zip file if it is not already zipped. It then gets the mobileme name and then copies the zipped file to the Public folder of your mobilme (.dot mac) account. The final part of the script creates the email that you need to send to the intended recipient.
I changed the copy command... now it works for me.
When I changed the copy command, the copying worked for me. I set the first argument to the full path of the file, not only the file name.
The copy command within the if statement reads now like this:
os.system ( "cp %s %s" % (sys.argv[1], localMobileMeFile) )
Haven't yet thought if/what this would mean to the folder/zipping part.
Is there a reason why not to work with os.path rather than strings?
However, I am not overly impressed how fast or smooth this goes...
The grand scheme of this is not so bad... :-)
Cheers,
Claus
Some Responses
Some general responses:
1) To handle spaces in the URL, use urllib:
This adds the percent escapes you need.
2) I started using os.path, but found it couldn't quite do what I needed. In the end, the string methods turned out to be more compact.
3) Be careful when using paths in shell commands. Best to quote them in case they have spaces:
drew
---------------------------
Drew McCormack
http://www.maccoremac.com
http://www.macanics.net
http://www.macresearch.org
Mobile Me User
By the way, does anyone know how to get the mobile me user name? Perhaps with AppleScript?
Drew
---------------------------
Drew McCormack
http://www.maccoremac.com
http://www.macanics.net
http://www.macresearch.org
Mobile Me User
The only way I could think of was to assume they had a mac mail account and use applescript.
Details in the applescript version I posted.
Mobile Me User
Details should also be in the mail preferences if you fancy digging through that.
Thanks!
Thanks drc. I was thinking that Applescript would be my preferred way to go here because the email message could be readily created this way. (There might be a way to do this in python too but I certainly don't know how.)
I an not really a fan of hunting for the buried Automater action menu, found in a submenu of a submenu... There are a couple of alternative options of which I am aware:
1. A wonderful utility by YellowMug Software called FileChute will take care of the actions in this script and more. There is also a free application for the iPhone that allows you to resend links. More info: http://www.yellowmug.com/filechute/
2. Any of these scripts could be packaged into an application by the excellent program Platypus. You can even make the application droppable so all you have to do is drop your files on it. More info: http://www.sveinbjorn.org/platypus
(You can also make programs directly with Applescript, of course.)
3. There is a contextual menu creation program called OnMyCommand that affords more (and better, IMHO) control over contextual menu items. It works well with scripts of all kinds. More info: http://free.abracode.com/cmworkshop/on_my_command.html
The last two items are freeware/donationware. FileChute is $18.
I was inspired and did a
I was inspired and did a little more fiddling with the applescript drc posted. It is now dropable (as in you can drop things on it to run the program) and it will take any number of files and/or folders. If a folder or if more than one item is dropped on it, it will zip them automatically. It will also handle Dropbox (if you have an account). Further details are provided in the script.
on open droppedFiles
-- insert your mobileMe username here
set mobileMeName to "your_mobileMe_username"
-- insert your Dropbox username here, or leave blank if you do not have Dropbox
set dropboxName to ""
-- NOTES
-- You can determine your Drobbox username (usually a string of numbers) by copying a file to your
-- Dropbox public folder and then right clicking on the file to get to the "Copy Public Link..." command.
-- This link will be of the form "http://dl.getdropbox.com/u//.
-- The portion you want for your dropboxName is .
-- When finished, save this file as an Application or Application Bundle and drop files/folders on it to run.
-- It WILL NOT work when saved as a script due to the "on open" command.
-- Once you save as an Application Bundle, you WILL NOT be able to edit the program, so keep a text backup.
-- You can put the program in your Dock or on your desktop. You can even change the icon, to one perhaps that
-- resembles mobileMe :) by replacing the file in the Application Bundle that is located at
-- .app/Contents/Resources/droplet.icns with another *.icns file
-- This program was insipired (and borrows from) an applescript posted here:
-- http://homepage.mac.com/swain/Macinchem/Applescript/mobileme_script.htm
-- Further information: http://www.macresearch.org/copy-public-link-menu-item-idisk
-- YOU SHOULD NOT NEED TO EDIT ANYTHING BELOW THIS LINE
set nFiles to 0
set nFolders to 0
set pathList to ""
-- build up list of all paths, determine if they're files or folders
repeat with aFile in droppedFiles
set filePath to POSIX path of (aFile as text)
set pathList to pathList & " " & filePath
if folder of (info for aFile) then
set nFolders to nFolders + 1
else
set nFiles to nFiles + 1
end if
end repeat
set nItems to nFiles + nFolders
-- set default name for files, separate file name from extension
if ((nItems > 1) or (nFolders > 0)) then
set defaultName to "Files"
set fileExtension to "zip"
else
set the fileInfo to the info for droppedFiles
set defaultFullName to the name of fileInfo
-- get the base name of the file
do shell script "echo \"" & defaultFullName & "\" | /usr/bin/sed 's/\\..*//'"
set defaultName to the result
-- get the file extension
do shell script "echo \"" & defaultFullName & "\" | /usr/bin/sed 's/.*\\.//'"
set fileExtension to the result
end if
-- determine if we're using mobileMe or DropBox
if dropboxName is not equal to "" then
display dialog "Enter a name for the group of files:" default answer defaultName buttons {"mobileMe", "Dropbox"}
else
display dialog "Enter a name for the group of files:" default answer defaultName
end if
-- TODO: shoud probably check for empty filename here
set dialogInfo to result
set fileName to text returned of dialogInfo
if dropboxName is not equal to "" then
set sendMethod to button returned of dialogInfo
else
set sendMethod to "mobileMe"
end if
-- setup localPath and linkPath depending on method used
if sendMethod is equal to "mobileMe" then
set localPath to "/Volumes/" & mobileMeName & "/Public" & "/" & fileName & "." & fileExtension
set linkPath to "http://public.me.com/" & mobileMeName & "/" & fileName & "." & fileExtension
else
do shell script "/usr/bin/whoami"
set shortName to the result
set localPath to "/Users/" & shortName & "/Dropbox/Public" & "/" & fileName & "." & fileExtension
set linkPath to "http://dl.getdropbox.com/u/" & dropboxName & "/" & fileName & "." & fileExtension
end if
-- zip if multiple files, otherwise copy to local path
if ((nFolders > 0) or (nItems > 1)) then
do shell script "/usr/bin/zip -r -j " & localPath & pathList
else
do shell script "/bin/cp" & pathList & " " & localPath
end if
-- generate email
tell application "Mail"
activate
make new outgoing message with properties {visible:true, subject:"Download link for " & fileName, content:"
You can download the file from this link: " & linkPath & "
"}
end tell
end open
I forgot to mention that
I forgot to mention that this DOES NOT work with spaces in filenames. I think you would have to escape and/or quote the pathList and localPath variables. For the linkPath, I am less certain of what needs to be done.
Spaces in filenames
Try putting the paths in single quotes e.g.
set localPath to "'/Users/" & shortName & "/Dropbox/Public" & "/" & fileName & "." & fileExtension & "'"
Thanks drc. I figured it was
Thanks drc. I figured it was something like that, but I doubt I'll have the time to mess with it in the near future. My strict "no spaces in filenames" policy limits my motivation to do so since I also have plenty of real work to do today. :)
I also noticed that two of the comment lines were eaten by the HTML tagging. These two lines:
-- This link will be of the form "http://dl.getdropbox.com/u//.
-- The portion you want for your dropboxName is .
should read:
-- This link will be of the form "http://dl.getdropbox.com/u/_some_number_/_file_name_.
-- The portion you want for your dropboxName is _some_number_.
FileChute available for 50% this weekend only (March 14th-15th)
For anyone interested in a more full-featured solution than the various scripts posted above, FileChute is on sale this weekend for 50% off. This already affordable program is a mere $8.95 from MacZOT (http://maczot.com).
Soooo....
Has a (final) script or whatever been created for this? I would really like to get this to work in my Snow Leopard services menu, but am at a loss on how to get these to run in it.
Thanks!!!