Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Enable title & description. Add argparse options.

 * Title and description hardcodings were not used. Added them.
 * Add argparse and some new options:
    --title TITLE               Title for all images
    --tags TAGS                 Space-separated tags for all images
    --description DESCRIPTION   Description for all images
    --drip-feed                 Wait a bit between uploading individual images
 * Store internal files in input directory rather than execution directory so it can be run from anywhere.
 * Some minor cosmetic things
  • Loading branch information...
commit 1663f5455c5face4806ed615d1af90f22068059b 1 parent 7816703
Hugo hugovk authored
Showing with 127 additions and 86 deletions.
  1. +127 −86 uploadr/uploadr.py
213 uploadr/uploadr.py
View
@@ -32,18 +32,28 @@
"""
-import sys, time, os, urllib2, shelve, string, xmltramp, mimetools, mimetypes, hashlib, webbrowser
-
+import argparse
+import hashlib
+import mimetools
+import mimetypes
+import os
+import shelve
+import string
+import sys
+import time
+import urllib2
+import webbrowser
+import xmltramp
#
##
## Items you will want to change
-##
+##
#
# Location to scan for new images
-#
-IMAGE_DIR = "images/"
+#
+IMAGE_DIR = "images/"
#
# Flickr settings
#
@@ -54,29 +64,34 @@
"is_friend": "0",
"is_family": "0" }
#
-# How often to check for new images to upload (in seconds )
+# How often to check for new images to upload (in seconds)
#
SLEEP_TIME = 1 * 60
#
+# Only with --drip-feed option:
+# How often to wait between uploading individual images (in seconds)
+#
+DRIP_TIME = 1 * 60
+#
# File we keep the history of uploaded images in.
#
-HISTORY_FILE = "uploadr.history"
+HISTORY_FILE = os.path.join(IMAGE_DIR, "uploadr.history")
##
## You shouldn't need to modify anything below here
##
-FLICKR["api_key" ] = os.environ['FLICKR_UPLOADR_PY_API_KEY']
-FLICKR["secret" ] = os.environ['FLICKR_UPLOADR_PY_SECRET']
+FLICKR["api_key"] = os.environ['FLICKR_UPLOADR_PY_API_KEY']
+FLICKR["secret"] = os.environ['FLICKR_UPLOADR_PY_SECRET']
class APIConstants:
- """ APIConstants class
+ """ APIConstants class
"""
base = "http://flickr.com/services/"
rest = base + "rest/"
auth = base + "auth/"
upload = base + "upload/"
-
+
token = "auth_token"
secret = "secret"
key = "api_key"
@@ -84,22 +99,22 @@ class APIConstants:
frob = "frob"
perms = "perms"
method = "method"
-
+
def __init__( self ):
""" Constructor
"""
pass
-
+
api = APIConstants()
class Uploadr:
- """ Uploadr class
+ """ Uploadr class
"""
-
+
token = None
perms = ""
- TOKEN_FILE = ".flickrToken"
-
+ TOKEN_FILE = os.path.join(IMAGE_DIR, ".flickrToken")
+
def __init__( self ):
""" Constructor
"""
@@ -116,45 +131,45 @@ def signCall( self, data):
foo = ""
for a in keys:
foo += (a + data[a])
-
+
f = FLICKR[ api.secret ] + api.key + FLICKR[ api.key ] + foo
#f = api.key + FLICKR[ api.key ] + foo
return hashlib.md5( f ).hexdigest()
-
+
def urlGen( self , base,data, sig ):
""" urlGen
"""
foo = base + "?"
- for d in data:
+ for d in data:
foo += d + "=" + data[d] + "&"
return foo + api.key + "=" + FLICKR[ api.key ] + "&" + api.sig + "=" + sig
-
-
+
+
def authenticate( self ):
""" Authenticate user so we can upload images
"""
- print("Getting new Token")
+ print("Getting new token")
self.getFrob()
self.getAuthKey()
- self.getToken()
+ self.getToken()
self.cacheToken()
def getFrob( self ):
"""
flickr.auth.getFrob
-
- Returns a frob to be used during authentication. This method call must be
+
+ Returns a frob to be used during authentication. This method call must be
signed.
-
+
This method does not require authentication.
Arguments
-
+
api.key (Required)
- Your API application key. See here for more details.
+ Your API application key. See here for more details.
"""
-
- d = {
+
+ d = {
api.method : "flickr.auth.getFrob"
}
sig = self.signCall( d )
@@ -166,15 +181,15 @@ def getFrob( self ):
else:
self.reportError( response )
except:
- print (("Error getting frob:" , str( sys.exc_info() )))
+ print("Error getting frob:" + str( sys.exc_info() ))
- def getAuthKey( self ):
+ def getAuthKey( self ):
"""
Checks to see if the user has authenticated this application
"""
d = {
- api.frob : FLICKR[ api.frob ],
- api.perms : "write"
+ api.frob : FLICKR[ api.frob ],
+ api.perms : "write"
}
sig = self.signCall( d )
url = self.urlGen( api.auth, d, sig )
@@ -188,28 +203,28 @@ def getAuthKey( self ):
print("You need to allow this program to access your Flickr site.")
print("A web browser should pop open with instructions.")
print("After you have allowed access restart uploadr.py")
- sys.exit()
+ sys.exit()
def getToken( self ):
"""
http://www.flickr.com/services/api/flickr.auth.getToken.html
-
+
flickr.auth.getToken
-
+
Returns the auth token for the given frob, if one has been attached. This method call must be signed.
Authentication
-
+
This method does not require authentication.
Arguments
-
+
NTC: We need to store the token in a file so we can get it and then check it insted of
getting a new on all the time.
-
+
api.key (Required)
Your API application key. See here for more details.
frob (Required)
- The frob to check.
- """
+ The frob to check.
+ """
d = {
api.method : "flickr.auth.getToken",
@@ -228,7 +243,7 @@ def getToken( self ):
except:
print(str(sys.exc_info()))
- def getCachedToken( self ):
+ def getCachedToken( self ):
"""
Attempts to get the flickr token from disk.
"""
@@ -236,7 +251,7 @@ def getCachedToken( self ):
return open( self.TOKEN_FILE ).read()
else :
return None
-
+
def cacheToken( self ):
@@ -246,22 +261,22 @@ def cacheToken( self ):
try:
open( self.TOKEN_FILE , "w").write( str(self.token) )
except:
- print("Issue writing token to local cache " , str(sys.exc_info()))
+ print("Issue writing token to local cache ", str(sys.exc_info()))
- def checkToken( self ):
+ def checkToken( self ):
"""
flickr.auth.checkToken
Returns the credentials attached to an authentication token.
Authentication
-
+
This method does not require authentication.
Arguments
-
+
api.key (Required)
Your API application key. See here for more details.
auth_token (Required)
- The authentication token to check.
+ The authentication token to check.
"""
if ( self.token == None ):
@@ -272,9 +287,9 @@ def checkToken( self ):
api.method : "flickr.auth.checkToken"
}
sig = self.signCall( d )
- url = self.urlGen( api.rest, d, sig )
+ url = self.urlGen( api.rest, d, sig )
try:
- res = self.getResponse( url )
+ res = self.getResponse( url )
if ( self.isGood( res ) ):
self.token = res.auth.token
self.perms = res.auth.perms
@@ -284,8 +299,8 @@ def checkToken( self ):
except:
print(str(sys.exc_info()))
return False
-
-
+
+
def upload( self ):
""" upload
"""
@@ -294,10 +309,13 @@ def upload( self ):
if ( not self.checkToken() ):
self.authenticate()
self.uploaded = shelve.open( HISTORY_FILE )
- for image in newImages:
- self.uploadImage( image )
+ for i, image in enumerate( newImages ):
+ success = self.uploadImage( image )
+ if args.drip_feed and success and i != len( newImages )-1:
+ print("Waiting " + str(DRIP_TIME) + " seconds before next upload")
+ time.sleep( DRIP_TIME )
self.uploaded.close()
-
+
def grabNewImages( self ):
""" grabNewImages
"""
@@ -312,39 +330,49 @@ def grabNewImages( self ):
images.append( os.path.normpath( dirpath + "/" + f ) )
images.sort()
return images
-
-
+
+
def uploadImage( self, image ):
""" uploadImage
"""
+ success = False
if ( not self.uploaded.has_key( image ) ):
- print("Uploading ", image , "...",)
+ print("Uploading " + image + "...")
try:
photo = ('photo', image, open(image,'rb').read())
+ if args.title: # Replace
+ FLICKR["title"] = args.title
+ if args.description: # Replace
+ FLICKR["description"] = args.description
+ if args.tags: # Append
+ FLICKR["tags"] += " " + args.tags + " "
d = {
- api.token : str(self.token),
- api.perms : str(self.perms),
- "tags" : str( FLICKR["tags"] ),
- "is_public" : str( FLICKR["is_public"] ),
- "is_friend" : str( FLICKR["is_friend"] ),
- "is_family" : str( FLICKR["is_family"] )
+ api.token : str(self.token),
+ api.perms : str(self.perms),
+ "title" : str( FLICKR["title"] ),
+ "description" : str( FLICKR["description"] ),
+ "tags" : str( FLICKR["tags"] ),
+ "is_public" : str( FLICKR["is_public"] ),
+ "is_friend" : str( FLICKR["is_friend"] ),
+ "is_family" : str( FLICKR["is_family"] )
}
sig = self.signCall( d )
d[ api.sig ] = sig
- d[ api.key ] = FLICKR[ api.key ]
- url = self.build_request(api.upload, d, (photo,))
+ d[ api.key ] = FLICKR[ api.key ]
+ url = self.build_request(api.upload, d, (photo,))
xml = urllib2.urlopen( url ).read()
res = xmltramp.parse(xml)
if ( self.isGood( res ) ):
- print("successful.")
+ print("Success.")
self.logUpload( res.photoid, image )
+ success = True
else :
- print("problem..")
+ print("Problem:")
self.reportError( res )
except:
print(str(sys.exc_info()))
-
+ return success
def logUpload( self, photoID, imageName ):
""" logUpload
@@ -354,7 +382,7 @@ def logUpload( self, photoID, imageName ):
imageName = str( imageName )
self.uploaded[ imageName ] = photoID
self.uploaded[ photoID ] = imageName
-
+
def build_request(self, theurl, fields, files, txheaders=None):
"""
build_request/encode_multipart_formdata code is from www.voidspace.org.uk/atlantibots/pythonutils.html
@@ -362,7 +390,7 @@ def build_request(self, theurl, fields, files, txheaders=None):
Given the fields to set and the files to encode it returns a fully formed urllib2.Request object.
You can optionally pass in additional headers to encode into the opject. (Content-type and Content-length will be overridden if they are set).
fields is a sequence of (name, value) elements for regular form fields - or a dictionary.
- files is a sequence of (name, filename, value) elements for data to be uploaded as files.
+ files is a sequence of (name, filename, value) elements for data to be uploaded as files.
"""
content_type, body = self.encode_multipart_formdata(fields, files)
@@ -370,7 +398,7 @@ def build_request(self, theurl, fields, files, txheaders=None):
txheaders['Content-type'] = content_type
txheaders['Content-length'] = str(len(body))
- return urllib2.Request(theurl, body, txheaders)
+ return urllib2.Request(theurl, body, txheaders)
def encode_multipart_formdata(self,fields, files, BOUNDARY = '-----'+mimetools.choose_boundary()+'-----'):
""" Encodes fields and files for uploading.
@@ -378,13 +406,13 @@ def encode_multipart_formdata(self,fields, files, BOUNDARY = '-----'+mimetools.c
files is a sequence of (name, filename, value) elements for data to be uploaded as files.
Return (content_type, body) ready for urllib2.Request instance
You can optionally pass in a boundary string to use or we'll let mimetools provide one.
- """
+ """
CRLF = '\r\n'
L = []
if isinstance(fields, dict):
fields = fields.items()
- for (key, value) in fields:
+ for (key, value) in fields:
L.append('--' + BOUNDARY)
L.append('Content-Disposition: form-data; name="%s"' % key)
L.append('')
@@ -401,8 +429,8 @@ def encode_multipart_formdata(self,fields, files, BOUNDARY = '-----'+mimetools.c
body = CRLF.join(L)
content_type = 'multipart/form-data; boundary=%s' % BOUNDARY # XXX what if no files are encoded
return content_type, body
-
-
+
+
def isGood( self, res ):
""" isGood
"""
@@ -411,14 +439,14 @@ def isGood( self, res ):
return True
else :
return False
-
-
+
+
def reportError( self, res ):
""" reportError
"""
try:
- print("Error:", str( res.err('code') + " " + res.err('msg') ))
+ print("Error: " + str( res.err('code') + " " + res.err('msg') ))
except:
print("Error: " + str( res ))
@@ -429,7 +457,7 @@ def getResponse( self, url ):
xml = urllib2.urlopen( url ).read()
return xmltramp.parse( xml )
-
+
def run( self ):
""" run
@@ -437,13 +465,26 @@ def run( self ):
while ( True ):
self.upload()
- print("Last check: " , str( time.asctime(time.localtime())))
+ print("Last check: " + str( time.asctime(time.localtime())))
time.sleep( SLEEP_TIME )
-
+
if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description='Upload images to Flickr.')
+ parser.add_argument('-d', '--daemon', action='store_true',
+ help='Run forever as a daemon')
+ parser.add_argument('-i', '--title', action='store',
+ help='Title for uploaded images')
+ parser.add_argument('-e', '--description', action='store',
+ help='Description for uploaded images')
+ parser.add_argument('-t', '--tags', action='store',
+ help='Space-separated tags for uploaded images')
+ parser.add_argument('-r', '--drip-feed', action='store_true',
+ help='Wait a bit between uploading individual images')
+ args = parser.parse_args()
+
flick = Uploadr()
-
- if ( len(sys.argv) >= 2 and sys.argv[1] == "-d"):
+
+ if args.daemon:
flick.run()
else:
flick.upload()
Please sign in to comment.
Something went wrong with that request. Please try again.