diff options
Diffstat (limited to 'pyload/api')
-rw-r--r-- | pyload/api/__init__.py | 196 | ||||
-rw-r--r-- | pyload/api/types.py | 12 |
2 files changed, 82 insertions, 126 deletions
diff --git a/pyload/api/__init__.py b/pyload/api/__init__.py index e7e082ecd..365828d0a 100644 --- a/pyload/api/__init__.py +++ b/pyload/api/__init__.py @@ -31,12 +31,17 @@ from utils import compare_time, freeSpace, html_unescape, save_filename if activated: try: + from lib.thrift.protocol import TBase from remote.thriftbackend.thriftgen.pyload.ttypes import * from remote.thriftbackend.thriftgen.pyload.Pyload import Iface + BaseObject = TBase + except ImportError: - print "Thrift not imported" from pyload.api.types import * + + print "Thrift not imported" + else: from pyload.api.types import * @@ -44,34 +49,37 @@ else: # unlisted functions are for admins only permMap = {} + # decorator only called on init, never initialized, so has no effect on runtime def permission(bits): class _Dec(object): def __new__(cls, func, *args, **kwargs): permMap[func.__name__] = bits return func - return _Dec urlmatcher = re.compile(r"((https?|ftps?|xdcc|sftp):((//)|(\\\\))+[\w\d:#@%/;$()~_?\+\-=\\\.&\[\]\|]*)", re.IGNORECASE) -class PERMS: + +class PERMS(object): ALL = 0 # requires no permission, but login ADD = 1 # can add packages - DELETE = 2 # can delete packages - STATUS = 4 # see and change server status - LIST = 16 # see queue and collector - MODIFY = 32 # moddify some attribute of downloads + DELETE = 2 # can delete packages + STATUS = 4 # see and change server status + LIST = 16 # see queue and collector + MODIFY = 32 # moddify some attribute of downloads DOWNLOAD = 64 # can download from webinterface - SETTINGS = 128 # can access settings - ACCOUNTS = 256 # can access accounts - LOGS = 512 # can see server logs + SETTINGS = 128 # can access settings + ACCOUNTS = 256 # can access accounts + LOGS = 512 # can see server logs + -class ROLE: - ADMIN = 0 #admin has all permissions implicit +class ROLE(object): + ADMIN = 0 # admin has all permissions implicit USER = 1 + def has_permission(userperms, perms): # bytewise or perms before if needed return perms == (userperms & perms) @@ -90,17 +98,16 @@ class Api(Iface): These can be configured via webinterface. Admin user have all permissions, and are the only ones who can access the methods with no specific permission. """ - EXTERNAL = Iface # let the json api know which methods are external def __init__(self, core): self.core = core def _convertPyFile(self, p): - f = FileData(p["id"], p["url"], p["name"], p["plugin"], p["size"], - p["format_size"], p["status"], p["statusmsg"], - p["package"], p["error"], p["order"]) - return f + fdata = FileData(p["id"], p["url"], p["name"], p["plugin"], p["size"], + p["format_size"], p["status"], p["statusmsg"], + p["package"], p["error"], p["order"]) + return fdata def _convertConfigFormat(self, c): sections = {} @@ -135,8 +142,7 @@ class Api(Iface): value = self.core.config[category][option] else: value = self.core.config.getPlugin(category, option) - - return str(value) if not isinstance(value, basestring) else value + return str(value) @permission(PERMS.SETTINGS) def setConfigValue(self, category, option, value, section="core"): @@ -148,13 +154,10 @@ class Api(Iface): :param section: 'plugin' or 'core """ self.core.addonManager.dispatchEvent("configChanged", category, option, value, section) - if section == "core": self.core.config[category][option] = value - - if option in ("limit_speed", "max_speed"): #not so nice to update the limit + if option in ("limit_speed", "max_speed"): # not so nice to update the limit self.core.requestFactory.updateBucket() - elif section == "plugin": self.core.config.setPlugin(category, option, value) @@ -188,7 +191,6 @@ class Api(Iface): """ return self.core.config.plugin - @permission(PERMS.STATUS) def pauseServer(self): """Pause server: Tt wont start any new downloads, but nothing gets aborted.""" @@ -227,10 +229,8 @@ class Api(Iface): self.core.files.getQueueCount(), self.core.files.getFileCount(), 0, not self.core.threadManager.pause and self.isTimeDownload(), self.core.config['reconnect']['activated'] and self.isTimeReconnect()) - for pyfile in [x.active for x in self.core.threadManager.threads if x.active and isinstance(x.active, PyFile)]: - serverStatus.speed += pyfile.getSpeed() #bytes/s - + serverStatus.speed += pyfile.getSpeed() # bytes/s return serverStatus @permission(PERMS.STATUS) @@ -266,7 +266,7 @@ class Api(Iface): if offset >= len(lines): return [] return lines[offset:] - except: + except Exception: return ['No log available'] @permission(PERMS.STATUS) @@ -299,13 +299,11 @@ class Api(Iface): for pyfile in self.core.threadManager.getActiveFiles(): if not isinstance(pyfile, PyFile): continue - data.append(DownloadInfo( pyfile.id, pyfile.name, pyfile.getSpeed(), pyfile.getETA(), pyfile.formatETA(), pyfile.getBytesLeft(), pyfile.getSize(), pyfile.formatSize(), pyfile.getPercent(), pyfile.status, pyfile.getStatusName(), pyfile.formatWait(), pyfile.waitUntil, pyfile.packageid, pyfile.package().name, pyfile.pluginname)) - return data @permission(PERMS.ADD) @@ -342,18 +340,14 @@ class Api(Iface): :return: """ urls = [] - if html: urls += [x[0] for x in urlmatcher.findall(html)] - if url: page = getURL(url) urls += [x[0] for x in urlmatcher.findall(page)] - # remove duplicates return self.checkURLs(set(urls)) - @permission(PERMS.ADD) def checkURLs(self, urls): """ Gets urls and returns pluginname mapped to list of matches urls. @@ -367,7 +361,7 @@ class Api(Iface): for url, plugintype, pluginname in data: try: plugins[plugintype][pluginname].append(url) - except: + except Exception: plugins[plugintype][pluginname] = [url] return plugins @@ -386,7 +380,6 @@ class Api(Iface): tmp = [(url, (url, OnlineStatus(url, (plugintype, pluginname), "unknown", 3, 0))) for url, plugintype, pluginname in data] data = parseNames(tmp) result = {} - for k, v in data.iteritems(): for url, status in v: status.packagename = k @@ -406,7 +399,6 @@ class Api(Iface): th = open(join(self.core.config["general"]["download_folder"], "tmp_" + container), "wb") th.write(str(data)) th.close() - return self.checkOnlineStatus(urls + [th.name]) @permission(PERMS.ADD) @@ -417,14 +409,12 @@ class Api(Iface): :return: `OnlineCheck`, if rid is -1 then no more data available """ result = self.core.threadManager.getInfoResult(rid) - if "ALL_INFO_FETCHED" in result: del result["ALL_INFO_FETCHED"] return OnlineCheck(-1, result) else: return OnlineCheck(rid, result) - @permission(PERMS.ADD) def generatePackages(self, links): """ Parses links, generates packages names from urls @@ -432,8 +422,7 @@ class Api(Iface): :param links: list of urls :return: package names mapped to urls """ - result = parseNames((x, x) for x in links) - return result + return parseNames((x, x) for x in links) @permission(PERMS.ADD) def generateAndAddPackages(self, links, dest=Destination.Queue): @@ -458,7 +447,6 @@ class Api(Iface): data = self.core.pluginManager.parseUrls(links) self.core.threadManager.createResultThread(data, True) - @permission(PERMS.LIST) def getPackageData(self, pid): """Returns complete information about package, and included files. @@ -467,15 +455,11 @@ class Api(Iface): :return: `PackageData` with .links attribute """ data = self.core.files.getPackageData(int(pid)) - if not data: raise PackageDoesNotExists(pid) - - pdata = PackageData(data["id"], data["name"], data["folder"], data["site"], data["password"], - data["queue"], data["order"], - links=[self._convertPyFile(x) for x in data["links"].itervalues()]) - - return pdata + return PackageData(data["id"], data["name"], data["folder"], data["site"], data["password"], + data["queue"], data["order"], + links=[self._convertPyFile(x) for x in data["links"].itervalues()]) @permission(PERMS.LIST) def getPackageInfo(self, pid): @@ -488,12 +472,9 @@ class Api(Iface): if not data: raise PackageDoesNotExists(pid) - - pdata = PackageData(data["id"], data["name"], data["folder"], data["site"], data["password"], - data["queue"], data["order"], - fids=[int(x) for x in data["links"]]) - - return pdata + return PackageData(data["id"], data["name"], data["folder"], data["site"], data["password"], + data["queue"], data["order"], + fids=[int(x) for x in data["links"]]) @permission(PERMS.LIST) def getFileData(self, fid): @@ -505,9 +486,7 @@ class Api(Iface): info = self.core.files.getFileData(int(fid)) if not info: raise FileDoesNotExists(fid) - - fdata = self._convertPyFile(info.values()[0]) - return fdata + return self._convertPyFile(info.values()[0]) @permission(PERMS.DELETE) def deleteFiles(self, fids): @@ -515,9 +494,8 @@ class Api(Iface): :param fids: list of file ids """ - for id in fids: - self.core.files.deleteLink(int(id)) - + for fid in fids: + self.core.files.deleteLink(int(fid)) self.core.files.save() @permission(PERMS.DELETE) @@ -526,9 +504,8 @@ class Api(Iface): :param pids: list of package ids """ - for id in pids: - self.core.files.deletePackage(int(id)) - + for pid in pids: + self.core.files.deletePackage(int(pid)) self.core.files.save() @permission(PERMS.LIST) @@ -581,7 +558,6 @@ class Api(Iface): links=[self._convertPyFile(x) for x in pack["links"].itervalues()]) for pack in self.core.files.getCompleteData(Destination.Collector).itervalues()] - @permission(PERMS.ADD) def addFiles(self, pid, links): """Adds files to specific package. @@ -590,7 +566,6 @@ class Api(Iface): :param links: list of urls """ self.core.files.addLinks(links, int(pid)) - self.core.log.info(_("Added %(count)d links to package #%(package)d ") % {"count": len(links), "package": pid}) self.core.files.save() @@ -651,7 +626,6 @@ class Api(Iface): :return: """ pyfiles = self.core.files.cache.values() - for pyfile in pyfiles: if pyfile.id in fids: pyfile.abortDownload() @@ -674,8 +648,8 @@ class Api(Iface): :param destination: `Destination` :param pid: package id """ - if destination not in (0, 1): return - self.core.files.setPackageLocation(pid, destination) + if destination in (0, 1): + self.core.files.setPackageLocation(pid, destination) @permission(PERMS.MODIFY) def moveFiles(self, fids, pid): @@ -685,7 +659,7 @@ class Api(Iface): :param pid: destination package :return: """ - #TODO: implement + # TODO: implement pass @@ -699,7 +673,6 @@ class Api(Iface): th = open(join(self.core.config["general"]["download_folder"], "tmp_" + filename), "wb") th.write(str(data)) th.close() - self.addPackage(th.name, [th.name], Destination.Queue) @permission(PERMS.MODIFY) @@ -727,14 +700,14 @@ class Api(Iface): :param pid: package id :param data: dict that maps attribute to desired value """ - p = self.core.files.getPackage(pid) - if not p: raise PackageDoesNotExists(pid) - + package = self.core.files.getPackage(pid) + if not package: + raise PackageDoesNotExists(pid) for key, value in data.iteritems(): - if key == "id": continue - setattr(p, key, value) - - p.sync() + if key == "id": + continue + setattr(package, key, value) + package.sync() self.core.files.save() @permission(PERMS.DELETE) @@ -757,13 +730,11 @@ class Api(Iface): :param destination: `Destination` :return: dict mapping order to package id """ - packs = self.core.files.getInfoData(destination) order = {} - for pid in packs: pack = self.core.files.getPackageData(int(pid)) - while pack["order"] in order.keys(): #just in case + while pack["order"] in order.keys(): # just in case pack["order"] += 1 order[pack["order"]] = pack["id"] return order @@ -775,10 +746,10 @@ class Api(Iface): :param pid: :return: dict mapping order to file id """ - rawData = self.core.files.getPackageData(int(pid)) + rawdata = self.core.files.getPackageData(int(pid)) order = {} - for id, pyfile in rawData["links"].iteritems(): - while pyfile["order"] in order.keys(): #just in case + for id, pyfile in rawdata["links"].iteritems(): + while pyfile["order"] in order.keys(): # just in case pyfile["order"] += 1 order[pyfile["order"]] = pyfile["id"] return order @@ -806,10 +777,9 @@ class Api(Iface): if task: task.setWatingForUser(exclusive=exclusive) data, type, result = task.getCaptcha() - t = CaptchaTask(int(task.id), standard_b64encode(data), type, result) - return t - else: - return CaptchaTask(-1) + ctask = CaptchaTask(int(task.id), standard_b64encode(data), type, result) + return ctask + return CaptchaTask(-1) @permission(PERMS.STATUS) def getCaptchaTaskStatus(self, tid): @@ -819,8 +789,8 @@ class Api(Iface): :return: string """ self.core.lastClientConnected = time() - t = self.core.captchaManager.getTaskByID(tid) - return t.getStatus() if t else "" + task = self.core.captchaManager.getTaskByID(tid) + return task.getStatus() if task else "" @permission(PERMS.STATUS) def setCaptchaResult(self, tid, result): @@ -835,7 +805,6 @@ class Api(Iface): task.setResult(result) self.core.captchaManager.removeTask(task) - @permission(PERMS.STATUS) def getEvents(self, uuid): """Lists occured events, may be affected to changes in future. @@ -844,7 +813,7 @@ class Api(Iface): :return: list of `Events` """ events = self.core.pullManager.getEvents(uuid) - newEvents = [] + new_events = [] def convDest(d): return Destination.Queue if d == "queue" else Destination.Collector @@ -863,8 +832,8 @@ class Api(Iface): event.destination = convDest(e[3]) elif e[0] == "reload": event.destination = convDest(e[1]) - newEvents.append(event) - return newEvents + new_events.append(event) + return new_events @permission(PERMS.ACCOUNTS) def getAccounts(self, refresh): @@ -874,12 +843,11 @@ class Api(Iface): :return: list of `AccountInfo` """ accs = self.core.accountManager.getAccountInfos(False, refresh) - accounts = [] for group in accs.values(): - accounts.extend([AccountInfo(acc["validuntil"], acc["login"], acc["options"], acc["valid"], - acc["trafficleft"], acc["maxtraffic"], acc["premium"], acc["type"]) - for acc in group]) - return accounts + accounts = [AccountInfo(acc["validuntil"], acc["login"], acc["options"], acc["valid"], + acc["trafficleft"], acc["maxtraffic"], acc["premium"], acc["type"]) + for acc in group] + return accounts or [] @permission(PERMS.ALL) def getAccountTypes(self): @@ -890,9 +858,9 @@ class Api(Iface): return self.core.accountManager.accounts.keys() @permission(PERMS.ACCOUNTS) - def updateAccount(self, plugin, account, password=None, options={}): + def updateAccount(self, plugin, account, password=None, options=None): """Changes pw/options for specific account.""" - self.core.accountManager.updateAccount(plugin, account, password, options) + self.core.accountManager.updateAccount(plugin, account, password, options or {}) @permission(PERMS.ACCOUNTS) def removeAccount(self, plugin, account): @@ -912,7 +880,7 @@ class Api(Iface): :param remoteip: Omit this argument, its only used internal :return: bool indicating login was successful """ - return True if self.checkAuth(username, password, remoteip) else False + return bool(self.checkAuth(username, password, remoteip)) def checkAuth(self, username, password, remoteip=None): """Check authentication and returns details @@ -941,24 +909,19 @@ class Api(Iface): else: return False - @permission(PERMS.ALL) def getUserData(self, username, password): """similar to `checkAuth` but returns UserData thrift type """ - user = self.checkAuth(username, password) + user = self.checkAuth(username, password) if user: return UserData(user["name"], user["email"], user["role"], user["permission"], user["template"]) else: return UserData() - def getAllUserData(self): """returns all known user and info""" - res = {} - for user, data in self.core.db.getAllUserData().iteritems(): - res[user] = UserData(user, data["email"], data["role"], data["permission"], data["template"]) - - return res + return dict((user, UserData(user, data["email"], data["role"], data["permission"], data["template"])) for user, data + in self.core.db.getAllUserData().iteritems()) @permission(PERMS.STATUS) def getServices(self): @@ -966,11 +929,7 @@ class Api(Iface): :return: dict with this style: {"plugin": {"method": "description"}} """ - data = {} - for plugin, funcs in self.core.addonManager.methods.iteritems(): - data[plugin] = funcs - - return data + return dict((plugin, funcs) for plugin, funcs in self.core.addonManager.methods.iteritems()) @permission(PERMS.STATUS) def hasService(self, plugin, func): @@ -996,13 +955,10 @@ class Api(Iface): func = info.func args = info.arguments parse = info.parseArguments - if not self.hasService(plugin, func): raise ServiceDoesNotExists(plugin, func) - try: ret = self.core.addonManager.callRPC(plugin, func, args, parse) - return str(ret) except Exception, e: raise ServiceException(e.message) @@ -1027,6 +983,6 @@ class Api(Iface): """ changes password for specific user """ return self.core.db.changePassword(user, oldpw, newpw) - def setUserPermission(self, user, permission, role): - self.core.db.setPermission(user, permission) + def setUserPermission(self, user, perm, role): + self.core.db.setPermission(user, perm) self.core.db.setRole(user, role) diff --git a/pyload/api/types.py b/pyload/api/types.py index a945e322a..81385bf9f 100644 --- a/pyload/api/types.py +++ b/pyload/api/types.py @@ -5,11 +5,11 @@ class BaseObject(object): __slots__ = [] -class Destination: +class Destination(object): Collector = 0 Queue = 1 -class DownloadStatus: +class DownloadStatus(object): Aborted = 9 Custom = 11 Decrypting = 10 @@ -26,11 +26,11 @@ class DownloadStatus: Unknown = 14 Waiting = 5 -class ElementType: +class ElementType(object): File = 1 Package = 0 -class Input: +class Input(object): BOOL = 4 CHOICE = 6 CLICK = 5 @@ -42,7 +42,7 @@ class Input: TEXT = 1 TEXTBOX = 2 -class Output: +class Output(object): CAPTCHA = 1 NOTIFICATION = 4 QUESTION = 2 @@ -238,7 +238,7 @@ class UserData(BaseObject): self.permission = permission self.templateName = templateName -class Iface: +class Iface(object): def addFiles(self, pid, links): pass def addPackage(self, name, links, dest): |