Commits

Ian Dotson  committed 2542958

Initial import from psvn/proj/smugsnarf/smugsnarf.py

  • Participants

Comments (0)

Files changed (1)

File smugsnarf.py

+#!/usr/bin/python
+
+""" smugsnarf: Retrieve photos from your SmugMug account. 
+    Ian Dotson <izdotson@gmail.com>
+
+    You'll need to request an API key from Smugmug
+    (http://www.smugmug.com/hack/apikeys)
+
+    ~/.smugsnarf.conf needs these vaules defined:
+
+        [account]
+        username=yourEmailAddr@somwhere.edu
+        # smugsnarf will prompt interactively if no password is specified
+        password=letsalleatpie
+        
+        [api]
+        apikey=blah
+        apikeysecret=baz
+        
+        [sync]
+        basedir=/nfs/lasercats15/smugmug-bu
+
+    TODO:   . Clean filenames to remove path seperators, etc.
+            . Implement md5sum checking
+            . Config file for apikey, etc
+            . Opt parsing
+    BUGS:   . No attempt is made to prevent downloading photos which appear in
+    multiple albums (via collections, etc.) multiple times.
+
+    """
+
+import os
+import sys
+import inspect
+import smugpy
+import requests
+import ConfigParser
+from getpass import getpass
+
+DEBUG = True
+
+
+def dprint(message):
+    """If DEBUG is set, print the supplied message prepended with the name of
+    the calling function."""
+
+    caller = inspect.getframeinfo(inspect.currentframe().f_back)[2]
+    if DEBUG: print ('%s: %s' %(caller, message))
+
+def get_albums(sm):
+    """Return a list of all available albums."""
+    
+    return sm.albums_get()['Albums']
+
+def get_images(sm, AlbumID, AlbumKey):
+    """Return a list of all images in a given album."""
+
+    dprint('%s %s' % (AlbumID, AlbumKey))
+
+    # Note that SmugMug's API allows us to request additional properties here
+    # via 'Extras', which saves us extra calls to images.getInfo
+    return sm.images_get(AlbumID=AlbumID, AlbumKey=AlbumKey,
+                         Extras='OriginalURL,FileName,Size')['Album']['Images']
+
+def dl_image(image, albumdir):
+    """Download the given image to albumdir."""
+
+    # Smugmug assigns every image an id and key. Build a unique but somewhat
+    # friendly localfilename by sticking id, key and the file's orignial name
+    # when uploaded
+    filename = '%s/%s:%s:%s' % (albumdir, image['id'], image['Key'], image['FileName'])
+
+    # SmugMug gives us OringialURL, a location where we can retrieve the image
+    url = image['OriginalURL']
+
+    # Only download the image if we haven't already retrieved it. If the file
+    # exists and is of the same size that SmugMug reports, skip downloading it.
+    smsize = image['Size'] # This is SmugMug's reported file size
+    if os.path.exists(filename):
+        localsize = os.path.getsize(filename)
+    else:
+        localsize = None
+
+    dprint ('Filename %s\ndl_image: URL: %s' % (filename, url))
+    dprint ('SMSize/LocalSize: %s/%s' % (smsize, localsize))
+
+    if smsize == localsize: # File exists and is of the correct size
+        dprint('Skipping %s, already retrieved with size %s.' %
+               (filename, smsize))
+    else:
+        dprint('Retrieving %s, size %s' % (filename, smsize))
+        file = open(filename, 'wb+')
+        r = requests.get(url)
+        file.write(r.content)
+        file.close()
+    
+
+def sync_albums(sm, basedir):
+    """Download every image in every album of a given SmugMug account."""
+
+    if not os.path.isdir(basedir):
+        print 'basedir: %s does not exist or isn\'t a directory.' % basedir
+        sys.exit(1)
+    albums = get_albums(sm)
+    for album in albums:
+        # Each album is downloaded into a directory of the form
+        # /basedir/almubid:albmuKey
+        albumdir = '%s/%d:%s' % (basedir, album['id'], album['Key'])
+        if not os.path.isdir(albumdir):
+            os.mkdir(albumdir)
+
+        # Store album metadata for each album in 'albuminfo' in case we need it
+        # at some point. This includes its name and category
+        # (http://wiki.smugmug.net/display/API/show+1.2.2?method=smugmug.albums.get)
+        albuminfofile = open(albumdir + '/albuminfo', 'w+')
+        albuminfofile.write(str(album))
+        albuminfofile.close()
+
+        images = get_images(sm, album['id'], album['Key'],)
+        for image in images:
+            dl_image(image, albumdir)
+
+def parseconfig():
+    config = ConfigParser.ConfigParser()
+    config.read(os.path.expanduser('~/.smugsnarf.conf'))
+    return config
+
+
+def main():
+    config = parseconfig()
+    username= config.get('account','username')
+    if not config.has_option('account','password'):
+        password = getpass('Enter SmugMug password for %s: ' % username)
+    else:
+        password = config.get('account','password')  
+    apikey, apikeysecret = config.get('api', 'apikey'), config.get('api',
+                                                                   'apikeysecret')
+    basedir = config.get('sync', 'basedir')
+
+    sm = smugpy.SmugMug(api_key=apikey, api_version="1.2.2", app_name='smugsync')
+    sm.login_withPassword(EmailAddress=username, Password=password)
+    sync_albums(sm, basedir)
+
+if __name__ == '__main__':
+    main()
+