# Offlickr # Hugo Haas import sys import libxml2 import urllib import getopt import time import os.path from flickrapi import FlickrAPI version = '0.1 - 2005-12-28' flickrAPIKey = '1391fcd0a9780b247cd6a101272acf71' flickrSecret = 'fd221d0336de3b6d' def usage(): print "Usage: Offlickr.py -d " print "Backs up Flickr photos and metadata" print "Options:" print "\t-f \tbeginning of the date range" print "\t\t\t(default: since you started using Flickr)" print "\t-t \tend of the date range" print "\t\t\t(default: until now)" print "\t-d \tdirectory for saving files (default: ./dst)" print "\t-p\t\tback up photos in addition to metadata" print "\t-b \tbrowser to use for authentication (default: opera)" print "\t-h\t\tthis help message" print "\nDates are specified in seconds since the Epoch (00:00:00 UTC, January 1, 1970)." print "\nVersion " + version def myReportHook(count, blockSize, totalSize): p = 100 * count * blockSize / totalSize if (p > 100): p = 100 print "\r %3d %%" % p, sys.stdout.flush() try: opts, args = getopt.getopt(sys.argv[1:], "hpb:f:t:d:i:", ["help"]) except getopt.GetoptError: usage() sys.exit(2) flickrUserId = None dateLo = '1' maxTime = '9999999999' dateHi = maxTime getPhotos = False d = 'dst' browser = 'opera' for o, a in opts: if o in ('-h', '--help'): usage() sys.exit() if o == '-i': flickrUserId = a if o == '-p': getPhotos = True if o == '-f': dateLo = a if o == '-t': dateHi = a if o == '-d': d = a if o == '-b': browser = a if flickrUserId == None: print "You need to specify a Flickr Id" sys.exit(1) if not os.path.isdir(d): print d + " is not a directory; please fix that." sys.exit(1) fapi = FlickrAPI(flickrAPIKey, flickrSecret) token = fapi.getToken(browser=browser) if dateHi == maxTime: t = time.time() print "For incremental backups, the current time is %.0f" % t print "You can rerun the program with '-f %.0f'" % t n = 0 i = 0 range = 500 # Max allowed by Flickr photos = [ ] # Get list of photos while True: n = n + 1 rsp = fapi.photos_search(api_key=flickrAPIKey, auth_token=token, user_id = flickrUserId, per_page = str(range), page = str(n), min_upload_date = dateLo, max_upload_date = dateHi) fapi.testFailure(rsp) if rsp.photos[0]['total'] == '0': print "No photos to back up" sys.exit(0) photos += rsp.photos[0].photo if len(photos) >= int(rsp.photos[0]['total']): break total = len(photos) print "Backing up" , total , "photos" for p in photos: i = i + 1 pid = str(int(p['id'])) # Making sure we don't have weird things here print str(i) + "/" + str(total) + ": " + pid + ": " + p['title'] # Get Metadata rsp = fapi.photos_getInfo(api_key=flickrAPIKey, auth_token=token, photo_id=pid) fapi.testFailure(rsp) doc = libxml2.parseDoc(rsp.xml) fn = d + '/' + pid + '.xml' f = open(fn, 'w') f.write(str(doc.xpathEval( "/rsp/photo")[0])) f.close() print 'Saved as ' + fn doc.freeDoc() # Do we want the picture too? if getPhotos == False: continue f = pid + '.' + rsp.photo[0]['originalformat'] rsp = fapi.photos_getSizes(api_key=flickrAPIKey, auth_token=token, photo_id=pid) fapi.testFailure(rsp) source = '' for s in rsp.sizes[0].size: if s['label'] == 'Original': source = s['source'] if source == '': print "Oopsie, no photo found" print 'Retrieving ' + source + ' as ' + f urllib.urlretrieve(source, d + '/' + f, reporthook=myReportHook) print "\r... done!"