This commit is contained in:
Kovid Goyal 2009-03-29 18:26:44 -07:00
parent b9d9df5f20
commit b98ada75f7
7 changed files with 187 additions and 141 deletions

View File

@ -1,6 +1,6 @@
from __future__ import with_statement from __future__ import with_statement
''' '''
Defines the plugin sytem for conversions. Defines the plugin system for conversions.
''' '''
import re, os, shutil import re, os, shutil
@ -236,6 +236,6 @@ class OutputFormatPlugin(Plugin):
#: (option_name, recommended_value, recommendation_level) #: (option_name, recommended_value, recommendation_level)
recommendations = set([]) recommendations = set([])
def convert(self, oeb_book, input_plugin, options, parse_cache, log): def convert(self, oeb_book, input_plugin, options, context, log):
raise NotImplementedError raise NotImplementedError

View File

@ -13,6 +13,11 @@ class OptionValues(object):
pass pass
class Plumber(object): class Plumber(object):
'''
The `Plumber` manages the conversion pipeline. An UI should call the methods
:method:`merge_ui_recommendations` and then :method:`run`. The plumber will
take care of the rest.
'''
metadata_option_names = [ metadata_option_names = [
'title', 'authors', 'title_sort', 'author_sort', 'cover', 'comments', 'title', 'authors', 'title_sort', 'author_sort', 'cover', 'comments',
@ -21,10 +26,17 @@ class Plumber(object):
] ]
def __init__(self, input, output, log): def __init__(self, input, output, log):
'''
:param input: Path to input file.
:param output: Path to output file/directory
'''
self.input = input self.input = input
self.output = output self.output = output
self.log = log self.log = log
# Initialize the conversion options that are independent of input and
# output formats. The input and output plugins can still disable these
# options via recommendations.
self.pipeline_options = [ self.pipeline_options = [
OptionRecommendation(name='verbose', OptionRecommendation(name='verbose',
@ -143,11 +155,15 @@ OptionRecommendation(name='language',
self.input_fmt = input_fmt self.input_fmt = input_fmt
self.output_fmt = output_fmt self.output_fmt = output_fmt
# Build set of all possible options. Two options are equal iff their
# names are the same.
self.input_options = self.input_plugin.options.union( self.input_options = self.input_plugin.options.union(
self.input_plugin.common_options) self.input_plugin.common_options)
self.output_options = self.output_plugin.options.union( self.output_options = self.output_plugin.options.union(
self.output_plugin.common_options) self.output_plugin.common_options)
# Remove the options that have been disabled by recommendations from the
# plugins.
self.merge_plugin_recommendations() self.merge_plugin_recommendations()
def get_option_by_name(self, name): def get_option_by_name(self, name):
@ -165,12 +181,21 @@ OptionRecommendation(name='language',
rec.recommended_value = val rec.recommended_value = val
def merge_ui_recommendations(self, recommendations): def merge_ui_recommendations(self, recommendations):
'''
Merge recommendations from the UI. As long as the UI recommendation
level is >= the baseline recommended level, the UI value is used,
*except* if the baseline has a recommendation level of `HIGH`.
'''
for name, val, level in recommendations: for name, val, level in recommendations:
rec = self.get_option_by_name(name) rec = self.get_option_by_name(name)
if rec is not None and rec.level <= level and rec.level < rec.HIGH: if rec is not None and rec.level <= level and rec.level < rec.HIGH:
rec.recommended_value = val rec.recommended_value = val
def read_user_metadata(self): def read_user_metadata(self):
'''
Read all metadata specified by the user. Command line options override
metadata from a specified OPF file.
'''
from calibre.ebooks.metadata import MetaInformation, string_to_authors from calibre.ebooks.metadata import MetaInformation, string_to_authors
from calibre.ebooks.metadata.opf2 import OPF from calibre.ebooks.metadata.opf2 import OPF
mi = MetaInformation(None, []) mi = MetaInformation(None, [])
@ -197,6 +222,9 @@ OptionRecommendation(name='language',
def setup_options(self): def setup_options(self):
'''
Setup the `self.opts` object.
'''
self.opts = OptionValues() self.opts = OptionValues()
for group in (self.input_options, self.pipeline_options, for group in (self.input_options, self.pipeline_options,
self.output_options): self.output_options):
@ -216,10 +244,18 @@ OptionRecommendation(name='language',
self.read_user_metadata() self.read_user_metadata()
def run(self): def run(self):
'''
Run the conversion pipeline
'''
# Setup baseline option values
self.setup_options() self.setup_options()
# Run any preprocess plugins
from calibre.customize.ui import run_plugins_on_preprocess from calibre.customize.ui import run_plugins_on_preprocess
self.input = run_plugins_on_preprocess(self.input) self.input = run_plugins_on_preprocess(self.input)
# Create an OEBBook from the input file. The input plugin does all the
# heavy lifting.
from calibre.ebooks.oeb.reader import OEBReader from calibre.ebooks.oeb.reader import OEBReader
from calibre.ebooks.oeb.base import OEBBook from calibre.ebooks.oeb.base import OEBBook
parse_cache, accelerators = {}, {} parse_cache, accelerators = {}, {}
@ -230,6 +266,7 @@ OptionRecommendation(name='language',
self.reader = OEBReader() self.reader = OEBReader()
self.oeb = OEBBook(self.log, parse_cache=parse_cache) self.oeb = OEBBook(self.log, parse_cache=parse_cache)
# Read OEB Book into OEBBook
self.reader(self.oeb, opfpath) self.reader(self.oeb, opfpath)

View File

@ -1260,7 +1260,7 @@ class OEBBook(object):
"""Create empty book. Optional arguments: """Create empty book. Optional arguments:
:param parse_cache: A cache of parsed XHTML/CSS. Keys are absolute :param parse_cache: A cache of parsed XHTML/CSS. Keys are absolute
paths to te cached files and values are lxml root objects and paths to the cached files and values are lxml root objects and
cssutils stylesheets. cssutils stylesheets.
:param:`encoding`: Default encoding for textual content read :param:`encoding`: Default encoding for textual content read
from an external container. from an external container.

View File

@ -12,6 +12,6 @@ class OEBOutput(OutputFormatPlugin):
file_type = 'oeb' file_type = 'oeb'
def convert(self, oeb_book, input_plugin, options, parse_cache, log): def convert(self, oeb_book, input_plugin, options, context, log):
pass pass

View File

@ -0,0 +1,10 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
from __future__ import with_statement
__license__ = 'GPL v3'
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'

View File

@ -24,7 +24,6 @@ class ManifestTrimmer(object):
def __call__(self, oeb, context): def __call__(self, oeb, context):
oeb.logger.info('Trimming unused files from manifest...') oeb.logger.info('Trimming unused files from manifest...')
used = set() used = set()
hrefs = oeb.manifest.hrefs
for term in oeb.metadata: for term in oeb.metadata:
for item in oeb.metadata[term]: for item in oeb.metadata[term]:
if item.value in oeb.manifest.hrefs: if item.value in oeb.manifest.hrefs: