%PDF- %PDF-
| Direktori : /usr/lib/calibre/calibre/gui2/store/ |
| Current File : //usr/lib/calibre/calibre/gui2/store/__init__.py |
__license__ = 'GPL 3'
__copyright__ = '2011, John Schember <john@nachtimwald.com>'
__docformat__ = 'restructuredtext en'
from calibre.utils.filenames import ascii_filename
class StorePlugin: # {{{
'''
A plugin representing an online ebook repository (store). The store can
be a commercial store that sells ebooks or a source of free downloadable
ebooks.
Note that this class is the base class for these plugins, however, to
integrate the plugin with calibre's plugin system, you have to make a
wrapper class that references the actual plugin. See the
:mod:`calibre.customize.builtins` module for examples.
If two :class:`StorePlugin` objects have the same name, the one with higher
priority takes precedence.
Sub-classes must implement :meth:`open`, and :meth:`search`.
Regarding :meth:`open`. Most stores only make themselves available
though a web site thus most store plugins will open using
:class:`calibre.gui2.store.web_store_dialog.WebStoreDialog`. This will
open a modal window and display the store website in a QWebView.
Sub-classes should implement and use the :meth:`genesis` if they require
plugin specific initialization. They should not override or otherwise
reimplement :meth:`__init__`.
Once initialized, this plugin has access to the main calibre GUI via the
:attr:`gui` member. You can access other plugins by name, for example::
self.gui.istores['Amazon Kindle']
Plugin authors can use affiliate programs within their plugin. The
distribution of money earned from a store plugin is 70/30. 70% going
to the pluin author / maintainer and 30% going to the calibre project.
The easiest way to handle affiliate money payouts is to randomly select
between the author's affiliate id and calibre's affiliate id so that
70% of the time the author's id is used.
See declined.txt for a list of stores that do not want to be included.
'''
minimum_calibre_version = (0, 9, 14)
def __init__(self, gui, name, config=None, base_plugin=None):
self.gui = gui
self.name = name
self.base_plugin = base_plugin
if config is None:
from calibre.utils.config import JSONConfig
config = JSONConfig('store/stores/' + ascii_filename(self.name))
self.config = config
def create_browser(self):
'''
If the server requires special headers, such as a particular user agent
or a referrer, then implement this method in you plugin to return a
customized browser instance. See the Gutenberg plugin for an example.
Note that if you implement the open() method in your plugin and use the
WebStoreDialog class, remember to pass self.createbrowser in the
constructor of WebStoreDialog.
'''
raise NotImplementedError()
def open(self, gui, parent=None, detail_item=None, external=False):
'''
Open the store.
:param gui: The main GUI. This will be used to have the job
system start downloading an item from the store.
:param parent: The parent of the store dialog. This is used
to create modal dialogs.
:param detail_item: A plugin specific reference to an item
in the store that the user should be shown.
:param external: When False open an internal dialog with the
store. When True open the users default browser to the store's
web site. :param:`detail_item` should still be respected when external
is True.
'''
raise NotImplementedError()
def search(self, query, max_results=10, timeout=60):
'''
Searches the store for items matching query. This should
return items as a generator.
Don't be lazy with the search! Load as much data as possible in the
:class:`calibre.gui2.store.search_result.SearchResult` object.
However, if data (such as cover_url)
isn't available because the store does not display cover images then it's okay to
ignore it.
At the very least a :class:`calibre.gui2.store.search_result.SearchResult`
returned by this function must have the title, author and id.
If you have to parse multiple pages to get all of the data then implement
:meth:`get_deatils` for retrieving additional information.
Also, by default search results can only include ebooks. A plugin can offer users
an option to include physical books in the search results but this must be
disabled by default.
If a store doesn't provide search on it's own use something like a site specific
google search to get search results for this function.
:param query: The string query search with.
:param max_results: The maximum number of results to return.
:param timeout: The maximum amount of time in seconds to spend downloading data for search results.
:return: :class:`calibre.gui2.store.search_result.SearchResult` objects
item_data is plugin specific and is used in :meth:`open` to open to a specific place in the store.
'''
raise NotImplementedError()
def get_details(self, search_result, timeout=60):
'''
Delayed search for information about specific search items.
Typically, this will be used when certain information such as
formats, drm status, cover url are not part of the main search
results and the information is on another web page.
Using this function allows for the main information (title, author)
to be displayed in the search results while other information can
take extra time to load. Splitting retrieving data that takes longer
to load into a separate function will give the illusion of the search
being faster.
:param search_result: A search result that need details set.
:param timeout: The maximum amount of time in seconds to spend downloading details.
:return: True if the search_result was modified otherwise False
'''
return False
def update_cache(self, parent=None, timeout=60, force=False, suppress_progress=False):
'''
Some plugins need to keep an local cache of available books. This function
is called to update the caches. It is recommended to call this function
from :meth:`open`. Especially if :meth:`open` does anything other than
open a web page.
This function can be called at any time. It is up to the plugin to determine
if the cache really does need updating. Unless :param:`force` is True, then
the plugin must update the cache. The only time force should be True is if
this function is called by the plugin's configuration dialog.
if :param:`suppress_progress` is False it is safe to assume that this function
is being called from the main GUI thread so it is safe and recommended to use
a QProgressDialog to display what is happening and allow the user to cancel
the operation. if :param:`suppress_progress` is True then run the update
silently. In this case there is no guarantee what thread is calling this
function so no Qt related functionality that requires being run in the main
GUI thread should be run. E.G. Open a QProgressDialog.
:param parent: The parent object to be used by an GUI dialogs.
:param timeout: The maximum amount of time that should be spent in
any given network connection.
:param force: Force updating the cache even if the plugin has determined
it is not necessary.
:param suppress_progress: Should a progress indicator be shown.
:return: True if the cache was updated, False otherwise.
'''
return False
def do_genesis(self):
self.genesis()
def genesis(self):
'''
Plugin specific initialization.
'''
pass
def config_widget(self):
'''
See :class:`calibre.customize.Plugin` for details.
'''
raise NotImplementedError()
def save_settings(self, config_widget):
'''
See :class:`calibre.customize.Plugin` for details.
'''
raise NotImplementedError()
def customization_help(self, gui=False):
'''
See :class:`calibre.customize.Plugin` for details.
'''
raise NotImplementedError()
# }}}