diff --git a/src/calibre/customize/__init__.py b/src/calibre/customize/__init__.py index 91623ea94e..bbd1c61d38 100644 --- a/src/calibre/customize/__init__.py +++ b/src/calibre/customize/__init__.py @@ -179,8 +179,7 @@ class Plugin(object): # {{{ help_text = self.customization_help(gui=True) help_text = QLabel(help_text, config_dialog) help_text.setWordWrap(True) - help_text.setTextInteractionFlags(Qt.LinksAccessibleByMouse - | Qt.LinksAccessibleByKeyboard) + help_text.setTextInteractionFlags(Qt.LinksAccessibleByMouse | Qt.LinksAccessibleByKeyboard) help_text.setOpenExternalLinks(True) v.addWidget(help_text) sc = plugin_customization(self) @@ -369,6 +368,21 @@ class FileTypePlugin(Plugin): # {{{ ''' pass # Default implementation does nothing + def postadd(self, book_id, fmt_map, db): + ''' + Called post add, i.e. after a book has been added to the db. Note that + this is different from :meth:`postimport`, which is called after a single book file + has been added to a book. postadd() is called only when an entire book record + with possibly more than one book file has been created for the first time. + This is useful if you wish to modify the book record in the database when the + book is first added to calibre. + + :param book_id: Database id of the added book. + :param fmt_map: Map of file format to path from which the file format was added + :param db: Library database + ''' + pass # Default implementation does nothing + # }}} class MetadataReaderPlugin(Plugin): # {{{ diff --git a/src/calibre/customize/ui.py b/src/calibre/customize/ui.py index 77da5f7a23..8f3b874f31 100644 --- a/src/calibre/customize/ui.py +++ b/src/calibre/customize/ui.py @@ -3,6 +3,7 @@ __license__ = 'GPL v3' __copyright__ = '2008, Kovid Goyal ' import os, shutil, traceback, functools, sys +from collections import defaultdict from calibre.customize import (CatalogPlugin, FileTypePlugin, PluginNotFound, MetadataReaderPlugin, MetadataWriterPlugin, @@ -44,7 +45,7 @@ def find_plugin(name): return plugin -def load_plugin(path_to_zip_file): # {{{ +def load_plugin(path_to_zip_file): # {{{ ''' Load plugin from zip file or raise InvalidPlugin error @@ -95,7 +96,8 @@ default_disabled_plugins = set([ ]) def is_disabled(plugin): - if plugin.name in config['enabled_plugins']: return False + if plugin.name in config['enabled_plugins']: + return False return plugin.name in config['disabled_plugins'] or \ plugin.name in default_disabled_plugins # }}} @@ -106,35 +108,30 @@ _on_import = {} _on_postimport = {} _on_preprocess = {} _on_postprocess = {} +_on_postadd = [] def reread_filetype_plugins(): global _on_import global _on_postimport global _on_preprocess global _on_postprocess - _on_import = {} - _on_postimport = {} - _on_preprocess = {} - _on_postprocess = {} + _on_import = defaultdict(list) + _on_postimport = defaultdict(list) + _on_preprocess = defaultdict(list) + _on_postprocess = defaultdict(list) + _on_postadd = [] for plugin in _initialized_plugins: if isinstance(plugin, FileTypePlugin): for ft in plugin.file_types: if plugin.on_import: - if not _on_import.has_key(ft): - _on_import[ft] = [] _on_import[ft].append(plugin) if plugin.on_postimport: - if not _on_postimport.has_key(ft): - _on_postimport[ft] = [] _on_postimport[ft].append(plugin) + _on_postadd.append(plugin) if plugin.on_preprocess: - if not _on_preprocess.has_key(ft): - _on_preprocess[ft] = [] _on_preprocess[ft].append(plugin) if plugin.on_postprocess: - if not _on_postprocess.has_key(ft): - _on_postprocess[ft] = [] _on_postprocess[ft].append(plugin) @@ -187,6 +184,20 @@ def run_plugins_on_postimport(db, book_id, fmt): plugin.name) traceback.print_exc() +def run_plugins_on_postadd(db, book_id, fmt_map): + customization = config['plugin_customization'] + for plugin in _on_postadd: + if is_disabled(plugin): + continue + plugin.site_customization = customization.get(plugin.name, '') + with plugin: + try: + plugin.postadd(book_id, fmt_map, db) + except Exception: + print ('Running file type plugin %s failed with traceback:'% + plugin.name) + traceback.print_exc() + # }}} # Plugin customization {{{ @@ -268,17 +279,14 @@ _metadata_writers = {} def reread_metadata_plugins(): global _metadata_readers global _metadata_writers - _metadata_readers = {} + _metadata_readers = defaultdict(list) + _metadata_writers = defaultdict(list) for plugin in _initialized_plugins: if isinstance(plugin, MetadataReaderPlugin): for ft in plugin.file_types: - if not _metadata_readers.has_key(ft): - _metadata_readers[ft] = [] _metadata_readers[ft].append(plugin) elif isinstance(plugin, MetadataWriterPlugin): for ft in plugin.file_types: - if not _metadata_writers.has_key(ft): - _metadata_writers[ft] = [] _metadata_writers[ft].append(plugin) def metadata_readers(): @@ -338,7 +346,7 @@ def get_file_type_metadata(stream, ftype): mi = MetaInformation(None, None) ftype = ftype.lower().strip() - if _metadata_readers.has_key(ftype): + if ftype in _metadata_readers: for plugin in _metadata_readers[ftype]: if not is_disabled(plugin): with plugin: @@ -355,7 +363,7 @@ def get_file_type_metadata(stream, ftype): def set_file_type_metadata(stream, mi, ftype, report_error=None): ftype = ftype.lower().strip() - if _metadata_writers.has_key(ftype): + if ftype in _metadata_writers: for plugin in _metadata_writers[ftype]: if not is_disabled(plugin): with plugin: @@ -708,4 +716,3 @@ def main(args=sys.argv): if __name__ == '__main__': sys.exit(main()) # }}} - diff --git a/src/calibre/db/cache.py b/src/calibre/db/cache.py index 0ebada3f02..00f7aedcab 100644 --- a/src/calibre/db/cache.py +++ b/src/calibre/db/cache.py @@ -15,7 +15,7 @@ from future_builtins import zip from calibre import isbytestring, as_unicode from calibre.constants import iswindows, preferred_encoding -from calibre.customize.ui import run_plugins_on_import, run_plugins_on_postimport +from calibre.customize.ui import run_plugins_on_import, run_plugins_on_postimport, run_plugins_on_postadd from calibre.db import SPOOL_SIZE, _get_next_series_num_for_list from calibre.db.categories import get_categories from calibre.db.locking import create_locks, DowngradeLockError, SafeReadLock @@ -1544,6 +1544,7 @@ class Cache(object): as per the simple duplicate detection heuristic used by :meth:`has_book`. ''' duplicates, ids = [], [] + fmt_map = {} for mi, format_map in books: book_id = self.create_book_entry(mi, add_duplicates=add_duplicates, apply_import_tags=apply_import_tags, preserve_uuid=preserve_uuid) if book_id is None: @@ -1551,7 +1552,9 @@ class Cache(object): else: ids.append(book_id) for fmt, stream_or_path in format_map.iteritems(): - self.add_format(book_id, fmt, stream_or_path, dbapi=dbapi, run_hooks=run_hooks) + if self.add_format(book_id, fmt, stream_or_path, dbapi=dbapi, run_hooks=run_hooks): + fmt_map[fmt.lower()] = getattr(stream_or_path, 'name', stream_or_path) or '' + run_plugins_on_postadd(dbapi or self, book_id, fmt_map) return ids, duplicates @write_api diff --git a/src/calibre/gui2/add.py b/src/calibre/gui2/add.py index 7399007914..9aa8a0c138 100644 --- a/src/calibre/gui2/add.py +++ b/src/calibre/gui2/add.py @@ -16,7 +16,7 @@ from PyQt5.Qt import QObject, Qt, pyqtSignal from calibre import prints, as_unicode from calibre.constants import DEBUG -from calibre.customize.ui import run_plugins_on_postimport +from calibre.customize.ui import run_plugins_on_postimport, run_plugins_on_postadd from calibre.db.adding import find_books_in_directory from calibre.db.utils import find_identical_books from calibre.ebooks.metadata.book.base import Metadata @@ -375,7 +375,7 @@ class Adder(QObject): [a('\t' + f) for f in paths] a(_('With error:')), a(traceback.format_exc()) return - self.add_formats(book_id, paths, mi) + self.add_formats(book_id, paths, mi, is_an_add=True) try: if self.add_formats_to_existing: self.db.update_data_for_find_identical_books(book_id, self.find_identical_books_data) @@ -388,8 +388,9 @@ class Adder(QObject): if DEBUG: prints('Added', mi.title, 'to db in: %.1f' % (time.time() - st)) - def add_formats(self, book_id, paths, mi, replace=True): + def add_formats(self, book_id, paths, mi, replace=True, is_an_add=False): fmap = {p.rpartition(os.path.extsep)[-1].lower():p for p in paths} + fmt_map = {} for fmt, path in fmap.iteritems(): # The onimport plugins have already been run by the read metadata # worker @@ -398,11 +399,14 @@ class Adder(QObject): try: if self.db.add_format(book_id, fmt, path, run_hooks=False, replace=replace): run_plugins_on_postimport(self.dbref(), book_id, fmt) + fmt_map[fmt.lower()] = path except Exception: a = self.report.append a(''), a('-' * 70) a(_('Failed to add the file {0} to the book: {1}').format(path, mi.title)) a(_('With error:')), a(traceback.format_exc()) + if is_an_add: + run_plugins_on_postadd(self.dbref(), book_id, fmt_map) def process_duplicates(self): if self.duplicates: