diff --git a/src/calibre/customize/__init__.py b/src/calibre/customize/__init__.py index ca8aba6031..a09a764703 100644 --- a/src/calibre/customize/__init__.py +++ b/src/calibre/customize/__init__.py @@ -5,6 +5,7 @@ __copyright__ = '2008, Kovid Goyal ' import sys from calibre.ptempfile import PersistentTemporaryFile +from calibre.constants import __version__, __author__ class Plugin(object): ''' @@ -127,7 +128,7 @@ class FileTypePlugin(Plugin): A plugin that is associated with a particular set of file types. ''' - #: List of file types for which this plugin should be run + #: Set of file types for which this plugin should be run #: For example: ``set(['lit', 'mobi', 'prc'])`` file_types = set([]) @@ -162,4 +163,57 @@ class FileTypePlugin(Plugin): :return: Absolute path to the modified ebook. ''' # Default implementation does nothing - return path_to_ebook \ No newline at end of file + return path_to_ebook + +class MetadataReaderPlugin(Plugin): + ''' + A plugin that implements reading metadata from a set of file types. + ''' + #: Set of file types for which this plugin should be run + #: For example: ``set(['lit', 'mobi', 'prc'])`` + file_types = set([]) + + supported_platforms = ['windows', 'osx', 'linux'] + version = tuple(map(int, (__version__.split('.'))[:3])) + author = 'Kovid Goyal' + + type = _('Metadata reader') + + def get_metadata(self, stream, type): + ''' + Return metadata for the file represented by stream (a file like object + that supports reading). Raise an exception when there is an error + with the input data. + + :param type: The type of file. Guaranteed to be one of the entries + in :member:`file_types`. + :return: A :class:`calibre.ebooks.metadata.MetaInformation` object + ''' + return None + +class MetadataWriterPlugin(Plugin): + ''' + A plugin that implements reading metadata from a set of file types. + ''' + #: Set of file types for which this plugin should be run + #: For example: ``set(['lit', 'mobi', 'prc'])`` + file_types = set([]) + + supported_platforms = ['windows', 'osx', 'linux'] + version = tuple(map(int, (__version__.split('.'))[:3])) + author = 'Kovid Goyal' + + type = _('Metadata writer') + + def set_metadata(self, stream, mi, type): + ''' + Set metadata for the file represented by stream (a file like object + that supports reading). Raise an exception when there is an error + with the input data. + + :param type: The type of file. Guaranteed to be one of the entries + in :member:`file_types`. + :param mi: A :class:`calibre.ebooks.metadata.MetaInformation` object + ''' + pass + \ No newline at end of file diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py index 324d70119d..28be488dce 100644 --- a/src/calibre/customize/builtins.py +++ b/src/calibre/customize/builtins.py @@ -2,8 +2,8 @@ from __future__ import with_statement __license__ = 'GPL v3' __copyright__ = '2008, Kovid Goyal ' -import textwrap -from calibre.customize import FileTypePlugin +import textwrap, os +from calibre.customize import FileTypePlugin, MetadataReaderPlugin, MetadataWriterPlugin from calibre.constants import __version__ class HTML2ZIP(FileTypePlugin): @@ -15,7 +15,7 @@ file containing all linked files. This plugin is run \ every time you add an HTML file to the library.\ ''')) version = tuple(map(int, (__version__.split('.'))[:3])) - file_types = ['html', 'htm', 'xhtml', 'xhtm'] + file_types = set(['html', 'htm', 'xhtml', 'xhtm']) supported_platforms = ['windows', 'osx', 'linux'] on_import = True @@ -24,6 +24,182 @@ every time you add an HTML file to the library.\ from calibre.ebooks.html import gui_main as html2oeb html2oeb(htmlfile, of) return of.name - + +class RTFMetadataReader(MetadataReaderPlugin): -plugins = [HTML2ZIP] \ No newline at end of file + name = 'Read RTF metadata' + file_types = set(['rtf']) + description = _('Read metadata from %s files')%'RTF' + + def get_metadata(self, stream, ftype): + from calibre.ebooks.metadata.rtf import get_metadata + return get_metadata(stream) + +class FB2MetadataReader(MetadataReaderPlugin): + + name = 'Read FB2 metadata' + file_types = set(['fb2']) + description = _('Read metadata from %s files')%'FB2' + + def get_metadata(self, stream, ftype): + from calibre.ebooks.metadata.fb2 import get_metadata + return get_metadata(stream) + + +class LRFMetadataReader(MetadataReaderPlugin): + + name = 'Read LRF metadata' + file_types = set(['lrf']) + description = _('Read metadata from %s files')%'LRF' + + def get_metadata(self, stream, ftype): + from calibre.ebooks.lrf.meta import get_metadata + return get_metadata(stream) + +class PDFMetadataReader(MetadataReaderPlugin): + + name = 'Read PDF metadata' + file_types = set(['pdf']) + description = _('Read metadata from %s files')%'PDF' + + def get_metadata(self, stream, ftype): + from calibre.ebooks.metadata.pdf import get_metadata + return get_metadata(stream) + +class LITMetadataReader(MetadataReaderPlugin): + + name = 'Read LIT metadata' + file_types = set(['lit']) + description = _('Read metadata from %s files')%'LIT' + + def get_metadata(self, stream, ftype): + from calibre.ebooks.metadata.lit import get_metadata + return get_metadata(stream) + +class IMPMetadataReader(MetadataReaderPlugin): + + name = 'Read IMP metadata' + file_types = set(['imp']) + description = _('Read metadata from %s files')%'IMP' + author = 'Ashish Kulkarni' + + def get_metadata(self, stream, ftype): + from calibre.ebooks.metadata.imp import get_metadata + return get_metadata(stream) + +class RBMetadataReader(MetadataReaderPlugin): + + name = 'Read RB metadata' + file_types = set(['rb']) + description = _('Read metadata from %s files')%'RB' + author = 'Ashish Kulkarni' + + def get_metadata(self, stream, ftype): + from calibre.ebooks.metadata.rb import get_metadata + return get_metadata(stream) + +class EPUBMetadataReader(MetadataReaderPlugin): + + name = 'Read EPUB metadata' + file_types = set(['epub']) + description = _('Read metadata from %s files')%'EPUB' + + def get_metadata(self, stream, ftype): + from calibre.ebooks.metadata.epub import get_metadata + return get_metadata(stream) + +class HTMLMetadataReader(MetadataReaderPlugin): + + name = 'Read HTML metadata' + file_types = set(['html']) + description = _('Read metadata from %s files')%'HTML' + + def get_metadata(self, stream, ftype): + from calibre.ebooks.metadata.html import get_metadata + return get_metadata(stream) + +class MOBIMetadataReader(MetadataReaderPlugin): + + name = 'Read MOBI metadata' + file_types = set(['mobi']) + description = _('Read metadata from %s files')%'MOBI' + + def get_metadata(self, stream, ftype): + from calibre.ebooks.mobi.reader import get_metadata + return get_metadata(stream) + +class ODTMetadataReader(MetadataReaderPlugin): + + name = 'Read ODT metadata' + file_types = set(['odt']) + description = _('Read metadata from %s files')%'ODT' + + def get_metadata(self, stream, ftype): + from calibre.ebooks.metadata.odt import get_metadata + return get_metadata(stream) + +class LRXMetadataReader(MetadataReaderPlugin): + + name = 'Read LRX metadata' + file_types = set(['lrx']) + description = _('Read metadata from %s files')%'LRX' + + def get_metadata(self, stream, ftype): + from calibre.ebooks.metadata.lrx import get_metadata + return get_metadata(stream) + +class ComicMetadataReader(MetadataReaderPlugin): + + name = 'Read comic metadata' + file_types = set(['cbr', 'cbz']) + description = _('Extract cover from comic files') + + def get_metadata(self, stream, ftype): + if ftype == 'cbr': + from calibre.libunrar import extract_member as extract_first + else: + from calibre.libunzip import extract_member as extract_first + from calibre.ebooks.metadata import MetaInformation + ret = extract_first(stream) + mi = MetaInformation(None, None) + if ret is not None: + path, data = ret + ext = os.path.splitext(path)[1][1:] + mi.cover_data = (ext.lower(), data) + return mi + +class EPUBMetadataWriter(MetadataWriterPlugin): + + name = 'Set EPUB metadata' + file_types = set(['epub']) + description = _('Set metadata in EPUB files') + + def set_metadata(self, stream, mi, type): + from calibre.ebooks.metadata.epub import set_metadata + set_metadata(stream, mi) + +class LRFMetadataWriter(MetadataWriterPlugin): + + name = 'Set LRF metadata' + file_types = set(['lrf']) + description = _('Set metadata in LRF files') + + def set_metadata(self, stream, mi, type): + from calibre.ebooks.lrf.meta import set_metadata + set_metadata(stream, mi) + +class RTFMetadataWriter(MetadataWriterPlugin): + + name = 'Set RTF metadata' + file_types = set(['rtf']) + description = _('Set metadata in RTF files') + + def set_metadata(self, stream, mi, type): + from calibre.ebooks.metadata.rtf import set_metadata + set_metadata(stream, mi) + +plugins = [HTML2ZIP] +plugins += [x for x in list(locals().values()) if isinstance(x, type) and \ + x.__name__.endswith('MetadataReader')] +plugins += [x for x in list(locals().values()) if isinstance(x, type) and \ + x.__name__.endswith('MetadataWriter')] \ No newline at end of file diff --git a/src/calibre/customize/ui.py b/src/calibre/customize/ui.py index 031d24aecb..a9f24b9447 100644 --- a/src/calibre/customize/ui.py +++ b/src/calibre/customize/ui.py @@ -4,9 +4,11 @@ __copyright__ = '2008, Kovid Goyal ' import os, shutil, traceback, functools, sys -from calibre.customize import Plugin, FileTypePlugin +from calibre.customize import Plugin, FileTypePlugin, MetadataReaderPlugin, \ + MetadataWriterPlugin from calibre.customize.builtins import plugins as builtin_plugins from calibre.constants import __version__, iswindows, isosx +from calibre.ebooks.metadata import MetaInformation from calibre.utils.config import make_config_dir, Config, ConfigProxy, \ plugin_dir, OptionParser @@ -90,7 +92,38 @@ def reread_filetype_plugins(): if not _on_postprocess.has_key(ft): _on_postprocess[ft] = [] _on_postprocess[ft].append(plugin) - + +_metadata_readers = {} +_metadata_writers = {} +def reread_metadata_plugins(): + global _metadata_readers + global _metadata_writers + _metadata_readers = {} + for plugin in _initialized_plugins: + if isinstance(plugin, MetadataReaderPlugin): + for ft in plugin.file_types: + _metadata_readers[ft] = plugin + elif isinstance(plugin, MetadataWriterPlugin): + for ft in plugin.file_types: + _metadata_writers[ft] = plugin + +def get_file_type_metadata(stream, ftype): + mi = MetaInformation(None, None) + try: + plugin = _metadata_readers[ftype.lower().strip()] + if not is_disabled(plugin): + mi = plugin.get_metadata(stream, ftype.lower().strip()) + except: + pass + return mi + +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()) + except: + traceback.print_exc() def _run_filetype_plugins(path_to_file, ft=None, occasion='preprocess'): occasion = {'import':_on_import, 'preprocess':_on_preprocess, @@ -184,6 +217,7 @@ def initialize_plugins(): traceback.print_exc() _initialized_plugins.sort(cmp=lambda x,y:cmp(x.priority, y.priority), reverse=True) reread_filetype_plugins() + reread_metadata_plugins() initialize_plugins() diff --git a/src/calibre/ebooks/metadata/meta.py b/src/calibre/ebooks/metadata/meta.py index 3264655f9c..3c5f07d271 100644 --- a/src/calibre/ebooks/metadata/meta.py +++ b/src/calibre/ebooks/metadata/meta.py @@ -5,30 +5,10 @@ __copyright__ = '2008, Kovid Goyal ' import os, re, collections from calibre.utils.config import prefs -from calibre.ebooks.metadata.rtf import get_metadata as rtf_metadata -from calibre.ebooks.metadata.fb2 import get_metadata as fb2_metadata -from calibre.ebooks.lrf.meta import get_metadata as lrf_metadata -from calibre.ebooks.metadata.pdf import get_metadata as pdf_metadata -from calibre.ebooks.metadata.lit import get_metadata as lit_metadata -from calibre.ebooks.metadata.imp import get_metadata as imp_metadata -from calibre.ebooks.metadata.rb import get_metadata as rb_metadata -from calibre.ebooks.metadata.epub import get_metadata as epub_metadata -from calibre.ebooks.metadata.html import get_metadata as html_metadata -from calibre.ebooks.mobi.reader import get_metadata as mobi_metadata -from calibre.ebooks.metadata.odt import get_metadata as odt_metadata -from calibre.ebooks.metadata.lrx import get_metadata as lrx_metadata + from calibre.ebooks.metadata.opf2 import OPF -from calibre.ebooks.metadata.rtf import set_metadata as set_rtf_metadata -from calibre.ebooks.lrf.meta import set_metadata as set_lrf_metadata -from calibre.ebooks.metadata.epub import set_metadata as set_epub_metadata -from calibre.ebooks.metadata.pdf import set_metadata as set_pdf_metadata -try: - from calibre.libunrar import extract_member as rar_extract_first -except OSError: - rar_extract_first = None - -from calibre.libunzip import extract_member as zip_extract_first +from calibre.customize.ui import get_file_type_metadata, set_file_type_metadata from calibre.ebooks.metadata import MetaInformation _METADATA_PRIORITIES = [ @@ -88,11 +68,7 @@ def get_metadata(stream, stream_type='lrf', use_libprs_metadata=False): mi = MetaInformation(None, None) if prefs['read_file_metadata']: - try: - func = eval(stream_type + '_metadata') - mi = func(stream) - except NameError: - pass + mi = get_file_type_metadata(stream, stream_type) name = os.path.basename(getattr(stream, 'name', '')) base = metadata_from_filename(name) @@ -104,37 +80,14 @@ def get_metadata(stream, stream_type='lrf', use_libprs_metadata=False): if opf is not None: base.smart_update(opf) - if stream_type in ('cbr', 'cbz'): - try: - cdata = get_comic_cover(stream, stream_type) - if cdata is not None: - base.cover_data = cdata - except: - import traceback - traceback.print_exc() - pass - return base -def get_comic_cover(stream, type): - extract_first = zip_extract_first if type.lower() == 'cbz' else rar_extract_first - ret = extract_first(stream) - if ret is not None: - path, data = ret - ext = os.path.splitext(path)[1][1:] - return (ext.lower(), data) - def set_metadata(stream, mi, stream_type='lrf'): - if stream_type: stream_type = stream_type.lower() - if stream_type == 'lrf': - set_lrf_metadata(stream, mi) - elif stream_type == 'epub': - set_epub_metadata(stream, mi) - elif stream_type == 'rtf': - set_rtf_metadata(stream, mi) - #elif stream_type == 'pdf': - # set_pdf_metadata(stream, mi) - + if stream_type: + stream_type = stream_type.lower() + set_file_type_metadata(stream, mi, stream_type) + + def metadata_from_filename(name, pat=None): name = os.path.splitext(name)[0] mi = MetaInformation(None, None) diff --git a/src/calibre/gui2/dialogs/config.py b/src/calibre/gui2/dialogs/config.py index 69579bd377..4b8cafd647 100644 --- a/src/calibre/gui2/dialogs/config.py +++ b/src/calibre/gui2/dialogs/config.py @@ -103,7 +103,7 @@ class PluginModel(QAbstractItemModel): if role == Qt.DisplayRole: ver = '.'.join(map(str, plugin.version)) desc = '\n'.join(textwrap.wrap(plugin.description, 50)) - ans='%s (%s) by %s\n%s'%(plugin.name, ver, plugin.author, desc) + ans='%s (%s) %s %s\n%s'%(plugin.name, ver, _('by'), plugin.author, desc) c = plugin_customization(plugin) if c: ans += '\nCustomization: '+c diff --git a/src/calibre/gui2/main.py b/src/calibre/gui2/main.py index e6b23d8157..f87b827a82 100644 --- a/src/calibre/gui2/main.py +++ b/src/calibre/gui2/main.py @@ -698,8 +698,6 @@ class Main(MainWindow, Ui_MainWindow): if d.exec_() == QDialog.Accepted: num = model.add_books(*duplicates, **dict(add_duplicates=True))[1] number_added += num - #self.library_view.sortByColumn(3, Qt.DescendingOrder) - #model.research() model.books_added(number_added) else: self.upload_books(paths, list(map(sanitize_file_name, names)), infos, on_card=on_card)