From 18959723a24867c9574644d9b3c3c901392d3292 Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Mon, 8 Sep 2014 01:41:49 +0200 Subject: Docs cleanup + remove script directory --- docs/access_api.rst | 2 +- docs/extend_pyload.rst | 5 +- docs/module_overview.rst | 10 +-- docs/plugin_licensing.rst | 18 ++++++ docs/write_addons.rst | 158 ++++++++++++++++++++++++++++++++++++++++++++++ docs/write_hooks.rst | 158 ---------------------------------------------- docs/write_plugins.rst | 12 ++-- docs/write_scripts.rst | 25 ++++++++ 8 files changed, 217 insertions(+), 171 deletions(-) create mode 100644 docs/plugin_licensing.rst create mode 100644 docs/write_addons.rst delete mode 100644 docs/write_hooks.rst create mode 100644 docs/write_scripts.rst (limited to 'docs') diff --git a/docs/access_api.rst b/docs/access_api.rst index 58fe56ca4..1d013c2c0 100644 --- a/docs/access_api.rst +++ b/docs/access_api.rst @@ -15,7 +15,7 @@ retrieving download status, manage queue, manage accounts, modify config and so This document is not intended to explain every function in detail, for a complete listing see :class:`Api `. -Of course its possible to access the ``core.api`` attribute in plugins and hooks, but much more +Of course its possible to access the ``core.api`` attribute in plugins and addons, but much more interesting is the possibillity to call function from different programs written in many different languages. pyLoad uses thrift as backend and provides its :class:`Api ` as service. diff --git a/docs/extend_pyload.rst b/docs/extend_pyload.rst index e8b60b63c..ccd4ac203 100755 --- a/docs/extend_pyload.rst +++ b/docs/extend_pyload.rst @@ -1,7 +1,7 @@ .. _extend_pyload: ******************** -How to extend pyLoad +How to extend pyLoad ******************** In general there a two different plugin types. These allow everybody to write powerful, modular plugins without knowing @@ -9,5 +9,6 @@ every detail of the pyLoad core. However you should have some basic knowledge of .. toctree:: - write_hooks.rst + write_addons.rst write_plugins.rst + write_scripts.rst diff --git a/docs/module_overview.rst b/docs/module_overview.rst index d76386ed7..fce9ecfca 100644 --- a/docs/module_overview.rst +++ b/docs/module_overview.rst @@ -1,3 +1,5 @@ +.. _module_overview: + Module Overview =============== @@ -11,7 +13,7 @@ You can find an overview of some important classes here: pyload.plugins.Plugin.Plugin pyload.plugins.Crypter.Crypter pyload.plugins.Account.Account - pyload.plugins.Hook.Hook - pyload.HookManager.HookManager - pyload.PyFile.PyFile - pyload.PyPackage.PyPackage + pyload.plugins.Addon.Addon + pyload.manager.AddonManager.AddonManager + pyload.datatypes.PyFile.PyFile + pyload.datatypes.PyPackage.PyPackage diff --git a/docs/plugin_licensing.rst b/docs/plugin_licensing.rst new file mode 100644 index 000000000..0e8590d62 --- /dev/null +++ b/docs/plugin_licensing.rst @@ -0,0 +1,18 @@ +.. _plugin_licensing: + +Plugin Licensing +================ + +According to the terms of the GNU General Public License, +pyload's plugins must be treated as an extension of the main program. +This means the plugins must be released under the GPL or a GPL-compatible +free software license, and that the terms of the GPL must be followed when +those plugins are distributed. + + * Any plugin published **without a license notice** is intend published under the **GNU GPLv3**. + * A different license can be used but it **must be GPL-compatible** and the license notice must be put in the plugin + file. + * Any plugin published **with a GPL incompatible license** will be rejected. + This includes *copyright all right reserved*. + * Is recommended to put the license notice at the top of the plugin file. + * Is recommended to **not** put the license notice when plugin is published under the GNU GPLv3. diff --git a/docs/write_addons.rst b/docs/write_addons.rst new file mode 100644 index 000000000..c9f050ebc --- /dev/null +++ b/docs/write_addons.rst @@ -0,0 +1,158 @@ +.. _write_addons: + +Addons +====== + +A Addon is a python file which is located at :file:`pyload/plugins/addon`. +The :class:`AddonManager ` will load it automatically on startup. Only one instance exists +over the complete lifetime of pyload. Your addon can interact on various events called by the :class:`AddonManager `, +do something complete autonomic and has full access to the :class:`Api ` and every detail of pyLoad. +The UpdateManager, CaptchaTrader, UnRar and many more are realised as addon. + +Addon header +----------- + +Your addon needs to subclass :class:`Addon ` and will inherit all of its method, make sure to check its documentation! + +All addons should start with something like this: :: + + from pyload.plugins.Addon import Addon + + class YourAddon(Addon): + __name__ = "YourAddon" + __version__ = "0.1" + __description__ = "Does really cool stuff" + __config__ = [ ("activated" , "bool" , "Activated" , "True" ) ] + __author_name__ = ("Me") + __author_mail__ = ("me@has-no-mail.com") + +All meta-data is defined in the header, you need at least one option at ``__config__`` so the user can toggle your +addon on and off. Dont't overwrite the ``init`` method if not neccesary, use ``setup`` instead. + +Using the Config +---------------- + +We are taking a closer look at the ``__config__`` parameter. +You can add more config values as desired by adding tuples of the following format to the config list: ``("name", "type", "description", "default value")``. +When everything went right you can access the config values with ``self.getConfig(name)`` and ``self.setConfig(name, value``. + + +Interacting on Events +--------------------- + +The next step is to think about where your Addon action takes places. + +The easiest way is to overwrite specific methods defined by the :class:`Addon ` base class. +The name is indicating when the function gets called. +See :class:`Addon ` page for a complete listing. + +You should be aware of the arguments the Addon is called with, whether its a :class:`PyFile ` +or :class:`PyPackage ` you should read its related documentation to know how to access her great power and manipulate them. + +A basic excerpt would look like: :: + + from pyload.plugins.Addon import Addon + + class YourAddon(Addon): + """ + Your Addon code here. + """ + + def activate(self): + print "Yay, the core is ready let's do some work." + + def downloadFinished(self, pyfile): + print "A Download just finished." + +Another and more flexible and powerful way is to use event listener. +All addon methods exists as event and very useful additional events are dispatched by the core. For a little overview look +at :class:`AddonManager `. Keep in mind that you can define own events and other people may listen on them. + +For your convenience it's possible to register listeners automatical via the ``event_map`` attribute. +It requires a `dict` that maps event names to function names or a `list` of function names. It's important that all names are strings :: + + from pyload.plugins.Addon import Addon + + class YourAddon(Addon): + """ + Your Addon code here. + """ + event_map = {'downloadFinished': "doSomeWork", + 'allDownloadsFnished': "someMethod", + 'activate': "initialize"} + + def initialize(self): + print "Initialized." + + def doSomeWork(self, pyfile): + print "This is equivalent to the above example." + + def someMethod(self): + print "The underlying event (allDownloadsFinished) for this method is not available through the base class" + +An advantage of the event listener is that you are able to register and remove the listeners at runtime. +Use `self.manager.addEvent("name", function)`, `self.manager.removeEvent("name", function)` and see doc for +:class:`AddonManager `. Contrary to ``event_map``, ``function`` has to be a reference +and **not** a `string`. + +We introduced events because it scales better if there a a huge amount of events and addons. So all future interaction will be exclusive +available as event and not accessible through overwriting addon methods. However you can safely do this, it will not be removed and is easier to implement. + + +Providing RPC services +---------------------- + +You may noticed that pyLoad has an :class:`Api `, which can be used internal or called by clients via RPC. +So probably clients want to be able to interact with your addon to request it's state or invoke some action. + +Sounds complicated but is very easy to do. Just use the ``Expose`` decorator: :: + + from pyload.plugins.Addon import Addon, Expose + + class YourAddon(Addon): + """ + Your Addon code here. + """ + + @Expose + def invoke(self, arg): + print "Invoked with", arg + +Thats all, it's available via the :class:`Api ` now. If you want to use it read :ref:`access_api`. +Here is a basic example: :: + + #Assuming client is a ThriftClient or Api object + + print client.getServices() + print client.call(ServiceCall("YourAddon", "invoke", "an argument")) + +Providing status information +---------------------------- +Your addon can store information in a ``dict`` that can easily be retrievied via the :class:`Api `. + +Just store everything in ``self.info``. :: + + from pyload.plugins.Addon import Addon + + class YourAddon(Addon): + """ + Your Addon code here. + """ + + def setup(self): + self.info = {'running': False} + + def activate(self): + self.info['running'] = True + +Usable with: :: + + #Assuming client is a ThriftClient or Api object + + print client.getAllInfo() + +Example +------- + Sorry but you won't find an example here ;-) + + Look at :file:`pyload/plugins/addon` and you will find plenty examples there. diff --git a/docs/write_hooks.rst b/docs/write_hooks.rst deleted file mode 100644 index ebf2ed368..000000000 --- a/docs/write_hooks.rst +++ /dev/null @@ -1,158 +0,0 @@ -.. _write_hooks: - -Hooks -===== - -A Hook is a python file which is located at :file:`pyload/plugins/hooks`. -The :class:`HookManager ` will load it automatically on startup. Only one instance exists -over the complete lifetime of pyload. Your hook can interact on various events called by the :class:`HookManager `, -do something complete autonomic and has full access to the :class:`Api ` and every detail of pyLoad. -The UpdateManager, CaptchaTrader, UnRar and many more are realised as hooks. - -Hook header ------------ - -Your hook needs to subclass :class:`Hook ` and will inherit all of its method, make sure to check its documentation! - -All Hooks should start with something like this: :: - - from pyload.plugins.Hook import Hook - - class YourHook(Hook): - __name__ = "YourHook" - __version__ = "0.1" - __description__ = "Does really cool stuff" - __config__ = [ ("activated" , "bool" , "Activated" , "True" ) ] - __author_name__ = ("Me") - __author_mail__ = ("me@has-no-mail.com") - -All meta-data is defined in the header, you need at least one option at ``__config__`` so the user can toggle your -hook on and off. Dont't overwrite the ``init`` method if not neccesary, use ``setup`` instead. - -Using the Config ----------------- - -We are taking a closer look at the ``__config__`` parameter. -You can add more config values as desired by adding tuples of the following format to the config list: ``("name", "type", "description", "default value")``. -When everything went right you can access the config values with ``self.getConfig(name)`` and ``self.setConfig(name, value``. - - -Interacting on Events ---------------------- - -The next step is to think about where your Hook action takes places. - -The easiest way is to overwrite specific methods defined by the :class:`Hook ` base class. -The name is indicating when the function gets called. -See :class:`Hook ` page for a complete listing. - -You should be aware of the arguments the Hooks are called with, whether its a :class:`PyFile ` -or :class:`PyPackage ` you should read its related documentation to know how to access her great power and manipulate them. - -A basic excerpt would look like: :: - - from pyload.plugins.Hook import Hook - - class YourHook(Hook): - """ - Your Hook code here. - """ - - def coreReady(self): - print "Yay, the core is ready let's do some work." - - def downloadFinished(self, pyfile): - print "A Download just finished." - -Another and more flexible and powerful way is to use event listener. -All hook methods exists as event and very useful additional events are dispatched by the core. For a little overview look -at :class:`HookManager `. Keep in mind that you can define own events and other people may listen on them. - -For your convenience it's possible to register listeners automatical via the ``event_map`` attribute. -It requires a `dict` that maps event names to function names or a `list` of function names. It's important that all names are strings :: - - from pyload.plugins.Hook import Hook - - class YourHook(Hook): - """ - Your Hook code here. - """ - event_map = {"downloadFinished": "doSomeWork", - "allDownloadsFnished": "someMethod", - "coreReady": "initialize"} - - def initialize(self): - print "Initialized." - - def doSomeWork(self, pyfile): - print "This is equivalent to the above example." - - def someMethod(self): - print "The underlying event (allDownloadsFinished) for this method is not available through the base class" - -An advantage of the event listener is that you are able to register and remove the listeners at runtime. -Use `self.manager.addEvent("name", function)`, `self.manager.removeEvent("name", function)` and see doc for -:class:`HookManager `. Contrary to ``event_map``, ``function`` has to be a reference -and **not** a `string`. - -We introduced events because it scales better if there a a huge amount of events and hooks. So all future interaction will be exclusive -available as event and not accessible through overwriting hook methods. However you can safely do this, it will not be removed and is easier to implement. - - -Providing RPC services ----------------------- - -You may noticed that pyLoad has an :class:`Api `, which can be used internal or called by clients via RPC. -So probably clients want to be able to interact with your hook to request it's state or invoke some action. - -Sounds complicated but is very easy to do. Just use the ``Expose`` decorator: :: - - from pyload.plugins.Hook import Hook, Expose - - class YourHook(Hook): - """ - Your Hook code here. - """ - - @Expose - def invoke(self, arg): - print "Invoked with", arg - -Thats all, it's available via the :class:`Api ` now. If you want to use it read :ref:`access_api`. -Here is a basic example: :: - - #Assuming client is a ThriftClient or Api object - - print client.getServices() - print client.call(ServiceCall("YourHook", "invoke", "an argument")) - -Providing status information ----------------------------- -Your hook can store information in a ``dict`` that can easily be retrievied via the :class:`Api `. - -Just store everything in ``self.info``. :: - - from pyload.plugins.Hook import Hook - - class YourHook(Hook): - """ - Your Hook code here. - """ - - def setup(self): - self.info = {"running": False} - - def coreReady(self): - self.info["running"] = True - -Usable with: :: - - #Assuming client is a ThriftClient or Api object - - print client.getAllInfo() - -Example -------- - Sorry but you won't find an example here ;-) - - Look at :file:`pyload/plugins/hooks` and you will find plenty examples there. diff --git a/docs/write_plugins.rst b/docs/write_plugins.rst index c2b25a934..f624b2fb5 100644 --- a/docs/write_plugins.rst +++ b/docs/write_plugins.rst @@ -19,7 +19,7 @@ Plugin header How basic hoster plugin header could look like: :: - from pyload.plugin.Hoster import Hoster + from pyload.plugins.Hoster import Hoster class MyFileHoster(Hoster): __name__ = "MyFileHoster" @@ -30,7 +30,7 @@ How basic hoster plugin header could look like: :: You have to define these meta-data, ``__pattern__`` has to be a regexp that sucessfully compiles with ``re.compile(__pattern__)``. -Just like :ref:`write_hooks` you can add and use config values exatly the same way. +Just like :ref:`write_addons` you can add and use config values exatly the same way. If you want a Crypter or Container plugin, just replace the word Hoster with your desired plugin type. @@ -41,7 +41,7 @@ We head to the next important section, the ``process`` method of your plugin. In fact the ``process`` method is the only functionality your plugin has to provide, but its always a good idea to split up tasks to not produce spaghetti code. An example ``process`` function could look like this :: - from pyload.plugin.Hoster import Hoster + from pyload.plugins.Hoster import Hoster class MyFileHoster(Hoster): """ @@ -58,7 +58,7 @@ An example ``process`` function could look like this :: # download the file, destination is determined by pyLoad self.download(parsed_url) -You need to know about the :class:`PyFile ` class, since an instance of it is given as parameter to every pyfile. +You need to know about the :class:`PyFile ` class, since an instance of it is given as parameter to every pyfile. Some tasks your plugin should handle: proof if file is online, get filename, wait if needed, download the file, etc.. Wait times @@ -71,7 +71,7 @@ Captcha decrypting __________________ To handle captcha input just use ``self.decryptCaptcha(url, ...)``, it will be send to clients -or handled by :class:`Hook ` plugins +or handled by :class:`Addon ` plugins Crypter ------- @@ -81,7 +81,7 @@ Well, they work nearly the same, only that the function they have to provide is Example: :: - from pyload.plugin.Crypter import Crypter + from pyload.plugins.Crypter import Crypter class MyFileCrypter(Crypter): """ diff --git a/docs/write_scripts.rst b/docs/write_scripts.rst new file mode 100644 index 000000000..55c0e1665 --- /dev/null +++ b/docs/write_scripts.rst @@ -0,0 +1,25 @@ +.. _write_scripts: + +Scripts +======= + +pyLoad is able to start any kind of scripts at given events. +Simply put your script in a suitable folder and pyLoad will execute it at the given events and pass some arguments to them. + + +***Note:*** +**Every script starting with symbol `#` will be ignored!** (ex.: `#converter.sh`) + +***Note:*** +You have to restart pyload when you change script names or locations. + + +Below you see the list of arguments, which are passed to the scripts. + +### Argument list ### + + - `download_preparing`: **`pluginname` `url`** + - `download_finished`: **`pluginname` `url` `filename` `filelocation`** + - `package_finshed`: **`packagename` `packagelocation`** + - `before_reconnect`: **`oldip`** + - `after_reconnect`: **`newip`** -- cgit v1.2.3