mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Add documentation for plugin system
This commit is contained in:
parent
7a3d089f17
commit
627f6be0ef
@ -19,12 +19,12 @@ class Plugin(object):
|
|||||||
|
|
||||||
Methods that should be overridden in sub classes:
|
Methods that should be overridden in sub classes:
|
||||||
|
|
||||||
* :method:`initialize`
|
* :meth:`initialize`
|
||||||
* :method:`customization_help`
|
* :meth:`customization_help`
|
||||||
|
|
||||||
Useful methods:
|
Useful methods:
|
||||||
|
|
||||||
* :method:`temporary_file`
|
* :meth:`temporary_file`
|
||||||
|
|
||||||
'''
|
'''
|
||||||
#: List of platforms this plugin works on
|
#: List of platforms this plugin works on
|
||||||
@ -93,6 +93,7 @@ class Plugin(object):
|
|||||||
a needed binary on the user's computer.
|
a needed binary on the user's computer.
|
||||||
|
|
||||||
:param gui: If True return HTML help, otherwise return plain text help.
|
:param gui: If True return HTML help, otherwise return plain text help.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@ -157,9 +158,10 @@ class FileTypePlugin(Plugin):
|
|||||||
simply return the path to the original ebook.
|
simply return the path to the original ebook.
|
||||||
|
|
||||||
The modified ebook file should be created with the
|
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.
|
:param path_to_ebook: Absolute path to the ebook.
|
||||||
|
|
||||||
:return: Absolute path to the modified ebook.
|
:return: Absolute path to the modified ebook.
|
||||||
'''
|
'''
|
||||||
# Default implementation does nothing
|
# Default implementation does nothing
|
||||||
@ -186,7 +188,8 @@ class MetadataReaderPlugin(Plugin):
|
|||||||
with the input data.
|
with the input data.
|
||||||
|
|
||||||
:param type: The type of file. Guaranteed to be one of the entries
|
: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: A :class:`calibre.ebooks.metadata.MetaInformation` object
|
||||||
'''
|
'''
|
||||||
return None
|
return None
|
||||||
@ -212,8 +215,9 @@ class MetadataWriterPlugin(Plugin):
|
|||||||
with the input data.
|
with the input data.
|
||||||
|
|
||||||
:param type: The type of file. Guaranteed to be one of the entries
|
: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
|
:param mi: A :class:`calibre.ebooks.metadata.MetaInformation` object
|
||||||
|
|
||||||
'''
|
'''
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -112,7 +112,8 @@ def get_file_type_metadata(stream, ftype):
|
|||||||
try:
|
try:
|
||||||
plugin = _metadata_readers[ftype.lower().strip()]
|
plugin = _metadata_readers[ftype.lower().strip()]
|
||||||
if not is_disabled(plugin):
|
if not is_disabled(plugin):
|
||||||
mi = plugin.get_metadata(stream, ftype.lower().strip())
|
with plugin:
|
||||||
|
mi = plugin.get_metadata(stream, ftype.lower().strip())
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
return mi
|
return mi
|
||||||
@ -121,7 +122,8 @@ def set_file_type_metadata(stream, mi, ftype):
|
|||||||
try:
|
try:
|
||||||
plugin = _metadata_writers[ftype.lower().strip()]
|
plugin = _metadata_writers[ftype.lower().strip()]
|
||||||
if not is_disabled(plugin):
|
if not is_disabled(plugin):
|
||||||
plugin.set_metadata(stream, mi, ftype.lower().strip())
|
with plugin:
|
||||||
|
plugin.set_metadata(stream, mi, ftype.lower().strip())
|
||||||
except:
|
except:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
@ -288,4 +290,4 @@ def main(args=sys.argv):
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
sys.exit(main())
|
sys.exit(main())
|
||||||
|
@ -72,7 +72,7 @@
|
|||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<property name="currentIndex" >
|
<property name="currentIndex" >
|
||||||
<number>4</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="page_3" >
|
<widget class="QWidget" name="page_3" >
|
||||||
<layout class="QVBoxLayout" name="verticalLayout" >
|
<layout class="QVBoxLayout" name="verticalLayout" >
|
||||||
|
BIN
src/calibre/gui2/images/news/endgadget.png
Normal file
BIN
src/calibre/gui2/images/news/endgadget.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 698 B |
BIN
src/calibre/gui2/images/news/fudzilla.png
Normal file
BIN
src/calibre/gui2/images/news/fudzilla.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 519 B |
112
src/calibre/manual/customize.rst
Normal file
112
src/calibre/manual/customize.rst
Normal 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.
|
@ -30,6 +30,7 @@ Sections
|
|||||||
metadata
|
metadata
|
||||||
faq
|
faq
|
||||||
xpath
|
xpath
|
||||||
|
customize
|
||||||
glossary
|
glossary
|
||||||
|
|
||||||
Convenience
|
Convenience
|
||||||
|
100
src/calibre/manual/plugins.rst
Normal file
100
src/calibre/manual/plugins.rst
Normal 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
|
30
src/calibre/web/feeds/recipes/endgadget.py
Normal file
30
src/calibre/web/feeds/recipes/endgadget.py
Normal 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')]
|
||||||
|
|
26
src/calibre/web/feeds/recipes/fudzilla.py
Normal file
26
src/calibre/web/feeds/recipes/fudzilla.py
Normal 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'
|
Loading…
x
Reference in New Issue
Block a user