diff options
Diffstat (limited to 'pyload/api')
-rw-r--r-- | pyload/api/AccountApi.py | 79 | ||||
-rw-r--r-- | pyload/api/AddonApi.py | 27 | ||||
-rw-r--r-- | pyload/api/ApiComponent.py | 23 | ||||
-rw-r--r-- | pyload/api/ConfigApi.py | 135 | ||||
-rw-r--r-- | pyload/api/CoreApi.py | 131 | ||||
-rw-r--r-- | pyload/api/DownloadApi.py | 171 | ||||
-rw-r--r-- | pyload/api/DownloadPreparingApi.py | 105 | ||||
-rw-r--r-- | pyload/api/FileApi.py | 167 | ||||
-rw-r--r-- | pyload/api/UserApi.py | 41 | ||||
-rw-r--r-- | pyload/api/UserInteractionApi.py | 61 | ||||
-rw-r--r-- | pyload/api/__init__.py | 8 |
11 files changed, 948 insertions, 0 deletions
diff --git a/pyload/api/AccountApi.py b/pyload/api/AccountApi.py new file mode 100644 index 000000000..d4b39c12b --- /dev/null +++ b/pyload/api/AccountApi.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from pyload.utils import to_bool +from pyload.Api import Api, RequirePerm, Permission, Conflict +from ApiComponent import ApiComponent + + +class AccountApi(ApiComponent): + """ All methods to control accounts """ + + @RequirePerm(Permission.All) + def getAccountTypes(self): + """All available account types. + + :return: string list + """ + return self.core.pluginManager.getPlugins("accounts").keys() + + @RequirePerm(Permission.Accounts) + def getAccounts(self): + """Get information about all entered accounts. + + :return: list of `AccountInfo` + """ + accounts = self.core.accountManager.getAllAccounts(self.primaryUID) + return [acc.toInfoData() for acc in accounts] + + @RequirePerm(Permission.Accounts) + def getAccountInfo(self, plugin, loginname, refresh=False): + """ Returns :class:`AccountInfo` for a specific account + + :param refresh: reload account info + """ + account = self.core.accountManager.getAccount(plugin, loginname) + + # Admins can see and refresh accounts + if not account or (self.primaryUID and self.primaryUID != account.owner): + return None + + if refresh: + # reload account in place + account.getAccountInfo(True) + + return account.toInfoData() + + @RequirePerm(Permission.Accounts) + def updateAccount(self, plugin, loginname, password): + """Creates an account if not existent or updates the password + + :return: newly created or updated account info + """ + # TODO: None pointer + return self.core.accountManager.updateAccount(plugin, loginname, password, self.user).toInfoData() + + + @RequirePerm(Permission.Accounts) + def updateAccountInfo(self, account): + """ Update account settings from :class:`AccountInfo` """ + inst = self.core.accountManager.getAccount(account.plugin, account.loginname, self.user) + if not account: + return + + inst.activated = to_bool(account.activated) + inst.shared = to_bool(account.shared) + inst.updateConfig(account.config) + + + @RequirePerm(Permission.Accounts) + def removeAccount(self, account): + """Remove account from pyload. + + :param account: :class:`ÀccountInfo` instance + """ + self.core.accountManager.removeAccount(account.plugin, account.loginname, self.primaryUID) + + +if Api.extend(AccountApi): + del AccountApi
\ No newline at end of file diff --git a/pyload/api/AddonApi.py b/pyload/api/AddonApi.py new file mode 100644 index 000000000..4ae686d2d --- /dev/null +++ b/pyload/api/AddonApi.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from pyload.Api import Api, RequirePerm, Permission + +from ApiComponent import ApiComponent + +class AddonApi(ApiComponent): + """ Methods to interact with addons """ + + def getAllInfo(self): + """Returns all information stored by addon plugins. Values are always strings + + :return: {"plugin": {"name": value } } + """ + return self.core.addonManager.getAllInfo() + + def getInfoByPlugin(self, plugin): + """Returns information stored by a specific plugin. + + :param plugin: pluginname + :return: dict of attr names mapped to value {"name": value} + """ + return self.core.addonManager.getInfo(plugin) + +if Api.extend(AddonApi): + del AddonApi
\ No newline at end of file diff --git a/pyload/api/ApiComponent.py b/pyload/api/ApiComponent.py new file mode 100644 index 000000000..bb333c259 --- /dev/null +++ b/pyload/api/ApiComponent.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from pyload.remote.apitypes import Iface + +# Workaround to let code-completion think, this is subclass of Iface +Iface = object +class ApiComponent(Iface): + + __slots__ = [] + + def __init__(self, core, user): + # Only for auto completion, this class can not be instantiated + from pyload import Core + from pyload.datatypes.User import User + assert isinstance(core, Core) + assert issubclass(ApiComponent, Iface) + self.core = core + assert isinstance(user, User) + self.user = user + self.primaryUID = 0 + # No instantiating! + raise Exception()
\ No newline at end of file diff --git a/pyload/api/ConfigApi.py b/pyload/api/ConfigApi.py new file mode 100644 index 000000000..2adc0c565 --- /dev/null +++ b/pyload/api/ConfigApi.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from pyload.Api import Api, RequirePerm, Permission, ConfigHolder, ConfigItem, ConfigInfo +from pyload.utils import to_string + +from ApiComponent import ApiComponent + +# helper function to create a ConfigHolder +def toConfigHolder(section, config, values): + holder = ConfigHolder(section, config.label, config.description, config.explanation) + holder.items = [ConfigItem(option, x.label, x.description, x.input, + to_string(values.get(option, x.input.default_value))) for option, x in + config.config.iteritems()] + return holder + + +class ConfigApi(ApiComponent): + """ Everything related to configuration """ + + def getConfigValue(self, section, option): + """Retrieve config value. + + :param section: name of category, or plugin + :param option: config option + :rtype: str + :return: config value as string + """ + value = self.core.config.get(section, option, self.primaryUID) + return to_string(value) + + def setConfigValue(self, section, option, value): + """Set new config value. + + :param section: + :param option: + :param value: new config value + """ + if option in ("limit_speed", "max_speed"): #not so nice to update the limit + self.core.requestFactory.updateBucket() + + self.core.config.set(section, option, value, self.primaryUID) + + def getConfig(self): + """Retrieves complete config of core. + + :rtype: dict of section -> ConfigHolder + """ + data = {} + for section, config, values in self.core.config.iterCoreSections(): + data[section] = toConfigHolder(section, config, values) + return data + + def getCoreConfig(self): + """ Retrieves core config sections + + :rtype: list of PluginInfo + """ + return [ConfigInfo(section, config.label, config.description, False, False) + for section, config, values in self.core.config.iterCoreSections()] + + @RequirePerm(Permission.Plugins) + def getPluginConfig(self): + """All plugins and addons the current user has configured + + :rtype: list of PluginInfo + """ + # TODO: include addons that are activated by default + # TODO: multi user + # TODO: better plugin / addon activated config + data = [] + active = [x.getName() for x in self.core.addonManager.activePlugins()] + for name, config, values in self.core.config.iterSections(self.primaryUID): + # skip unmodified and inactive addons + if not values and name not in active: continue + + item = ConfigInfo(name, config.label, config.description, + self.core.pluginManager.getCategory(name), + self.core.pluginManager.isUserPlugin(name), + # TODO: won't work probably + values.get("activated", None if "activated" not in config.config else config.config[ + "activated"].input.default_value)) + data.append(item) + + return data + + @RequirePerm(Permission.Plugins) + def getAvailablePlugins(self): + """List of all available plugins, that are configurable + + :rtype: list of PluginInfo + """ + # TODO: filter user_context / addons when not allowed + plugins = [ConfigInfo(name, config.label, config.description, + self.core.pluginManager.getCategory(name), + self.core.pluginManager.isUserPlugin(name)) + for name, config, values in self.core.config.iterSections(self.primaryUID)] + + return plugins + + @RequirePerm(Permission.Plugins) + def loadConfig(self, name): + """Get complete config options for desired section + + :param name: Name of plugin or config section + :rtype: ConfigHolder + """ + # requires at least plugin permissions, but only admin can load core config + config, values = self.core.config.getSection(name, self.primaryUID) + return toConfigHolder(name, config, values) + + + @RequirePerm(Permission.Plugins) + def saveConfig(self, config): + """Used to save a configuration, core config can only be saved by admins + + :param config: :class:`ConfigHolder` + """ + for item in config.items: + self.core.config.set(config.name, item.name, item.value, sync=False, user=self.primaryUID) + # save the changes + self.core.config.saveValues(self.primaryUID, config.name) + + @RequirePerm(Permission.Plugins) + def deleteConfig(self, plugin): + """Deletes modified config + + :param plugin: plugin name + """ + #TODO: delete should deactivate addons? + self.core.config.delete(plugin, self.primaryUID) + + +if Api.extend(ConfigApi): + del ConfigApi
\ No newline at end of file diff --git a/pyload/api/CoreApi.py b/pyload/api/CoreApi.py new file mode 100644 index 000000000..ebb194134 --- /dev/null +++ b/pyload/api/CoreApi.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from pyload.Api import Api, RequirePerm, Permission, ServerStatus, Interaction +from pyload.utils.fs import join, free_space +from pyload.utils import compare_time + +from ApiComponent import ApiComponent + +class CoreApi(ApiComponent): + """ This module provides methods for general interaction with the core, like status or progress retrieval """ + + @RequirePerm(Permission.All) + def getServerVersion(self): + """pyLoad Core version """ + return self.core.version + + @RequirePerm(Permission.All) + def getWSAddress(self): + """Gets and address for the websocket based on configuration""" + # TODO SSL (wss) + return "ws://%%s:%d" % self.core.config['remote']['port'] + + @RequirePerm(Permission.All) + def getServerStatus(self): + """Some general information about the current status of pyLoad. + + :return: `ServerStatus` + """ + queue = self.core.files.getQueueStats(self.primaryUID) + total = self.core.files.getDownloadStats(self.primaryUID) + + serverStatus = ServerStatus(0, + total[0], queue[0], + total[1], queue[1], + self.isInteractionWaiting(Interaction.All), + not self.core.threadManager.pause and self.isTimeDownload(), + self.core.threadManager.pause, + self.core.config['reconnect']['activated'] and self.isTimeReconnect()) + + + for pyfile in self.core.threadManager.getActiveDownloads(self.primaryUID): + serverStatus.speed += pyfile.getSpeed() #bytes/s + + return serverStatus + + @RequirePerm(Permission.All) + def getProgressInfo(self): + """ Status of all currently running tasks + + :rtype: list of :class:`ProgressInfo` + """ + return self.core.threadManager.getProgressList(self.primaryUID) + + def pauseServer(self): + """Pause server: It won't start any new downloads, but nothing gets aborted.""" + self.core.threadManager.pause = True + + def unpauseServer(self): + """Unpause server: New Downloads will be started.""" + self.core.threadManager.pause = False + + def togglePause(self): + """Toggle pause state. + + :return: new pause state + """ + self.core.threadManager.pause ^= True + return self.core.threadManager.pause + + def toggleReconnect(self): + """Toggle reconnect activation. + + :return: new reconnect state + """ + self.core.config["reconnect"]["activated"] ^= True + return self.core.config["reconnect"]["activated"] + + def freeSpace(self): + """Available free space at download directory in bytes""" + return free_space(self.core.config["general"]["download_folder"]) + + + def quit(self): + """Clean way to quit pyLoad""" + self.core.do_kill = True + + def restart(self): + """Restart pyload core""" + self.core.do_restart = True + + def getLog(self, offset=0): + """Returns most recent log entries. + + :param offset: line offset + :return: List of log entries + """ + filename = join(self.core.config['log']['log_folder'], 'log.txt') + try: + fh = open(filename, "r") + lines = fh.readlines() + fh.close() + if offset >= len(lines): + return [] + return lines[offset:] + except: + return ['No log available'] + + @RequirePerm(Permission.All) + def isTimeDownload(self): + """Checks if pyload will start new downloads according to time in config. + + :return: bool + """ + start = self.core.config['downloadTime']['start'].split(":") + end = self.core.config['downloadTime']['end'].split(":") + return compare_time(start, end) + + @RequirePerm(Permission.All) + def isTimeReconnect(self): + """Checks if pyload will try to make a reconnect + + :return: bool + """ + start = self.core.config['reconnect']['startTime'].split(":") + end = self.core.config['reconnect']['endTime'].split(":") + return compare_time(start, end) and self.core.config["reconnect"]["activated"] + + +if Api.extend(CoreApi): + del CoreApi
\ No newline at end of file diff --git a/pyload/api/DownloadApi.py b/pyload/api/DownloadApi.py new file mode 100644 index 000000000..d855dd882 --- /dev/null +++ b/pyload/api/DownloadApi.py @@ -0,0 +1,171 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from os.path import isabs + +from pyload.Api import Api, RequirePerm, Permission +from pyload.utils.fs import join + +from ApiComponent import ApiComponent + +class DownloadApi(ApiComponent): + """ Component to create, add, delete or modify downloads.""" + + @RequirePerm(Permission.Add) + def createPackage(self, name, folder, root, password="", site="", comment="", paused=False): + """Create a new package. + + :param name: display name of the package + :param folder: folder name or relative path, abs path are not allowed + :param root: package id of root package, -1 for top level package + :param password: single pw or list of passwords separated with new line + :param site: arbitrary url to site for more information + :param comment: arbitrary comment + :param paused: No downloads will be started when True + :return: pid of newly created package + """ + + if isabs(folder): + folder = folder.replace("/", "_") + + folder = folder.replace("http://", "").replace(":", "").replace("\\", "_").replace("..", "") + + self.core.log.info(_("Added package %(name)s as folder %(folder)s") % {"name": name, "folder": folder}) + pid = self.core.files.addPackage(name, folder, root, password, site, comment, paused) + + return pid + + + @RequirePerm(Permission.Add) + def addPackage(self, name, links, password=""): + """Convenient method to add a package to the top-level and for adding links. + + :return: package id + """ + return self.addPackageChild(name, links, password, -1, False) + + @RequirePerm(Permission.Add) + def addPackageP(self, name, links, password, paused): + """ Same as above with additional paused attribute. """ + return self.addPackageChild(name, links, password, -1, paused) + + @RequirePerm(Permission.Add) + def addPackageChild(self, name, links, password, root, paused): + """Adds a package, with links to desired package. + + :param root: parents package id + :return: package id of the new package + """ + if self.core.config['general']['folder_per_package']: + folder = name + else: + folder = "" + + pid = self.createPackage(name, folder, root, password) + self.addLinks(pid, links) + + return pid + + @RequirePerm(Permission.Add) + def addLinks(self, pid, links): + """Adds links to specific package. Initiates online status fetching. + + :param pid: package id + :param links: list of urls + """ + hoster, crypter = self.core.pluginManager.parseUrls(links) + + if hoster: + self.core.files.addLinks(hoster, pid) + self.core.threadManager.createInfoThread(hoster, pid) + + self.core.threadManager.createDecryptThread(crypter, pid) + + self.core.log.info((_("Added %d links to package") + " #%d" % pid) % len(hoster)) + self.core.files.save() + + @RequirePerm(Permission.Add) + def uploadContainer(self, filename, data): + """Uploads and adds a container file to pyLoad. + + :param filename: filename, extension is important so it can correctly decrypted + :param data: file content + """ + th = open(join(self.core.config["general"]["download_folder"], "tmp_" + filename), "wb") + th.write(str(data)) + th.close() + + return self.addPackage(th.name, [th.name]) + + @RequirePerm(Permission.Delete) + def deleteFiles(self, fids): + """Deletes several file entries from pyload. + + :param fids: list of file ids + """ + for fid in fids: + self.core.files.deleteFile(fid) + + self.core.files.save() + + @RequirePerm(Permission.Delete) + def deletePackages(self, pids): + """Deletes packages and containing links. + + :param pids: list of package ids + """ + for pid in pids: + self.core.files.deletePackage(pid) + + self.core.files.save() + + + @RequirePerm(Permission.Modify) + def restartPackage(self, pid): + """Restarts a package, resets every containing files. + + :param pid: package id + """ + self.core.files.restartPackage(pid) + + @RequirePerm(Permission.Modify) + def restartFile(self, fid): + """Resets file status, so it will be downloaded again. + + :param fid: file id + """ + self.core.files.restartFile(fid) + + @RequirePerm(Permission.Modify) + def recheckPackage(self, pid): + """Check online status of all files in a package, also a default action when package is added. """ + self.core.files.reCheckPackage(pid) + + @RequirePerm(Permission.Modify) + def restartFailed(self): + """Restarts all failed failes.""" + self.core.files.restartFailed() + + @RequirePerm(Permission.Modify) + def stopAllDownloads(self): + """Aborts all running downloads.""" + + pyfiles = self.core.files.cachedFiles() + for pyfile in pyfiles: + pyfile.abortDownload() + + @RequirePerm(Permission.Modify) + def stopDownloads(self, fids): + """Aborts specific downloads. + + :param fids: list of file ids + :return: + """ + pyfiles = self.core.files.cachedFiles() + for pyfile in pyfiles: + if pyfile.id in fids: + pyfile.abortDownload() + + +if Api.extend(DownloadApi): + del DownloadApi
\ No newline at end of file diff --git a/pyload/api/DownloadPreparingApi.py b/pyload/api/DownloadPreparingApi.py new file mode 100644 index 000000000..a7e32c4eb --- /dev/null +++ b/pyload/api/DownloadPreparingApi.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from itertools import chain + +from pyload.Api import Api, DownloadStatus as DS,\ + RequirePerm, Permission, OnlineCheck, LinkStatus, urlmatcher +from pyload.utils import uniqify +from pyload.utils.fs import join +from pyload.utils.packagetools import parseNames +from pyload.network.RequestFactory import getURL + +from ApiComponent import ApiComponent + +class DownloadPreparingApi(ApiComponent): + """ All kind of methods to parse links or retrieve online status """ + + @RequirePerm(Permission.Add) + def parseLinks(self, links): + """ Gets urls and returns pluginname mapped to list of matching urls. + + :param links: + :return: {plugin: urls} + """ + data, crypter = self.core.pluginManager.parseUrls(links) + plugins = {} + + for url, plugin in chain(data, crypter): + if plugin in plugins: + plugins[plugin].append(url) + else: + plugins[plugin] = [url] + + return plugins + + @RequirePerm(Permission.Add) + def checkLinks(self, links): + """ initiates online status check, will also decrypt files. + + :param links: + :return: initial set of data as :class:`OnlineCheck` instance containing the result id + """ + hoster, crypter = self.core.pluginManager.parseUrls(links) + + #: TODO: withhold crypter, derypt or add later + # initial result does not contain the crypter links + tmp = [(url, LinkStatus(url, url, -1, DS.Queued, pluginname)) for url, pluginname in hoster] + data = parseNames(tmp) + rid = self.core.threadManager.createResultThread(self.primaryUID, hoster + crypter) + + return OnlineCheck(rid, data) + + @RequirePerm(Permission.Add) + def checkContainer(self, filename, data): + """ checks online status of urls and a submitted container file + + :param filename: name of the file + :param data: file content + :return: :class:`OnlineCheck` + """ + th = open(join(self.core.config["general"]["download_folder"], "tmp_" + filename), "wb") + th.write(str(data)) + th.close() + return self.checkLinks([th.name]) + + @RequirePerm(Permission.Add) + def checkHTML(self, html, url): + """Parses html content or any arbitrary text for links and returns result of `checkURLs` + + :param html: html source + :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)] + + return self.checkLinks(uniqify(urls)) + + @RequirePerm(Permission.Add) + def pollResults(self, rid): + """ Polls the result available for ResultID + + :param rid: `ResultID` + :return: `OnlineCheck`, if rid is -1 then there is no more data available + """ + result = self.core.threadManager.getInfoResult(rid) + if result and result.owner == self.primaryUID: + return result.toApiData() + + @RequirePerm(Permission.Add) + def generatePackages(self, links): + """ Parses links, generates packages names from urls + + :param links: list of urls + :return: package names mapped to urls + """ + result = parseNames((x, x) for x in links) + return result + + +if Api.extend(DownloadPreparingApi): + del DownloadPreparingApi
\ No newline at end of file diff --git a/pyload/api/FileApi.py b/pyload/api/FileApi.py new file mode 100644 index 000000000..984729b8c --- /dev/null +++ b/pyload/api/FileApi.py @@ -0,0 +1,167 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from pyload.Api import Api, RequirePerm, Permission, DownloadState, PackageDoesNotExists, FileDoesNotExists +from pyload.utils import uniqify + +from ApiComponent import ApiComponent + +# TODO: user context +class FileApi(ApiComponent): + """Everything related to available packages or files. Deleting, Modifying and so on.""" + + @RequirePerm(Permission.All) + def getAllFiles(self): + """ same as `getFileTree` for toplevel root and full tree""" + return self.getFileTree(-1, True) + + @RequirePerm(Permission.All) + def getFilteredFiles(self, state): + """ same as `getFilteredFileTree` for toplevel root and full tree""" + return self.getFilteredFileTree(-1, state, True) + + @RequirePerm(Permission.All) + def getFileTree(self, pid, full): + """ Retrieve data for specific package. full=True will retrieve all data available + and can result in greater delays. + + :param pid: package id + :param full: go down the complete tree or only the first layer + :return: :class:`TreeCollection` + """ + return self.core.files.getTree(pid, full, DownloadState.All) + + @RequirePerm(Permission.All) + def getFilteredFileTree(self, pid, full, state): + """ Same as `getFileTree` but only contains files with specific download state. + + :param pid: package id + :param full: go down the complete tree or only the first layer + :param state: :class:`DownloadState`, the attributes used for filtering + :return: :class:`TreeCollection` + """ + return self.core.files.getTree(pid, full, state) + + @RequirePerm(Permission.All) + def getPackageContent(self, pid): + """ Only retrieve content of a specific package. see `getFileTree`""" + return self.getFileTree(pid, False) + + @RequirePerm(Permission.All) + def getPackageInfo(self, pid): + """Returns information about package, without detailed information about containing files + + :param pid: package id + :raises PackageDoesNotExists: + :return: :class:`PackageInfo` + """ + info = self.core.files.getPackageInfo(pid) + if not info: + raise PackageDoesNotExists(pid) + return info + + @RequirePerm(Permission.All) + def getFileInfo(self, fid): + """ Info for specific file + + :param fid: file id + :raises FileDoesNotExists: + :return: :class:`FileInfo` + + """ + info = self.core.files.getFileInfo(fid) + if not info: + raise FileDoesNotExists(fid) + return info + + def getFilePath(self, fid): + """ Internal method to get the filepath""" + info = self.getFileInfo(fid) + pack = self.core.files.getPackage(info.package) + return pack.getPath(), info.name + + @RequirePerm(Permission.All) + def findFiles(self, pattern): + return self.core.files.getTree(-1, True, DownloadState.All, pattern) + + @RequirePerm(Permission.All) + def searchSuggestions(self, pattern): + names = self.core.db.getMatchingFilenames(pattern, self.primaryUID) + # TODO: stemming and reducing the names to provide better suggestions + return uniqify(names) + + @RequirePerm(Permission.All) + def findPackages(self, tags): + pass + + @RequirePerm(Permission.Modify) + def updatePackage(self, pack): + """Allows to modify several package attributes. + + :param pid: package id + :param data: :class:`PackageInfo` + """ + pid = pack.pid + p = self.core.files.getPackage(pid) + if not p: raise PackageDoesNotExists(pid) + + #TODO: fix + for key, value in data.iteritems(): + if key == "id": continue + setattr(p, key, value) + + p.sync() + self.core.files.save() + + @RequirePerm(Permission.Modify) + def setPackageFolder(self, pid, path): + pass + + @RequirePerm(Permission.Modify) + def movePackage(self, pid, root): + """ Set a new root for specific package. This will also moves the files on disk\ + and will only work when no file is currently downloading. + + :param pid: package id + :param root: package id of new root + :raises PackageDoesNotExists: When pid or root is missing + :return: False if package can't be moved + """ + return self.core.files.movePackage(pid, root) + + @RequirePerm(Permission.Modify) + def moveFiles(self, fids, pid): + """Move multiple files to another package. This will move the files on disk and\ + only work when files are not downloading. All files needs to be continuous ordered + in the current package. + + :param fids: list of file ids + :param pid: destination package + :return: False if files can't be moved + """ + return self.core.files.moveFiles(fids, pid) + + @RequirePerm(Permission.Modify) + def orderPackage(self, pid, position): + """Set new position for a package. + + :param pid: package id + :param position: new position, 0 for very beginning + """ + self.core.files.orderPackage(pid, position) + + @RequirePerm(Permission.Modify) + def orderFiles(self, fids, pid, position): + """ Set a new position for a bunch of files within a package. + All files have to be in the same package and must be **continuous**\ + in the package. That means no gaps between them. + + :param fids: list of file ids + :param pid: package id of parent package + :param position: new position: 0 for very beginning + """ + self.core.files.orderFiles(fids, pid, position) + + +if Api.extend(FileApi): + del FileApi
\ No newline at end of file diff --git a/pyload/api/UserApi.py b/pyload/api/UserApi.py new file mode 100644 index 000000000..d6fbb2646 --- /dev/null +++ b/pyload/api/UserApi.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from pyload.Api import Api, RequirePerm, Permission + +from ApiComponent import ApiComponent + +class UserApi(ApiComponent): + """ Api methods to retrieve user profile and manage users. """ + + @RequirePerm(Permission.All) + def getUserData(self): + """ Retrieves :class:`UserData` for the currently logged in user. """ + + @RequirePerm(Permission.All) + def setPassword(self, username, old_password, new_password): + """ Changes password for specific user. User can only change their password. + Admins can change every password! """ + + def getAllUserData(self): + """ Retrieves :class:`UserData` of all exisitng users.""" + + def addUser(self, username, password): + """ Adds an user to the db. + + :param username: desired username + :param password: password for authentication + """ + + def updateUserData(self, data): + """ Change parameters of user account. """ + + def removeUser(self, uid): + """ Removes user from the db. + + :param uid: users uid + """ + + +if Api.extend(UserApi): + del UserApi
\ No newline at end of file diff --git a/pyload/api/UserInteractionApi.py b/pyload/api/UserInteractionApi.py new file mode 100644 index 000000000..f5a9e9290 --- /dev/null +++ b/pyload/api/UserInteractionApi.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from pyload.Api import Api, RequirePerm, Permission, Interaction + +from ApiComponent import ApiComponent + +class UserInteractionApi(ApiComponent): + """ Everything needed for user interaction """ + + @RequirePerm(Permission.Interaction) + def isInteractionWaiting(self, mode): + """ Check if task is waiting. + + :param mode: binary or'ed output type + :return: boolean + """ + return self.core.interactionManager.isTaskWaiting(self.primaryUID, mode) + + @RequirePerm(Permission.Interaction) + def getInteractionTasks(self, mode): + """Retrieve task for specific mode. + + :param mode: binary or'ed interaction types which should be retrieved + :rtype list of :class:`InteractionTask` + """ + tasks = self.core.interactionManager.getTasks(self.primaryUID, mode) + # retrieved tasks count as seen + for t in tasks: + t.seen = True + if t.type == Interaction.Notification: + t.setWaiting(self.core.interactionManager.CLIENT_THRESHOLD) + + return tasks + + @RequirePerm(Permission.Interaction) + def setInteractionResult(self, iid, result): + """Set Result for a interaction task. It will be immediately removed from task queue afterwards + + :param iid: interaction id + :param result: result as json string + """ + task = self.core.interactionManager.getTaskByID(iid) + if task and self.primaryUID == task.owner: + task.setResult(result) + + @RequirePerm(Permission.Interaction) + def getAddonHandler(self): + pass + + @RequirePerm(Permission.Interaction) + def callAddonHandler(self, plugin, func, pid_or_fid): + pass + + @RequirePerm(Permission.Download) + def generateDownloadLink(self, fid, timeout): + pass + + +if Api.extend(UserInteractionApi): + del UserInteractionApi
\ No newline at end of file diff --git a/pyload/api/__init__.py b/pyload/api/__init__.py new file mode 100644 index 000000000..a2b292a27 --- /dev/null +++ b/pyload/api/__init__.py @@ -0,0 +1,8 @@ +__all__ = ["CoreApi", "ConfigApi", "DownloadApi", "DownloadPreparingApi", "FileApi", + "UserInteractionApi", "AccountApi", "AddonApi", "UserApi"] + +# Import all components +# from .import * +# Above does not work in py 2.5 +for name in __all__: + __import__(__name__ + "." + name)
\ No newline at end of file |