From 90daad4321e8263d87dc0fd6ea118bdcd43d5e5d Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 30 Apr 2012 14:50:50 +0530 Subject: [PATCH] Add azw3 output plugin (thin wrapper around the standalone kf8 mobi output code) --- src/calibre/customize/builtins.py | 5 +- .../ebooks/conversion/plugins/mobi_output.py | 121 +++++++++++++---- src/calibre/ebooks/mobi/writer2/resources.py | 6 +- src/calibre/gui2/convert/azw3_output.py | 33 +++++ src/calibre/gui2/convert/azw3_output.ui | 125 ++++++++++++++++++ 5 files changed, 258 insertions(+), 32 deletions(-) create mode 100644 src/calibre/gui2/convert/azw3_output.py create mode 100644 src/calibre/gui2/convert/azw3_output.ui diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py index e64bba428d..f77b1d3528 100644 --- a/src/calibre/customize/builtins.py +++ b/src/calibre/customize/builtins.py @@ -539,7 +539,8 @@ from calibre.ebooks.conversion.plugins.epub_output import EPUBOutput from calibre.ebooks.conversion.plugins.fb2_output import FB2Output from calibre.ebooks.conversion.plugins.lit_output import LITOutput from calibre.ebooks.conversion.plugins.lrf_output import LRFOutput -from calibre.ebooks.conversion.plugins.mobi_output import MOBIOutput +from calibre.ebooks.conversion.plugins.mobi_output import (MOBIOutput, + AZW3Output) from calibre.ebooks.conversion.plugins.oeb_output import OEBOutput from calibre.ebooks.conversion.plugins.pdb_output import PDBOutput from calibre.ebooks.conversion.plugins.pdf_output import PDFOutput @@ -580,7 +581,7 @@ plugins += [ FB2Output, LITOutput, LRFOutput, - MOBIOutput, + MOBIOutput, AZW3Output, OEBOutput, PDBOutput, PDFOutput, diff --git a/src/calibre/ebooks/conversion/plugins/mobi_output.py b/src/calibre/ebooks/conversion/plugins/mobi_output.py index e759df5b78..38678f0c41 100644 --- a/src/calibre/ebooks/conversion/plugins/mobi_output.py +++ b/src/calibre/ebooks/conversion/plugins/mobi_output.py @@ -6,8 +6,32 @@ __license__ = 'GPL v3' __copyright__ = '2009, Kovid Goyal ' __docformat__ = 'restructuredtext en' -from calibre.customize.conversion import OutputFormatPlugin -from calibre.customize.conversion import OptionRecommendation +from calibre.customize.conversion import (OutputFormatPlugin, + OptionRecommendation) + +def remove_html_cover(oeb, log): + from calibre.ebooks.oeb.base import OEB_DOCS + + if not oeb.metadata.cover \ + or 'cover' not in oeb.guide: + return + href = oeb.guide['cover'].href + del oeb.guide['cover'] + item = oeb.manifest.hrefs[href] + if item.spine_position is not None: + log.warn('Found an HTML cover: ', item.href, 'removing it.', + 'If you find some content missing from the output MOBI, it ' + 'is because you misidentified the HTML cover in the input ' + 'document') + oeb.spine.remove(item) + if item.media_type in OEB_DOCS: + oeb.manifest.remove(item) + +def extract_mobi(output_path, opts): + if opts.extract_to is not None: + from calibre.ebooks.mobi.debug.main import inspect_mobi + ddir = opts.extract_to + inspect_mobi(output_path, ddir=ddir) class MOBIOutput(OutputFormatPlugin): @@ -140,25 +164,6 @@ class MOBIOutput(OutputFormatPlugin): # Fix up the periodical href to point to first section href toc.nodes[0].href = toc.nodes[0].nodes[0].href - def remove_html_cover(self): - from calibre.ebooks.oeb.base import OEB_DOCS - - oeb = self.oeb - if not oeb.metadata.cover \ - or 'cover' not in oeb.guide: - return - href = oeb.guide['cover'].href - del oeb.guide['cover'] - item = oeb.manifest.hrefs[href] - if item.spine_position is not None: - self.log.warn('Found an HTML cover: ', item.href, 'removing it.', - 'If you find some content missing from the output MOBI, it ' - 'is because you misidentified the HTML cover in the input ' - 'document') - oeb.spine.remove(item) - if item.media_type in OEB_DOCS: - self.oeb.manifest.remove(item) - def convert(self, oeb, output_path, input_plugin, opts, log): from calibre.utils.config import tweaks from calibre.ebooks.mobi.writer2.resources import Resources @@ -169,7 +174,7 @@ class MOBIOutput(OutputFormatPlugin): mobi_type = 'old' # Amazon does not support KF8 periodicals create_kf8 = mobi_type in ('new', 'both') - self.remove_html_cover() + remove_html_cover(self.oeb, self.log) resources = Resources(oeb, opts, self.is_periodical, add_fonts=create_kf8) self.check_for_periodical() @@ -185,7 +190,7 @@ class MOBIOutput(OutputFormatPlugin): ) if create_kf8 else None if mobi_type == 'new': kf8.write(output_path) - self.extract_mobi(output_path, opts) + extract_mobi(output_path, opts) return self.log('Creating MOBI 6 output') @@ -225,11 +230,69 @@ class MOBIOutput(OutputFormatPlugin): writer = MobiWriter(opts, resources, kf8, write_page_breaks_after_item=write_page_breaks_after_item) writer(oeb, output_path) - self.extract_mobi(output_path, opts) + extract_mobi(output_path, opts) + +class AZW3Output(OutputFormatPlugin): + + name = 'AZW3 Output' + author = 'Kovid Goyal' + file_type = 'azw3' + + options = set([ + OptionRecommendation(name='prefer_author_sort', + recommended_value=False, level=OptionRecommendation.LOW, + help=_('When present, use author sort field as author.') + ), + OptionRecommendation(name='no_inline_toc', + recommended_value=False, level=OptionRecommendation.LOW, + help=_('Don\'t add Table of Contents to the book. Useful if ' + 'the book has its own table of contents.')), + OptionRecommendation(name='toc_title', recommended_value=None, + help=_('Title for any generated in-line table of contents.') + ), + OptionRecommendation(name='dont_compress', + recommended_value=False, level=OptionRecommendation.LOW, + help=_('Disable compression of the file contents.') + ), + OptionRecommendation(name='personal_doc', recommended_value='[PDOC]', + help=_('Tag marking book to be filed with Personal Docs') + ), + OptionRecommendation(name='mobi_toc_at_start', + recommended_value=False, + help=_('When adding the Table of Contents to the book, add it at the start of the ' + 'book instead of the end. Not recommended.') + ), + OptionRecommendation(name='extract_to', recommended_value=None, + help=_('Extract the contents of the MOBI file to the' + ' specified directory. If the directory already ' + 'exists, it will be deleted.') + ), + OptionRecommendation(name='share_not_sync', recommended_value=False, + help=_('Enable sharing of book content via Facebook etc. ' + ' on the Kindle. WARNING: Using this feature means that ' + ' the book will not auto sync its last read position ' + ' on multiple devices. Complain to Amazon.') + ), + ]) + + def convert(self, oeb, output_path, input_plugin, opts, log): + from calibre.ebooks.mobi.writer2.resources import Resources + from calibre.ebooks.mobi.writer8.main import create_kf8_book + + self.oeb, self.opts, self.log = oeb, opts, log + + resources = Resources(self.oeb, self.opts, self.is_periodical, + add_fonts=True, process_images=False) + remove_html_cover(self.oeb, self.log) + + # Split on pagebreaks so that the resulting KF8 works better with + # calibre's viewer, which does not support CSS page breaks + from calibre.ebooks.oeb.transforms.split import Split + Split()(self.oeb, self.opts) + + kf8 = create_kf8_book(self.oeb, self.opts, resources, for_joint=False) + + kf8.write(output_path) + extract_mobi(output_path, opts) - def extract_mobi(self, output_path, opts): - if opts.extract_to is not None: - from calibre.ebooks.mobi.debug.main import inspect_mobi - ddir = opts.extract_to - inspect_mobi(output_path, ddir=ddir) diff --git a/src/calibre/ebooks/mobi/writer2/resources.py b/src/calibre/ebooks/mobi/writer2/resources.py index 2fcb93790c..273e1e044f 100644 --- a/src/calibre/ebooks/mobi/writer2/resources.py +++ b/src/calibre/ebooks/mobi/writer2/resources.py @@ -19,9 +19,11 @@ PLACEHOLDER_GIF = b'GIF89a\x01\x00\x01\x00\x80\x00\x00\x00\x00\x00\xff\xff\xff!\ class Resources(object): - def __init__(self, oeb, opts, is_periodical, add_fonts=False): + def __init__(self, oeb, opts, is_periodical, add_fonts=False, + process_images=True): self.oeb, self.log, self.opts = oeb, oeb.log, opts self.is_periodical = is_periodical + self.process_images = True self.item_map = {} self.records = [] @@ -34,6 +36,8 @@ class Resources(object): self.add_resources(add_fonts) def process_image(self, data): + if not self.process_images: + return data return (mobify_image(data) if self.opts.mobi_keep_original_images else rescale_image(data)) diff --git a/src/calibre/gui2/convert/azw3_output.py b/src/calibre/gui2/convert/azw3_output.py new file mode 100644 index 0000000000..8b1ef25aac --- /dev/null +++ b/src/calibre/gui2/convert/azw3_output.py @@ -0,0 +1,33 @@ +#!/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 ' +__docformat__ = 'restructuredtext en' + + +from calibre.gui2.convert.azw3_output_ui import Ui_Form +from calibre.gui2.convert import Widget + +font_family_model = None + +class PluginWidget(Widget, Ui_Form): + + TITLE = _('AZW3 Output') + HELP = _('Options specific to')+' AZW3 '+_('output') + COMMIT_NAME = 'azw3_output' + ICON = I('mimetypes/mobi.png') + + def __init__(self, parent, get_option, get_help, db=None, book_id=None): + Widget.__init__(self, parent, + ['prefer_author_sort', 'toc_title', + 'mobi_ignore_margins', 'mobi_toc_at_start', + 'dont_compress', 'no_inline_toc', 'share_not_sync', + 'personal_doc']#, 'mobi_navpoints_only_deepest'] + ) + self.db, self.book_id = db, book_id + + self.initialize_options(get_option, get_help, db, book_id) + + diff --git a/src/calibre/gui2/convert/azw3_output.ui b/src/calibre/gui2/convert/azw3_output.ui new file mode 100644 index 0000000000..657a38861d --- /dev/null +++ b/src/calibre/gui2/convert/azw3_output.ui @@ -0,0 +1,125 @@ + + + Form + + + + 0 + 0 + 588 + 342 + + + + Form + + + + + + Use author &sort for author + + + + + + + &Title for Table of Contents: + + + opt_toc_title + + + + + + + + + + Disable compression of the file contents + + + + + + + Do not add Table of Contents to book + + + + + + + Put generated Table of Contents at &start of book instead of end + + + + + + + Ignore &margins + + + + + + + Kindle options + + + + + + + + Personal Doc tag: + + + + + + + + + + + + Enable sharing of book content via Facebook, etc. WARNING: Disables last read syncing + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + +