Sync to pluginize

This commit is contained in:
John Schember 2009-04-11 22:23:35 -04:00
commit 00f24eaf5d
5 changed files with 93 additions and 63 deletions

View File

@ -30,7 +30,7 @@ def _config():
c.add_opt('filetype_mapping', default={}, help=_('Mapping for filetype plugins')) c.add_opt('filetype_mapping', default={}, help=_('Mapping for filetype plugins'))
c.add_opt('plugin_customization', default={}, help=_('Local plugin customization')) c.add_opt('plugin_customization', default={}, help=_('Local plugin customization'))
c.add_opt('disabled_plugins', default=set([]), help=_('Disabled plugins')) c.add_opt('disabled_plugins', default=set([]), help=_('Disabled plugins'))
return ConfigProxy(c) return ConfigProxy(c)
config = _config() config = _config()
@ -45,7 +45,7 @@ class PluginNotFound(ValueError):
def load_plugin(path_to_zip_file): def load_plugin(path_to_zip_file):
''' '''
Load plugin from zip file or raise InvalidPlugin error Load plugin from zip file or raise InvalidPlugin error
:return: A :class:`Plugin` instance. :return: A :class:`Plugin` instance.
''' '''
print 'Loading plugin from', path_to_zip_file print 'Loading plugin from', path_to_zip_file
@ -61,9 +61,9 @@ def load_plugin(path_to_zip_file):
if x.minimum_calibre_version > version or \ if x.minimum_calibre_version > version or \
platform not in x.supported_platforms: platform not in x.supported_platforms:
continue continue
return x return x
raise InvalidPlugin(_('No valid plugin found in ')+path_to_zip_file) raise InvalidPlugin(_('No valid plugin found in ')+path_to_zip_file)
_initialized_plugins = [] _initialized_plugins = []
@ -122,8 +122,8 @@ def reread_metadata_plugins():
for ft in plugin.file_types: for ft in plugin.file_types:
if not _metadata_writers.has_key(ft): if not _metadata_writers.has_key(ft):
_metadata_writers[ft] = [] _metadata_writers[ft] = []
_metadata_writers[ft].append(plugin) _metadata_writers[ft].append(plugin)
def metadata_readers(): def metadata_readers():
ans = set([]) ans = set([])
for plugins in _metadata_readers.values(): for plugins in _metadata_readers.values():
@ -136,8 +136,8 @@ def metadata_writers():
for plugins in _metadata_writers.values(): for plugins in _metadata_writers.values():
for plugin in plugins: for plugin in plugins:
ans.add(plugin) ans.add(plugin)
return ans return ans
def get_file_type_metadata(stream, ftype): def get_file_type_metadata(stream, ftype):
mi = MetaInformation(None, None) mi = MetaInformation(None, None)
ftype = ftype.lower().strip() ftype = ftype.lower().strip()
@ -163,21 +163,21 @@ def set_file_type_metadata(stream, mi, ftype):
plugin.set_metadata(stream, mi, ftype.lower().strip()) plugin.set_metadata(stream, mi, ftype.lower().strip())
break break
except: except:
print 'Failed to set metadata for', repr(getattr(mi, 'title', '')) print 'Failed to set metadata for', repr(getattr(mi, 'title', ''))
traceback.print_exc() traceback.print_exc()
def _run_filetype_plugins(path_to_file, ft=None, occasion='preprocess'): def _run_filetype_plugins(path_to_file, ft=None, occasion='preprocess'):
occasion = {'import':_on_import, 'preprocess':_on_preprocess, occasion = {'import':_on_import, 'preprocess':_on_preprocess,
'postprocess':_on_postprocess}[occasion] 'postprocess':_on_postprocess}[occasion]
customization = config['plugin_customization'] customization = config['plugin_customization']
if ft is None: if ft is None:
ft = os.path.splitext(path_to_file)[-1].lower().replace('.', '') ft = os.path.splitext(path_to_file)[-1].lower().replace('.', '')
nfp = path_to_file nfp = path_to_file
for plugin in occasion.get(ft, []): for plugin in occasion.get(ft, []):
if is_disabled(plugin): if is_disabled(plugin):
continue continue
plugin.site_customization = customization.get(plugin.name, '') plugin.site_customization = customization.get(plugin.name, '')
with plugin: with plugin:
try: try:
nfp = plugin.run(path_to_file) nfp = plugin.run(path_to_file)
@ -190,13 +190,13 @@ def _run_filetype_plugins(path_to_file, ft=None, occasion='preprocess'):
nfp = path_to_file nfp = path_to_file
return nfp return nfp
run_plugins_on_import = functools.partial(_run_filetype_plugins, run_plugins_on_import = functools.partial(_run_filetype_plugins,
occasion='import') occasion='import')
run_plugins_on_preprocess = functools.partial(_run_filetype_plugins, run_plugins_on_preprocess = functools.partial(_run_filetype_plugins,
occasion='preprocess') occasion='preprocess')
run_plugins_on_postprocess = functools.partial(_run_filetype_plugins, run_plugins_on_postprocess = functools.partial(_run_filetype_plugins,
occasion='postprocess') occasion='postprocess')
def initialize_plugin(plugin, path_to_zip_file): def initialize_plugin(plugin, path_to_zip_file):
try: try:
@ -206,7 +206,7 @@ def initialize_plugin(plugin, path_to_zip_file):
tb = traceback.format_exc() tb = traceback.format_exc()
raise InvalidPlugin((_('Initialization of plugin %s failed with traceback:') raise InvalidPlugin((_('Initialization of plugin %s failed with traceback:')
%tb) + '\n'+tb) %tb) + '\n'+tb)
def add_plugin(path_to_zip_file): def add_plugin(path_to_zip_file):
make_config_dir() make_config_dir()
@ -248,18 +248,18 @@ def input_format_plugins():
for plugin in _initialized_plugins: for plugin in _initialized_plugins:
if isinstance(plugin, InputFormatPlugin): if isinstance(plugin, InputFormatPlugin):
yield plugin yield plugin
def plugin_for_input_format(fmt): def plugin_for_input_format(fmt):
for plugin in input_format_plugins(): for plugin in input_format_plugins():
if fmt.lower() in plugin.file_types: if fmt.lower() in plugin.file_types:
return plugin return plugin
def available_input_formats(): def available_input_formats():
formats = [] formats = set([])
for plugin in input_format_plugins(): for plugin in input_format_plugins():
if not is_disabled(plugin): if not is_disabled(plugin):
for format in plugin.file_types: for format in plugin.file_types:
formats.append(format) formats.add(format)
return formats return formats
def output_format_plugins(): def output_format_plugins():
@ -273,10 +273,10 @@ def plugin_for_output_format(fmt):
return plugin return plugin
def available_output_formats(): def available_output_formats():
formats = [] formats = set([])
for plugin in output_format_plugins(): for plugin in output_format_plugins():
if not is_disabled(plugin): if not is_disabled(plugin):
formats.append(plugin.file_type) formats.add(plugin.file_type)
return formats return formats
def disable_plugin(plugin_or_name): def disable_plugin(plugin_or_name):
@ -309,21 +309,21 @@ def initialize_plugins():
except: except:
print 'Failed to initialize plugin...' print 'Failed to initialize plugin...'
traceback.print_exc() traceback.print_exc()
_initialized_plugins.sort(cmp=lambda x,y:cmp(x.priority, y.priority), reverse=True) _initialized_plugins.sort(cmp=lambda x,y:cmp(x.priority, y.priority), reverse=True)
reread_filetype_plugins() reread_filetype_plugins()
reread_metadata_plugins() reread_metadata_plugins()
initialize_plugins() initialize_plugins()
def option_parser(): def option_parser():
parser = OptionParser(usage=_('''\ parser = OptionParser(usage=_('''\
%prog options %prog options
Customize calibre by loading external plugins. Customize calibre by loading external plugins.
''')) '''))
parser.add_option('-a', '--add-plugin', default=None, parser.add_option('-a', '--add-plugin', default=None,
help=_('Add a plugin by specifying the path to the zip file containing it.')) help=_('Add a plugin by specifying the path to the zip file containing it.'))
parser.add_option('-r', '--remove-plugin', default=None, parser.add_option('-r', '--remove-plugin', default=None,
help=_('Remove a custom plugin by name. Has no effect on builtin plugins')) help=_('Remove a custom plugin by name. Has no effect on builtin plugins'))
parser.add_option('--customize-plugin', default=None, parser.add_option('--customize-plugin', default=None,
help=_('Customize plugin. Specify name of plugin and customization string separated by a comma.')) help=_('Customize plugin. Specify name of plugin and customization string separated by a comma.'))
@ -377,16 +377,16 @@ def main(args=sys.argv):
print print
for plugin in initialized_plugins(): for plugin in initialized_plugins():
print fmt%( print fmt%(
plugin.type, plugin.name, plugin.type, plugin.name,
plugin.version, is_disabled(plugin), plugin.version, is_disabled(plugin),
plugin_customization(plugin) plugin_customization(plugin)
) )
print '\t', plugin.description print '\t', plugin.description
if plugin.is_customizable(): if plugin.is_customizable():
print '\t', plugin.customization_help() print '\t', plugin.customization_help()
print print
return 0 return 0
if __name__ == '__main__': if __name__ == '__main__':
sys.exit(main()) sys.exit(main())

View File

@ -179,10 +179,13 @@ OptionRecommendation(name='language',
raise ValueError('Input file must have an extension') raise ValueError('Input file must have an extension')
input_fmt = input_fmt[1:].lower() input_fmt = input_fmt[1:].lower()
output_fmt = os.path.splitext(output)[1] if os.path.exists(output) and os.path.isdir(output):
if not output_fmt: output_fmt = 'oeb'
output_fmt = '.oeb' else:
output_fmt = output_fmt[1:].lower() output_fmt = os.path.splitext(output)[1]
if not output_fmt:
output_fmt = '.oeb'
output_fmt = output_fmt[1:].lower()
self.input_plugin = plugin_for_input_format(input_fmt) self.input_plugin = plugin_for_input_format(input_fmt)
self.output_plugin = plugin_for_output_format(output_fmt) self.output_plugin = plugin_for_output_format(output_fmt)

View File

@ -5,20 +5,20 @@ __copyright__ = '2008 Kovid Goyal <kovid at kovidgoyal.net>'
Iterate over the HTML files in an ebook. Useful for writing viewers. Iterate over the HTML files in an ebook. Useful for writing viewers.
''' '''
import re, os, math, copy import re, os, math
from cStringIO import StringIO from cStringIO import StringIO
from PyQt4.Qt import QFontDatabase from PyQt4.Qt import QFontDatabase
from calibre.ebooks.epub.from_any import MAP from calibre.customize.ui import available_input_formats
from calibre.ebooks.epub.from_html import TITLEPAGE from calibre.ebooks.epub.from_html import TITLEPAGE
from calibre.ebooks.epub import config from calibre.ebooks.metadata.opf2 import OPF, OPFCreator
from calibre.ebooks.metadata.opf2 import OPF
from calibre.ptempfile import TemporaryDirectory from calibre.ptempfile import TemporaryDirectory
from calibre.ebooks.chardet import xml_to_unicode from calibre.ebooks.chardet import xml_to_unicode
from calibre.ebooks.html_old import create_dir
from calibre.utils.zipfile import safe_replace, ZipFile from calibre.utils.zipfile import safe_replace, ZipFile
from calibre.utils.config import DynamicConfig from calibre.utils.config import DynamicConfig
from calibre.utils.logging import Log
from calibre import CurrentDir
def character_count(html): def character_count(html):
''' '''
@ -50,11 +50,28 @@ class SpineItem(unicode):
obj.max_page = -1 obj.max_page = -1
return obj return obj
def html2opf(path, tdir, opts): class FakeOpts(object):
opts = copy.copy(opts) verbose = 0
opts.output = tdir breadth_first = False
create_dir(path, opts) max_levels = 5
return os.path.join(tdir, 'metadata.opf') input_encoding = None
def html2opf(path, tdir, log):
from calibre.ebooks.html.input import get_filelist
from calibre.ebooks.metadata.meta import get_metadata
with CurrentDir(tdir):
fl = get_filelist(path, tdir, FakeOpts(), log)
mi = get_metadata(open(path, 'rb'), 'html')
mi = OPFCreator(os.getcwdu(), mi)
mi.guide = None
entries = [(f.path, 'application/xhtml+xml') for f in fl]
mi.create_manifest(entries)
mi.create_spine([f.path for f in fl])
mi.render(open('metadata.opf', 'wb'))
opfpath = os.path.abspath('metadata.opf')
return opfpath
def opf2opf(path, tdir, opts): def opf2opf(path, tdir, opts):
return path return path
@ -62,24 +79,22 @@ def opf2opf(path, tdir, opts):
def is_supported(path): def is_supported(path):
ext = os.path.splitext(path)[1].replace('.', '').lower() ext = os.path.splitext(path)[1].replace('.', '').lower()
ext = re.sub(r'(x{0,1})htm(l{0,1})', 'html', ext) ext = re.sub(r'(x{0,1})htm(l{0,1})', 'html', ext)
return ext in list(MAP.keys())+['html', 'opf'] return ext in available_input_formats()
class EbookIterator(object): class EbookIterator(object):
CHARACTERS_PER_PAGE = 1000 CHARACTERS_PER_PAGE = 1000
def __init__(self, pathtoebook): def __init__(self, pathtoebook, log=None):
self.log = log
if log is None:
self.log = Log()
pathtoebook = pathtoebook.strip() pathtoebook = pathtoebook.strip()
self.pathtoebook = os.path.abspath(pathtoebook) self.pathtoebook = os.path.abspath(pathtoebook)
self.config = DynamicConfig(name='iterator') self.config = DynamicConfig(name='iterator')
ext = os.path.splitext(pathtoebook)[1].replace('.', '').lower() ext = os.path.splitext(pathtoebook)[1].replace('.', '').lower()
ext = re.sub(r'(x{0,1})htm(l{0,1})', 'html', ext) ext = re.sub(r'(x{0,1})htm(l{0,1})', 'html', ext)
map = dict(MAP) self.ebook_ext = ext
map['html'] = html2opf
map['opf'] = opf2opf
if ext not in map.keys():
raise UnsupportedFormatError(ext)
self.to_opf = map[ext]
def search(self, text, index): def search(self, text, index):
text = text.lower() text = text.lower()
@ -115,14 +130,24 @@ class EbookIterator(object):
def __enter__(self): def __enter__(self):
self._tdir = TemporaryDirectory('_ebook_iter') self._tdir = TemporaryDirectory('_ebook_iter')
self.base = self._tdir.__enter__() self.base = self._tdir.__enter__()
opts = config('').parse() if self.ebook_ext == 'opf':
self.pathtoopf = self.to_opf(self.pathtoebook, self.base, opts) self.pathtoopf = self.pathtoebook
elif self.ebook_ext == 'html':
self.pathtoopf = html2opf(self.pathtoebook, self.base, self.log)
else:
from calibre.ebooks.conversion.plumber import Plumber
plumber = Plumber(self.pathtoebook, self.base, self.log)
plumber.setup_options()
self.pathtoopf = plumber.input_plugin(open(plumber.input, 'rb'),
plumber.opts, plumber.input_fmt, self.log,
{}, self.base)
self.opf = OPF(self.pathtoopf, os.path.dirname(self.pathtoopf)) self.opf = OPF(self.pathtoopf, os.path.dirname(self.pathtoopf))
self.spine = [SpineItem(i.path) for i in self.opf.spine] self.spine = [SpineItem(i.path) for i in self.opf.spine]
cover = self.opf.cover cover = self.opf.cover
if os.path.splitext(self.pathtoebook)[1].lower() in \ if self.ebook_ext in ('lit', 'mobi', 'prc', 'opf') and cover:
('.lit', '.mobi', '.prc') and cover:
cfile = os.path.join(os.path.dirname(self.spine[0]), 'calibre_ei_cover.html') cfile = os.path.join(os.path.dirname(self.spine[0]), 'calibre_ei_cover.html')
open(cfile, 'wb').write(TITLEPAGE%cover) open(cfile, 'wb').write(TITLEPAGE%cover)
self.spine[0:0] = [SpineItem(cfile)] self.spine[0:0] = [SpineItem(cfile)]
@ -131,7 +156,6 @@ class EbookIterator(object):
self.opf.path_to_html_toc not in self.spine: self.opf.path_to_html_toc not in self.spine:
self.spine.append(SpineItem(self.opf.path_to_html_toc)) self.spine.append(SpineItem(self.opf.path_to_html_toc))
sizes = [i.character_count for i in self.spine] sizes = [i.character_count for i in self.spine]
self.pages = [math.ceil(i/float(self.CHARACTERS_PER_PAGE)) for i in sizes] self.pages = [math.ceil(i/float(self.CHARACTERS_PER_PAGE)) for i in sizes]
for p, s in zip(self.pages, self.spine): for p, s in zip(self.pages, self.spine):

View File

@ -17,14 +17,14 @@ from calibre.gui2.viewer.bookmarkmanager import BookmarkManager
from calibre.gui2.main_window import MainWindow from calibre.gui2.main_window import MainWindow
from calibre.gui2 import Application, ORG_NAME, APP_UID, choose_files, \ from calibre.gui2 import Application, ORG_NAME, APP_UID, choose_files, \
info_dialog, error_dialog info_dialog, error_dialog
from calibre.ebooks.epub.iterator import EbookIterator from calibre.ebooks.oeb.iterator import EbookIterator
from calibre.ebooks.epub.from_any import SOURCE_FORMATS
from calibre.ebooks import DRMError from calibre.ebooks import DRMError
from calibre.gui2.dialogs.conversion_error import ConversionErrorDialog from calibre.gui2.dialogs.conversion_error import ConversionErrorDialog
from calibre.constants import islinux from calibre.constants import islinux
from calibre.utils.config import Config, StringConfig from calibre.utils.config import Config, StringConfig
from calibre.gui2.library import SearchBox from calibre.gui2.library import SearchBox
from calibre.ebooks.metadata import MetaInformation from calibre.ebooks.metadata import MetaInformation
from calibre.customize.ui import available_input_formats
class TOCItem(QStandardItem): class TOCItem(QStandardItem):
@ -362,7 +362,8 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
def open_ebook(self, checked): def open_ebook(self, checked):
files = choose_files(self, 'ebook viewer open dialog', files = choose_files(self, 'ebook viewer open dialog',
_('Choose ebook'), _('Choose ebook'),
[(_('Ebooks'), SOURCE_FORMATS)], all_files=False, [(_('Ebooks'), available_input_formats())],
all_files=False,
select_only_single_file=True) select_only_single_file=True)
if files: if files:
self.load_ebook(files[0]) self.load_ebook(files[0])

View File

@ -445,6 +445,8 @@ class BasicNewsRecipe(object):
:param progress_reporter: A Callable that takes two arguments: progress (a number between 0 and 1) and a string message. The message should be optional. :param progress_reporter: A Callable that takes two arguments: progress (a number between 0 and 1) and a string message. The message should be optional.
''' '''
self.log = Log() self.log = Log()
if options.verbose:
self.log.filter_level = self.log.DEBUG
if not isinstance(self.title, unicode): if not isinstance(self.title, unicode):
self.title = unicode(self.title, 'utf-8', 'replace') self.title = unicode(self.title, 'utf-8', 'replace')