def currentFlickrURL(kind, format = ""): '''Return a URL for the Flickr image currently showing in the browser. The string parameter "kind" can be either "Short" or one of the standard Flickr image sizes: "Original", "Large", "Medium 640", "Medium", "Small", "Thumbnail", or "Square". If it's Short, the function will return a flic.kr URL for the image page. If it's one of the others, the function will return the URL of the image of that size, if available. The function works through Apple Events and supports only the Safari and Chrome browsers.''' # Flickr parameters fuser = '******' key = 'Get key from Flickr' secret = 'Get secret from Flickr' # Make sure we're asking for a legitimate kind. kind = kind.capitalize() kinds = ["Short", "Original", "Large", "Medium 640", "Medium", "Small", "Thumbnail", "Square"] if kind not in kinds: return "Not a legitimate kind of URL" # Get the image ID. try: imageID = currentFlickrID() except IndexError: return "Not a Flickr image" # Establish the connection with Flickr. flickr = FlickrAPI(api_key=key, secret=secret) # Get the URL. if kind == "Short": return shorturl.url(photo_id = imageID) else: esizes = flickr.photos_getSizes(photo_id = imageID, format = 'etree') if format == '': for i in esizes[0]: if i.attrib['label'] == kind: return i.attrib['source'] break # If the size wasn't found. return "Size not found" elif format == 'md': einfo = flickr.photos_getInfo(photo_id = imageID, format = 'etree') photourl = einfo.find('photo/urls/url').text phototitle = einfo.find('photo/title').text if not phototitle: phototitle = "Untitled" for i in esizes[0]: if i.attrib['label'] == kind: jpgurl = i.attrib['source'] return "[![" + phototitle + "](" + jpgurl + ")](" + photourl + ")" break # If the size wasn't found. return "Size not found"
def currentFlickrURL(kind): '''Return a URL for the Flickr image currently showing in the browser. The string parameter "kind" can be either "Short" or one of the standard Flickr image sizes: "Original", "Large", "Medium 800", "Medium 640", "Medium", "Small 320", "Small", "Thumbnail", "Large Square", or "Square". If it's Short, the function will return a flic.kr URL for the image page. If it's one of the others, the function will return the URL of the image of that size, if available. The function works through Apple Events and supports only the Safari browser.''' # Flickr parameters fuser = '******' key = 'Get key from Flickr' secret = 'Get secret from Flickr' # Make sure we're asking for a legitimate kind. kind = ' '.join([x.capitalize() for x in kind.split()]) kinds = ["Short", "Original", "Large", "Medium 800", "Medium 640", "Medium", "Small 320", "Small", "Thumbnail", "Large Square", "Square"] if kind not in kinds: return "Not a legitimate kind of URL" # Get the image ID. try: imageID = currentFlickrID() except IndexError: return "Not a Flickr image" # Establish the connection with Flickr. flickr = FlickrAPI(api_key=key, secret=secret) # Get the URL. if kind == "Short": return shorturl.url(photo_id = imageID) else: etree = flickr.photos_getSizes(photo_id = imageID, format = 'etree') for i in etree[0]: if i.attrib['label'] == kind: return i.attrib['source'] break # If the size wasn't found. return "Size not found"
def currentFlickrURL(kind): '''Return a URL for the Flickr image currently showing in the browser. The string parameter "kind" can be either "Short" or one of the standard Flickr image sizes: "Original", "Large", "Medium 800", "Medium 640", "Medium", "Small 320", "Small", "Thumbnail", "Large Square", or "Square". If it's Short, the function will return a flic.kr URL for the image page. If it's one of the others, the function will return the URL of the image of that size, if available. The function works through Apple Events and supports only the Safari browser.''' # Flickr parameters fuser = '******' key = 'Get key from Flickr' secret = 'Get secret from Flickr' # Make sure we're asking for a legitimate kind. kind = ' '.join([x.capitalize() for x in kind.split()]) kinds = [ "Short", "Original", "Large", "Medium 800", "Medium 640", "Medium", "Small 320", "Small", "Thumbnail", "Large Square", "Square" ] if kind not in kinds: return "Not a legitimate kind of URL" # Get the image ID. try: imageID = currentFlickrID() except IndexError: return "Not a Flickr image" # Establish the connection with Flickr. flickr = FlickrAPI(api_key=key, secret=secret) # Get the URL. if kind == "Short": return shorturl.url(photo_id=imageID) else: etree = flickr.photos_getSizes(photo_id=imageID, format='etree') for i in etree[0]: if i.attrib['label'] == kind: return i.attrib['source'] break # If the size wasn't found. return "Size not found"
class Offlickr: def __init__( self, key, secret, httplib=None, dryrun=False, verbose=False, ): """Instantiates an Offlickr object An API key is needed, as well as an API secret""" self.__flickrAPIKey = key self.__flickrSecret = secret self.__httplib = httplib # Get authentication token # note we must explicitly select the xmlnode parser to be compatible with FlickrAPI 1.2 self.fapi = FlickrAPI(self.__flickrAPIKey, self.__flickrSecret, format='xmlnode') (token, frob) = self.fapi.get_token_part_one() if not token: raw_input('Press ENTER after you authorized this program') self.fapi.get_token_part_two((token, frob)) self.token = token test_login = self.fapi.test_login() uid = test_login.user[0]['id'] self.flickrUserId = uid self.dryrun = dryrun self.verbose = verbose def __testFailure(self, rsp): """Returns whether the previous call was successful""" if rsp['stat'] == 'fail': print 'Error!' return True else: return False def getPhotoList(self, dateLo, dateHi): """Returns a list of photo given a time frame""" n = 0 flickr_max = 500 photos = [] print 'Retrieving list of photos' while True: if self.verbose: print 'Requesting a page...' n = n + 1 rsp = self.fapi.photos_search( api_key=self.__flickrAPIKey, auth_token=self.token, user_id=self.flickrUserId, per_page=str(flickr_max), page=str(n), min_upload_date=dateLo, max_upload_date=dateHi, ) if self.__testFailure(rsp): return None if rsp.photos[0]['total'] == '0': return None photos += rsp.photos[0].photo if self.verbose: print ' %d photos so far' % len(photos) if len(photos) >= int(rsp.photos[0]['total']): break return photos def getGeotaggedPhotoList(self, dateLo, dateHi): """Returns a list of photo given a time frame""" n = 0 flickr_max = 500 photos = [] print 'Retrieving list of photos' while True: if self.verbose: print 'Requesting a page...' n = n + 1 rsp = \ self.fapi.photos_getWithGeoData(api_key=self.__flickrAPIKey, auth_token=self.token, user_id=self.flickrUserId, per_page=str(flickr_max), page=str(n)) if self.__testFailure(rsp): return None if rsp.photos[0]['total'] == '0': return None photos += rsp.photos[0].photo if self.verbose: print ' %d photos so far' % len(photos) if len(photos) >= int(rsp.photos[0]['total']): break return photos def getPhotoLocation(self, pid): """Returns a string containing location of a photo (in XML)""" rsp = \ self.fapi.photos_geo_getLocation(api_key=self.__flickrAPIKey, auth_token=self.token, photo_id=pid) if self.__testFailure(rsp): return None doc = libxml2.parseDoc(rsp.xml) info = doc.xpathEval('/rsp/photo')[0].serialize() doc.freeDoc() return info def getPhotoLocationPermission(self, pid): """Returns a string containing location permision for a photo (in XML)""" rsp = \ self.fapi.photos_geo_getPerms(api_key=self.__flickrAPIKey, auth_token=self.token, photo_id=pid) if self.__testFailure(rsp): return None doc = libxml2.parseDoc(rsp.xml) info = doc.xpathEval('/rsp/perms')[0].serialize() doc.freeDoc() return info def getPhotosetList(self): """Returns a list of photosets for a user""" rsp = self.fapi.photosets_getList(api_key=self.__flickrAPIKey, auth_token=self.token, user_id=self.flickrUserId) if self.__testFailure(rsp): return None return rsp.photosets[0].photoset def getPhotosetInfo(self, pid, method): """Returns a string containing information about a photoset (in XML)""" rsp = method(api_key=self.__flickrAPIKey, auth_token=self.token, photoset_id=pid) if self.__testFailure(rsp): return None doc = libxml2.parseDoc(rsp.xml) info = doc.xpathEval('/rsp/photoset')[0].serialize() doc.freeDoc() return info def getPhotoMetadata(self, pid): """Returns an array containing containing the photo metadata (as a string), and the format of the photo""" if self.verbose: print 'Requesting metadata for photo %s' % pid rsp = self.fapi.photos_getInfo(api_key=self.__flickrAPIKey, auth_token=self.token, photo_id=pid) if self.__testFailure(rsp): return None doc = libxml2.parseDoc(rsp.xml) metadata = doc.xpathEval('/rsp/photo')[0].serialize() doc.freeDoc() return [metadata, rsp.photo[0]['originalformat']] def getPhotoComments(self, pid): """Returns an XML string containing the photo comments""" if self.verbose: print 'Requesting comments for photo %s' % pid rsp = \ self.fapi.photos_comments_getList(api_key=self.__flickrAPIKey, auth_token=self.token, photo_id=pid) if self.__testFailure(rsp): return None doc = libxml2.parseDoc(rsp.xml) comments = doc.xpathEval('/rsp/comments')[0].serialize() doc.freeDoc() return comments def getPhotoSizes(self, pid): """Returns a string with is a list of available sizes for a photo""" rsp = self.fapi.photos_getSizes(api_key=self.__flickrAPIKey, auth_token=self.token, photo_id=pid) if self.__testFailure(rsp): return None return rsp def getOriginalPhoto(self, pid): """Returns a URL which is the original photo, if it exists""" source = None rsp = self.getPhotoSizes(pid) if rsp == None: return None for s in rsp.sizes[0].size: if s['label'] == 'Original': source = s['source'] for s in rsp.sizes[0].size: if s['label'] == 'Video Original': source = s['source'] return [source, s['label'] == 'Video Original'] def __downloadReportHook( self, count, blockSize, totalSize, ): if not self.__verbose: return p = ((100 * count) * blockSize) / totalSize if p > 100: p = 100 print '\r %3d %%' % p, sys.stdout.flush() def downloadURL( self, url, target, filename, verbose=False, ): """Saves a photo in a file""" if self.dryrun: return self.__verbose = verbose tmpfile = '%s/%s.TMP' % (target, filename) if self.__httplib == 'wget': cmd = 'wget -q -t 0 -T 120 -w 10 -c -O %s %s' % (tmpfile, url) os.system(cmd) else: urllib.urlretrieve(url, tmpfile, reporthook=self.__downloadReportHook) os.rename(tmpfile, '%s/%s' % (target, filename))
def currentFlickrURL(kind, linkformat = ""): '''Return a URL for the Flickr image currently showing in the browser. The string parameter "kind" can be either "Short" or one of the standard Flickr image sizes: "Original", "Large", "Medium 800", "Medium 640", "Medium", "Small 320", "Small", "Thumbnail", "Large Square", or "Square". If it's Short, the function will return a flic.kr URL for the image page. If it's one of the others, the function will return the URL of the image of that size, if available. The "linkformat" parameter can be omitted, or can be supplied as either "md" or "html" as long as "kind" is not "Short". Pass "md" to create a Markdown image reference where the image is linked back to its Flickr page, or provide "html" to create an HTML img tag surrounded by an a tag linking to the image's Flickr page. The function works through Apple Events and supports only the Safari browser.''' # Flickr parameters fuser = '******' key = 'Get key from Flickr' secret = 'Get secret from Flickr' # Make sure we're asking for a legitimate kind. kind = ' '.join([x.capitalize() for x in kind.split()]) kinds = ["Short", "Original", "Large", "Medium 800", "Medium 640", "Medium", "Small 320", "Small", "Thumbnail", "Large Square", "Square"] if kind not in kinds: return "Not a legitimate kind of URL" # Get the image ID. try: imageID = currentFlickrID() except IndexError: return "Not a Flickr image" # Establish the connection with Flickr. flickr = FlickrAPI(api_key=key, secret=secret) # Get the URL. if kind == "Short": return shorturl.url(photo_id = imageID) else: etree = flickr.photos_getSizes(photo_id = imageID, format = 'etree') if linkformat == '': for i in etree[0]: if i.attrib['label'] == kind: return i.attrib['source'] break # If the size wasn't found. return "Size not found" elif linkformat == 'md': einfo = flickr.photos_getInfo(photo_id = imageID, format = 'etree') photourl = einfo.find('photo/urls/url').text phototitle = einfo.find('photo/title').text if not phototitle: phototitle = "Untitled" for i in etree[0]: if i.attrib['label'] == kind: jpgurl = i.attrib['source'] return "[![" + phototitle + "](" + jpgurl + ")](" + photourl + ")" break # If the size wasn't found. return "Size not found" elif linkformat == 'html': einfo = flickr.photos_getInfo(photo_id = imageID, format = 'etree') photourl = einfo.find('photo/urls/url').text phototitle = einfo.find('photo/title').text if not phototitle: phototitle = "Untitled" for i in etree[0]: if i.attrib['label'] == kind: jpgurl = i.attrib['source'] photowidth = i.attrib['width'] photoheight = i.attrib['height'] return "<a href='" + photourl + "' title='" + phototitle + "'><img src='" + jpgurl + "' width='" + photowidth + "' height='" + photoheight + "'></a>" break # If the size wasn't found. return "Size not found" else: return "Invalid link format requested"
def upload_to_flickr(filename, bits, type): flickr = FlickrAPI(api_key = api_key, secret = secret, token = token, cache=False) f = flickr.uploadbits(filename, bits, type) res = flickr.photos_getSizes(photo_id = f.photoid[0].text) return res.sizes[0].size[3].attrib['source']
class TransFlickr: extras = "original_format,date_upload,last_update" def __init__(self, browserName): self.fapi = FlickrAPI(flickrAPIKey, flickrSecret) self.user_id = "" # proceed with auth # TODO use auth.checkToken function if available, # and wait after opening browser. print "Authorizing with flickr..." log.info("authorizing with flickr...") try: self.authtoken = self.fapi.getToken(browser=browserName) except: print ("Can't retrieve token from browser %s" % browserName) print ("\tIf you're behind a proxy server," " first set http_proxy environment variable.") print "\tPlease close all your browser windows, and try again" log.error(format_exc()) log.error("can't retrieve token from browser %s", browserName) sys.exit(-1) if self.authtoken == None: print "Unable to authorize (reason unknown)" log.error('not able to authorize; exiting') sys.exit(-1) #Add some authorization checks here(?) print "Authorization complete." log.info('authorization complete') def uploadfile(self, filepath, taglist, bufData, mode): #Set public 4(always), 1(public). Public overwrites f&f. public = mode&1 #Set friends and family 4(always), 2(family), 1(friends). friends = mode>>3 & 1 family = mode>>4 & 1 #E.g. 745 - 4:No f&f, but 5:public #E.g. 754 - 5:friends, but not public #E.g. 774 - 7:f&f, but not public log.info("uploading file %s", filepath) log.info(" data length: %s", len(bufData)) log.info(" taglist: %s", taglist) log.info(" permissions: family %s, friends %s, public %s", family, friends, public) filename = os.path.splitext(os.path.basename(filepath))[0] rsp = self.fapi.upload(filename=filepath, jpegData=bufData, title=filename, tags=taglist, is_public=public and "1" or "0", is_friend=friends and "1" or "0", is_family=family and "1" or "0") if rsp is None: log.error("response None from attempt to write file %s", filepath) log.error("will attempt recovery...") recent_rsp = None trytimes = 2 while(trytimes): log.info("sleeping for 3 seconds...") time.sleep(3) trytimes -= 1 # Keep on trying to retrieve the recently uploaded photo, till we # actually get the information, or the function throws an exception. while(recent_rsp is None or not recent_rsp): recent_rsp = self.fapi.photos_recentlyUpdated( auth_token=self.authtoken, min_date='1', per_page='1') pic = recent_rsp.photos[0].photo[0] log.info('we are looking for %s', filename) log.info('most recently updated pic is %s', pic['title']) if filename == pic['title']: id = pic['id'] log.info("file %s uploaded with photoid %s", filepath, id) return id log.error("giving up; upload of %s appears to have failed", filepath) return None else: id = rsp.photoid[0].elementText log.info("file %s uploaded with photoid %s", filepath, id) return id def put2Set(self, set_id, photo_id): log.info("uploading photo %s to set id %s", photo_id, set_id) rsp = self.fapi.photosets_addPhoto(auth_token=self.authtoken, photoset_id=set_id, photo_id=photo_id) if rsp: log.info("photo uploaded to set") else: log.error(rsp.errormsg) def createSet(self, path, photo_id): log.info("creating set %s with primary photo %s", path, photo_id) path, title = os.path.split(path) rsp = self.fapi.photosets_create(auth_token=self.authtoken, title=title, primary_photo_id=photo_id) if rsp: log.info("created set %s", title) return rsp.photoset[0]['id'] else: log.error(rsp.errormsg) def deleteSet(self, set_id): log.info("deleting set %s", set_id) if str(set_id)=="0": log.info("ignoring attempt to delete set wtih set_id 0 (a locally " "created set that has not yet acquired an id via uploading") return rsp = self.fapi.photosets_delete(auth_token=self.authtoken, photoset_id=set_id) if rsp: log.info("deleted set %s", set_id) else: log.error(rsp.errormsg) def getPhotoInfo(self, photoId): log.debug("id: %s", photoId) rsp = self.fapi.photos_getInfo(auth_token=self.authtoken, photo_id=photoId) if not rsp: log.error("can't retrieve information about photo %s; got error %s", photoId, rsp.errormsg) return None #XXX: should see if there's some other 'format' option we can fall back to. try: format = rsp.photo[0]['originalformat'] except KeyError: format = 'jpg' perm_public = rsp.photo[0].visibility[0]['ispublic'] perm_family = rsp.photo[0].visibility[0]['isfamily'] perm_friend = rsp.photo[0].visibility[0]['isfriend'] if perm_public == '1': mode = 0755 else: b_cnt = 4 if perm_family == '1': b_cnt += 2 if perm_friend == '1': b_cnt += 1 mode = "07" + str(b_cnt) + "4" mode = int(mode) if hasattr(rsp.photo[0],'permissions'): permcomment = rsp.photo[0].permissions[0]['permcomment'] permaddmeta = rsp.photo[0].permissions[0]['permaddmeta'] else: permcomment = permaddmeta = [None] commMeta = '%s%s' % (permcomment,permaddmeta) # Required for chmod. desc = rsp.photo[0].description[0].elementText title = rsp.photo[0].title[0].elementText if hasattr(rsp.photo[0].tags[0], "tag"): taglist = [ a.elementText for a in rsp.photo[0].tags[0].tag ] else: taglist = [] license = rsp.photo[0]['license'] owner = rsp.photo[0].owner[0]['username'] ownerNSID = rsp.photo[0].owner[0]['nsid'] url = rsp.photo[0].urls[0].url[0].elementText posted = rsp.photo[0].dates[0]['posted'] lastupdate = rsp.photo[0].dates[0]['lastupdate'] return (format, mode, commMeta, desc, title, taglist, license, owner, ownerNSID, url, int(posted), int(lastupdate)) def setPerm(self, photoId, mode, comm_meta="33"): log.debug("id: %s, mode: %s, comm_meta=%s", photoId, mode, comm_meta) public = mode&1 #Set public 4(always), 1(public). Public overwrites f&f #Set friends and family 4(always), 2(family), 1(friends) friends = mode>>3 & 1 family = mode>>4 & 1 if len(comm_meta)<2: # This wd patch string index out of range bug, caused # because some photos may not have comm_meta value set. comm_meta="33" rsp = self.fapi.photos_setPerms(auth_token=self.authtoken, is_public=str(public), is_friend=str(friends), is_family=str(family), perm_comment=comm_meta[0], perm_addmeta=comm_meta[1], photo_id=photoId) if not rsp: log.error("couldn't set permission for photo %s; got error %s", photoId, rsp.errormsg) return False log.info("permissions have been set for photo %s", photoId) return True def setTags(self, photoId, tags): log.debug("id: %s, tags: %s", photoId, tags) templist = [ '"%s"'%(a,) for a in string.split(tags, ',')] + ['flickrfs'] tagstring = ' '.join(templist) rsp = self.fapi.photos_setTags(auth_token=self.authtoken, photo_id=photoId, tags=tagstring) if not rsp: log.error("couldn't set tags for %s; got error %s", photoId, rsp.errormsg) return False return True def setMeta(self, photoId, title, desc): log.debug("id: %s, title: %s, desc: %s", photoId, title, desc) rsp = self.fapi.photos_setMeta(auth_token=self.authtoken, photo_id=photoId, title=title, description=desc) if not rsp: log.error("couldn't set meta info for photo %s; got error", photoId, rsp.errormsg) return False return True def getLicenses(self): log.debug("started") rsp = self.fapi.photos_licenses_getInfo() if not rsp: log.error("couldn't retrieve licenses; got error %s", rsp.errormsg) return None licenseDict = {} for l in rsp.licenses[0].license: licenseDict[l['id']] = l['name'] keys = licenseDict.keys() keys.sort() sortedLicenseList = [] for k in keys: # Add tuple of license key, and license value. sortedLicenseList.append((k, licenseDict[k])) return sortedLicenseList def setLicense(self, photoId, license): log.debug("id: %s, license: %s", photoId, license) rsp = self.fapi.photos_licenses_setLicense(auth_token=self.authtoken, photo_id=photoId, license_id=license) if not rsp: log.error("couldn't set license info for photo %s; got error %s", photoId, rsp.errormsg) return False return True def getPhoto(self, photoId): log.debug("id: %s", photoId) rsp = self.fapi.photos_getSizes(auth_token=self.authtoken, photo_id=photoId) if not rsp: log.error("error while trying to retrieve size information" " for photo %s", photoId) return None buf = "" for a in rsp.sizes[0].size: if a['label']=='Original': try: f = urllib2.urlopen(a['source']) buf = f.read() except: log.error("exception in getPhoto") log.error(format_exc()) return "" if not buf: f = urllib2.urlopen(rsp.sizes[0].size[-1]['source']) buf = f.read() return buf def removePhotofromSet(self, photoId, photosetId): log.debug("id: %s, setid: %s", photoId, photosetId) rsp = self.fapi.photosets_removePhoto(auth_token=self.authtoken, photo_id=photoId, photoset_id=photosetId) if rsp: log.info("photo %s removed from set %s", photoId, photosetId) else: log.error(rsp.errormsg) def getBandwidthInfo(self): log.debug("retrieving bandwidth information") rsp = self.fapi.people_getUploadStatus(auth_token=self.authtoken) if not rsp: log.error("can't retrieve bandwidth information; got error %s", rsp.errormsg) return (None,None) bw = rsp.user[0].bandwidth[0] log.debug("max bandwidth: %s, bandwidth used: %s", bw['max'], bw['used']) return (bw['max'], bw['used']) def getUserId(self): log.debug("entered") rsp = self.fapi.auth_checkToken(api_key=flickrAPIKey, auth_token=self.authtoken) if not rsp: log.error("unable to get userid; got error %s", rsp.errormsg) return None usr = rsp.auth[0].user[0] log.info("got NSID %s", usr['nsid']) #Set self.user_id to this value self.user_id = usr['nsid'] return usr['nsid'] def getPhotosetList(self): log.debug("entered") if self.user_id is "": self.getUserId() #This will set the value of self.user_id rsp = self.fapi.photosets_getList(auth_token=self.authtoken, user_id=self.user_id) if not rsp: log.error("error getting photoset list; got error %s", rsp.errormsg) return [] if not hasattr(rsp.photosets[0], "photoset"): log.info("no sets found for userid %s", self.user_id) return [] else: log.info("%s sets found for userid %s", len(rsp.photosets[0].photoset), self.user_id) return rsp.photosets[0].photoset def parseInfoFromPhoto(self, photo, perms=None): info = {} info['id'] = photo['id'] info['title'] = photo['title'].replace('/', '_') # Some pics don't contain originalformat attribute, so set it to jpg by default. try: info['format'] = photo['originalformat'] except KeyError: info['format'] = 'jpg' try: info['dupload'] = photo['dateupload'] except KeyError: info['dupload'] = '0' try: info['dupdate'] = photo['lastupdate'] except KeyError: info['dupdate'] = '0' info['perms'] = perms return info def parseInfoFromFullInfo(self, id, fullInfo): info = {} info['id'] = id info['title'] = fullInfo[4] info['format'] = fullInfo[0] info['dupload'] = fullInfo[10] info['dupdate'] = fullInfo[11] info['mode'] = fullInfo[1] return info def getPhotosFromPhotoset(self, photoset_id): log.debug("set id: %s", photoset_id) photosPermsMap = {} # I'm not utilizing the value part of this dictionary. Its arbitrarily # set to i. for i in range(0,3): page = 1 while True: rsp = self.fapi.photosets_getPhotos(auth_token=self.authtoken, photoset_id=photoset_id, extras=self.extras, page=str(page), privacy_filter=str(i)) if not rsp: break if not hasattr(rsp.photoset[0], 'photo'): log.error("photoset %s doesn't have attribute photo", rsp.photoset[0]['id']) break for p in rsp.photoset[0].photo: photosPermsMap[p] = str(i) page += 1 if page > int(rsp.photoset[0]['pages']): break if photosPermsMap: break return photosPermsMap def getPhotoStream(self, user_id): log.debug("userid: %s", user_id) retList = [] pageNo = 1 maxPage = 1 while pageNo<=maxPage: log.info("retreiving page number %s of %s", pageNo, maxPage) rsp = self.fapi.photos_search(auth_token=self.authtoken, user_id=user_id, per_page="500", page=str(pageNo), extras=self.extras) if not rsp: log.error("can't retrive photos from your stream; got error %s", rsp.errormsg) return retList if not hasattr(rsp.photos[0], 'photo'): log.error("photos.search response doesn't have attribute photos; " "returning list acquired so far") return retList for a in rsp.photos[0].photo: retList.append(a) maxPage = int(rsp.photos[0]['pages']) pageNo = pageNo + 1 return retList def getTaggedPhotos(self, tags, user_id=None): log.debug("tags: %s user_id: %s", tags, user_id) kw = kwdict(auth_token=self.authtoken, tags=tags, tag_mode="all", extras=self.extras, per_page="500") if user_id is not None: kw = kwdict(user_id=user_id, **kw) rsp = self.fapi.photos_search(**kw) log.debug("search for photos with tags %s has been" " successfully finished" % tags) if not rsp: log.error("couldn't search for the photos; got error %s", rsp.errormsg) return if not hasattr(rsp.photos[0], 'photo'): return [] return rsp.photos[0].photo
def importFromFlickr(): if g.user is None: return jsonify(result = False, error = "You need to be logged in to import from Flickr") if not g.user.flickr_auth: return jsonify(result = False, error = "Your account has not been authenticated with Flickr") try: # Yes yes, a massive try block, the horror! But almost every single line in here throws an error from FlickrAPI photoID = request.form.get('photoID') api_key = os.environ['PARAM1'] api_secret = os.environ['PARAM2'] flickr = FlickrAPI(api_key, api_secret, store_token = False) # Get original photo's URL sizes = flickr.photos_getSizes(photo_id = photoID).find('sizes')[-1] photo_url = sizes.attrib['source'] img_width = int(sizes.attrib['width']) # necessary to correctly scale notes img_height = int(sizes.attrib['height']) # Pull a blob of most of the photo's metadata photo_info = flickr.photos_getInfo(photo_id = photoID).find('photo') # Check if the person importing this photo actually owns it flickr_screen_name = photo_info.find('owner').attrib['username'] if flickr_screen_name.lower() != g.user.name.lower(): return jsonify(result = False, error = 'You dog! You don\'t own this photo! %s does. For shame.' % flickr_screen_name) # Pull photo's title, desc, timestamps from metadata blob flickr_owner_id = photo_info.find('owner').attrib['nsid'] # used to retrieve views title = photo_info.find('title').text desc = photo_info.find('description').text time_taken = photo_info.find('dates').attrib['taken'] # '2013-06-22 11:16:32' ... wtf? time_posted = photo_info.find('dates').attrib['posted'] # '1372279163' # flickr notes are in a 0..500px coordinate space, where 500 maps to max(img_width, img_height) # brickr notes are normalized to a 0..100 % coordinate space, regardless of image aspect ratio (because I'm smarter) # flickr notes don't have timestamp info scale_w = 500 if img_width >= img_height else (500 / img_height * img_width) scale_h = 500 if img_width < img_height else (500 / img_width * img_height) notes = [] for note in photo_info.find('notes'): notes.append({ 'user_id': note.attrib['author'], 'screen_name': note.attrib['authorname'], 'text': note.text, 'x': int(note.attrib['x']) / scale_w * 100, 'y': int(note.attrib['y']) / scale_h * 100, 'w': int(note.attrib['w']) / scale_w * 100, 'h': int(note.attrib['h']) / scale_h * 100 }) # Photo tags are easy tags = [] for tag in photo_info.find('tags'): if tag.attrib['machine_tag'] != '1': # Ignore ugly automatically created inivisible-to-users tags tags.append(tag.attrib['raw']) # Import comments - needs its own Flickr API call comments = [] if int(photo_info.find('comments').text) > 0: comment_rsp = flickr.photos_comments_getList(photo_id = photoID).find('comments') for comment in comment_rsp: comments.append({ 'user_id': comment.attrib.get('author'), 'screen_name': comment.attrib.get('authorname'), 'timestamp': comment.attrib.get('datecreate'), 'iconfarm': comment.attrib.get('iconfarm'), 'iconserver': comment.attrib.get('iconserver'), 'text': comment.text }) # Import Favorites. These come in at most 50 per request. Another dedicated Flickr API call favorites = [] favorite_rsp = flickr.photos_getFavorites(photo_id = photoID, per_page = '50').find('photo') for fav in favorite_rsp: favorites.append({ 'user_id': fav.attrib.get('nsid'), 'screen_name': fav.attrib.get('username'), 'timestamp': fav.attrib.get('favedate'), 'iconfarm': comment.attrib.get('iconfarm'), 'iconserver': comment.attrib.get('iconserver') }) fav_page_count = int(favorite_rsp.attrib['pages']) if fav_page_count > 1: for i in range(2, fav_page_count + 1): favorite_rsp = flickr.photos_getFavorites(photo_id = photoID, page = str(i), per_page = '50').find('photo') for fav in favorite_rsp: favorites.append({ 'user_id': fav.attrib['nsid'], 'screen_name': fav.attrib.get('username'), 'timestamp': fav.attrib.get('favedate'), 'iconfarm': comment.attrib.get('iconfarm'), 'iconserver': comment.attrib.get('iconserver') }) # View count # There's no direct flickr API to get a photo's view count (weird) # But we can add 'views' to the list of extra info returned by photo.search... (weird) # Can't search by photo ID (not weird), but can search by min & max upload time... set those to the photo's upload time, and we find the exact photo... (lucky) views = flickr.photos_search(user_id = flickr_owner_id, min_upload_date = time_posted, max_upload_date = time_posted, extras = 'views') views = views.find('photos')[0].attrib['views'] except Exception as e: return jsonify(result = False, error = "F**k me. Flickr Import went horribly awry. Send this message to Remi:\n\nPhoto: %s - %s" % (photoID, e.__repr__())) try: # So, we've pulled absolutely everything about this one photo out of Flickr. # Now dump it all into Brickr. You're welcome. photo = Photo(photo_url, g.user, title, desc) file_object = urllib2.urlopen(photo_url) # Download photo from Flickr fp = StringIO(file_object.read()) if not photo.save_file(fp): return jsonify(result = False, error = "Well shit. So, everything exported FROM Flickr just fine. But we failed to save the exported photo file. Send this message to Remi:\n\nPhoto: %s - Flickr Export - %s" % (photoID, photo_url)) # Flickr buddy icon URL: # http://farm{icon-farm}.staticflickr.com/{icon-server}/buddyicons/{nsid}.jpg # http://farm4.staticflickr.com/3692/buddyicons/[email protected] photo.views = views db.session.add(photo) db.session.commit() # Shit, should do everything in one commit, but we need a photo ID before adding things to the photo... for c in comments: user = User.get_user_or_placeholder(c['screen_name'], c['user_id']) comment = Comment(user, photo, c['text'], datetime.date.fromtimestamp(float(c['timestamp']))) db.session.add(comment) for n in notes: user = User.get_user_or_placeholder(n['screen_name'], n['user_id']) note = Note(user, photo, n['text'], n['x'], n['y'], n['w'], n['h']) db.session.add(note) for t in tags: tag = Tag.get_or_create(t) photo.tags.extend([tag]) db.session.add(tag) for f in favorites: user = User.get_user_or_placeholder(f['screen_name'], f['user_id']) fav = Favorite(user, photo) db.session.add(fav) db.session.commit() return jsonify(result = True, url = url_for('photos.photo', user_url = g.user.url, photoID = photo.id)) except Exception as e: return jsonify(result = False, error = "Well shit. So, everything exported FROM flickr just fine. But dumping it INTO Brickr is apparently too much to ask. Send this message to Remi:\n\nPhoto: %s - Brickr Import - %s" % (photoID, e.__repr__()))
def remap(line): if flickr.match(line): global fapi, token if fapi is None: fapi = FlickrAPI(flickrAPIKey, flickrSecret) token = fapi.getToken(browser="lynx") id = flickr.match(line).group(1) print " talking to Flickr about: ",id rsp = fapi.photos_getInfo(api_key=flickrAPIKey,auth_token=token,photo_id=id) fapi.testFailure(rsp) description = rsp.photo[0].description[0].elementText URL = rsp.photo[0].urls[0].url[0].elementText rsp = fapi.photos_getSizes(api_key=flickrAPIKey,auth_token=token,photo_id=id) fapi.testFailure(rsp) localbig = '' for x in rsp.sizes[0].size: if x.attrib['label'] == 'Large': localbig = x.attrib['source'].split('/')[-1] os.system('curl -o html/photos/%s "%s"' % (localbig, x.attrib['source'])) for x in rsp.sizes[0].size: #if x.attrib['label'] == 'Square': if x.attrib['label'] == 'Small': localpath = x.attrib['source'].split('/')[-1] big = '' if localbig != '': big = '[<a href="photos/%s">local</a>]' % localbig os.system('curl -o html/photos/%s "%s"' % (localpath, x.attrib['source'])) return '<div class="photo"><a href="%(url)s"><img src="%(src)s" height="%(height)s" width="%(width)s" alt="%(alt)s" /></a><div class="caption">%(caption)s%(localbig)s</div></div>' % \ {'src':'photos/%s'%localpath,#x.attrib['source'], 'height':x.attrib['height'], 'width':x.attrib['width'], 'caption': description, 'url':URL, 'alt':description, 'localbig':big } elif localphoto.match(line): m = localphoto.match(line) caption = m.group(1) id = m.group(2) thumb = id.split('.')[0] + '-thumb.jpeg' if not os.path.exists(thumb): cmd = 'convert -resize 240x240 ' + os.path.join(BASE,'photos/'+id) + ' ' + os.path.join(BASE,'photos/'+thumb) print cmd os.system(cmd) ## FIXME size probably wrong; figure out real size of ## thumbnail or at least whether its rotated or not return '<div class="photo"><a href="photos/%s"><img src="photos/%s" height="180" width="240" alt="%s" /></a><div class="caption">%s</div></div>' % (id, thumb, caption, caption) elif googledoc.match(line): url = googledoc.match(line).group(1) print " talking to Google about:",url html = googledocToHtml(urlopen(url).readlines()) return html elif resultdoc.match(line): name = resultdoc.match(line).group(1) url = resultdoc.match(line).group(2) print " talking to Google about results:",url html = resultdocToHtml(urlopen(url).readlines(), url, name) return html elif rideschedule.match(line): year = rideschedule.match(line).group(1).strip() region = rideschedule.match(line).group(2).strip().lower() if not year in ridelist.keys(): print " talking to Google about schedule:",year,region if int(year) > 2010: ridelist[year] = rideScheduleCsvToRideList(urlopen(PRELIM_RIDE_SCHEDULES[year]).readlines(), year) else: ridelist[year] = pre2010rideScheduleCsvToRideList(urlopen(PRELIM_RIDE_SCHEDULES[year]).readlines(), year) print year,ridelist[year] officialkey = region.strip().lower() + ':' + year.strip() if OFFICIAL_RIDE_SCHEDULES.has_key(officialkey): print " talking to Google about official schedule",year,region,OFFICIAL_RIDE_SCHEDULES[officialkey] if int(year.strip()) <= 2010: html = officialRideScheduleToHtml(urlopen(OFFICIAL_RIDE_SCHEDULES[officialkey]).readlines(), ridelist[year], year, region) else: html = officialRideListToHtml(ridelist[year], year, region) else: print "NO official ride schedule yet for",region,year,officialkey html = rideListToHtml(ridelist[year], region) return html elif membership.match(line): url = membership.match(line).group(1).strip() html = membershipToHtml(urlopen(url).readlines()) return html return line
#person = fapi.flickr_people_getInfo(user_id="tuxmann") #print person.username # and print them if hasattr(rsp.photosets[0], "photoset"): print 'yeup!' else: print 'nope' for a in rsp.photosets[0].photoset: # print "%10s: %s" % (a['id'], a['title'].encode("ascii", "replace")) print "%10s" % (str(a.title[0].elementText),) #getPhoto Sizes and urls rsp = fapi.photos_getSizes(photo_id="43050580", api_key=flickrAPIKey, auth_token=token) fapi.testFailure(rsp) for a in rsp.sizes[0].size: if a['label']=="Large": print "%s: %20s: %s" % (a['label'], a['source'], a['url']) import urllib2 f = urllib2.urlopen(a['source']) newfile = open('newfile', "w") tempbuf = str(f.read()) print 'converted to string of size: ' + str(long(tempbuf.__len__())) newfile.write(tempbuf) print 'wrote to newfile' newfile.close() # upload the file foo.jpg rsp = fapi.upload("/tmp/bsd_vs_tux.jpg", api_key=flickrAPIKey, auth_token=token, \
class Importer(object): def __init__(self): self.flickr = FlickrAPI(FLICKR_KEY) def get_photosets(self, username, filename=None): filename = filename or username+'.json' if os.path.exists(filename): print "Looks like we already have information about your photos." if raw_input("Refresh? (y/n): ").lower().startswith('n'): return deserialize(open(filename).read()) print "Downloading information about your photos." if '@' in username: response = self.flickr.people_findByEmail(find_email=username) else: response = self.flickr.people_findByUsername(username=username) nsid = response[0].get('nsid') response = self.flickr.photosets_getList(user_id=nsid) photosets = [] photo_ids = [] for ps in response[0]: photoset = {'id': ps.get('id'), 'title': ps[0].text, 'description': ps[1].text, 'photos':[]} photos_response = self.flickr.photosets_getPhotos(photoset_id=photoset['id'], extras='url_o') for pxml in photos_response[0]: photo = {'id':pxml.get('id'), 'title':pxml.get('title')} photoset['photos'].append(photo) photo_ids.append(photo['id']) print photoset['title'],'-',len(photoset['photos']),'photos' photosets.append(photoset) # get photos not in photosets photos_response = self.flickr.photos_search(user_id=nsid, per_page=500) photoset = {'id':'stream', 'title':'Flickr Stream', 'description':'Photos from my flickr stream', 'photos':[]} for pxml in response[0]: photo = {'id':pxml.get('id'), 'title':pxml.get('title')} if photo['id'] not in photo_ids: photoset['photos'].append(photo) photo_ids.append(photo['id']) if photoset['photos']: print photoset['title'],'-',len(photoset['photos']),'photos' photosets.append(photoset) f = open(filename, "w") f.write(serialize(photosets)) f.close() return photosets def download_images(self, photosets, directory): print "Downloading your photos" if not os.path.exists(directory): os.mkdir(directory) default = None for photoset in photosets: dirpath = os.path.join(directory, photoset['id']+' - '+photoset['title']) if not os.path.exists(dirpath): os.mkdir(dirpath) for photo in photoset['photos']: filename = os.path.join(dirpath, photo['id']+'.jpg') if os.path.exists(filename): if default is None: print "Photo", photo['id'], "has already been downloaded." default = raw_input("Download again? (y/n/Y/N) (capital to not ask again): ") if default == 'n': default = None continue elif default == 'N': continue elif default == 'y': default = None f = open(filename, 'w') if not photo.get('url'): try: sizes_response = self.flickr.photos_getSizes(photo_id=photo['id']) except: print "Failed to download photo:", photo['id'], '... sorry!' else: photo['url'] = sizes_response[0][-1].get('source') if photo.get('url'): print "Downloading", photo['title'], 'from', photo['url'] remote = urllib2.urlopen(photo['url']) f.write(remote.read()) f.close() remote.close() def upload_images(self, photosets, directory): client = DivvyshotClient() for photoset in photosets: event_data = client.create_event(name=photoset['title'], description=photoset['description']) event_path = '/api/v2/json/event/%s/photo/' % event_data['url_slug'] for photo in photoset['photos']: print "Uploading", photo['title'] filename = os.path.join(directory, photoset['id']+' - '+photoset['title'], photo['id']+'.jpg') if not os.path.exists(filename): print "Looks like photo",photo['id'],'did not get downloaded.' continue photo_data = client.create_photo(event_data['url_slug'], filename) photo_data = client.update_photo(photo_data['url_slug'], name=photo['title']) print "Finished uploading", photo_data['name'] os.remove(filename) def do_import(self): username = raw_input("Your flickr username/email: ") # Step 1: grab the list of photos from flickr photosets = self.get_photosets(username) # Step 2: download the images from flickr self.download_images(photosets, username) self.upload_images(photosets, username)
class Offlickr: def __init__(self, key, secret, uid, httplib=None, browser="lynx", verbose=False): """Instantiates an Offlickr object An API key is needed, as well as an API secret and a user id. A browser can be specified to be used for authorizing the program to access the user account.""" self.__flickrAPIKey = key self.__flickrSecret = secret self.__httplib = httplib # Get authentication token self.fapi = FlickrAPI(self.__flickrAPIKey, self.__flickrSecret) self.token = self.fapi.getToken(browser=browser) self.flickrUserId = uid self.verbose = verbose def __testFailure(self, rsp): """Returns whether the previous call was successful""" if rsp['stat'] == "fail": print "Error!" return True else: return False def getPhotoList(self, dateLo, dateHi): """Returns a list of photo given a time frame""" n = 0 flickr_max = 500 photos = [] print "Retrieving list of photos" while True: if self.verbose: print "Requesting a page..." n = n + 1 rsp = self.fapi.photos_search( api_key=self.__flickrAPIKey, auth_token=self.token, user_id=self.flickrUserId, per_page=str(flickr_max), # Max allowed by Flickr page=str(n), min_upload_date=dateLo, max_upload_date=dateHi) if self.__testFailure(rsp): return None if rsp.photos[0]['total'] == '0': return None photos += rsp.photos[0].photo if self.verbose: print " %d photos so far" % len(photos) if len(photos) >= int(rsp.photos[0]['total']): break return photos def getPhotosetList(self): """Returns a list of photosets for a user""" rsp = self.fapi.photosets_getList(api_key=self.__flickrAPIKey, auth_token=self.token, user_id=self.flickrUserId) if self.__testFailure(rsp): return None return rsp.photosets[0].photoset def getPhotosetInfo(self, pid, method): """Returns a string containing information about a photoset (in XML)""" rsp = method(api_key=self.__flickrAPIKey, auth_token=self.token, photoset_id=pid) if self.__testFailure(rsp): return None doc = libxml2.parseDoc(rsp.xml) info = str(doc.xpathEval("/rsp/photoset")[0]) doc.freeDoc() return info def getPhotoMetadata(self, pid): """Returns an array containing containing the photo metadata (as a string), and the format of the photo""" if self.verbose: print "Requesting metadata for photo %s" % pid rsp = self.fapi.photos_getInfo(api_key=self.__flickrAPIKey, auth_token=self.token, photo_id=pid) if self.__testFailure(rsp): return None doc = libxml2.parseDoc(rsp.xml) metadata = doc.xpathEval("/rsp/photo")[0].serialize() doc.freeDoc() return [metadata, rsp.photo[0]['originalformat']] def getPhotoComments(self, pid): """Returns an XML string containing the photo comments""" if self.verbose: print "Requesting comments for photo %s" % pid rsp = self.fapi.photos_comments_getList(api_key=self.__flickrAPIKey, auth_token=self.token, photo_id=pid) if self.__testFailure(rsp): return None doc = libxml2.parseDoc(rsp.xml) comments = doc.xpathEval("/rsp/comments")[0].serialize() doc.freeDoc() return comments def getPhotoSizes(self, pid): """Returns a string with is a list of available sizes for a photo""" rsp = self.fapi.photos_getSizes(api_key=self.__flickrAPIKey, auth_token=self.token, photo_id=pid) if self.__testFailure(rsp): return None return rsp def getOriginalPhoto(self, pid): """Returns a URL which is the original photo, if it exists""" source = None rsp = self.getPhotoSizes(pid) if rsp == None: return None for s in rsp.sizes[0].size: if s['label'] == 'Original': source = s['source'] return source def __downloadReportHook(self, count, blockSize, totalSize): if self.__verbose == False: return p = 100 * count * blockSize / totalSize if (p > 100): p = 100 print "\r %3d %%" % p, sys.stdout.flush() def downloadURL(self, url, target, filename, verbose=False): """Saves a photo in a file""" self.__verbose = verbose tmpfile = "%s/%s.TMP" % (target, filename) if self.__httplib == 'wget': cmd = 'wget -q -t 0 -T 120 -w 10 -c -O %s %s' % (tmpfile, url) os.system(cmd) else: urllib.urlretrieve(url, tmpfile, reporthook=self.__downloadReportHook) os.rename(tmpfile, "%s/%s" % (target, filename))