Python FTP Uploader in right click menu
Filed under: Python
This tutorial will show you an example of how I’ve been using Python to make my life easier and make my computer do what I want. Here we’re going to add an option to the right click menu to upload a file to your FTP storage. Like so:

I’ve been using Python for a while now and have come to love it. The language is very intuitive, and most of the time I know exactly how to do things which I’ve never done before; because they’re done in the most intuitive way. It’s very good when it comes to doing little tasks quickly. For example I have scripts that watch the household internet usage, or fetch a live proxy server list for me, or crawl image boards to make slideshows. I think this upload function is the most handy thing I made thusfar, so I thought it’ll be nice to share. I think everyone who regularily puts pictures on their site to show to others knows how annoying it is to be whipping out the ftp client just for that.
This is probably going to be my first actual tutorial. Ever. Lets see how I go!
For the actual upload, we want it to be quiet and unobtrusive because this isn’t a full blown app, its a little script that’ll sit in your right click menu. Python’s FTPLib has great documentation here but it’s so straightforward that we don’t even really need it beyond the example. Lets try to get a connection to our server going.
[python]
from ftplib import FTP
import os, sys, webbrowser
server = ‘ftp.blah.com’
username = ‘joe’
password = ‘password’
ftp = FTP(server)
ftp.login(username, password)
ftp.retrlines(‘LIST’)
ftp.close()
[/python]
Replace the details with your own and hit F5. Assuming the connection goes through, you’ll get a printout of your ftp root folder. If not, an exception will be thrown, most likley saying that the authentication failed. That means your details are wrong.
Anyway, now we have our basic connection, lets move on to the actual script to upload a file. Since this is a script and not a gui app, it’ll receive the name of the file to upload as a program parameter. In python we have sys.argv for that.
[python]
import sys
print “Params: “+str(len(sys.argv)) #the number of params
print sys.argv #the entire list of params
print sys.argv[0] #the first param (path to this prog)
print “Press enter”
raw_input(“”) #inputs a string, but here just acts as a ‘wait for enter’
[/python]
You can try make a new script for that. Save it somwhere and hop over to it in explorer. If you run>cmd and drag the script into the command promt, you can now give it parameters by appending things after its filename.
Nifty, isn’t it. Now lets put it all together into one big upload script. Here’s mine.
[python]
from ftplib import FTP
import os, sys, webbrowser
website_url = “http://messy-mind.net/”
server = ‘ftp.messy-mind.net’
username = ‘lalala’
password = ‘tralala’
#if we have two arguments (the second being the file to upload)
if len(sys.argv) == 2:
remote_folder = “temporary” #this is the folder I want to put my files on the server
fname = sys.argv[1] #this is the second param, the file to upload
name = os.path.basename(fname) #fetch the filename alone for the remote name
name = name.replace(” “,”-”) #take out spaces from the name to make it nice for the web
#Connect to server
ftp = FTP(server)
ftp.login(username, password)
ftp.cwd(‘public_html/’+remote_folder) #hop to remote_folder
ftp.retrlines(‘LIST’) #print out a dir listing for good measure
#Upload the file to the server
print “Uploading…”,
ftp.storbinary(“STOR “+name, open(fname,”rb”))
ftp.close()
print “Done!”
#Show the file in the default browser
webbrowser.open(website_url+remote_folder+”/”+name)
else:
print “No filename given”
[/python]
That’s it! The comments should be enough to make sense of it all. Drop it into cmd and pass on a file. You should get something like this and then your browser should pop up showing what you just uploaded.
Now for the second part; getting this into the right click menu. We’ll be messing around with registry so I’m just going to give you the functions I wrote up with no intermediate steps so there’s no room for you to screw up and kill your windows install or something.
The idea is that windows registry has a place where you can put your own right click function and associate it with a program. The only problem I ran into is that windows doesn’t allow you to associate with .py scripts and stubbornly demands exe. So I wrote a little program called runner which simply executes a given script and passes params on to it. Here is the framework to allow a script to register itself as a right click item
[python]
import sys, os
from _winreg import *
def register(command_name,association=sys.argv[0],runner=”runner.exe”):
association = os.path.realpath(association)
runner = os.path.realpath(runner)
if not os.path.isfile(runner):
print “Runder does not exist at “+runner
return 0
try:
reg = CreateKey(HKEY_CLASSES_ROOT,”*\\Shell\\”+command_name+”\\Command”)
runner_path = runner.replace(“\\”,”\\\\”)
association_path = association.replace(“\\”,”\\\\”)
key = runner_path + ” ” +association_path + ” %1″
print command_name+” :: “+key
SetValue(reg, “”, REG_SZ, key)
CloseKey(reg)
except:
print “Failed to set registry”
def unregister(command_name):
try:
if command_name==”":
return 0 #don’t allow everything under shell to be deleted
DeleteKey(HKEY_CLASSES_ROOT,”*\\Shell\\”+command_name+”\\Command”)
DeleteKey(HKEY_CLASSES_ROOT,”*\\Shell\\”+command_name)
print (“Deleted HKEY_CLASSES_ROOT\\”+”*\\Shell\\”+command_name)
except:
print “Command “+command_name+” was not registered”
command_name = “Test”
if len(sys.argv)==1:
register(command_name)
if len(sys.argv)==2:
if sys.argv[1] == “-unreg”:
unregister(command_name)
raw_input(“”)
sys.exit()
print sys.argv
raw_input(“”)
[/python]
If you download the Python script runner and throw it into the same folder as that script, running the script will result in ‘Test’ being added to the right click menu on any file. Running the script and passing -unreg as a parameter will take that back off. You can use this framework to add any option that does anything.
Putting it all together.
Now we know how to upload and how to stick things into the right click menu. It’s just a matter of taking the context menu framework and extending it with the upload function. Here’s mine.
[python]
import sys, os
from _winreg import *
from ftplib import FTP
import webbrowser
website_url = “http://gear.64digits.com/”
server = ‘ftp.gear.64digits.com’
username = ‘lalala’
password = ‘tralala’
def upload(fname):
remote_folder = “temporary” #this if the folder I want to put my files on the server
name = os.path.basename(fname) #fetch the filename alone for the remote name
name = name.replace(” “,”-”) #take out spaces from the name to make it nice for the web
#Connect to server
ftp = FTP(server)
ftp.login(username, password)
ftp.cwd(‘public_html/’+remote_folder) #hop to remote_folder
ftp.retrlines(‘LIST’) #print out a dir listing for good measure
#Upload the file to the server
print “Uploading…”,
ftp.storbinary(“STOR “+name, open(fname,”rb”))
ftp.close()
print “Done!”
#Show the file in the default browser
webbrowser.open(website_url+remote_folder+”/”+name)
def register(command_name,association=sys.argv[0],runner=”runner.exe”):
#The params are:
#name to register as, this shows in in the right click menu for all files
#the script to associate it with (defaults to this script)
#the location of the runner (defaults to runner.exe in same place as script)
association = os.path.realpath(association)
runner = os.path.realpath(runner)
if not os.path.isfile(runner):
print “Runder does not exist at “+runner
return 0
try:
reg = CreateKey(HKEY_CLASSES_ROOT,”*\\Shell\\”+command_name+”\\Command”)
runner_path = runner.replace(“\\”,”\\\\”)
association_path = association.replace(“\\”,”\\\\”)
key = runner_path + ” ” +association_path + ” %1″
print command_name+” :: “+key
SetValue(reg, “”, REG_SZ, key)
CloseKey(reg)
except:
print “Failed to set registry”
def unregister(command_name):
#the param is the name of the command
try:
if command_name==”":
return 0 #don’t allow everything under shell to be deleted
DeleteKey(HKEY_CLASSES_ROOT,”*\\Shell\\”+command_name+”\\Command”)
DeleteKey(HKEY_CLASSES_ROOT,”*\\Shell\\”+command_name)
print (“Deleted HKEY_CLASSES_ROOT\\”+”*\\Shell\\”+command_name)
except:
print “Command “+command_name+” was not registered”
command_name = “Upload”
#If no arguments are given, register ourselves
if len(sys.argv)==1:
register(command_name)
#Otherwise unregister if the command is -unreg, or otherwise do whatever we want
if len(sys.argv)==2:
if sys.argv[1] == “-unreg”:
unregister(command_name)
sys.exit()
#At this point we can call functions to operate on the param given
#which is the name of the file that was right clicked
upload(sys.argv[1])
[/python]
We’re done! Stick that script somwhere, make sure runner.exe resides in the same folder, and run the script to have it register itself under Upload. Last but not least, after you’re done with a script and want to use it, you’ll want to prevent it from opening up the dos prompt window. To do that, just rename it from .py into .pyw which is the format for gui apps, only we’re not using any gui functionality. Of course you’ll then want to run the .pyw to have it register itself in the menu, overwriting the previous .py reference.
Well, that’s all. I hope that wasn’t too terrible. You can use the framework here to do anything you want with a file through right click. Personally for me the upload function is wonderful. No waiting for stupid imageshack, no whipping out ftp client. Just click and a few seconds later its already in your browser! You might want to look into things like adding a system tray icon to display the progress, and perhaps support for uploading entire folders. One thing I wanted to do was to put the uploaded url into clipboard, but I haven’t been able to find a Python library that claims to do this and actually works.
Here is the finished product.
Just unzip to a premanent location, open it in notepad to put in your FTP details, and run the .pyw script so the Upload option will appear in right click menu. If you need to get rid of it, run uploader.pyw -unreg
And I’m in no way responsible for any damage you might do to your computer while messing around with this. The registry functions are pretty safe but editing them can result in big damage.







October 7th, 2007 at 4:06 pm
Pretty useful, although I’d have to go through an entirely different process altogether to add it to my right-click menus. Anyways, kudos to the work you’ve done here.
I’m more of a sucker for PERL, though. Ha. Anyways. Yeah.
Good job.
October 7th, 2007 at 7:25 pm
Oh, PS: Assuming anyone wants to translate this to, say, Linux, with the KDE environment, I cooked up a quick thing for that. Basically, you want to do the same thing, except you don’t have to fuck around with the registry. Do this instead:
Create a file named http://ftp.desktop, and copy it to ~/.kde/share/apps/konqueror/servicemenus/ (if that directory doesn’t exist, make it.)
The contents of the file should be:
[Desktop Entry]
ServicesType=all/all
Actions=ftpSend
[Desktop Action ftpSend]
Name=FTP to your site
Exec=python /path/to/uploader.py filename
And assuming you want to get rid of it, it’s quite simple:
rm ~/.kde/share/apps/konqueror/servicemenus/ftp.desktop
And so you have it. You might have to modify some of the code to fix it for Linux, but the idea is the same.
October 7th, 2007 at 7:28 pm
Er, revision of the previous comment, the Exec line is wrong.
It should be:
Exec=/python /path/to/uploader.py %f
February 11th, 2008 at 10:55 pm
I just wanted to point out the end product download has changed with the new domain, and is found at http://www.messy-mind.net/blog/wp-content/uploads/2007/10/uploader.zip instead. I’m sure this applies for other downloads as well.
October 14th, 2008 at 5:02 pm
You use Windows?
It makes me sick.
*barfing noises*
November 7th, 2008 at 9:55 am
Nice tutorial, exactly what I was looking for. A bit better support to show the Python code would have been nice though.