GR Catalog Plugin implementation

This commit is contained in:
GRiker 2010-01-13 07:15:52 -07:00
parent 2673542326
commit 00b4b1194a
3 changed files with 191 additions and 4 deletions

View File

@ -48,7 +48,7 @@ class Plugin(object):
#: the plugins are run in order of decreasing priority #: the plugins are run in order of decreasing priority
#: i.e. plugins with higher priority will be run first. #: i.e. plugins with higher priority will be run first.
#: The highest possible priority is ``sys.maxint``. #: The highest possible priority is ``sys.maxint``.
#: Default pririty is 1. #: Default priority is 1.
priority = 1 priority = 1
#: The earliest version of calibre this plugin requires #: The earliest version of calibre this plugin requires
@ -226,4 +226,55 @@ class MetadataWriterPlugin(Plugin):
''' '''
pass pass
class CatalogPlugin(Plugin):
'''
A plugin that implements a catalog generator.
'''
#: Output file type for which this plugin should be run
#: For example: 'epub' or 'xml'
file_types = set([])
type = _('Catalog generator')
#: CLI parser options specific to this plugin, declared as namedtuple Option
#:
#: from collections import namedtuple
#: Option = namedtuple('Option', 'option, default, dest, help')
#: cli_options = [Option('--catalog-title',
#: default = 'My Catalog',
#: dest = 'catalog_title',
#: help = (_('Title of generated catalog. \nDefault:') + " '" +
#: '%default' + "'"))]
cli_options = []
def run(self, path_to_output, opts, log):
'''
Run the plugin. Must be implemented in subclasses.
It should generate the catalog in the format specified
in file_types, returning the absolute path to the
generated catalog file. If an error is encountered
it should raise an Exception and return None. The default
implementation simply returns None.
The generated catalog file should be created with the
:meth:`temporary_file` method.
:param path_to_output: Absolute path to the generated catalog file.
:param opts: A dictionary of keyword arguments
:return: Absolute path to the modified ebook.
Access the opts object as a dictionary with this code:
opts_dict = vars(opts)
keys = opts_dict.keys()
keys.sort()
print "opts:"
for key in keys:
print "\t%s: %s" % (key, opts_dict[key])
'''
# Default implementation does nothing
print "CatalogPlugin.generate_catalog() default method, should be overridden in subclass"
return None

View File

@ -5,8 +5,8 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
import os, shutil, traceback, functools, sys, re import os, shutil, traceback, functools, sys, re
from contextlib import closing from contextlib import closing
from calibre.customize import Plugin, FileTypePlugin, MetadataReaderPlugin, \ from calibre.customize import Plugin, CatalogPlugin, FileTypePlugin, \
MetadataWriterPlugin MetadataReaderPlugin, MetadataWriterPlugin
from calibre.customize.conversion import InputFormatPlugin, OutputFormatPlugin from calibre.customize.conversion import InputFormatPlugin, OutputFormatPlugin
from calibre.customize.profiles import InputProfile, OutputProfile from calibre.customize.profiles import InputProfile, OutputProfile
from calibre.customize.builtins import plugins as builtin_plugins from calibre.customize.builtins import plugins as builtin_plugins
@ -300,6 +300,7 @@ def find_plugin(name):
if plugin.name == name: if plugin.name == name:
return plugin return plugin
def input_format_plugins(): def input_format_plugins():
for plugin in _initialized_plugins: for plugin in _initialized_plugins:
if isinstance(plugin, InputFormatPlugin): if isinstance(plugin, InputFormatPlugin):
@ -328,6 +329,7 @@ def available_input_formats():
formats.add('zip'), formats.add('rar') formats.add('zip'), formats.add('rar')
return formats return formats
def output_format_plugins(): def output_format_plugins():
for plugin in _initialized_plugins: for plugin in _initialized_plugins:
if isinstance(plugin, OutputFormatPlugin): if isinstance(plugin, OutputFormatPlugin):
@ -347,6 +349,27 @@ def available_output_formats():
formats.add(plugin.file_type) formats.add(plugin.file_type)
return formats return formats
def catalog_plugins():
for plugin in _initialized_plugins:
if isinstance(plugin, CatalogPlugin):
yield plugin
def available_catalog_formats():
formats = set([])
for plugin in catalog_plugins():
if not is_disabled(plugin):
for format in plugin.file_types:
formats.add(format)
return formats
def plugin_for_catalog_format(fmt):
for plugin in catalog_plugins():
if fmt.lower() in plugin.file_types:
return plugin
else:
return None
def device_plugins(): def device_plugins():
for plugin in _initialized_plugins: for plugin in _initialized_plugins:
if isinstance(plugin, DevicePlugin): if isinstance(plugin, DevicePlugin):

View File

@ -583,8 +583,121 @@ def command_export(args, dbpath):
do_export(get_db(dbpath, opts), ids, dir, opts) do_export(get_db(dbpath, opts), ids, dir, opts)
return 0 return 0
# GR additions
def catalog_option_parser(args):
from calibre.customize.ui import available_catalog_formats, plugin_for_catalog_format
from calibre.utils.logging import Log
def add_plugin_parser_options(fmt, parser, log):
# Fetch the extension-specific CLI options from the plugin
plugin = plugin_for_catalog_format(fmt)
for option in plugin.cli_options:
parser.add_option(option.option,
default=option.default,
dest=option.dest,
help=option.help)
# print_help(parser, log)
return plugin
def print_help(parser, log):
help = parser.format_help().encode(preferred_encoding, 'replace')
log(help)
def validate_command_line(parser, args, log):
# calibredb catalog path/to/destination.[epub|csv|xml|...] [options]
# Validate form
if not len(args) or args[0].startswith('-'):
print_help(parser, log)
log.error("\n\nYou must specify a catalog output file of the form 'path/to/destination.extension'\n"
"To review options for an output format, type 'calibredb catalog <.extension> --help'\n"
"For example, 'calibredb catalog .xml --help'\n")
raise SystemExit(1)
# Validate plugin exists for specified output format
output = os.path.abspath(args[0])
file_extension = output[output.rfind('.') + 1:]
if not file_extension in available_catalog_formats():
print_help(parser, log)
log.error("No catalog plugin available for extension '%s'.\n" % file_extension +
"Catalog plugins available for %s\n" % ', '.join(available_catalog_formats()) )
raise SystemExit(1)
return output, file_extension
# Entry point
log = Log()
parser = get_parser(_(
'''
%prog catalog /path/to/destination.(epub|csv|xml|...) [options]
Export a catalog in format specified by path/to/destination extension.
Options control how entries are displayed in the generated catalog ouput.
'''))
# Confirm that a plugin handler exists for specified output file extension
# Will raise SystemExit(1) if no plugin matching file_extension
output, fmt = validate_command_line(parser, args, log)
# Add options common to all catalog plugins
parser.add_option('-s', '--search', default=None, dest='search_text',
help=_("Filter the results by the search query. For the format of the search query, please see the search-related documentation in the User Manual.\n"+
"Default: no filtering"))
parser.add_option('-v','--verbose', default=False, action='store_true',
dest='verbose',
help=_('Show detailed output information. Useful for debugging'))
# Add options specific to fmt plugin
plugin = add_plugin_parser_options(fmt, parser, log)
# Merge options from GUI Preferences
'''
from calibre.library.save_to_disk import config
c = config()
for pref in ['asciiize', 'update_metadata', 'write_opf', 'save_cover']:
opt = c.get_option(pref)
switch = '--dont-'+pref.replace('_', '-')
parser.add_option(switch, default=True, action='store_false',
help=opt.help+' '+_('Specifying this switch will turn '
'this behavior off.'), dest=pref)
for pref in ['timefmt', 'template', 'formats']:
opt = c.get_option(pref)
switch = '--'+pref
parser.add_option(switch, default=opt.default,
help=opt.help, dest=pref)
for pref in ('replace_whitespace', 'to_lowercase'):
opt = c.get_option(pref)
switch = '--'+pref.replace('_', '-')
parser.add_option(switch, default=False, action='store_true',
help=opt.help)
'''
return parser, plugin, log
def command_catalog(args, dbpath):
parser, plugin, log = catalog_option_parser(args)
opts, args = parser.parse_args(sys.argv[1:])
if len(args) < 2:
parser.print_help()
print
print >>sys.stderr, _('Error: You must specify a catalog output file')
return 1
if opts.verbose:
log("library.cli:command_catalog dispatching to plugin %s" % plugin.name)
plugin.run(args[1], opts)
return 0
# end of GR additions
COMMANDS = ('list', 'add', 'remove', 'add_format', 'remove_format', COMMANDS = ('list', 'add', 'remove', 'add_format', 'remove_format',
'show_metadata', 'set_metadata', 'export') 'show_metadata', 'set_metadata', 'export', 'catalog')
def option_parser(): def option_parser():