summaryrefslogtreecommitdiffstats
path: root/module/api
diff options
context:
space:
mode:
authorGravatar RaNaN <Mast3rRaNaN@hotmail.de> 2013-01-03 21:00:58 +0100
committerGravatar RaNaN <Mast3rRaNaN@hotmail.de> 2013-01-03 21:00:58 +0100
commit7c6374b4b5d452ab239f8b725038f2a2eb82368f (patch)
tree392f5809fb908eb7f22dffd273821bcc831da3dc /module/api
parentseperate api into several components (diff)
downloadpyload-7c6374b4b5d452ab239f8b725038f2a2eb82368f.tar.xz
split api into more components
Diffstat (limited to 'module/api')
-rw-r--r--module/api/AccountApi.py49
-rw-r--r--module/api/AddonApi.py27
-rw-r--r--module/api/ApiComponent.py7
-rw-r--r--module/api/CollectorApi.py37
-rw-r--r--module/api/DownloadApi.py182
-rw-r--r--module/api/DownloadPreparingApi.py121
-rw-r--r--module/api/FileApi.py153
-rw-r--r--module/api/UserInteractionApi.py65
-rw-r--r--module/api/__init__.py5
9 files changed, 644 insertions, 2 deletions
diff --git a/module/api/AccountApi.py b/module/api/AccountApi.py
new file mode 100644
index 000000000..396824a55
--- /dev/null
+++ b/module/api/AccountApi.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from module.Api import Api, RequirePerm, Permission
+
+from ApiComponent import ApiComponent
+
+class AccountApi(ApiComponent):
+ """ All methods to control accounts """
+
+ @RequirePerm(Permission.Accounts)
+ def getAccounts(self, refresh):
+ """Get information about all entered accounts.
+
+ :param refresh: reload account info
+ :return: list of `AccountInfo`
+ """
+ accs = self.core.accountManager.getAllAccounts(refresh)
+ accounts = []
+ for plugin in accs.itervalues():
+ accounts.extend(plugin.values())
+
+ return 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 updateAccount(self, plugin, account, password=None, options={}):
+ """Changes pw/options for specific account."""
+ self.core.accountManager.updateAccount(plugin, account, password, options)
+
+ @RequirePerm(Permission.Accounts)
+ def removeAccount(self, plugin, account):
+ """Remove account from pyload.
+
+ :param plugin: pluginname
+ :param account: accountname
+ """
+ self.core.accountManager.removeAccount(plugin, account)
+
+
+if Api.extend(AccountApi):
+ del AccountApi \ No newline at end of file
diff --git a/module/api/AddonApi.py b/module/api/AddonApi.py
new file mode 100644
index 000000000..917c7dc4c
--- /dev/null
+++ b/module/api/AddonApi.py
@@ -0,0 +1,27 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from module.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/module/api/ApiComponent.py b/module/api/ApiComponent.py
index 2b09d05a3..ba96b3be9 100644
--- a/module/api/ApiComponent.py
+++ b/module/api/ApiComponent.py
@@ -1,12 +1,17 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
-class ApiComponent:
+from module.remote.ttypes import Iface
+
+# Workaround to let code-completion think, this is subclass of Iface
+Iface = object
+class ApiComponent(Iface):
def __init__(self, core):
# Only for auto completion, this class can not be instantiated
from pyload import Core
assert isinstance(core, Core)
+ assert issubclass(ApiComponent, Iface)
self.core = core
# No instantiating!
raise Exception() \ No newline at end of file
diff --git a/module/api/CollectorApi.py b/module/api/CollectorApi.py
new file mode 100644
index 000000000..eb36f7a21
--- /dev/null
+++ b/module/api/CollectorApi.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from module.Api import Api, RequirePerm, Permission
+
+from ApiComponent import ApiComponent
+
+class CollectorApi(ApiComponent):
+ """ Link collector """
+
+ @RequirePerm(Permission.All)
+ def getCollector(self):
+ pass
+
+ @RequirePerm(Permission.Add)
+ def addToCollector(self, links):
+ pass
+
+ @RequirePerm(Permission.Add)
+ def addFromCollector(self, name, new_name):
+ pass
+
+ @RequirePerm(Permission.Delete)
+ def deleteCollPack(self, name):
+ pass
+
+ @RequirePerm(Permission.Add)
+ def renameCollPack(self, name, new_name):
+ pass
+
+ @RequirePerm(Permission.Delete)
+ def deleteCollLink(self, url):
+ pass
+
+
+if Api.extend(CollectorApi):
+ del CollectorApi \ No newline at end of file
diff --git a/module/api/DownloadApi.py b/module/api/DownloadApi.py
new file mode 100644
index 000000000..ba49435b3
--- /dev/null
+++ b/module/api/DownloadApi.py
@@ -0,0 +1,182 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from os.path import isabs
+
+from module.Api import Api, RequirePerm, Permission
+from module.utils.fs import join
+
+from ApiComponent import ApiComponent
+
+class DownloadApi(ApiComponent):
+ """ Component to create, add, delete or modify downloads."""
+
+ @RequirePerm(Permission.Add)
+ def generateAndAddPackages(self, links, paused=False):
+ """Generates and add packages
+
+ :param links: list of urls
+ :param paused: paused package
+ :return: list of package ids
+ """
+ return [self.addPackageP(name, urls, "", paused) for name, urls
+ in self.generatePackages(links).iteritems()]
+
+ @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/module/api/DownloadPreparingApi.py b/module/api/DownloadPreparingApi.py
new file mode 100644
index 000000000..4fc5b1ff9
--- /dev/null
+++ b/module/api/DownloadPreparingApi.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from itertools import chain
+
+from module.Api import Api, RequirePerm, Permission, OnlineCheck, LinkStatus, urlmatcher
+from module.utils.fs import join
+from module.network.RequestFactory import getURL
+from module.common.packagetools import parseNames
+
+from ApiComponent import ApiComponent
+
+class DownloadPreparingApi(ApiComponent):
+ """ All kind of methods to parse links or retrieve online status """
+
+ @RequirePerm(Permission.Add)
+ def parseURLs(self, html=None, url=None):
+ """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)]
+
+ # remove duplicates
+ return self.checkURLs(set(urls))
+
+
+ @RequirePerm(Permission.Add)
+ def checkURLs(self, urls):
+ """ Gets urls and returns pluginname mapped to list of matching urls.
+
+ :param urls:
+ :return: {plugin: urls}
+ """
+ data, crypter = self.core.pluginManager.parseUrls(urls)
+ 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 checkOnlineStatus(self, urls):
+ """ initiates online status check, will also decrypt files.
+
+ :param urls:
+ :return: initial set of data as :class:`OnlineCheck` instance containing the result id
+ """
+ data, crypter = self.core.pluginManager.parseUrls(urls)
+
+ # initial result does not contain the crypter links
+ tmp = [(url, (url, LinkStatus(url, pluginname, "unknown", 3, 0))) for url, pluginname in data]
+ data = parseNames(tmp)
+ result = {}
+
+ for k, v in data.iteritems():
+ for url, status in v:
+ status.packagename = k
+ result[url] = status
+
+ data.update(crypter) # hoster and crypter will be processed
+ rid = self.core.threadManager.createResultThread(data, False)
+
+ return OnlineCheck(rid, result)
+
+ @RequirePerm(Permission.Add)
+ def checkOnlineStatusContainer(self, urls, container, data):
+ """ checks online status of urls and a submitted container file
+
+ :param urls: list of urls
+ :param container: container file name
+ :param data: file content
+ :return: :class:`OnlineCheck`
+ """
+ th = open(join(self.core.config["general"]["download_folder"], "tmp_" + container), "wb")
+ th.write(str(data))
+ th.close()
+ urls.append(th.name)
+ return self.checkOnlineStatus(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 "ALL_INFO_FETCHED" in result:
+ del result["ALL_INFO_FETCHED"]
+ return OnlineCheck(-1, result)
+ else:
+ return OnlineCheck(rid, result)
+
+
+ @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/module/api/FileApi.py b/module/api/FileApi.py
new file mode 100644
index 000000000..f470cfa3e
--- /dev/null
+++ b/module/api/FileApi.py
@@ -0,0 +1,153 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from module.Api import Api, RequirePerm, Permission, DownloadState, PackageDoesNotExists, FileDoesNotExists
+
+from ApiComponent import ApiComponent
+
+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
+
+ @RequirePerm(Permission.All)
+ def findFiles(self, pattern):
+ pass
+
+ @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/module/api/UserInteractionApi.py b/module/api/UserInteractionApi.py
new file mode 100644
index 000000000..ded305c30
--- /dev/null
+++ b/module/api/UserInteractionApi.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from module.Api import Api, RequirePerm, Permission, InteractionTask
+
+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(mode)
+
+ @RequirePerm(Permission.Interaction)
+ def getInteractionTask(self, mode):
+ """Retrieve task for specific mode.
+
+ :param mode: binary or'ed output type
+ :return: :class:`InteractionTask`
+ """
+ task = self.core.interactionManager.getTask(mode)
+ return InteractionTask(-1) if not task else task
+
+
+ @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 string
+ """
+ task = self.core.interactionManager.getTaskByID(iid)
+ if task:
+ task.setResult(result)
+
+ @RequirePerm(Permission.Interaction)
+ def getNotifications(self):
+ """List of all available notifcations. They stay in queue for some time, client should\
+ save which notifications it already has seen.
+
+ :return: list of :class:`InteractionTask`
+ """
+ return self.core.interactionManager.getNotifications()
+
+ @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/module/api/__init__.py b/module/api/__init__.py
index f7ceb6183..754ed4b19 100644
--- a/module/api/__init__.py
+++ b/module/api/__init__.py
@@ -1 +1,4 @@
-__all__ = ["CoreApi", "ConfigApi"] \ No newline at end of file
+__all__ = ["CoreApi", "ConfigApi", "DownloadApi", "DownloadPreparingApi", "FileApi",
+ "CollectorApi", "UserInteractionApi", "AccountApi", "AddonApi"]
+# Import all components
+from .import * \ No newline at end of file