summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/api/access_api.rst (renamed from docs/access_api.rst)3
-rw-r--r--docs/api/datatypes.rst352
-rw-r--r--docs/api/overview.rst35
-rw-r--r--docs/conf.py4
-rwxr-xr-xdocs/extend_pyload.rst13
-rw-r--r--docs/index.rst43
-rw-r--r--docs/module_overview.rst6
-rw-r--r--docs/plugins/account_plugin.rst5
-rw-r--r--docs/plugins/base_plugin.rst5
-rw-r--r--docs/plugins/crypter_plugin.rst5
-rw-r--r--docs/plugins/hook_plugin.rst (renamed from docs/write_hooks.rst)4
-rw-r--r--docs/plugins/hoster_plugin.rst (renamed from docs/write_plugins.rst)7
-rwxr-xr-xdocs/plugins/overview.rst31
-rw-r--r--module/HookManager.py2
-rw-r--r--module/network/HTTPDownload.py6
-rw-r--r--module/network/HTTPRequest.py2
-rw-r--r--module/plugins/Account.py3
-rw-r--r--module/plugins/Crypter.py5
-rw-r--r--module/plugins/Hook.py27
-rw-r--r--module/plugins/MultiHoster.py58
-rw-r--r--module/plugins/internal/MultiHoster.py2
-rw-r--r--module/remote/thriftbackend/pyload.thrift5
-rw-r--r--module/threads/DecrypterThread.py2
-rw-r--r--pavement.py17
24 files changed, 580 insertions, 62 deletions
diff --git a/docs/access_api.rst b/docs/api/access_api.rst
index df69da8b2..efa1ae3fc 100644
--- a/docs/access_api.rst
+++ b/docs/api/access_api.rst
@@ -26,8 +26,9 @@ Using Thrift
------------
Every thrift service has to define all data structures and declare every method which should be usable via rpc.
-This file is located :file:`module/remote/thriftbackend/pyload.thrift`, its very helpful to inform about
+This file is located at :file:`module/remote/thriftbackend/pyload.thrift`, its very helpful to inform about
arguments and detailed structure of return types. However it does not contain any information about what the functions does.
+You can also look at it :doc:`here <datatypes>`
Assuming you want to use the API in any other language than python than check if it is
supported here http://wiki.apache.org/thrift/LibraryFeatures?action=show&redirect=LanguageSupport.
diff --git a/docs/api/datatypes.rst b/docs/api/datatypes.rst
new file mode 100644
index 000000000..02e3209cc
--- /dev/null
+++ b/docs/api/datatypes.rst
@@ -0,0 +1,352 @@
+.. _api_datatypes:
+
+***********************
+API Datatype Definition
+***********************
+
+Below you find a copy of :file:`module/remote/thriftbackend/pyload.thrift`, which is used to generate the data structs
+for various languages. It is also a good overview of avaible methods and return data.
+
+.. code-block:: c
+
+ .. [[[cog cog.out(open('module/remote/thriftbackend/pyload.thrift', 'rb').read()) ]]]
+ namespace java org.pyload.thrift
+
+ typedef i32 FileID
+ typedef i32 PackageID
+ typedef i32 ResultID
+ typedef i32 InteractionID
+ typedef list<string> LinkList
+ typedef string PluginName
+ typedef byte Progress
+ typedef byte Priority
+
+
+ enum DownloadStatus {
+ Finished
+ Offline,
+ Online,
+ Queued,
+ Skipped,
+ Waiting,
+ TempOffline,
+ Starting,
+ Failed,
+ Aborted,
+ Decrypting,
+ Custom,
+ Downloading,
+ Processing,
+ Unknown
+ }
+
+ enum Destination {
+ Collector,
+ Queue
+ }
+
+ // types for user interaction
+ // some may only be place holder currently not supported
+ // also all input - output combination are not reasonable, see InteractionManager for further info
+ enum Input {
+ NONE,
+ TEXT,
+ TEXTBOX,
+ PASSWORD,
+ BOOL, // confirm like, yes or no dialog
+ CLICK, // for positional captchas
+ CHOICE, // choice from list
+ MULTIPLE, // multiple choice from list of elements
+ LIST, // arbitary list of elements
+ TABLE // table like data structure
+ }
+ // more can be implemented by need
+
+ // this describes the type of the outgoing interaction
+ // ensure they can be logcial or'ed
+ enum Output {
+ CAPTCHA = 1,
+ QUESTION = 2,
+ NOTIFICATION = 4,
+ }
+
+ struct DownloadInfo {
+ 1: FileID fid,
+ 2: string name,
+ 3: i64 speed,
+ 4: i32 eta,
+ 5: string format_eta,
+ 6: i64 bleft,
+ 7: i64 size,
+ 8: string format_size,
+ 9: Progress percent,
+ 10: DownloadStatus status,
+ 11: string statusmsg,
+ 12: string format_wait,
+ 13: i64 wait_until,
+ 14: PackageID packageID,
+ 15: string packageName,
+ 16: PluginName plugin,
+ }
+
+ struct ServerStatus {
+ 1: bool pause,
+ 2: i16 active,
+ 3: i16 queue,
+ 4: i16 total,
+ 5: i64 speed,
+ 6: bool download,
+ 7: bool reconnect
+ }
+
+ struct FileData {
+ 1: FileID fid,
+ 2: string url,
+ 3: string name,
+ 4: PluginName plugin,
+ 5: i64 size,
+ 6: string format_size,
+ 7: DownloadStatus status,
+ 8: string statusmsg,
+ 9: PackageID packageID,
+ 10: string error,
+ 11: i16 order
+ }
+
+ struct PackageData {
+ 1: PackageID pid,
+ 2: string name,
+ 3: string folder,
+ 4: string site,
+ 5: string password,
+ 6: Destination dest,
+ 7: i16 order,
+ 8: optional i16 linksdone,
+ 9: optional i64 sizedone,
+ 10: optional i64 sizetotal,
+ 11: optional i16 linkstotal,
+ 12: optional list<FileData> links,
+ 13: optional list<FileID> fids
+ }
+
+ struct InteractionTask {
+ 1: InteractionID iid,
+ 2: Input input,
+ 3: list<string> structure,
+ 4: list<string> preset,
+ 5: Output output,
+ 6: list<string> data,
+ 7: string title,
+ 8: string description,
+ 9: string plugin,
+ }
+
+ struct ConfigItem {
+ 1: string name,
+ 2: string long_name,
+ 3: string description,
+ 4: string type,
+ 5: string default_value,
+ 6: string value,
+ }
+
+ struct ConfigSection {
+ 1: string name,
+ 2: string long_name,
+ 3: string description,
+ 4: string long_description,
+ 5: optional list<ConfigItem> items,
+ 6: optional map<string, InteractionTask> handler,
+ }
+
+ struct CaptchaTask {
+ 1: i16 tid,
+ 2: binary data,
+ 3: string type,
+ 4: string resultType
+ }
+
+ struct EventInfo {
+ 1: string eventname,
+ 2: list<string> event_args,
+ }
+
+ struct UserData {
+ 1: string name,
+ 2: string email,
+ 3: i32 role,
+ 4: i32 permission,
+ 5: string templateName
+ }
+
+ struct AccountInfo {
+ 1: PluginName plugin,
+ 2: string loginname,
+ 3: bool valid,
+ 4: i64 validuntil,
+ 5: i64 trafficleft,
+ 6: i64 maxtraffic,
+ 7: bool premium,
+ 8: bool activated,
+ 9: map<string, string> options,
+ }
+
+ struct ServiceCall {
+ 1: PluginName plugin,
+ 2: string func,
+ 3: string arguments, // empty string or json encoded list
+ }
+
+ struct OnlineStatus {
+ 1: string name,
+ 2: PluginName plugin,
+ 3: string packagename,
+ 4: DownloadStatus status,
+ 5: i64 size, // size <= 0 : unknown
+ }
+
+ struct OnlineCheck {
+ 1: ResultID rid, // -1 -> nothing more to get
+ 2: map<string, OnlineStatus> data, //url to result
+ }
+
+
+ // exceptions
+
+ exception PackageDoesNotExists{
+ 1: PackageID pid
+ }
+
+ exception FileDoesNotExists{
+ 1: FileID fid
+ }
+
+ exception UserDoesNotExists{
+ 1: string user
+ }
+
+ exception ServiceDoesNotExists{
+ 1: string plugin
+ 2: string func
+ }
+
+ exception ServiceException{
+ 1: string msg
+ }
+
+ service Pyload {
+
+ //config
+ string getConfigValue(1: string section, 2: string option),
+ void setConfigValue(1: string section, 2: string option, 3: string value),
+ map<string, ConfigSection> getConfig(),
+ map<PluginName, ConfigSection> getPluginConfig(),
+ ConfigSection configureSection(1: string section),
+
+ // server status
+ void pauseServer(),
+ void unpauseServer(),
+ bool togglePause(),
+ ServerStatus statusServer(),
+ i64 freeSpace(),
+ string getServerVersion(),
+ void kill(),
+ void restart(),
+ list<string> getLog(1: i32 offset),
+ bool isTimeDownload(),
+ bool isTimeReconnect(),
+ bool toggleReconnect(),
+
+ // download preparing
+
+ // packagename - urls
+ map<string, LinkList> generatePackages(1: LinkList links),
+ map<PluginName, LinkList> checkURLs(1: LinkList urls),
+ map<PluginName, LinkList> parseURLs(1: string html, 2: string url),
+
+ // parses results and generates packages
+ OnlineCheck checkOnlineStatus(1: LinkList urls),
+ OnlineCheck checkOnlineStatusContainer(1: LinkList urls, 2: string filename, 3: binary data)
+
+ // poll results from previosly started online check
+ OnlineCheck pollResults(1: ResultID rid),
+
+ // downloads - information
+ list<DownloadInfo> statusDownloads(),
+ PackageData getPackageData(1: PackageID pid) throws (1: PackageDoesNotExists e),
+ PackageData getPackageInfo(1: PackageID pid) throws (1: PackageDoesNotExists e),
+ FileData getFileData(1: FileID fid) throws (1: FileDoesNotExists e),
+ list<PackageData> getQueue(),
+ list<PackageData> getCollector(),
+ list<PackageData> getQueueData(),
+ list<PackageData> getCollectorData(),
+ map<i16, PackageID> getPackageOrder(1: Destination destination),
+ map<i16, FileID> getFileOrder(1: PackageID pid)
+
+ // downloads - adding/deleting
+ list<PackageID> generateAndAddPackages(1: LinkList links, 2: Destination dest),
+ PackageID addPackage(1: string name, 2: LinkList links, 3: Destination dest, 4: string password),
+ void addFiles(1: PackageID pid, 2: LinkList links),
+ void uploadContainer(1: string filename, 2: binary data),
+ void deleteFiles(1: list<FileID> fids),
+ void deletePackages(1: list<PackageID> pids),
+
+ // downloads - modifying
+ void pushToQueue(1: PackageID pid),
+ void pullFromQueue(1: PackageID pid),
+ void restartPackage(1: PackageID pid),
+ void restartFile(1: FileID fid),
+ void recheckPackage(1: PackageID pid),
+ void stopAllDownloads(),
+ void stopDownloads(1: list<FileID> fids),
+ void setPackageName(1: PackageID pid, 2: string name),
+ void movePackage(1: Destination destination, 2: PackageID pid),
+ void moveFiles(1: list<FileID> fids, 2: PackageID pid),
+ void orderPackage(1: PackageID pid, 2: i16 position),
+ void orderFile(1: FileID fid, 2: i16 position),
+ void setPackageData(1: PackageID pid, 2: map<string, string> data) throws (1: PackageDoesNotExists e),
+ list<PackageID> deleteFinished(),
+ void restartFailed(),
+
+ //events
+ list<EventInfo> getEvents(1: string uuid)
+
+ //accounts
+ list<AccountInfo> getAccounts(1: bool refresh),
+ list<string> getAccountTypes()
+ void updateAccount(1: PluginName plugin, 2: string account, 3: string password, 4: map<string, string> options),
+ void removeAccount(1: PluginName plugin, 2: string account),
+
+ //auth
+ bool login(1: string username, 2: string password),
+ UserData getUserData(1: string username, 2:string password) throws (1: UserDoesNotExists ex),
+ map<string, UserData> getAllUserData(),
+
+ //services
+
+ // servicename : description
+ map<PluginName, map<string, string>> getServices(),
+ bool hasService(1: PluginName plugin, 2: string func),
+ string call(1: ServiceCall info) throws (1: ServiceDoesNotExists ex, 2: ServiceException e),
+
+
+ //info
+ // {plugin: {name: value}}
+ map<PluginName, map<string,string>> getAllInfo(),
+ map<string, string> getInfoByPlugin(1: PluginName plugin),
+
+ //scheduler
+
+ // TODO
+
+
+ // User interaction
+
+ //captcha
+ bool isCaptchaWaiting(),
+ CaptchaTask getCaptchaTask(1: bool exclusive),
+ string getCaptchaTaskStatus(1: InteractionID tid),
+ void setCaptchaResult(1: InteractionID tid, 2: string result),
+ }
+ .. [[[end]]]
+
diff --git a/docs/api/overview.rst b/docs/api/overview.rst
new file mode 100644
index 000000000..02cee3e0d
--- /dev/null
+++ b/docs/api/overview.rst
@@ -0,0 +1,35 @@
+.. _overview:
+
+=======================================
+API - Application Programming Interface
+=======================================
+
+From Wikipedia, the free encyclopedia [1]_:
+
+ An application programming interface (API) is a source code based specification intended to be used as an interface
+ by software components to communicate with each other. An API may include specifications for routines,
+ data structures, object classes, and variables.
+
+.. rubric:: Motivation
+
+The idea of the centralized pyLoad :class:`Api <module.Api.Api>` is to give uniform access to all integral parts
+and plugins in pyLoad, and furthermore to other clients, written in arbitrary programming languages.
+Most of the :class:`Api <module.Api.Api>` functionality is exposed via RPC [2]_ and accessible via thrift [3]_ or
+simple JSON objects [4]_. In conclusion the :class:`Api <module.Api.Api>` is accessible via many programming language,
+over network from remote maschines and over browser with javascript.
+
+
+.. rubric:: Contents
+
+.. toctree::
+
+ access_api.rst
+ datatypes.rst
+
+
+.. rubric:: Footnotes
+
+.. [1] http://en.wikipedia.org/wiki/Application_programming_interface
+.. [2] http://en.wikipedia.org/wiki/Remote_procedure_call
+.. [3] http://en.wikipedia.org/wiki/Thrift_(protocol)
+.. [4] http://en.wikipedia.org/wiki/Json \ No newline at end of file
diff --git a/docs/conf.py b/docs/conf.py
index 09e4d0c1c..454ed5967 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -65,8 +65,8 @@ v = options.version.split(".")
cog.outl("version = '%s'" % ".".join(v[:2]))
cog.outl("release = '%s'" % ".".join(v))
]]]"""
-version = '0.4'
-release = '0.4.9'
+version = '0.5'
+release = '0.5.0'
# [[[end]]]
diff --git a/docs/extend_pyload.rst b/docs/extend_pyload.rst
deleted file mode 100755
index 337cb6854..000000000
--- a/docs/extend_pyload.rst
+++ /dev/null
@@ -1,13 +0,0 @@
-.. _extend_pyload:
-
-********************
-How to extend pyLoad
-********************
-
-In general there a two different plugin types. These allow everybody to write powerful, modular plugins without knowing
-every detail of the pyLoad core. However you should have some basic knowledge of python.
-
-.. toctree::
-
- write_hooks.rst
- write_plugins.rst \ No newline at end of file
diff --git a/docs/index.rst b/docs/index.rst
index 757fd7537..befac0fd2 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -1,27 +1,46 @@
-.. pyLoad documentation master file, created by
- sphinx-quickstart on Sat Jun 4 11:54:34 2011.
- You can adapt this file completely to your liking, but it should at least
- contain the root `toctree` directive.
+.. pyLoad documentation master file
-Welcome to pyLoad's documentation!
-==================================
+=====================
+pyLoad Documentation
+=====================
-Great that you found your way to the pyLoad documentation!
+.. image:: _static/logo.png
+ :height: 144
+ :width: 412
-We have collected some information here to help developer writing plugins and understandig our code.
-If you want to help us developing visit us in our IRC channel #pyload on freenode.net or leave a message in our forum.
-Contents:
+Great that you found your way to the pyLoad [1]_ documentation!
+
+This is the ultimate document to get started extending or accessing pyLoad in your own way.
+We will cover on how to access the API so you can write your own client to pyLoad. The next big part gives you an idea
+how to extend pyLoad and write your own powerful plugins, which perfectly integrate into our system.
+
+The complete pyLoad source and this documentation is available at bitbucket [2]_. If you would like to contribute
+come around in our irc channel [3]_ or open a pull request.
+In case you still have question, ask them at our forum [4]_ or in our official irc channel at #pyload @ irc.freenode.net
+
+We wish you the best of luck and happy programming.
+-- the pyLoad Team
+
+Contents
+--------
.. toctree::
:maxdepth: 2
- access_api.rst
- extend_pyload.rst
+ api/overview.rst
+ plugins/overview.rst
module_overview.rst
.. currentmodule:: module
+.. rubric:: Footnotes
+
+.. [1] http://pyload.org
+.. [2] http://pyload.org/irc
+.. [3] http://bitbucket.org/spoob/pyload/overview
+.. [4] http://forum.pyload.org
+
==================
* :ref:`genindex`
diff --git a/docs/module_overview.rst b/docs/module_overview.rst
index 309dccdfd..b8db51538 100644
--- a/docs/module_overview.rst
+++ b/docs/module_overview.rst
@@ -1,7 +1,8 @@
+
Module Overview
===============
-You can find an overview of some important classes here:
+A little selection of most important modules in pyLoad.
.. autosummary::
:toctree: module
@@ -10,8 +11,9 @@ You can find an overview of some important classes here:
module.plugins.Base.Base
module.plugins.Hoster.Hoster
module.plugins.Crypter.Crypter
- module.plugins.Account.Account
module.plugins.Hook.Hook
+ module.plugins.Account.Account
+ module.plugins.MultiHoster.MultiHoster
module.HookManager.HookManager
module.interaction.EventManager.EventManager
module.interaction.InteractionManager.InteractionManager
diff --git a/docs/plugins/account_plugin.rst b/docs/plugins/account_plugin.rst
new file mode 100644
index 000000000..75bf61a75
--- /dev/null
+++ b/docs/plugins/account_plugin.rst
@@ -0,0 +1,5 @@
+.. _account_plugin:
+
+Account - Premium Access
+========================
+
diff --git a/docs/plugins/base_plugin.rst b/docs/plugins/base_plugin.rst
new file mode 100644
index 000000000..62ab248ef
--- /dev/null
+++ b/docs/plugins/base_plugin.rst
@@ -0,0 +1,5 @@
+.. _base_plugin:
+
+Base Plugin - And here it begins...
+===================================
+
diff --git a/docs/plugins/crypter_plugin.rst b/docs/plugins/crypter_plugin.rst
new file mode 100644
index 000000000..d910ec412
--- /dev/null
+++ b/docs/plugins/crypter_plugin.rst
@@ -0,0 +1,5 @@
+.. _crypter_plugin:
+
+Crypter - Extract links from pages
+==================================
+
diff --git a/docs/write_hooks.rst b/docs/plugins/hook_plugin.rst
index dd60367b7..e263ece2e 100644
--- a/docs/write_hooks.rst
+++ b/docs/plugins/hook_plugin.rst
@@ -1,7 +1,7 @@
.. _write_hooks:
-Hooks
-=====
+Hook - Do everything you want
+=============================
A Hook is a python file which is located at :file:`module/plugins/hooks`.
The :class:`HookManager <module.HookManager.HookManager>` will load it automatically on startup. Only one instance exists
diff --git a/docs/write_plugins.rst b/docs/plugins/hoster_plugin.rst
index b513a5978..59f35f5cb 100644
--- a/docs/write_plugins.rst
+++ b/docs/plugins/hoster_plugin.rst
@@ -1,7 +1,7 @@
-.. _write_plugins:
+.. _hoster_plugin:
-Plugins
-=======
+Hoster - Load files to disk
+===========================
A Plugin is a python file located at one of the subfolders in :file:`module/plugins/`. Either :file:`hoster`, :file:`crypter`
or :file:`container`, depending of it's type.
@@ -22,7 +22,6 @@ How basic hoster plugin header could look like: ::
from module.plugin.Hoster import Hoster
class MyFileHoster(Hoster):
- __name__ = "MyFileHoster"
__version__ = "0.1"
__pattern__ = r"http://myfilehoster.example.com/file_id/[0-9]+"
__config__ = []
diff --git a/docs/plugins/overview.rst b/docs/plugins/overview.rst
new file mode 100755
index 000000000..23913b787
--- /dev/null
+++ b/docs/plugins/overview.rst
@@ -0,0 +1,31 @@
+.. _overview:
+
+================
+Extending pyLoad
+================
+
+.. pull-quote::
+ Any sufficiently advanced technology is indistinguishable from magic.
+
+ -- Arthur C. Clarke
+
+
+.. rubric:: Motivation
+
+pyLoad offers an comfortable and powerful plugin system to make extending possible. With it you only need to have some
+python knowledge and can just start right away writing your own plugins. This document gives you an overwiew about the
+conceptual part. You should not left out the `Base` part, since it contains basic functionality for all plugins types.
+
+.. rubric:: Contents
+
+.. toctree::
+
+ base_plugin.rst
+ crypter_plugin.rst
+ hoster_plugin.rst
+ account_plugin.rst
+ hook_plugin.rst
+
+
+
+.. rubric:: Footnotes \ No newline at end of file
diff --git a/module/HookManager.py b/module/HookManager.py
index d0ceb89b2..51bc706ca 100644
--- a/module/HookManager.py
+++ b/module/HookManager.py
@@ -63,7 +63,7 @@ class HookManager:
func = getattr(hook, f)
return func(*args)
except Exception, e:
- plugin.logError(_("Error executing %s" % event), e)
+ hook.logError(_("Error when executing %s" % f), e)
if self.core.debug:
print_exc()
diff --git a/module/network/HTTPDownload.py b/module/network/HTTPDownload.py
index fe8075539..0d5fc59c9 100644
--- a/module/network/HTTPDownload.py
+++ b/module/network/HTTPDownload.py
@@ -17,9 +17,9 @@
@author: RaNaN
"""
-from os import remove, fsync
+from os import remove
from os.path import dirname
-from time import sleep, time
+from time import time
from shutil import move
from logging import getLogger
@@ -28,7 +28,7 @@ import pycurl
from HTTPChunk import ChunkInfo, HTTPChunk
from HTTPRequest import BadHeader
-from module.plugins.Plugin import Abort
+from module.plugins.Hoster import Abort
from module.utils import save_join, fs_encode
class HTTPDownload():
diff --git a/module/network/HTTPRequest.py b/module/network/HTTPRequest.py
index d4c33bbff..cd13dd01f 100644
--- a/module/network/HTTPRequest.py
+++ b/module/network/HTTPRequest.py
@@ -25,7 +25,7 @@ from httplib import responses
from logging import getLogger
from cStringIO import StringIO
-from module.plugins.Plugin import Abort
+from module.plugins.Hoster import Abort
def myquote(url):
return quote(url.encode('utf_8') if isinstance(url, unicode) else url, safe="%/:=&?~#+!$,;'@()*[]")
diff --git a/module/plugins/Account.py b/module/plugins/Account.py
index 59ce87ed2..e5b90d95e 100644
--- a/module/plugins/Account.py
+++ b/module/plugins/Account.py
@@ -4,12 +4,13 @@ from time import time
from traceback import print_exc
from threading import RLock
-from Plugin import Base
from module.utils import compare_time, parseFileSize, lock
from module.config.converter import from_string
from module.Api import AccountInfo
from module.network.CookieJar import CookieJar
+from Base import Base
+
class WrongPassword(Exception):
pass
diff --git a/module/plugins/Crypter.py b/module/plugins/Crypter.py
index 5d164da64..3e423881e 100644
--- a/module/plugins/Crypter.py
+++ b/module/plugins/Crypter.py
@@ -23,7 +23,10 @@ class Package:
return self.name == other.name and self.urls == other.urls
def __repr__(self):
- return "<CrypterPackage name=%s, links=%s, dest=%s" % (self.name, self.urls, self.dest)
+ return u"<CrypterPackage name=%s, links=%s, dest=%s" % (self.name, self.urls, self.dest)
+
+ def __hash__(self):
+ return hash(self.name) ^ hash(frozenset(self.urls)) ^ hash(self.dest)
class PyFileMockup:
""" Legacy class needed by old crypter plugins """
diff --git a/module/plugins/Hook.py b/module/plugins/Hook.py
index 76bc19dbe..c1090aa70 100644
--- a/module/plugins/Hook.py
+++ b/module/plugins/Hook.py
@@ -136,30 +136,31 @@ class Hook(Base):
""" Used to deactivate the hook. """
pass
- def downloadPreparing(self, pyfile):
+ def periodical(self):
pass
-
- def downloadFinished(self, pyfile):
+
+ def newCaptchaTask(self, task):
+ """ new captcha task for the plugin, it MUST set the handler and timeout or will be ignored """
pass
- def packageFinished(self, pypack):
+ def captchaCorrect(self, task):
pass
- def beforeReconnecting(self, ip):
+ def captchaInvalid(self, task):
pass
-
- def afterReconnecting(self, ip):
+
+ # public events starts from here
+ def downloadPreparing(self, pyfile):
pass
- def periodical(self):
+ def downloadFinished(self, pyfile):
pass
- def newCaptchaTask(self, task):
- """ new captcha task for the plugin, it MUST set the handler and timeout or will be ignored """
+ def packageFinished(self, pypack):
pass
- def captchaCorrect(self, task):
+ def beforeReconnecting(self, ip):
pass
-
- def captchaInvalid(self, task):
+
+ def afterReconnecting(self, ip):
pass \ No newline at end of file
diff --git a/module/plugins/MultiHoster.py b/module/plugins/MultiHoster.py
new file mode 100644
index 000000000..f7e560c10
--- /dev/null
+++ b/module/plugins/MultiHoster.py
@@ -0,0 +1,58 @@
+# -*- coding: utf-8 -*-
+
+from time import time
+
+from Account import Account
+
+#noinspection PyUnresolvedReferences
+class MultiHoster(Account):
+ """
+ Base class for MultiHoster services.
+ This is also an Account instance so you should see :class:`Account` and overwrite necessary methods.
+ Multihoster becomes only active when an Account was entered and the MultiHoster hook was activated.
+ You need to overwrite `loadHosterList` and a corresponding :class:`Hoster` plugin with the same name should
+ be available to make your service working.
+ """
+
+ #: List of hoster names that will be replaced so pyLoad will recognize them: (orig_name, pyload_name)
+ replacements = [("freakshare.net", "freakshare.com")]
+
+ #: Load new hoster list every x seconds
+ hoster_timeout = 300
+
+ def __init__(self, *args, **kwargs):
+
+ # Hoster list
+ self.hoster = []
+ # Timestamp
+ self.ts = 0
+
+ Account.__init__(*args, **kwargs)
+
+ def loadHosterList(self, req):
+ """Load list of supported hoster
+
+ :return: List of domain names
+ """
+ raise NotImplementedError
+
+ def getHosterList(self, force=False):
+ if self.ts + self.hoster_timeout < time() or force:
+ req = self.getAccountRequest()
+ try:
+ self.hoster = self.loadHosterList(req)
+ except Exception, e:
+ self.logError(e)
+ return []
+ finally:
+ req.close()
+
+ for rep in self.replacements:
+ if rep[0] in self.hosters:
+ self.hosters.remove(rep[0])
+ if rep[1] not in self.hosters:
+ self.hosters.append(rep[1])
+
+ self.ts = time()
+
+ return self.hosters \ No newline at end of file
diff --git a/module/plugins/internal/MultiHoster.py b/module/plugins/internal/MultiHoster.py
index 1629fdc5f..2252c4460 100644
--- a/module/plugins/internal/MultiHoster.py
+++ b/module/plugins/internal/MultiHoster.py
@@ -23,7 +23,7 @@ class MultiHoster(Hook):
try:
self.hosters = self.getHoster()
except Exception, e:
- self.logError("%s" % str(e))
+ self.logError(e)
return []
for rep in self.replacements:
diff --git a/module/remote/thriftbackend/pyload.thrift b/module/remote/thriftbackend/pyload.thrift
index d33b468c3..98e678c8e 100644
--- a/module/remote/thriftbackend/pyload.thrift
+++ b/module/remote/thriftbackend/pyload.thrift
@@ -2,7 +2,6 @@ namespace java org.pyload.thrift
typedef i32 FileID
typedef i32 PackageID
-typedef i32 TaskID
typedef i32 ResultID
typedef i32 InteractionID
typedef list<string> LinkList
@@ -334,6 +333,6 @@ service Pyload {
//captcha
bool isCaptchaWaiting(),
CaptchaTask getCaptchaTask(1: bool exclusive),
- string getCaptchaTaskStatus(1: TaskID tid),
- void setCaptchaResult(1: TaskID tid, 2: string result),
+ string getCaptchaTaskStatus(1: InteractionID tid),
+ void setCaptchaResult(1: InteractionID tid, 2: string result),
}
diff --git a/module/threads/DecrypterThread.py b/module/threads/DecrypterThread.py
index 8edb97c34..ce3c8cd83 100644
--- a/module/threads/DecrypterThread.py
+++ b/module/threads/DecrypterThread.py
@@ -72,7 +72,7 @@ class DecrypterThread(BaseThread):
self.log.info(_("Decrypted %(count)d links into package %(name)s") % {"count": len(urls), "name": pack.name})
self.m.core.api.addFiles(self.pid, urls)
- for p in pack_names:
+ for p in pack_names.itervalues():
self.m.core.api.addPackage(p.name, p.urls, p.dest, pack.password)
if not result:
diff --git a/pavement.py b/pavement.py
index 8ebd5bfc5..f3e8651c5 100644
--- a/pavement.py
+++ b/pavement.py
@@ -5,6 +5,21 @@ from paver.easy import *
from paver.setuputils import setup
from paver.doctools import cog
+import fnmatch
+
+# patch to let it support list of patterns
+def new_fnmatch(self, pattern):
+ if type(pattern) == list:
+ for p in pattern:
+ if fnmatch.fnmatch(self.name, p):
+ return True
+ return False
+ else:
+ return fnmatch.fnmatch(self.name, pattern)
+
+path.fnmatch = new_fnmatch
+
+
import sys
import re
from urllib import urlretrieve
@@ -86,7 +101,7 @@ options(
virtual="virtualenv2",
),
cog=Bunch(
- pattern="*.py",
+ pattern=["*.py", "*.rst"],
)
)