import os,os.path import requests, urllib, urlparse import json headers2dict = lambda h: dict([l.strip().split(": ") for l in h.strip().splitlines()]) class PhotoStationAPI(): def __init__(self, ps_url): self.url = "%s/webapi/"%ps_url self.sid = "" self.user = "" self.headers = headers2dict(""" User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Referer: %s/photo/ """%ps_url) def login(self,user,password): data = "api=SYNO.PhotoStation.Auth&method=login&version=1&username=%s&password=%s&remember_me=on"%(user,password) js = self._call2("auth.php",data) if not js["success"]: raise Exception("Can not login") self.sid=js["data"]["sid"] self.user = user return self.sid def logout(self): pass def get_album_list( self, album_id="", offset=0,limit=-1, additional="album_permission,photo_exif,video_codec,video_quality,thumb_size,file_location,item_count,album_sorting", #album_permission,photo_exif,video_codec,video_quality,thumb_size,file_location sort_by="preference", # 'filename', 'takendate', 'createdate', 'preference', 'default' sort_direction="asc" ): data = "api=SYNO.PhotoStation.Album&method=list&version=1&offset=%s&limit=%s&recursive=false&type=album,photo,video&additional=%s&sort_direction=%s&sort_by=%s&ignore=thumbnail&id=%s"%( offset,limit,additional,sort_direction,sort_by,album_id) js = self._call2("album.php",data) if js["success"] and "data" in js: return js["data"] else: raise Exception("Error reading album list") def get_album_list2( self, album_id="", offset=0,limit=-1, additional="album_permission,photo_exif,video_codec,video_quality,thumb_size,file_location,item_count,album_sorting", #album_permission,photo_exif,video_codec,video_quality,thumb_size,file_location sort_by="preference", # filename, sort_direction="asc" ): lst = [] js = self.get_album_list(album_id,offset,limit,additional,sort_by,sort_direction) for f in js["items"]: if f["type"] == u"photo": name = f["info"]["name"] desc = [ f["info"]["description"], f["additional"]["file_location"], f["info"]["takendate"], "%sx%s"%(f["info"]["resolutionx"],f["info"]["resolutiony"]), "%s %s"%(f["additional"]["photo_exif"]["camera"],f["additional"]["photo_exif"]["camera_model"]), "%s %s %s"%(f["additional"]["photo_exif"]["aperture"],f["additional"]["photo_exif"]["exposure"],f["additional"]["photo_exif"]["focal_length"]) ] elif f["type"] == u"video": name = f["info"]["name"] desc = [ f["info"]["description"], f["additional"]["file_location"], ] elif f["type"] == u"album": name = f["info"]["name"] desc = [ f["info"]["description"], f["additional"]["file_location"], "%s photos, %s videos"%(f["additional"]["item_count"]["photo"],f["additional"]["item_count"]["video"]) ] desc = filter(None, desc) desc = "\n".join(desc) img = self.get_thumb_url(f["id"],"small") lst.append([ f["info"]["name"].encode("utf8"), f["id"].encode("utf8"), #id img.encode("utf8"), # thumburl desc.encode("utf8"), # desc #f["type"].encode("utf8") ]) return lst def get_album_info(self,album_id=""): data = "id=%s&additional=album_sorting,item_count&api=SYNO.PhotoStation.Album&method=getinfo&version=1&ps_username=%s"%( album_id,self.user) js = self._call2("album.php",data) if js["success"] and "data" in js: return js["data"] else: raise Exception("Error reading album info") def get_category(self, category_id=""): if category_id: # api=SYNO.PhotoStation.Category&method=list&version=1&offset=0&limit=1000 data = "id=%s&api=SYNO.PhotoStation.Category&method=listitem&version=1&offset=0&limit=500&additional=album_permission,thumb_size" % category_id else: data = "api=SYNO.PhotoStation.Category&method=list&version=1&offset=0&limit=1000" js = self._call2("category.php",data) if js["success"] and "data" in js: return js["data"] else: raise Exception("Error reading album info") def get_smart_album(self, id=""): if id: #TODO data = "id=%s&api=SYNO.PhotoStation.Category&method=listitem&version=1&offset=0&limit=500&additional=album_permission,thumb_size" % id else: #sort_by=title&sort_direction=desc&api=SYNO.PhotoStation.SmartAlbum&method=list&version=1&offset=0&limit=500&additional=thumb_size data = "sort_by=title&sort_direction=desc&api=SYNO.PhotoStation.SmartAlbum&method=list&version=1&offset=0&limit=500&additional=thumb_size" js = self._call2("smart_album.php",data) if js["success"] and "data" in js: return js["data"] else: raise Exception("Error reading album info") def get_photo_info(self,id): data = "id=%s&version=1&api=SYNO.PhotoStation.Photo&method=getinfo&ps_username=%s&additional=album_permission,photo_exif,video_codec,video_quality,thumb_size,file_location,item_count,album_sorting"%(id,self.user) js = self._call2("photo.php",data) if js["success"] and "data" in js: return js["data"][0] else: raise Exception("Error reading photo/video info") def get_thumb(self,id,size="peview",rotate=0 ): # siz = preview|small|large data = "api=SYNO.PhotoStation.Thumb&method=get&version=1&size=%s&id=%s&rotate_version=%s"%(size,id,rotate) content = self._call2("thumb.php",data) return content def get_thumb_url(self,id,size="small",rotate=0 ): # http://home.blue.lv/photo/webapi/thumb.php?api=SYNO.PhotoStation.Thumb&method=get&version=1&size=large&id=photo_323031372f323031372d30312d787820537475626169_53353032303031372e4a5047&rotate_version=0&thumb_sig=&PHPSESSID=p51g2ssj3b2o3legsoqfqdc8r3 url = "%sthumb.php?api=SYNO.PhotoStation.Thumb&method=get&version=1&size=%s&id=%s&rotate_version=%s&thumb_sig=&PHPSESSID=%s"%( self.url, size, id, rotate, self.sid ) return url def get_video_streams(self,id): urls = [] js = self.get_photo_info(id) if not js: return urls name = js["info"]["name"] for q in js["additional"]["video_quality"]: s = {} quality_id = q["id"] data = "api=SYNO.PhotoStation.Download&method=getvideo&version=1&id=%s&quality_id=%s"%(id,quality_id) url = "%s/download.php/%s?%s&PHPSESSID=%s"%(self.url,name,data,self.sid) s["name"] = name s["url"] = url s["img"] = self.get_thumb_url(id, size='small') s["quality"] = "%sx%s"%(q["resolutionx"],q["resolutiony"]) s["bitrate"] = q["video_bitrate"] s["desc"] = "%s %s\n%s\n%sx%s %s/%s"%(js["info"]["name"],js["info"]["description"], js["info"]["takendate"], js["additional"]["video_codec"]["resolutionx"],js["additional"]["video_codec"]["resolutiony"],js["additional"]["video_codec"]["vcodec"],js["additional"]["video_codec"]["acodec"]) urls.append(s) return urls def _call(self,path,data): url = self.url+path if isinstance(data,basestring): data = urlparse.parse_qs(data) if self.sid: self.headers["Cookie"] = "PHPSESSID=%s;"%self.sid try: r = requests.post(url,data,headers=self.headers) js = json.loads(r.content) return js except Exception as e: return {} def _call2(self,path,data): "GET request to PhotoStation API" if isinstance(data,dict): data = urllib.urlencode(data) if self.sid: if not "PHPSESSID" in data: data = data +"&PHPSESSID=%s"%self.sid #self.headers["Cookie"] = "PHPSESSID=%s;"%self.sid try: url = self.url + path +"?"+data print url r = requests.get(url,headers=self.headers) js = json.loads(r.content) return js except Exception as e: return {} def _check_url(self,url): if self.sid: if not "PHPSESSID" in url: self.headers["Cookie"] = "PHPSESSID=%s; photo_remember_me=1"%self.sid pass r = requests.get(url,headers=self.headers) if r.status_code <> 200 or "text/plain" in r.headers["Content-Type"] and "error" in r.content: return False else: return True if __name__ == "__main__": ps = PhotoStationAPI("http://home.blue.lv/photo") print ps.login("user","Kaskade7") js = ps.get_category("category_1") album_id = u'album_323031372f323031372d30312d313320536c69646f73616e61' js = ps.get_album_info(album_id) js = ps.get_album_list2(album_id) photo_id = "photo_323031372f323031372d30312d787820537475626169_53353032303031372e4a5047" js = ps.get_photo_info(photo_id) url = ps.get_thumb_url(photo_id,"large") print url print ps._check_url(url) video_id = "video_323031372f323031372d30312d7878205374756261692f636c697073_30303136342e4d5453" js = ps.get_photo_info(video_id) urls = ps.get_video_streams(video_id) print urls[0]["url"] a=1