diff --git a/src/calibre/customize/__init__.py b/src/calibre/customize/__init__.py index 0863226e05..8a72ac0c35 100644 --- a/src/calibre/customize/__init__.py +++ b/src/calibre/customize/__init__.py @@ -334,6 +334,16 @@ class FileTypePlugin(Plugin): # {{{ #: methods of the plugin are called. on_postimport = False + #: If True, this plugin is run after a book file is added + #: to the database. In this case the postconvert method of + #: the plugin is called. + on_postconvert = False + + #: If True, this plugin is run after a book file is deleted + #: from the database. In this case the postdelete method of + #: the plugin is called. + on_postdelete = False + #: If True, this plugin is run just before a conversion on_preprocess = False @@ -378,6 +388,28 @@ class FileTypePlugin(Plugin): # {{{ ''' pass # Default implementation does nothing + def postconvert(self, book_id, book_format, db): + ''' + Called post conversion, i.e., after the book file has been added to the database. It is + useful for modifying the book record based on the contents of the newly added file. + + :param book_id: Database id of the added book. + :param book_format: The file type of the book that was added. + :param db: Library database. + ''' + pass # Default implementation does nothing + + def postdelete(self, book_id, book_format, db): + ''' + Called post deletion, i.e., after the book file has been deleted from the database. It is + useful for modifying the book record based on the format of the deleted file. + + :param book_id: Database id of the added book. + :param book_format: The file type of the book that was added. + :param db: Library database. + ''' + 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 diff --git a/src/calibre/customize/ui.py b/src/calibre/customize/ui.py index 3d77efd9d2..c4f6d1995b 100644 --- a/src/calibre/customize/ui.py +++ b/src/calibre/customize/ui.py @@ -122,15 +122,19 @@ def is_disabled(plugin): _on_import = {} _on_postimport = {} +_on_postconvert = {} +_on_postdelete = {} _on_preprocess = {} _on_postprocess = {} _on_postadd = [] def reread_filetype_plugins(): - global _on_import, _on_postimport, _on_preprocess, _on_postprocess, _on_postadd + global _on_import, _on_postimport, _on_postconvert, _on_postdelete, _on_preprocess, _on_postprocess, _on_postadd _on_import = defaultdict(list) _on_postimport = defaultdict(list) + _on_postconvert = defaultdict(list) + _on_postdelete = defaultdict(list) _on_preprocess = defaultdict(list) _on_postprocess = defaultdict(list) _on_postadd = [] @@ -146,6 +150,10 @@ def reread_filetype_plugins(): if plugin.on_postimport: _on_postimport[ft].append(plugin) _on_postadd.append(plugin) + if plugin.on_postconvert: + _on_postconvert[ft].append(plugin) + if plugin.on_postdelete: + _on_postdelete[ft].append(plugin) if plugin.on_preprocess: _on_preprocess[ft].append(plugin) if plugin.on_postprocess: @@ -155,6 +163,7 @@ def reread_filetype_plugins(): def plugins_for_ft(ft, occasion): op = { 'import':_on_import, 'preprocess':_on_preprocess, 'postprocess':_on_postprocess, 'postimport':_on_postimport, + 'postconvert':_on_postconvert, 'postdelete':_on_postdelete, }[occasion] for p in chain(op.get(ft, ()), op.get('*', ())): if not is_disabled(p): @@ -207,6 +216,34 @@ def run_plugins_on_postimport(db, book_id, fmt): traceback.print_exc() +def run_plugins_on_postconvert(db, book_id, fmt): + customization = config['plugin_customization'] + fmt = fmt.lower() + for plugin in plugins_for_ft(fmt, 'postconvert'): + plugin.site_customization = customization.get(plugin.name, '') + with plugin: + try: + plugin.postconvert(book_id, fmt, db) + except: + print('Running file type plugin %s failed with traceback:'% + plugin.name) + traceback.print_exc() + + +def run_plugins_on_postdelete(db, book_id, fmt): + customization = config['plugin_customization'] + fmt = fmt.lower() + for plugin in plugins_for_ft(fmt, 'postdelete'): + plugin.site_customization = customization.get(plugin.name, '') + with plugin: + try: + plugin.postdelete(book_id, fmt, db) + except: + print('Running file type plugin %s failed with traceback:'% + plugin.name) + traceback.print_exc() + + def run_plugins_on_postadd(db, book_id, fmt_map): customization = config['plugin_customization'] for plugin in _on_postadd: diff --git a/src/calibre/db/cache.py b/src/calibre/db/cache.py index 17a7676a7e..a91a99930c 100644 --- a/src/calibre/db/cache.py +++ b/src/calibre/db/cache.py @@ -24,7 +24,7 @@ from time import monotonic, sleep, time from calibre import as_unicode, detect_ncpus, isbytestring from calibre.constants import iswindows, preferred_encoding from calibre.customize.ui import ( - run_plugins_on_import, run_plugins_on_postadd, run_plugins_on_postimport, + run_plugins_on_import, run_plugins_on_postadd, run_plugins_on_postimport, run_plugins_on_postdelete, ) from calibre.db import SPOOL_SIZE, _get_next_series_num_for_list from calibre.db.annotations import merge_annotations @@ -1865,6 +1865,10 @@ class Cache: size_map = table.remove_formats(formats_map, self.backend) self.fields['size'].table.update_sizes(size_map) + + for book_id, fmts in iteritems(formats_map): + run_plugins_on_postdelete(self, book_id, fmt) + self._update_last_modified(tuple(formats_map)) self.event_dispatcher(EventType.formats_removed, formats_map) diff --git a/src/calibre/gui2/actions/convert.py b/src/calibre/gui2/actions/convert.py index 0cfd8c39b1..bedd359ea5 100644 --- a/src/calibre/gui2/actions/convert.py +++ b/src/calibre/gui2/actions/convert.py @@ -9,7 +9,7 @@ import os from functools import partial from qt.core import QModelIndex, QTimer -from calibre.customize.ui import plugin_for_input_format +from calibre.customize.ui import plugin_for_input_format, run_plugins_on_postconvert from calibre.gui2 import Dispatcher, error_dialog, gprefs from calibre.gui2.actions import InterfaceAction from calibre.gui2.tools import convert_bulk_ebook, convert_single_ebook @@ -274,6 +274,7 @@ class ConvertAction(InterfaceAction): with open(temp_files[-1].name, 'rb') as data: db.add_format(book_id, fmt, data, index_is_id=True) + run_plugins_on_postconvert(db, book_id, fmt) self.gui.book_converted.emit(book_id, fmt) self.gui.status_bar.show_message(job.description + ' ' + _('completed'), 2000)