Add documentation for plugin system

This commit is contained in:
Kovid Goyal 2008-12-25 15:42:28 -08:00
parent 7a3d089f17
commit 627f6be0ef
10 changed files with 286 additions and 11 deletions

View File

@ -19,12 +19,12 @@ class Plugin(object):
Methods that should be overridden in sub classes:
* :method:`initialize`
* :method:`customization_help`
* :meth:`initialize`
* :meth:`customization_help`
Useful methods:
* :method:`temporary_file`
* :meth:`temporary_file`
'''
#: List of platforms this plugin works on
@ -93,6 +93,7 @@ class Plugin(object):
a needed binary on the user's computer.
:param gui: If True return HTML help, otherwise return plain text help.
'''
raise NotImplementedError
@ -157,9 +158,10 @@ class FileTypePlugin(Plugin):
simply return the path to the original ebook.
The modified ebook file should be created with the
:method:`temporary_file` method.
:meth:`temporary_file` method.
:param path_to_ebook: Absolute path to the ebook.
:return: Absolute path to the modified ebook.
'''
# Default implementation does nothing
@ -186,7 +188,8 @@ class MetadataReaderPlugin(Plugin):
with the input data.
:param type: The type of file. Guaranteed to be one of the entries
in :member:`file_types`.
in :attr:`file_types`.
:return: A :class:`calibre.ebooks.metadata.MetaInformation` object
'''
return None
@ -212,8 +215,9 @@ class MetadataWriterPlugin(Plugin):
with the input data.
:param type: The type of file. Guaranteed to be one of the entries
in :member:`file_types`.
in :attr:`file_types`.
:param mi: A :class:`calibre.ebooks.metadata.MetaInformation` object
'''
pass

View File

@ -112,7 +112,8 @@ def get_file_type_metadata(stream, ftype):
try:
plugin = _metadata_readers[ftype.lower().strip()]
if not is_disabled(plugin):
mi = plugin.get_metadata(stream, ftype.lower().strip())
with plugin:
mi = plugin.get_metadata(stream, ftype.lower().strip())
except:
pass
return mi
@ -121,7 +122,8 @@ def set_file_type_metadata(stream, mi, ftype):
try:
plugin = _metadata_writers[ftype.lower().strip()]
if not is_disabled(plugin):
plugin.set_metadata(stream, mi, ftype.lower().strip())
with plugin:
plugin.set_metadata(stream, mi, ftype.lower().strip())
except:
traceback.print_exc()
@ -288,4 +290,4 @@ def main(args=sys.argv):
return 0
if __name__ == '__main__':
sys.exit(main())
sys.exit(main())

View File

@ -72,7 +72,7 @@
</sizepolicy>
</property>
<property name="currentIndex" >
<number>4</number>
<number>0</number>
</property>
<widget class="QWidget" name="page_3" >
<layout class="QVBoxLayout" name="verticalLayout" >

Binary file not shown.

After

Width:  |  Height:  |  Size: 698 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 519 B

View File

@ -0,0 +1,112 @@
.. include:: global.rst
.. currentmodule:: calibre.customize.__init__
.. _customize:
Customizing |app|
==================================
|app| has a highly modular design. Various parts of it can be customized. You can learn how to create
*recipes* to add new sources of online content to |app| in the Section :ref:`news`. Here, you will learn how to
use *plugins* to customize and control various aspects of |app|'s behavior.
Theer are different kinds of plugins, corresponding to different aspects of |app|. As more and more aspects of |app|
are modularized, new plugin types will be added.
.. contents::
:depth: 2
:local:
A Hello World plugin
------------------------
Suppose you have an installation of |app| that you are using to self publish various e-documents in EPUB and LRF
format. You would like all file generated by |app| to have their publisher set as "Hello world", here's how to do it.
Create a file name :file:`my_plugin.py` (the file name must end with plugin.py) and enter the following Python code into it:
.. code-block:: python
import os
from calibre.customize import FileTypePlugin
class HelloWorld(FileTypePlugin):
name = 'Hello World Plugin' # Name of the plugin
description = 'Set the publisher to Hello World for all new conversions'
supported_platforms = ['windows', 'osx', 'linux'] # Platforms this plugin will run on
author = 'Acme Inc.' # The author of this plugin
version = (1, 0, 0) # The version number of this plugin
file_types = set(['epub', 'lrf']) # The file types that this plugin will be applied to
on_postprocess = True # Run this plugin after conversion is complete
def run(self, path_to_ebook):
from calibre.ebooks.metadata.meta import get_metadata, set_metadata
file = open(path_to_ebook, 'r+b')
ext = os.path.splitext(path_to_ebook)[-1][1:].lower()
mi = get_metadata(file, ext)
mi.publisher = 'Hello World'
set_metadata(file, ext, mi)
return path_to_ebook
That's all. To add this code to |app| as a plugin, simply create a zip file with::
zip plugin.zip my_plugin.py
Now either use the configuration dialog in |app| GUI to add this zip file as a plugin, or
use the command::
calibre-customize -a plugin.zip
Every time you use calibre to convert a book, the plugin's :meth:`run` method will be called and the
converted book will have its publisher set to "Hello World". For more information about
|app|'s plugin system, read on...
The Plugin base class
------------------------
As you may have noticed above, all |app| plugins are classes. The Plugin classes are organized in a hierarchy at the top of which
is :class:`calibre.customize.Plugin`. The has excellent in source documentation for its various features, here I will discuss a
few of the important ones.
First, all plugins must supply a list of platforms they have been tested on by setting the ``supported_platforms`` member as in the
example above.
If the plugin needs to do any initialization, it should implement the :meth:`initialize` method. The path to the plugin zip file
is available as ``self.plugin_path``. The initialization method could be used to load any needed resources from the zip file.
If the plugin needs to be customized (i.e. it needs some information from the user), it should implement the :meth:`customization_help`
method, to indicate to |app| that it needs user input. This can be useful, for example, to ask the user to input the path to a needed system
binary or the URL of a website, etc. When |app| asks the user for the customization information, the string retuned by the :meth:`customization_help`
method is used as help text to le thte user know what information is needed.
Another useful method is :meth:`temporary_file`, which returns a file handle to an opened temporary file. If your plugin needs to make use
of temporary files, it should use this method. Temporary file cleanup is then taken care of automatically.
In addition, whenever plugins are run, their zip files are automatically added to the start of ``sys.path``, so you can directly import
any python files you bundle in the zip files. Note that this is not available when the plugin is being initialized, only when it is being run.
Finally, plugins can have a priority (a positive integer). Higher priority plugins are run in preference tolower priority ones in a given context.
By default all plugins have priority 1. You can change that by setting the member :attr:'priority` in your subclass.
See :ref:`pluginsPlugin` for details.
File type plugins
-------------------
File type plugins are intended to be associated with specific file types (as identified by extension). They can be run on several different occassions.
* When books/formats are added ot the |app| database (if :attr:`on_import` is set to True).
* Just before an any2whatever converter is run on an input file (if :attr:`on_preprocess` is set to True).
* After an any2whatever converter has run, on the output file (if :attr:`on_postprocess` is set to True).
File type plugins specify which file types they are associated with by specifying the :attr:`file_types` member as in the above example.
the actual work should be done in the :meth:`run` method, which must return the path to the modified ebook (it can be the same as the original
if the modifcations are done in place).
See :ref:`pluginsFTPlugin` for details.
Metadata plugins
-------------------
Metadata plugins add the ability to read/write metadata from ebook files to |app|. See :ref:`pluginsMetadataPlugin` for details.

View File

@ -30,6 +30,7 @@ Sections
metadata
faq
xpath
customize
glossary
Convenience

View File

@ -0,0 +1,100 @@
.. include:: global.rst
.. _plugins:
API Documentation for plugins
===============================
.. module:: calibre.customize.__init__
:synopsis: Defines various abstract base classes that can be subclassed to create plugins.
Defines various abstract base classes that can be subclassed to create powerful plugins. The useful
classes are:
.. contents::
:depth: 1
:local:
.. _pluginsPlugin:
Plugin
-----------------
.. class:: Plugin
Abstract base class that contains a number of members and methods to create your plugin. All
plugins must inherit from this class or a subclass of it.
The members and methods are:
.. automember:: Plugin.name
.. automember:: Plugin.author
.. automember:: Plugin.description
.. automember:: Plugin.version
.. automember:: Plugin.supported_platforms
.. automember:: Plugin.priority
.. automember:: Plugin.minimum_calibre_version
.. automember:: Plugin.can_be_disabled
.. automethod:: Plugin.initialize
.. automethod:: Plugin.customization_help
.. automethod:: Plugin.temporary_file
.. _pluginsFTPlugin:
FileTypePlugin
-----------------
.. class:: Plugin
Abstract base class that contains a number of members and methods to create your file type plugin. All file type
plugins must inherit from this class or a subclass of it.
The members and methods are:
.. automember:: FileTypePlugin.file_types
.. automember:: FileTypePlugin.on_import
.. automember:: FileTypePlugin.on_preprocess
.. automember:: FileTypePlugin.on_postprocess
.. automethod:: FileTypePlugin.run
.. _pluginsMetadataPlugin:
Metadata plugins
-------------------
.. class:: MetadataReaderPlugin
Abstract base class that contains a number of members and methods to create your metadata reader plugin. All metadata
reader plugins must inherit from this class or a subclass of it.
The members and methods are:
.. automember:: MetadataReaderPlugin.file_types
.. automethod:: MetadataReaderPlugin.get_metadata
.. class:: MetadataWriterPlugin
Abstract base class that contains a number of members and methods to create your metadata writer plugin. All metadata
writer plugins must inherit from this class or a subclass of it.
The members and methods are:
.. automember:: MetadataWriterPlugin.file_types
.. automethod:: MetadataWriterPlugin.set_metadata

View File

@ -0,0 +1,30 @@
#!/usr/bin/env python
__license__ = 'GPL v3'
__copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>'
'''
engadget.com
'''
import string,re
from calibre.web.feeds.news import BasicNewsRecipe
class Engadget(BasicNewsRecipe):
title = u'Engadget'
__author__ = 'Darko Miletic'
description = 'Tech news'
oldest_article = 7
max_articles_per_feed = 100
no_stylesheets = True
use_embedded_content = False
keep_only_tags = [ dict(name='div', attrs={'class':'post'}) ]
remove_tags = [
dict(name='object')
,dict(name='div', attrs={'class':'postmeta'})
,dict(name='div', attrs={'class':'quigoads'})
]
feeds = [ (u'Posts', u'http://www.engadget.com/rss.xml')]

View File

@ -0,0 +1,26 @@
#!/usr/bin/env python
__license__ = 'GPL v3'
__copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>'
'''
fudzilla.com
'''
import string,re
from calibre.web.feeds.news import BasicNewsRecipe
class Fudzilla(BasicNewsRecipe):
title = u'Fudzilla'
__author__ = 'Darko Miletic'
description = 'Tech news'
oldest_article = 7
max_articles_per_feed = 100
no_stylesheets = True
use_embedded_content = False
feeds = [ (u'Posts', u'http://www.fudzilla.com/index.php?option=com_rss&feed=RSS2.0&no_html=1')]
def print_version(self, url):
nurl = url.replace('http://www.fudzilla.com/index.php','http://www.fudzilla.com/index2.php')
nmain, nsep, nrest = nurl.partition('&Itemid=')
return nmain + '&pop=1&page=0&Itemid=1'