def get(self): """Fuction to handle GET requests.""" html = xhtml.HTML(self) # Fetch the application settings prefs = AppPrefs().fetch() # Check to see if the user preferences object has anything of value in it if not getattr(prefs, "api_key"): self.redirect("/static/unconfig.html") return if getattr(prefs, "category"): self.redirect("/category/%s" % prefs.category) return html.header(prefs.title) # So far, so good. Try connecting to SmugMug. try: smugmug = SmugMug(api_key=prefs.api_key, api_version="1.3.0", app_name=prefs.app_name) categories = smugmug.categories_get(NickName=prefs.nickname) albums = smugmug.albums_get(NickName=prefs.nickname) except Exception, e: # Hmmm... something's not right. self.response.out.write("There was a problem connecting to SmugMug: %s" % e) return
def __init__(self, api_key, gallery, link_type, nickname): self.smugmug = SmugMug(api_key=api_key, api_version="1.3.0", app_name="TwiMug") self.gallery = gallery self.link_type = link_type self.nickname = nickname
def __init__(self, api_key, email=None, password=None): self.api_key = api_key self.email = email self.password = password self.smugmug = SmugMug(api_key=api_key, api_version="1.2.2", app_name="SmugLine") self.login() self.md5_sums = {}
class TestApiImageUploadOauth(unittest.TestCase): def setUp(self): self.smugmug = SmugMug(api_key=API_KEY, api_version='1.3.0', app_name='TestApp', oauth_secret=OAUTH_SECRET) def test_image_upload_oauth(self): self.smugmug.set_oauth_token('ABC','123') rsp = self.smugmug.images_upload(File='tests/smuggy.jpg', AlbumID=1234) self.assertEqual(rsp['method'], 'smugmug.images.upload') self.smugmug.reset_auth()
def __init__(self, api_key=None, email=None, password=None): """initalize class""" self.api_key = api_key self.email = email self.password = password # using the old API (1.2.2), which is easier to use for one shot scripts (avoids OAuth) self.smugmug = SmugMug(api_key=options.api_key, api_version="1.2.2", app_name=__script_name__) # login self.smugmug.login_withPassword(EmailAddress=options.email, Password=options.password)
def _smugmugOauthRequestToken(self, access="Public", perm="Read"): smugmug = SmugMug(api_key=self.api_key, oauth_secret=self.oauth_secret, app_name=self.app_name) # Get a token that is short-lived (probably about 5 minutes) and can be used # only to setup authorization at SmugMug response = smugmug.auth_getRequestToken() # Get the URL that the user must visit to authorize this app (implicilty includes the request token in the URL) url = smugmug.authorize(access=access, perm=perm) return url, response['Auth'] # (should contain a 'Token')
class TestLogin130(unittest.TestCase): def setUp(self): self.smugmug = SmugMug(api_key=API_KEY, api_version='1.3.0', app_name='TestApp') def test_login_anonymously(self): if sys.version_info < (2, 7): self.assertRaises(SmugMugException, lambda: self.smugmug.login_anonymously()) else: with self.assertRaises(SmugMugException): self.smugmug.login_anonymously() def test_login_withHash(self): if sys.version_info < (2, 7): self.assertRaises( SmugMugException, lambda: self.smugmug.login_withHash(UserID='test', PasswordHash='ABCDE')) else: with self.assertRaises(SmugMugException): self.smugmug.login_withHash(UserID='test', PasswordHash='ABCDE') def test_login_withPassword(self): if sys.version_info < (2, 7): self.assertRaises( SmugMugException, lambda: self.smugmug.login_withPassword( EmailAddress='*****@*****.**', Password='******')) else: with self.assertRaises(SmugMugException): self.smugmug.login_withPassword( EmailAddress='*****@*****.**', Password='******')
class TestOauth(unittest.TestCase): def setUp(self): self.smugmug = SmugMug(api_key=API_KEY, api_version='1.3.0', app_name='TestApp', oauth_secret=OAUTH_SECRET) def test_get_request_token(self): self.smugmug.auth_getRequestToken() self.assertNotEqual(self.smugmug.oauth_token, None) self.assertNotEqual(self.smugmug.oauth_token_secret, None) self.smugmug.reset_auth() def test_get_access_token(self): self.smugmug.auth_getAccessToken() self.assertNotEqual(self.smugmug.oauth_token, None) self.assertNotEqual(self.smugmug.oauth_token_secret, None) self.smugmug.reset_auth() def test_request_signature(self): url = 'http://api.smugmug.com/services/api/json/' parameters = dict( method = 'smugmug.albums.get', NickName = 'williams' ) timestamp = 1341423551 nonce = 'b7cdabcabc3c4f7f91508da3bca9798f' signed_args = self.smugmug._get_oauth_request_params(url=url, parameters=parameters, method='POST', timestamp=timestamp, nonce=nonce) self.assertEqual(signed_args['oauth_signature'], 'f++GOXf9BhSVhGy1dxGSbmaA0ng=')
def smug_init(): smugmug = SmugMug(api_key=settings['smugmug']['api_key'],\ oauth_secret=settings['smugmug']['oauth_secret'],\ app_name=settings['smugmug']['app']) oauth_token_id = settings['smugmug']['oauth_token_id'] oauth_token_secret = settings['smugmug']['oauth_token_secret'] smugmug.set_oauth_token(oauth_token_id, oauth_token_secret) return smugmug
def test_oauth_not_supported(self): if sys.version_info < (2, 7): self.assertRaises( SmugMugException, lambda: SmugMug(api_key=API_KEY, oauth_secret=OAUTH_SECRET, api_version="1.2.0")) else: with self.assertRaises(SmugMugException): SmugMug(api_key=API_KEY, oauth_secret=OAUTH_SECRET, api_version="1.2.0")
class TestApiImageUploadOauth(unittest.TestCase): def setUp(self): self.smugmug = SmugMug(api_key=API_KEY, api_version='1.3.0', app_name='TestApp', oauth_secret=OAUTH_SECRET) def test_image_upload_oauth(self): self.smugmug.set_oauth_token('ABC', '123') rsp = self.smugmug.images_upload(File='tests/smuggy.jpg', AlbumID=1234) self.assertEqual(rsp['method'], 'smugmug.images.upload') self.smugmug.reset_auth()
def __init__(self, api_key=None, email=None, password=None): if api_key is None: self.api_key = os.environ.get('SMUGMUG_API', None) else: self.api_key = api_key self.email = email self.password = password self.smugmug = SmugMug(api_key=self.api_key, api_version="1.2.2", app_name="SmugLine") self.login() self.md5_sums = {}
def smugmugOauthRequestToken(access="Public", perm="Read"): smugmug = SmugMug(api_key=API_KEY, oauth_secret=OAUTH_SECRET, app_name=APP_NAME) # Get a token that is short-lived (probably about 5 minutes) and can be used # only to setup authorization at SmugMug response = smugmug.auth_getRequestToken() # Get the URL that the user must visit to authorize this app (implicilty includes the request token in the URL) url = smugmug.authorize(access=access, perm=perm) return url, response['Auth'] # (should contain a 'Token')
def login(verbose): if verbose: print "LOGGING IN..." smugmug = SmugMug(api_key=login_info.API_KEY, api_version="1.2.2", app_name="CrimsonStore") smugmug.login_withPassword(EmailAddress=login_info.USER_NAME, Password=login_info.PASSWORD) if verbose: print "LOGGED IN\n" return smugmug
def smugmugOauthGetAccessToken(requestToken): # Use the request token to log in (which should be authorized now) smugmug = SmugMug(api_key=API_KEY, oauth_secret=OAUTH_SECRET, oauth_token=requestToken['Token']['id'], oauth_token_secret=requestToken['Token']['Secret'], app_name=APP_NAME) # The request token is good for 1 operation: to get an access token. response = smugmug.auth_getRequestToken() # The access token should be good until the user explicitly # disables it at smugmug.com in their settings panel. return response['Auth'];
def smugmugOauthGetAccessToken(requestToken): # Use the request token to log in (which should be authorized now) smugmug = SmugMug(api_key=API_KEY, oauth_secret=OAUTH_SECRET, oauth_token=requestToken['Token']['id'], oauth_token_secret=requestToken['Token']['Secret'], app_name=APP_NAME) # The request token is good for 1 operation: to get an access token. response = smugmug.auth_getRequestToken() # The access token should be good until the user explicitly # disables it at smugmug.com in their settings panel. return response['Auth']
def smug_init(): smugmug = SmugMug(api_key=settings['smugmug']['api_key'],\ oauth_secret=settings['smugmug']['oauth_secret'],\ app_name=settings['smugmug']['app']) #oauth handshake #smugmug.auth_getRequestToken() #raw_input("Authorize app at %s\n" % (smugmug.authorize(access="Full"))) #result = smugmug.auth_getAccessToken() oauth_token_id = settings['smugmug']['oauth_token_id'] oauth_token_secret = settings['smugmug']['oauth_token_secret'] smugmug.set_oauth_token(oauth_token_id, oauth_token_secret) return smugmug
class TestApi130(unittest.TestCase): def setUp(self): self.smugmug = SmugMug(api_key=API_KEY, api_version='1.3.0', app_name='TestApp') def test_anonymous_dynamic_method(self): rsp = self.smugmug.albums_get(NickName='test') self.assertEqual(rsp['method'], 'smugmug.albums.get')
def smugmugOauthUseAccessToken(accessToken): # Use the access token to log in smugmug = SmugMug(api_key=API_KEY, oauth_secret=OAUTH_SECRET, oauth_token=accessToke['Token']['id'], oauth_token_secret=accessToken['Token']['Secret'], app_name=APP_NAME) return smugmug
def smug_auth(): smugmug = SmugMug(api_key=config.get('smugmug', 'key'), oauth_secret=config.get('smugmug', 'secret'), api_version="1.3.0", app_name="flickr-to-smugmug") if config.has_option('smugmug', 'oauth_token'): smugmug.set_oauth_token(config.get('smugmug', 'oauth_token'), config.get('smugmug', 'oauth_token_secret')) else: smugmug.auth_getRequestToken() get_input("Authorize app at %s\n\nPress Enter when complete.\n" % (smugmug.authorize(access='Full', perm='Modify'))) smugmug.auth_getAccessToken() config.set('smugmug', 'oauth_token', smugmug.oauth_token) config.set('smugmug', 'oauth_token_secret', smugmug.oauth_token_secret) save() return smugmug
def __init__(self, api_key=None, email=None, password=None): if api_key is None: self.api_key = os.environ.get('SMUGMUG_API', None) else: self.api_key = api_key self.email = email self.password = password self.smugmug = SmugMug( api_key=self.api_key, api_version="1.2.2", app_name="SmugLine") self.login() self.md5_sums = {}
class TestLogin130(unittest.TestCase): def setUp(self): self.smugmug = SmugMug(api_key=API_KEY, api_version='1.3.0', app_name='TestApp') def test_login_anonymously(self): if sys.version_info < (2, 7): self.assertRaises(SmugMugException, lambda: self.smugmug.login_anonymously()) else: with self.assertRaises(SmugMugException): self.smugmug.login_anonymously() def test_login_withHash(self): if sys.version_info < (2, 7): self.assertRaises(SmugMugException, lambda: self.smugmug.login_withHash(UserID='test', PasswordHash='ABCDE')) else: with self.assertRaises(SmugMugException): self.smugmug.login_withHash(UserID='test', PasswordHash='ABCDE') def test_login_withPassword(self): if sys.version_info < (2, 7): self.assertRaises(SmugMugException, lambda: self.smugmug.login_withPassword(EmailAddress='*****@*****.**', Password='******')) else: with self.assertRaises(SmugMugException): self.smugmug.login_withPassword(EmailAddress='*****@*****.**', Password='******')
#!/usr/bin/env python from __future__ import print_function from smugpy import SmugMug import sys #Aliasing for differences in Python 2.x and 3.x if sys.version_info < (3,): get_input = raw_input else: get_input = input API_KEY = "XXXXXXXXXXXXXXXXXXXXXXXXX" OAUTH_SECRET = "YYYYYYYYYYYYYYYYYYYYYYY" smugmug = SmugMug(api_key=API_KEY, oauth_secret=OAUTH_SECRET, app_name="TestApp") #Oauth handshake smugmug.auth_getRequestToken() get_input("Authorize app at %s\n\nPress Enter when complete.\n" % (smugmug.authorize())) smugmug.auth_getAccessToken() albums = smugmug.albums_get(NickName="williams") # Moon River Photography, thanks Andy! for album in albums["Albums"]: print("%s, %s" % (album["id"], album["Title"]))
SCRIPTPATH = os.path.dirname(os.path.abspath(__file__)) # parse command line arguments arguments = docopt(__doc__, version='smugmuglinkgen.py 0.1') # parse config file config = configparser.ConfigParser() config.read(SCRIPTPATH+'/smugmuglinkgen.conf') API_KEY = config.get('main', 'api_key') API_SECRET = config.get('main', 'api_secret') TOKEN = config.get('main', 'token') SECRET = config.get('main', 'secret') USERNAME = config.get('main', 'smugmug_user') # set up smugmug API smugmug = SmugMug(api_key=API_KEY, oauth_secret=API_SECRET, app_name="get_gallery_links") # oauth if TOKEN and SECRET: smugmug.set_oauth_token(TOKEN, SECRET) response = smugmug.auth_checkAccessToken() #print response else: smugmug.auth_getRequestToken() raw_input("Authorize app at %s\n\nPress Enter when complete.\n" % (smugmug.authorize(access='Full'))) response = smugmug.auth_getAccessToken() print(" token: %s" % response['Auth']['Token']['id']) print(" secret: %s" % response['Auth']['Token']['Secret']) print("Enter these values into smugmuglinkgen.conf to skip this auth process the next time around.") # the real work starts here
def setUp(self): self.smugmug = SmugMug(api_key=API_KEY, api_version='1.3.0', app_name='TestApp', oauth_secret=OAUTH_SECRET)
def setUp(self): self.smugmug = SmugMug(api_key=API_KEY, api_version='1.2.2', app_name='TestApp')
class TestLogin(unittest.TestCase): def setUp(self): self.smugmug = SmugMug(api_key=API_KEY, api_version='1.2.2', app_name='TestApp') def test_login_anonymously(self): self.smugmug.login_anonymously() self.assertNotEqual(self.smugmug.session_id, None) self.smugmug.reset_auth() def test_login_withHash(self): self.smugmug.login_withHash(UserID='test', PasswordHash='ABCDE') self.assertNotEqual(self.smugmug.session_id, None) self.smugmug.reset_auth() def test_login_withPassword(self): self.smugmug.login_withPassword(EmailAddress='*****@*****.**', Password='******') self.assertNotEqual(self.smugmug.session_id, None) self.smugmug.reset_auth()
#!/usr/bin/env python from smugpy import SmugMug API_KEY = "XXXXXXXXXXXXXXXXXXXXXXXXX" smugmug = SmugMug(api_key=API_KEY, api_version="1.3.0", app_name="TestApp") albums = smugmug.albums_get(NickName="williams") # Moon River Photography, thanks Andy! for album in albums["Albums"]: print "%s, %s" % (album["id"], album["Title"])
#!/usr/bin/env python from smugpy import SmugMug API_KEY = "XXXXXXXXXXXXXXXXXXXXXXXXX" smugmug = SmugMug(api_key=API_KEY, app_name="TestApp") smugmug.login_anonymously() albums = smugmug.albums_get( NickName="williams") # Moon River Photography, thanks Andy! for album in albums["Albums"]: print "%s, %s" % (album["id"], album["Title"])
class SmugMugClient: def __init__(self, api_key, gallery, link_type, nickname): self.smugmug = SmugMug(api_key=api_key, api_version="1.3.0", app_name="TwiMug") self.gallery = gallery self.link_type = link_type self.nickname = nickname def get_albums(self): albums = self.smugmug.albums_get(NickName=self.nickname) return albums def get_album_info(self, album_name): for album in self.get_albums()["Albums"]: if album["Title"] == album_name: return album def get_images_for_album(self, album_id, album_key): images = self.smugmug.images_get(AlbumID=album_id, AlbumKey=album_key) return images def get_image_urls(self, image_id, image_key): urls = self.smugmug.images_getURLs(ImageID=image_id, ImageKey=image_key) return urls def get_last_image_urls(self): last_image = self.get_last_image_info() urls = self.get_image_urls(last_image["id"], last_image["Key"]) return urls def get_last_image_info(self): album = self.get_album_info(self.gallery) images = self.get_images_for_album(album["id"], album["Key"]) last_image = images["Album"]["Images"][-1] return last_image def get_last_image_extended_info(self): last_image = self.get_last_image_info() extended_info = self.smugmug.images_getInfo(ImageID=last_image["id"], ImageKey=last_image["Key"]) return extended_info["Image"] def get_last_image_url(self): urls = self.get_last_image_urls() return urls["Image"][self.link_type] def save_last_image_url(self): url = self.get_last_image_url() with open("last_image_url", "w") as file: file.write(url) def load_last_image_url(self): url = "" with open("last_image_url", "r") as file: url = file.readline() return url
#!/usr/bin/env python from smugpy import SmugMug API_KEY = "XXXXXXXXXXXXXXXXXXXXXXXXX" smugmug = SmugMug(api_key=API_KEY, app_name="TestApp") smugmug.login_anonymously() albums = smugmug.albums_get(NickName="williams") # Moon River Photography, thanks Andy! for album in albums["Albums"]: print "%s, %s" % (album["id"], album["Title"])
class SmugLine(object): def __init__(self, api_key, email=None, password=None): self.api_key = api_key self.email = email self.password = password self.smugmug = SmugMug(api_key=api_key, api_version="1.2.2", app_name="SmugLine") self.login() self.md5_sums = {} def get_filter(self, media_type="images"): if media_type == "videos": return VIDEO_FILTER if media_type == "images": return IMG_FILTER if media_type == "all": return ALL_FILTER def upload_file(self, album, image): result = "-1" retries = 0 while (result != "smugmug.images.upload") and (retries < 5): try: retries = retries + 1 if result == "-2": print ("Exception, retrying (attempt {0}).".format(retries)) time.sleep(retries * 3) rsp = self.smugmug.images_upload(AlbumID=album["id"], **image) result = rsp["method"] except Exception as inst: print inst result = "-2" pass if result == "-2": print ("ERROR: File upload failed.") # source: http://stackoverflow.com/a/16696317/305019 def download_file(self, url, folder, filename=None): local_filename = os.path.join(folder, filename or url.split("/")[-1]) if os.path.exists(local_filename): print ("{0} already exists...skipping".format(local_filename)) return r = requests.get(url, stream=True) with open(local_filename, "wb") as f: for chunk in r.iter_content(chunk_size=1024): if chunk: # filter out keep-alive new chunks f.write(chunk) f.flush() return local_filename def set_file_timestamp(self, filename, image): # apply the image date image_info = self.get_image_info(image) timestamp = time.strptime(image_info["Image"]["Date"], "%Y-%m-%d %H:%M:%S") t = time.mktime(timestamp) os.utime(filename, (t, t)) def upload_json(self, source_folder, json_file): images = json.load(open(json_file)) # prepend folder for image in images: image["File"] = source_folder + image["File"] # group by album groups = [] images.sort(key=lambda x: x["AlbumName"]) for k, g in groupby(images, key=lambda x: x["AlbumName"]): groups.append(list(g)) for group in groups: album_name = group[0]["AlbumName"] album = self.get_or_create_album(album_name) self._upload(group, album_name, album) def upload_folder(self, source_folder, album_name, file_filter=IMG_FILTER): album = self.get_or_create_album(album_name) images = self.get_images_from_folder(source_folder, file_filter) self._upload(images, album_name, album) def account_folder_number(self, source_folder): images = self.get_images_from_folder(source_folder, file_filter) return len(images) def upload_folder_structure(self, album_title, source_folder, file_filter, uploaded_files, total_files): album_name = source_folder.replace("./", "").split("/", 1)[1] subcategory_name = source_folder.replace("./", "").split("/", 1)[0] categories = self.smugmug.categories_get() category = None for candidate_category in categories["Categories"]: if candidate_category["Name"] == album_title: category = candidate_category if category is None: category = self.smugmug.categories_create(Name=album)["Category"] subcategories = self.smugmug.subcategories_get(CategoryID=category["id"]) subcategory = None for candidate_subcategory in subcategories["SubCategories"]: if candidate_subcategory["Name"] == subcategory_name: subcategory = candidate_subcategory if subcategory is None: subcategory = self.smugmug.subcategories_create(Name=subcategory_name, CategoryID=category["id"])[ "SubCategory" ] album = self.create_album(album_name, "unlisted", subcategory["id"]) images = self.get_images_from_folder(source_folder, file_filter) self._upload(images, album_name, album, uploaded_files, total_files) def download_album(self, album_name, dest_folder, file_filter=IMG_FILTER): album = self.get_album_by_name(album_name) if album is None: print ("Album {0} not found".format(album_name)) return images = self._get_images_for_album(album, file_filter) self._download(images, dest_folder) def _upload(self, images, album_name, album, uploaded_files, total_files): images = self._remove_duplicates(images, album) for image in images: print ("[{0:03d}/{1:03d}] Uploading {2}".format(uploaded_files, total_files, image)) self.upload_file(album, image) uploaded_files = uploaded_files + 1 def _download(self, images, dest_folder): for img in images: print ("downloading {0} -> {1}".format(img["FileName"], dest_folder)) filename = self.download_file(img["OriginalURL"], dest_folder, img["FileName"]) self.set_file_timestamp(filename, img) def _get_remote_images(self, album, extras=None): remote_images = self.smugmug.images_get(AlbumID=album["id"], AlbumKey=album["Key"], Extras=extras) return remote_images def _get_md5_hashes_for_album(self, album): remote_images = self._get_remote_images(album, "MD5Sum") md5_sums = [x["MD5Sum"] for x in remote_images["Album"]["Images"]] self.md5_sums[album["id"]] = md5_sums return md5_sums def _get_images_for_album(self, album, file_filter=IMG_FILTER): extras = "FileName,OriginalURL" images = self._get_remote_images(album, extras)["Album"]["Images"] for image in [img for img in images if file_filter.match(img["FileName"])]: yield image def _file_md5(self, filename, block_size=2 ** 20): md5 = hashlib.md5() f = open(filename, "rb") while True: data = f.read(block_size) if not data: break md5.update(data) return md5.hexdigest() def _include_file(self, f, md5_sums): try: if self._file_md5(f) in md5_sums: print ("skipping {0} (duplicate)".format(f)) return False return True except IOError as err: errno, strerror = err print ("I/O Error({0}): {1}...skipping".format(errno, strerror)) return False def _remove_duplicates(self, images, album): md5_sums = self._get_md5_hashes_for_album(album) return [x for x in images if self._include_file(x.get("File"), md5_sums)] def get_albums(self): albums = self.smugmug.albums_get(NickName=self.nickname) return albums def list_albums(self): print ("available albums:") for album in self.get_albums()["Albums"]: if album["Title"]: print (album["Title"]) def get_or_create_album(self, album_name): album = self.get_album_by_name(album_name) if album: return album return self.create_album(album_name) def get_album_by_name(self, album_name): albums = self.get_albums() try: matches = [x for x in albums["Albums"] if x.get("Title").lower() == album_name.lower()] return matches[0] except: return None def _format_album_name(self, album_name): return album_name[0].upper() + album_name[1:] def get_album_info(self, album): return self.smugmug.albums_getInfo(AlbumID=album["id"], AlbumKey=album["Key"]) def get_image_info(self, image): return self.smugmug.images_getInfo(ImageKey=image["Key"]) def create_album(self, album_name, privacy="unlisted"): public = privacy == "public" album_name = self._format_album_name(album_name) album = self.smugmug.albums_create(Title=album_name, Public=public) album_info = self.get_album_info(album["Album"]) return album_info["Album"] def create_album(self, album_name, privacy, category): public = privacy == "public" album_name = self._format_album_name(album_name) album = self.smugmug.albums_create(Title=album_name, Public=public, CategoryID=category) album_info = self.get_album_info(album["Album"]) return album_info["Album"] def get_images_from_folder(self, folder, img_filter=IMG_FILTER): matches = [] for root, dirnames, filenames in os.walk(folder): matches.extend({"File": os.path.join(root, name)} for name in filenames if img_filter.match(name)) return matches def _set_email_and_password(self): # for python2 try: input = raw_input except NameError: pass if self.email is None: self.email = input("Email address: ") if self.password is None: self.password = getpass.getpass() def login(self): self._set_email_and_password() self.user_info = self.smugmug.login_withPassword(EmailAddress=self.email, Password=self.password) self.nickname = self.user_info["Login"]["User"]["NickName"] return self.user_info def _delete_image(self, image): print ("deleting image {0} (md5: {1})".format(image["FileName"], image["MD5Sum"])) self.smugmug.images_delete(ImageID=image["id"]) def clear_duplicates(self, album_name): album = self.get_album_by_name(album_name) remote_images = self._get_remote_images(album, "MD5Sum,FileName") md5_sums = [] for image in remote_images["Album"]["Images"]: if image["MD5Sum"] in md5_sums: self._delete_image(image) md5_sums.append(image["MD5Sum"])
class TestApi(unittest.TestCase): def setUp(self): self.smugmug = SmugMug(api_key=API_KEY, api_version='1.2.2', app_name='TestApp') def test_ping(self): rsp = self.smugmug.service_ping() self.assertEqual(rsp['stat'], 'ok') def test_dynamic_method(self): self.smugmug.login_anonymously() rsp = self.smugmug.albums_get(NickName='test') self.assertEqual(rsp['method'], 'smugmug.albums.get') self.smugmug.reset_auth() def test_authorize(self): expected = 'http://api.smugmug.com/services/oauth/authorize.mg?oauth_token=ABC&Access=Public&Permissions=Read' self.smugmug.set_oauth_token('ABC','123') url = self.smugmug.authorize(access='Public', perm='Read') self.assertEqual(url, expected) self.smugmug.reset_auth() def test_failed_api(self): if sys.version_info < (2, 7): self.assertRaises(SmugMugException, lambda: self.smugmug.bad_apimethod()) else: with self.assertRaises(SmugMugException): self.smugmug.bad_apimethod()
def test_no_api_key(self): if sys.version_info < (2, 7): self.assertRaises(SmugMugException, lambda: SmugMug()) else: with self.assertRaises(SmugMugException): SmugMug()
#!/usr/bin/env python2 import os from smugpy import SmugMug API_KEY = os.environ['SMUGMUG_API_KEY'] NICKNAME = os.environ['SMUGMUG_NICKNAME'] smugmug = SmugMug(api_key=API_KEY, api_version="1.3.0", app_name="Download") albums = smugmug.albums_get(NickName=NICKNAME) for album in albums["Albums"]: print "%s, %s" % (album["id"], album["Title"])
#!/usr/bin/env python from __future__ import print_function from smugpy import SmugMug import sys #Aliasing for differences in Python 2.x and 3.x if sys.version_info < (3, ): get_input = raw_input else: get_input = input API_KEY = "XXXXXXXXXXXXXXXXXXXXXXXXX" OAUTH_SECRET = "YYYYYYYYYYYYYYYYYYYYYYY" smugmug = SmugMug(api_key=API_KEY, oauth_secret=OAUTH_SECRET, app_name="TestApp") #Oauth handshake smugmug.auth_getRequestToken() get_input("Authorize app at %s\n\nPress Enter when complete.\n" % (smugmug.authorize())) smugmug.auth_getAccessToken() albums = smugmug.albums_get( NickName="williams") # Moon River Photography, thanks Andy! for album in albums["Albums"]: print("%s, %s" % (album["id"], album["Title"]))
class TestApi(unittest.TestCase): def setUp(self): self.smugmug = SmugMug(api_key=API_KEY, api_version='1.2.2', app_name='TestApp') def test_ping(self): rsp = self.smugmug.service_ping() self.assertEqual(rsp['stat'], 'ok') def test_dynamic_method(self): self.smugmug.login_anonymously() rsp = self.smugmug.albums_get(NickName='test') self.assertEqual(rsp['method'], 'smugmug.albums.get') self.smugmug.reset_auth() def test_authorize(self): expected = 'http://api.smugmug.com/services/oauth/authorize.mg?oauth_token=ABC&Access=Public&Permissions=Read' self.smugmug.set_oauth_token('ABC', '123') url = self.smugmug.authorize(access='Public', perm='Read') self.assertEqual(url, expected) self.smugmug.reset_auth() def test_failed_api(self): if sys.version_info < (2, 7): self.assertRaises(SmugMugException, lambda: self.smugmug.bad_apimethod()) else: with self.assertRaises(SmugMugException): self.smugmug.bad_apimethod()
class SmugLine(object): def __init__(self, api_key, email=None, password=None): self.api_key = api_key self.email = email self.password = password self.smugmug = SmugMug( api_key=api_key, api_version="1.2.2", app_name="SmugLine") self.login() self.md5_sums = {} def get_filter(self, media_type='images'): if media_type == 'videos': return VIDEO_FILTER if media_type == 'images': return IMG_FILTER if media_type == 'all': return ALL_FILTER def upload_file(self, album, image): self.smugmug.images_upload(AlbumID=album['id'], **image) def upload_json(self, source_folder, json_file): images = json.load(open(json_file)) # prepend folder for image in images: image['File'] = source_folder + image['File'] # group by album groups = [] images.sort(key=lambda x: x['AlbumName']) for k, g in groupby(images, key=lambda x: x['AlbumName']): groups.append(list(g)) for group in groups: album_name = group[0]['AlbumName'] album = self.get_or_create_album(album_name) self._upload(group, album_name, album) def upload_folder(self, source_folder, album_name, file_filter=IMG_FILTER): album = self.get_or_create_album(album_name) images = self.get_images_from_folder(source_folder, file_filter) self._upload(images, album_name, album) def upload_with_folders(self, source_folder, file_filter=IMG_FILTER): excludes = ['.DS_Store', '.git', 'desktop.ini'] for root, dirnames, filenames in os.walk(source_folder, topdown=True): # exclude some common "hidden" files and dirs dirnames[:] = [d for d in dirnames if d not in excludes] filenames[:] = [f for f in filenames if f not in excludes] # skip the root if (root != source_folder): # if there are NO subfolders and there are images, create SmugMug album # named root and upload all filenames if (not dirnames and filenames): album_description = root[len(source_folder) + 1:] album_name = album_description # album_name = album_description[album_description.find('/') + 1:] album = self.get_or_create_album(album_name, "") images = self.get_images_from_folder(root, file_filter) self._upload(images, album_name, album) return def _upload(self, images, album_name, album): images = self._remove_duplicates(images, album) for image in images: print('uploading {0} -> {1}'.format(image, album_name)) self.upload_file(album, image) def _get_remote_images(self, album, extras=None): remote_images = self.smugmug.images_get( AlbumID=album['id'], AlbumKey=album['Key'], Extras=extras) return remote_images def _get_md5_hashes_for_album(self, album): remote_images = self._get_remote_images(album, 'MD5Sum') md5_sums = [x['MD5Sum'] for x in remote_images['Album']['Images']] self.md5_sums[album['id']] = md5_sums return md5_sums def _file_md5(self, filename, block_size=2**20): md5 = hashlib.md5() f = open(filename, 'rb') while True: data = f.read(block_size) if not data: break md5.update(data) return md5.hexdigest() def _include_file(self, f, md5_sums): if self._file_md5(f) in md5_sums: print('skipping {0} (duplicate)'.format(f)) return False return True def _remove_duplicates(self, images, album): md5_sums = self._get_md5_hashes_for_album(album) return [x for x in images if self._include_file(x.get('File'), md5_sums)] def get_albums(self): albums = self.smugmug.albums_get(NickName=self.nickname) return albums def list_albums(self): print('available albums:') for album in self.get_albums()['Albums']: if album['Title']: print(album['Title']) def get_or_create_album(self, album_name, album_description): album = self.get_album_by_name(album_name) if album: return album return self.create_album(album_name, album_description) def get_album_by_name(self, album_name): albums = self.get_albums() try: matches = [x for x in albums['Albums'] \ if x.get('Title').lower() == album_name.lower()] return matches[0] except: return None def _format_album_name(self, album_name): return album_name[0].upper() + album_name[1:] def get_album_info(self, album): return self.smugmug.albums_getInfo(AlbumID=album['id'], AlbumKey=album['Key']) def create_album(self, album_name, album_description, privacy='unlisted'): public = (privacy == 'public') album_name = self._format_album_name(album_name) album = self.smugmug.albums_create(Title=album_name, Public=public, SortMethod="DateTimeOriginal") album_info = self.get_album_info(album['Album']) print('{0} album {1} created. URL: {2}'.format( privacy, album_name, album_info['Album']['URL'])) return album_info['Album'] def get_images_from_folder(self, folder, img_filter=IMG_FILTER): matches = [] for root, dirnames, filenames in os.walk(folder): matches.extend( {'File' : os.path.join(root, name)} for name in filenames \ if img_filter.match(name)) return matches def _set_email_and_password(self): # for python2 try: input = raw_input except NameError: pass if self.email is None: self.email = input('Email address: ') if self.password is None: self.password = getpass.getpass() def login(self): self._set_email_and_password() self.user_info = self.smugmug.login_withPassword( EmailAddress=self.email, Password=self.password) self.nickname = self.user_info['Login']['User']['NickName'] return self.user_info def _delete_image(self, image): print('deleting image {0} (md5: {1})'.format(image['FileName'], image['MD5Sum'])) self.smugmug.images_delete(ImageID=image['id']) def clear_duplicates(self, album_name): album = self.get_album_by_name(album_name) remote_images = self._get_remote_images(album, 'MD5Sum,FileName') md5_sums = [] for image in remote_images['Album']['Images']: if image['MD5Sum'] in md5_sums: self._delete_image(image) md5_sums.append(image['MD5Sum'])
class TestApiImageUpload(unittest.TestCase): def setUp(self): self.smugmug = SmugMug(api_key=API_KEY, api_version='1.2.2', app_name='TestApp') def test_image_upload_missing_param(self): self.smugmug.login_withHash(UserID='test', PasswordHash='ABCDE') if sys.version_info < (2, 7): self.assertRaises(SmugMugException, lambda: self.smugmug.images_upload()) else: with self.assertRaises(SmugMugException): self.smugmug.images_upload() self.smugmug.reset_auth() def test_image_upload_without_auth(self): if sys.version_info < (2, 7): self.assertRaises( SmugMugException, lambda: self.smugmug.images_upload(File='tests/smuggy.jpg', AlbumID=1234)) else: with self.assertRaises(SmugMugException): self.smugmug.images_upload(File='tests/smuggy.jpg', AlbumID=1234) self.smugmug.reset_auth() def test_image_upload(self): self.smugmug.login_withHash(UserID='test', PasswordHash='ABCDE') rsp = self.smugmug.images_upload(File='tests/smuggy.jpg', AlbumID=1234) self.assertEqual(rsp['method'], 'smugmug.images.upload') self.smugmug.reset_auth() def test_image_upload_with_filename(self): self.smugmug.login_withHash(UserID='test', PasswordHash='ABCDE') rsp = self.smugmug.images_upload(File='tests/smuggy.jpg', AlbumID=1234, FileName='rename.jpg') self.assertEqual(rsp['method'], 'smugmug.images.upload') self.smugmug.reset_auth()
class SmugMugCommandLine(object): def __init__(self, api_key=None, email=None, password=None): """initalize class""" self.api_key = api_key self.email = email self.password = password # using the old API (1.2.2), which is easier to use for one shot scripts (avoids OAuth) self.smugmug = SmugMug(api_key=options.api_key, api_version="1.2.2", app_name=__script_name__) # login self.smugmug.login_withPassword(EmailAddress=options.email, Password=options.password) def template_get(self, template_name=None): """find template by name""" response = self.smugmug.albumtemplates_get() for template in response['AlbumTemplates']: if template['AlbumTemplateName'] == template_name: return template return None def category_get(self, category_name=None): """find category by name""" response = self.smugmug.categories_get() for category in response['Categories']: if category['Name'] == category_name: return category return None def subcategory_get(self, subcategory_name=None): """find subcategory by name""" response = self.smugmug.subcategories_get(CategoryID=self.category['id']) for subcategory in response['SubCategories']: if subcategory['Name'] == subcategory_name: return subcategory return None def album_get(self, album_name=None): """find album by name""" response = self.smugmug.albums_get() for album in response['Albums']: if album['Title'] == album_name: return album return None def album_getInfo(self, album_id=None, album_key=None): """get album info""" response = self.smugmug.albums_getInfo(AlbumID=album_id, AlbumKey=album_key) album = response['Album'] return album def album_create(self, title=None, category_id=None, subcategory_id=None, album_template_id=None): """create ablum""" response = self.smugmug.albums_create(AlbumTemplateID=album_template_id, CategoryID=category_id, SubCategoryID=subcategory_id, Title=title) album = response['Album'] return album def images_getInfo(self, image_id=None, image_key=None): """get image info""" response = self.smugmug.images_getInfo(ImageID=image_id, ImageKey=image_key) image_info = response['Image'] return image_info def images_get(self, album_id=None, album_key=None): """get all image for an ablum""" response = self.smugmug.images_get(AlbumID=album_id, AlbumKey=album_key) images = response['Album']['Images'] return images def images_get_filenames(self, album_id=None, album_key=None): """get all images for an ablum as a collection of filenames""" filename_list = list() images = self.images_get(album_id=album_id, album_key=album_key) for image in images: image_info = self.images_getInfo(image_id=image['id'], image_key=image['Key']) filename_list.append(image_info['FileName']) return filename_list
class SmugLine(object): def __init__(self, api_key=None, email=None, password=None): if api_key is None: self.api_key = os.environ.get('SMUGMUG_API', None) else: self.api_key = api_key self.email = email self.password = password self.smugmug = SmugMug(api_key=self.api_key, api_version="1.2.2", app_name="SmugLine") self.login() self.md5_sums = {} def get_filter(self, media_type='images'): if media_type == 'videos': return VIDEO_FILTER if media_type == 'images': return IMG_FILTER if media_type == 'all': return ALL_FILTER def upload_file(self, album, image): retries = 5 while retries: try: self.smugmug.images_upload(AlbumID=album['id'], **image) return except HTTPError: print("retry ", image) retries -= 1 # source: http://stackoverflow.com/a/16696317/305019 def download_file(self, url, folder, filename=None): local_filename = os.path.join(folder, filename or url.split('/')[-1]) if os.path.exists(local_filename): print('{0} already exists...skipping'.format(local_filename)) return r = requests.get(url, stream=True) with open(local_filename, 'wb') as f: for chunk in r.iter_content(chunk_size=1024): if chunk: # filter out keep-alive new chunks f.write(chunk) f.flush() return local_filename def set_file_timestamp(self, filename, image): if filename is None: return # apply the image date image_info = self.get_image_info(image) timestamp = time.strptime(image_info['Image']['Date'], '%Y-%m-%d %H:%M:%S') t = time.mktime(timestamp) os.utime(filename, (t, t)) def upload_json(self, source_folder, json_file): images = json.load(open(json_file)) # prepend folder for image in images: image['File'] = source_folder + image['File'] # group by album groups = [] images.sort(key=lambda x: x['AlbumName']) for k, g in groupby(images, key=lambda x: x['AlbumName']): groups.append(list(g)) for group in groups: album_name = group[0]['AlbumName'] album = self.get_or_create_album(album_name) self._upload(group, album_name, album) def upload_folder(self, source_folder, album_name, file_filter=IMG_FILTER): album = self.get_or_create_album(album_name) images = self.get_images_from_folder(source_folder, file_filter) self._upload(images, album_name, album) def download_album(self, album_name, dest_folder, file_filter=IMG_FILTER): album = self.get_album_by_name(album_name) if album is None: print('Album {0} not found'.format(album_name)) return images = self._get_images_for_album(album, file_filter) self._download(images, dest_folder) def _upload(self, images, album_name, album): images = self._remove_duplicates(images, album) print('uploading {0} images'.format(len(images))) for image in images: print(' uploading {0} -> {1}'.format(image, album_name)) self.upload_file(album, image) print('Done uploading {0} images'.format(len(images))) def _download(self, images, dest_folder): for img in images: print('downloading {0} -> {1}'.format(img['FileName'], dest_folder)) if 'OriginalURL' not in img: print('no permission to download {0}...skipping'.format( img['FileName'])) continue filename = self.download_file(img['OriginalURL'], dest_folder, img['FileName']) self.set_file_timestamp(filename, img) def _get_remote_images(self, album, extras=None): remote_images = self.smugmug.images_get(AlbumID=album['id'], AlbumKey=album['Key'], Extras=extras) return remote_images def _get_md5_hashes_for_album(self, album): remote_images = self._get_remote_images(album, 'MD5Sum') md5_sums = [x['MD5Sum'] for x in remote_images['Album']['Images']] self.md5_sums[album['id']] = md5_sums return md5_sums def _get_images_for_album(self, album, file_filter=IMG_FILTER): extras = 'FileName,OriginalURL' images = self._get_remote_images(album, extras)['Album']['Images'] for image in [img for img in images \ if file_filter.match(img['FileName'])]: yield image def _file_md5(self, filename, block_size=2**20): md5 = hashlib.md5() f = open(filename, 'rb') while True: data = f.read(block_size) if not data: break md5.update(data) return md5.hexdigest() def _include_file(self, f, md5_sums): try: if self._file_md5(f) in md5_sums: print('skipping {0} (duplicate)'.format(f)) return False return True except IOError as err: # see https://github.com/PyCQA/pylint/issues/165 # pylint: disable=unpacking-non-sequence errno, strerror = err print('I/O Error({0}): {1}...skipping'.format(errno, strerror)) return False def _remove_duplicates(self, images, album): md5_sums = self._get_md5_hashes_for_album(album) return [ x for x in images if self._include_file(x.get('File'), md5_sums) ] def get_albums(self): albums = self.smugmug.albums_get(NickName=self.nickname) return albums def list_albums(self): print('available albums:') for album in self.get_albums()['Albums']: if album['Title']: print(album['Title'].encode('utf-8')) def get_or_create_album(self, album_name): album = self.get_album_by_name(album_name) if album: return album return self.create_album(album_name) def get_album_by_name(self, album_name): albums = self.get_albums() try: matches = [x for x in albums['Albums'] \ if x.get('Title').lower() == album_name.lower()] return matches[0] except: return None def _format_album_name(self, album_name): return album_name[0].upper() + album_name[1:] def get_album_info(self, album): return self.smugmug.albums_getInfo(AlbumID=album['id'], AlbumKey=album['Key']) def get_image_info(self, image): return self.smugmug.images_getInfo(ImageKey=image['Key']) def create_album(self, album_name, privacy='unlisted'): public = (privacy == 'public') album_name = self._format_album_name(album_name) album = self.smugmug.albums_create(Title=album_name, Public=public) album_info = self.get_album_info(album['Album']) print('{0} album {1} created. URL: {2}'.format( privacy, album_name, album_info['Album']['URL'])) return album_info['Album'] def get_images_from_folder(self, folder, img_filter=IMG_FILTER): matches = [] for root, dirnames, filenames in os.walk(folder): matches.extend( {'File': os.path.join(root, name)} for name in filenames \ if img_filter.match(name)) return matches def _set_email_and_password(self): # for python2 try: input = raw_input except NameError: pass if self.email is None: self.email = os.environ.get('SMUGMUG_EMAIL', None) if self.email is None: self.email = input('Email address: ') if self.password is None: self.password = os.environ.get('SMUGMUG_PASSWORD', None) if self.password is None: self.password = getpass.getpass() def login(self): self._set_email_and_password() self.user_info = self.smugmug.login_withPassword( EmailAddress=self.email, Password=self.password) self.nickname = self.user_info['Login']['User']['NickName'] return self.user_info def _delete_image(self, image): print('deleting image {0} (md5: {1})'.format(image['FileName'], image['MD5Sum'])) self.smugmug.images_delete(ImageID=image['id']) def clear_duplicates(self, album_name): album = self.get_album_by_name(album_name) remote_images = self._get_remote_images(album, 'MD5Sum,FileName') md5_sums = [] for image in remote_images['Album']['Images']: if image['MD5Sum'] in md5_sums: self._delete_image(image) md5_sums.append(image['MD5Sum'])
class SmugLine(object): def __init__(self, api_key, email=None, password=None): self.api_key = api_key self.email = email self.password = password self.smugmug = SmugMug( api_key=api_key, api_version="1.2.2", app_name="SmugLine") self.login() self.md5_sums = {} def get_filter(self, media_type='images'): if media_type == 'videos': return VIDEO_FILTER if media_type == 'images': return IMG_FILTER if media_type == 'all': return ALL_FILTER def upload_file(self, album, image): self.smugmug.images_upload(AlbumID=album['id'], **image) # source: http://stackoverflow.com/a/16696317/305019 def download_file(self, url, folder, filename=None): local_filename = os.path.join(folder, filename or url.split('/')[-1]) if os.path.exists(local_filename): print('{0} already exists...skipping'.format(local_filename)) return r = requests.get(url, stream=True) with open(local_filename, 'wb') as f: for chunk in r.iter_content(chunk_size=1024): if chunk: # filter out keep-alive new chunks f.write(chunk) f.flush() return local_filename def upload_json(self, source_folder, json_file): images = json.load(open(json_file)) # prepend folder for image in images: image['File'] = source_folder + image['File'] # group by album groups = [] images.sort(key=lambda x: x['AlbumName']) for k, g in groupby(images, key=lambda x: x['AlbumName']): groups.append(list(g)) for group in groups: album_name = group[0]['AlbumName'] album = self.get_or_create_album(album_name) self._upload(group, album_name, album) def upload_folder(self, source_folder, album_name, file_filter=IMG_FILTER): album = self.get_or_create_album(album_name) images = self.get_images_from_folder(source_folder, file_filter) self._upload(images, album_name, album) def download_album(self, album_name, dest_folder, file_filter=IMG_FILTER): album = self.get_album_by_name(album_name) if album is None: print('Album {0} not found'.format(album_name)) return images = self._get_images_for_album(album, file_filter) self._download(images, dest_folder) def _upload(self, images, album_name, album): images = self._remove_duplicates(images, album) for image in images: print('uploading {0} -> {1}'.format(image, album_name)) self.upload_file(album, image) def _download(self, images, dest_folder): for img in images: print('downloading {0} -> {1}'.format(img['FileName'], dest_folder)) self.download_file(img['OriginalURL'], dest_folder, img['FileName']) def _get_remote_images(self, album, extras=None): remote_images = self.smugmug.images_get( AlbumID=album['id'], AlbumKey=album['Key'], Extras=extras) return remote_images def _get_md5_hashes_for_album(self, album): remote_images = self._get_remote_images(album, 'MD5Sum') md5_sums = [x['MD5Sum'] for x in remote_images['Album']['Images']] self.md5_sums[album['id']] = md5_sums return md5_sums def _get_images_for_album(self, album, file_filter=IMG_FILTER): extras = 'FileName,OriginalURL' images = self._get_remote_images(album, extras)['Album']['Images'] for image in [img for img in images \ if file_filter.match(img['FileName'])]: yield image def _file_md5(self, filename, block_size=2**20): md5 = hashlib.md5() f = open(filename, 'rb') while True: data = f.read(block_size) if not data: break md5.update(data) return md5.hexdigest() def _include_file(self, f, md5_sums): try: if self._file_md5(f) in md5_sums: print('skipping {0} (duplicate)'.format(f)) return False return True except IOError as err: errno, strerror = err print('I/O Error({0}): {1}...skipping'.format(errno, strerror)) return False def _remove_duplicates(self, images, album): md5_sums = self._get_md5_hashes_for_album(album) return [x for x in images if self._include_file(x.get('File'), md5_sums)] def get_albums(self): albums = self.smugmug.albums_get(NickName=self.nickname) return albums def list_albums(self): print('available albums:') for album in self.get_albums()['Albums']: if album['Title']: print(album['Title']) def get_or_create_album(self, album_name): album = self.get_album_by_name(album_name) if album: return album return self.create_album(album_name) def get_album_by_name(self, album_name): albums = self.get_albums() try: matches = [x for x in albums['Albums'] \ if x.get('Title').lower() == album_name.lower()] return matches[0] except: return None def _format_album_name(self, album_name): return album_name[0].upper() + album_name[1:] def get_album_info(self, album): return self.smugmug.albums_getInfo(AlbumID=album['id'], AlbumKey=album['Key']) def create_album(self, album_name, privacy='unlisted'): public = (privacy == 'public') album_name = self._format_album_name(album_name) album = self.smugmug.albums_create(Title=album_name, Public=public) album_info = self.get_album_info(album['Album']) print('{0} album {1} created. URL: {2}'.format( privacy, album_name, album_info['Album']['URL'])) return album_info['Album'] def get_images_from_folder(self, folder, img_filter=IMG_FILTER): matches = [] for root, dirnames, filenames in os.walk(folder): matches.extend( {'File': os.path.join(root, name)} for name in filenames \ if img_filter.match(name)) return matches def _set_email_and_password(self): # for python2 try: input = raw_input except NameError: pass if self.email is None: self.email = input('Email address: ') if self.password is None: self.password = getpass.getpass() def login(self): self._set_email_and_password() self.user_info = self.smugmug.login_withPassword( EmailAddress=self.email, Password=self.password) self.nickname = self.user_info['Login']['User']['NickName'] return self.user_info def _delete_image(self, image): print('deleting image {0} (md5: {1})'.format(image['FileName'], image['MD5Sum'])) self.smugmug.images_delete(ImageID=image['id']) def clear_duplicates(self, album_name): album = self.get_album_by_name(album_name) remote_images = self._get_remote_images(album, 'MD5Sum,FileName') md5_sums = [] for image in remote_images['Album']['Images']: if image['MD5Sum'] in md5_sums: self._delete_image(image) md5_sums.append(image['MD5Sum'])
__author__ = 'hle' from smugpy import SmugMug if __name__ == '__main__': API_KEY = "Ai1WhX5ErNtHYR5YFg4qFAiww6PGZs1d" smugmug = SmugMug(api_key=API_KEY, api_version="1.3.0", app_name="TestApp") albums = smugmug.albums_get(NickName="williams") for album in albums["Albums"]: print("%s, %s" % (album["id"], album["Title"]))
class SmugLine(object): def __init__(self, api_key, email=None, password=None): self.api_key = api_key self.email = email self.password = password self.smugmug = SmugMug(api_key=api_key, api_version="1.2.2", app_name="SmugLine") self.login() self.md5_sums = {} def get_filter(self, media_type='images'): if media_type == 'videos': return VIDEO_FILTER if media_type == 'images': return IMG_FILTER if media_type == 'all': return ALL_FILTER def upload_file(self, album, image): self.smugmug.images_upload(AlbumID=album['id'], **image) def upload_json(self, source_folder, json_file): images = json.load(open(json_file)) # prepend folder for image in images: image['File'] = source_folder + image['File'] # group by album groups = [] images.sort(key=lambda x: x['AlbumName']) for k, g in groupby(images, key=lambda x: x['AlbumName']): groups.append(list(g)) for group in groups: album_name = group[0]['AlbumName'] album = self.get_or_create_album(album_name) self._upload(group, album_name, album) def upload_folder(self, source_folder, album_name, file_filter=IMG_FILTER): album = self.get_or_create_album(album_name) images = self.get_images_from_folder(source_folder, file_filter) self._upload(images, album_name, album) def _upload(self, images, album_name, album): images = self._remove_duplicates(images, album) for image in images: print('uploading {0} -> {1}'.format(image, album_name)) self.upload_file(album, image) def _get_remote_images(self, album, extras=None): remote_images = self.smugmug.images_get(AlbumID=album['id'], AlbumKey=album['Key'], Extras=extras) return remote_images def _get_md5_hashes_for_album(self, album): remote_images = self._get_remote_images(album, 'MD5Sum') md5_sums = [x['MD5Sum'] for x in remote_images['Album']['Images']] self.md5_sums[album['id']] = md5_sums return md5_sums def _file_md5(self, filename, block_size=2**20): md5 = hashlib.md5() f = open(filename, 'rb') while True: data = f.read(block_size) if not data: break md5.update(data) return md5.hexdigest() def _include_file(self, f, md5_sums): if self._file_md5(f) in md5_sums: print('skipping {0} (duplicate)'.format(f)) return False return True def _remove_duplicates(self, images, album): md5_sums = self._get_md5_hashes_for_album(album) return [ x for x in images if self._include_file(x.get('File'), md5_sums) ] def get_albums(self): albums = self.smugmug.albums_get(NickName=self.nickname) return albums def list_albums(self): print('available albums:') for album in self.get_albums()['Albums']: if album['Title']: print(album['Title']) def get_or_create_album(self, album_name): album = self.get_album_by_name(album_name) if album: return album return self.create_album(album_name) def get_album_by_name(self, album_name): albums = self.get_albums() try: matches = [x for x in albums['Albums'] \ if x.get('Title').lower() == album_name.lower()] return matches[0] except: return None def _format_album_name(self, album_name): return album_name[0].upper() + album_name[1:] def get_album_info(self, album): return self.smugmug.albums_getInfo(AlbumID=album['id'], AlbumKey=album['Key']) def create_album(self, album_name, privacy='unlisted'): public = (privacy == 'public') album_name = self._format_album_name(album_name) album = self.smugmug.albums_create(Title=album_name, Public=public) album_info = self.get_album_info(album['Album']) print('{0} album {1} created. URL: {2}'.format( privacy, album_name, album_info['Album']['URL'])) return album_info['Album'] def get_images_from_folder(self, folder, img_filter=IMG_FILTER): matches = [] for root, dirnames, filenames in os.walk(folder): matches.extend( {'File' : os.path.join(root, name)} for name in filenames \ if img_filter.match(name)) return matches def _set_email_and_password(self): # for python2 try: input = raw_input except NameError: pass if self.email is None: self.email = input('Email address: ') if self.password is None: self.password = getpass.getpass() def login(self): self._set_email_and_password() self.user_info = self.smugmug.login_withPassword( EmailAddress=self.email, Password=self.password) self.nickname = self.user_info['Login']['User']['NickName'] return self.user_info def _delete_image(self, image): print('deleting image {0} (md5: {1})'.format(image['FileName'], image['MD5Sum'])) self.smugmug.images_delete(ImageID=image['id']) def clear_duplicates(self, album_name): album = self.get_album_by_name(album_name) remote_images = self._get_remote_images(album, 'MD5Sum,FileName') md5_sums = [] for image in remote_images['Album']['Images']: if image['MD5Sum'] in md5_sums: self._delete_image(image) md5_sums.append(image['MD5Sum'])
class SmugLine(object): def __init__(self, api_key, email=None, password=None): self.api_key = api_key self.email = email self.password = password self.smugmug = SmugMug( api_key=api_key, api_version="1.2.2", app_name="SmugLine") self.login() self.md5_sums = {} def get_filter(self, media_type='images'): if media_type == 'videos': return VIDEO_FILTER if media_type == 'images': return IMG_FILTER if media_type == 'all': return ALL_FILTER def upload_file(self, source_file, album): album_id = album['id'] self.smugmug.images_upload(File=source_file, AlbumID=album_id) def upload(self, source_folder, album_name, file_filter=IMG_FILTER): album = self.get_or_create_album(album_name) images = self.get_images_from_folder(source_folder, file_filter) images = self._remove_duplicates(images, album) for image in images: print('uploading {0} -> {1}'.format(image, album_name)) self.upload_file(image, album) def _get_remote_images(self, album, extras=None): remote_images = self.smugmug.images_get( AlbumID=album['id'], AlbumKey=album['Key'], Extras=extras) return remote_images def _get_md5_hashes_for_album(self, album): remote_images = self._get_remote_images(album, 'MD5Sum') md5_sums = [x['MD5Sum'] for x in remote_images['Album']['Images']] self.md5_sums[album['id']] = md5_sums return md5_sums def _file_md5(self, filename, block_size=2**20): md5 = hashlib.md5() f = open(filename) while True: data = f.read(block_size) if not data: break md5.update(data) return md5.hexdigest() def _include_file(self, f, md5_sums): if self._file_md5(f) in md5_sums: print('skipping {0} (duplicate)'.format(f)) return False return True def _remove_duplicates(self, images, album): md5_sums = self._get_md5_hashes_for_album(album) return [x for x in images if self._include_file(x, md5_sums)] def get_albums(self): albums = self.smugmug.albums_get(NickName=self.nickname) return albums def list_albums(self): print('available albums:') for album in self.get_albums()['Albums']: if album['Title']: print(album['Title']) def get_or_create_album(self, album_name): album = self.get_album_by_name(album_name) if album: return album return self.create_album(album_name) def get_album_by_name(self, album_name): albums = self.get_albums() try: matches = [x for x in albums['Albums'] \ if x.get('Title') == album_name] return matches[0] except: return None def _format_album_name(self, album_name): return album_name[0].upper() + album_name[1:] def get_album_info(self, album): return self.smugmug.albums_getInfo(AlbumID=album['id'], AlbumKey=album['Key']) def create_album(self, album_name, privacy='unlisted'): public = (privacy == 'public') album_name = self._format_album_name(album_name) album = self.smugmug.albums_create(Title=album_name, Public=public) album_info = self.get_album_info(album['Album']) print('{0} album {1} created. URL: {2}'.format( privacy, album_name, album_info['Album']['URL'])) return album_info['Album'] def get_images_from_folder(self, folder, img_filter=IMG_FILTER): matches = [] for root, dirnames, filenames in os.walk(folder): matches.extend( os.path.join(root, name) for name in filenames \ if img_filter.match(name)) return matches def _set_email_and_password(self): if self.email is None: self.email = raw_input('Email address: ') if self.password is None: self.password = getpass.getpass() def login(self): self._set_email_and_password() self.user_info = self.smugmug.login_withPassword( EmailAddress=self.email, Password=self.password) self.nickname = self.user_info['Login']['User']['NickName'] return self.user_info def _delete_image(self, image): print('deleting image {0} (md5: {1})'.format(image['FileName'], image['MD5Sum'])) self.smugmug.images_delete(ImageID=image['id']) def clear_duplicates(self, album_name): album = self.get_album_by_name(album_name) remote_images = self._get_remote_images(album, 'MD5Sum,FileName') md5_sums = [] for image in remote_images['Album']['Images']: if image['MD5Sum'] in md5_sums: self._delete_image(image) md5_sums.append(image['MD5Sum'])
#!/usr/bin/env python from smugpy import SmugMug API_KEY = "XXXXXXXXXXXXXXXXXXXXXXXXX" smugmug = SmugMug(api_key=API_KEY, api_version="1.3.0", app_name="TestApp") albums = smugmug.albums_get( NickName="williams") # Moon River Photography, thanks Andy! for album in albums["Albums"]: print "%s, %s" % (album["id"], album["Title"])
class TestApiImageUpload(unittest.TestCase): def setUp(self): self.smugmug = SmugMug(api_key=API_KEY, api_version='1.2.2', app_name='TestApp') def test_image_upload_missing_param(self): self.smugmug.login_withHash(UserID='test', PasswordHash='ABCDE') if sys.version_info < (2, 7): self.assertRaises(SmugMugException, lambda: self.smugmug.images_upload()) else: with self.assertRaises(SmugMugException): self.smugmug.images_upload() self.smugmug.reset_auth() def test_image_upload_without_auth(self): if sys.version_info < (2, 7): self.assertRaises(SmugMugException, lambda: self.smugmug.images_upload(File='tests/smuggy.jpg', AlbumID=1234)) else: with self.assertRaises(SmugMugException): self.smugmug.images_upload(File='tests/smuggy.jpg', AlbumID=1234) self.smugmug.reset_auth() def test_image_upload(self): self.smugmug.login_withHash(UserID='test', PasswordHash='ABCDE') rsp = self.smugmug.images_upload(File='tests/smuggy.jpg', AlbumID=1234) self.assertEqual(rsp['method'], 'smugmug.images.upload') self.smugmug.reset_auth() def test_image_upload_with_filename(self): self.smugmug.login_withHash(UserID='test', PasswordHash='ABCDE') rsp = self.smugmug.images_upload(File='tests/smuggy.jpg', AlbumID=1234, FileName='rename.jpg') self.assertEqual(rsp['method'], 'smugmug.images.upload') self.smugmug.reset_auth()