Added support for metadata reading/writing plugins

This commit is contained in:
Kovid Goyal 2008-12-24 09:48:25 -08:00
parent 5769ce558c
commit 21e5196614
6 changed files with 282 additions and 67 deletions

View File

@ -5,6 +5,7 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
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
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

View File

@ -2,8 +2,8 @@ from __future__ import with_statement
__license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
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]
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')]

View File

@ -4,9 +4,11 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
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()

View File

@ -5,30 +5,10 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
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)

View File

@ -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

View File

@ -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)