# -*- coding: utf-8 -*- 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) self.api = self._call2("query.php", "api=SYNO.API.Info&method=query&version=1&query=all") 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) self.sid=js["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) return self._call2("album.php",data) 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_categories(self): return self.call_api("Category", "list", offset=0, limit=120) 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) return self._call2("album.php",data) def get_category_list2(self): return self.call_api("Category", "list", offset=0, limit=-1) def get_category_list(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=-1&additional=album_permission,photo_exif,video_codec,video_quality,thumb_size,file_location,item_count,album_sorting" % category_id else: data = "api=SYNO.PhotoStation.Category&method=list&version=1&offset=0&limit=-1" return self._call2("category.php",data) 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" return self._call2("smart_album.php",data) 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 isinstance(js, list): return js[0] else: return js 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 ): # small (M),preview (PREVIEW),large (XL) # 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_photo_url(self,id): url = "%sdownload.php?api=SYNO.PhotoStation.Download&method=getphoto&version=1&id=%s&PHPSESSID=%s" % ( self.url, id, self.sid ) return url def get_video_url(self,id, quality_id=""): if not quality_id: url = "%sdownload.php?api=SYNO.PhotoStation.Download&method=getvideo&version=1&id=%s&PHPSESSID=%s" % ( self.url, id, self.sid ) else: url = "%sdownload.php?api=SYNO.PhotoStation.Download&method=getvideo&version=1&id=%s&quality_id=%s&PHPSESSID=%s" % ( self.url, id, quality_id, 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) except Exception as e: raise Exception(e) if not (js["success"] and "data" in js): raise Exception("PhotoStation API %s error %s\n%s" % ( path, js["error"]["code"], data)) else: return js["data"] 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) except Exception as e: raise Exception(e) if not (js["success"] and "data" in js): raise Exception("PhotoStation API %s error %s\n%s" % ( path, js["error"]["code"], data)) else: return js["data"] 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 def call_api(self, obj, method, **kwargs): proc = "SYNO.PhotoStation." + obj if proc not in self.api: raise Exception("Not valid API object name ", obj) path = self.api[proc]["path"] data = {} data["api"] = proc data["method"] = method data["version"] = 1 data.update(kwargs) return self._call2(path, data) API = { "SYNO.PhotoStation.Auth": { "path": "auth.php", "methods": { "1": ["login", "logout", "checkauth"] } }, "SYNO.PhotoStation.Info": { "path": "info.php", "methods": { "1": ["getinfo"] } }, "SYNO.PhotoStation.Album": { "path": "album.php", "methods": { "1": ["list", "getinfo", "create", "edit", "delete", "arrangeitem", "move", "cleararrangeitem", "cancel"] } }, "SYNO.PhotoStation.Permission": { "path": "permission.php", "methods": { "1": ["getalbum", "editalbum", "editgroup", "list_public_share", "edit_public_share"] } }, "SYNO.PhotoStation.Photo": { "path": "photo.php", "methods": { "1": ["list", "listexif", "listfeatureditem", "listgpsgroup", "listgpsgroupeditem", "getinfo", "getexif", "edit", "delete", "copy", "cancel"] } }, "SYNO.PhotoStation.Thumb": { "path": "thumb.php", "methods": { "1": ["get", "get_dsm_thumb"] } }, "SYNO.PhotoStation.Cover": { "path": "cover.php", "methods": { "1": ["set"] } }, "SYNO.PhotoStation.SmartAlbum": { "path": "smart_album.php", "methods": { "1": ["list", "getinfo", "create", "edit", "delete"] } }, "SYNO.PhotoStation.File": { "path": "file.php", "methods": { "1": ["uploadphoto", "uploadvideo"] } }, "SYNO.PhotoStation.Download": { "path": "download.php", "methods": { "1": ["getphoto", "getvideo", "getitem"] } }, "SYNO.PhotoStation.ory": { "path": "ory.php", "methods": { "1": ["list", "getinfo", "create", "edit", "delete", "arrangeory", "listitem", "additem", "removeitem", "arrangeitem"] } }, "SYNO.PhotoStation.About": { "path": "about.php", "methods": { "1": ["get", "set", "set_visibility"] } }, "SYNO.PhotoStation.Tag": { "path": "tag.php", "methods": { "1": ["list", "getinfo", "create", "edit", "delete", "searchplace", "delete_unconfirmed_tag"] } }, "SYNO.PhotoStation.PhotoTag": { "path": "photo_tag.php", "methods": { "1": ["list", "people_tag", "geo_tag", "desc_tag", "delete", "people_tag_confirm"] } }, "SYNO.PhotoStation.Comment": { "path": "comment.php", "methods": { "1": ["list", "create", "delete"] } }, "SYNO.PhotoStation.Timeline": { "path": "timeline.php", "methods": { "1": ["getindex"] } }, "SYNO.PhotoStation.Group": { "path": "group.php", "methods": { "1": ["list", "get", "get_dsm_group", "getmember", "create", "edit", "editmember", "delete"] } }, "SYNO.PhotoStation.Rotate": { "path": "rotate.php", "methods": { "1": ["set"] } }, "SYNO.PhotoStation.SlideshowMusic": { "path": "slideshow_music.php", "methods": { "1": ["list", "get", "add", "edit", "delete"] } }, "SYNO.PhotoStation.DsmShare": { "path": "dsm_share.php", "methods": { "1": ["list", "copy", "copymusic"] } }, "SYNO.PhotoStation.SharedAlbum": { "path": "shared_album.php", "methods": { "1": ["list", "getinfo", "getinfo_public", "create", "edit", "delete", "add_items", "remove_items", "edit_public_share", "get_single_item", "set_single_item"] } }, "SYNO.PhotoStation.PhotoLog": { "path": "log.php", "methods": { "1": ["list", "clear", "export"] } }, "SYNO.PhotoStation.Path": { "path": "path.php", "methods": { "1": [" ", "checkpath"] } } } if __name__ == "__main__": ps = PhotoStationAPI("http://home.blue.lv/photo") print ps.login("user","Kaskade7") js = ps.call_api("Category", "list", offset=0, limit=120) js = ps.get_category_list("category_1") #js = ps.get_category("category_1") video_id = "video_323031372f323031372d31322d3234205a69656d6173737665746b692f636c697073_30303133332e4d5453" quality_id = "2f766f6c756d65312f70686f746f2f323031372f323031372d31322d3234205a69656d6173737665746b692f636c6970732f4065614469722f30303133332e4d54532f53594e4f50484f544f5f46494c4d5f4d2e6d7034" url = ps.get_video_url(video_id, quality_id) url0 = ps.get_video_url(video_id, "") album_id = u'album_323031372f323031372d30312d313320536c69646f73616e61' js = ps.get_album_info(album_id) js = ps.get_album_list(album_id) album_id = "album_323031372f323031372d30312d313320536c69646f73616e612f766964656f" js = ps.get_album_list(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