diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py index 1ddb2843a1..4e47c70bb0 100644 --- a/src/calibre/customize/builtins.py +++ b/src/calibre/customize/builtins.py @@ -665,13 +665,17 @@ class ActionCopyToLibrary(InterfaceActionBase): name = 'Copy To Library' actual_plugin = 'calibre.gui2.actions.copy_to_library:CopyToLibraryAction' +class ActionTweakEpub(InterfaceActionBase): + name = 'Tweak ePub' + actual_plugin = 'calibre.gui2.actions.tweak_epub:TweakEpubAction' + plugins += [ActionAdd, ActionFetchAnnotations, ActionGenerateCatalog, ActionConvert, ActionDelete, ActionEditMetadata, ActionView, ActionFetchNews, ActionSaveToDisk, ActionShowBookDetails, ActionRestart, ActionOpenFolder, ActionConnectShare, ActionSendToDevice, ActionHelp, ActionPreferences, ActionSimilarBooks, ActionAddToLibrary, ActionEditCollections, ActionChooseLibrary, - ActionCopyToLibrary] + ActionCopyToLibrary, ActionTweakEpub] # }}} diff --git a/src/calibre/devices/apple/driver.py b/src/calibre/devices/apple/driver.py index 608171bc1f..2559d0149e 100644 --- a/src/calibre/devices/apple/driver.py +++ b/src/calibre/devices/apple/driver.py @@ -740,7 +740,7 @@ class ITUNES(DriverBase): # Purge the booklist, self.cached_books, thumb cache for i,bl_book in enumerate(booklists[0]): - if DEBUG: + if False: self.log.info(" evaluating '%s' by '%s' uuid:%s" % (bl_book.title, bl_book.author,bl_book.uuid)) diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index e58dce5559..c284900734 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -39,7 +39,7 @@ gprefs.defaults['action-layout-context-menu'] = ( 'Edit Metadata', 'Send To Device', 'Save To Disk', 'Connect Share', 'Copy To Library', None, 'Convert Books', 'View', 'Open Folder', 'Show Book Details', - 'Similar Books', None, 'Remove Books', + 'Similar Books', 'Tweak ePub', None, 'Remove Books', ) gprefs.defaults['action-layout-context-menu-device'] = ( diff --git a/src/calibre/gui2/actions/tweak_epub.py b/src/calibre/gui2/actions/tweak_epub.py new file mode 100755 index 0000000000..67ec34c12b --- /dev/null +++ b/src/calibre/gui2/actions/tweak_epub.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python +# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai + +__license__ = 'GPL v3' +__copyright__ = '2010, Kovid Goyal ' +__docformat__ = 'restructuredtext en' + +from calibre.gui2 import error_dialog +from calibre.gui2.actions import InterfaceAction +from calibre.gui2.dialogs.tweak_epub import TweakEpub + +class TweakEpubAction(InterfaceAction): + + name = 'Tweak ePub' + action_spec = (_('Tweak ePub'), 'trim.png', + _('Make small changes to ePub format books'), + _('T')) + dont_add_to = frozenset(['toolbar-device', 'context-menu-device']) + action_type = 'current' + + def genesis(self): + self.qaction.triggered.connect(self.edit_epub_in_situ) + + def edit_epub_in_situ(self, *args): + row = self.gui.library_view.currentIndex() + if not row.isValid(): + return error_dialog(self.gui, _('Cannot tweak ePub'), + _('No book selected'), show=True) + + # Confirm 'EPUB' in formats + book_id = self.gui.library_view.model().id(row) + try: + path_to_epub = self.gui.library_view.model().db.format_abspath( + book_id, 'EPUB', index_is_id=True) + except: + path_to_epub = None + + if not path_to_epub: + return error_dialog(self.gui, _('Cannot tweak ePub'), + _('No ePub available. First convert the book to ePub.'), + show=True) + + + # Launch a modal dialog waiting for user to complete or cancel + dlg = TweakEpub(self.gui, path_to_epub) + if dlg.exec_() == dlg.Accepted: + self.update_db(book_id, dlg._output) + dlg.cleanup() + + def update_db(self, book_id, rebuilt): + ''' + Update the calibre db with the tweaked epub + ''' + self.gui.library_view.model().db.add_format(book_id, 'EPUB', + open(rebuilt, 'rb'), index_is_id=True) + diff --git a/src/calibre/gui2/dialogs/tweak_epub.py b/src/calibre/gui2/dialogs/tweak_epub.py new file mode 100755 index 0000000000..fb3643884b --- /dev/null +++ b/src/calibre/gui2/dialogs/tweak_epub.py @@ -0,0 +1,84 @@ +#!/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__ = '2010, Kovid Goyal ' +__docformat__ = 'restructuredtext en' + +import os, shutil +from contextlib import closing +from zipfile import ZipFile, ZIP_DEFLATED, ZIP_STORED + +from PyQt4.Qt import QDialog + +from calibre.gui2 import open_local_file +from calibre.gui2.dialogs.tweak_epub_ui import Ui_Dialog +from calibre.libunzip import extract as zipextract +from calibre.ptempfile import PersistentTemporaryDirectory + +class TweakEpub(QDialog, Ui_Dialog): + ''' + Display controls for tweaking ePubs + + To do: + - need way to kill file browser proc in cleanup() + ''' + + def __init__(self, parent, epub): + QDialog.__init__(self, parent) + + self._epub = epub + self._exploded = None + #self._file_browser_proc = None + self._output = None + + # Run the dialog setup generated from tweak_epub.ui + self.setupUi(self) + + self.cancel_button.clicked.connect(self.reject) + self.explode_button.clicked.connect(self.explode) + self.rebuild_button.clicked.connect(self.rebuild) + + # Position update dialog overlaying top left of app window + parent_loc = parent.pos() + self.move(parent_loc.x(),parent_loc.y()) + + def cleanup(self): + # Delete directory containing exploded ePub + if self._exploded is not None: + shutil.rmtree(self._exploded, ignore_errors=True) + + + def display_exploded(self): + ''' + Generic subprocess launch of native file browser + User can use right-click to 'Open with ...' + ''' + open_local_file(self._exploded) + + def explode(self, *args): + if self._exploded is None: + self._exploded = PersistentTemporaryDirectory("_exploded", prefix='') + zipextract(self._epub, self._exploded) + self.display_exploded() + self.rebuild_button.setEnabled(True) + self.explode_button.setEnabled(False) + + def rebuild(self, *args): + self._output = os.path.join(self._exploded, 'rebuilt.epub') + with closing(ZipFile(self._output, 'w', compression=ZIP_DEFLATED)) as zf: + # Write mimetype + zf.write(os.path.join(self._exploded,'mimetype'), 'mimetype', compress_type=ZIP_STORED) + # Write everything else + exclude_files = ['.DS_Store','mimetype','iTunesMetadata.plist','rebuilt.epub'] + for root, dirs, files in os.walk(self._exploded): + for fn in files: + if fn in exclude_files: + continue + absfn = os.path.join(root, fn) + zfn = os.path.relpath(absfn, + self._exploded).replace(os.sep, '/') + zf.write(absfn, zfn) + return QDialog.accept(self) + diff --git a/src/calibre/gui2/dialogs/tweak_epub.ui b/src/calibre/gui2/dialogs/tweak_epub.ui new file mode 100644 index 0000000000..9daa5a8f67 --- /dev/null +++ b/src/calibre/gui2/dialogs/tweak_epub.ui @@ -0,0 +1,87 @@ + + + Dialog + + + Qt::NonModal + + + + 0 + 0 + 382 + 242 + + + + Tweak ePub + + + false + + + false + + + + + + Display contents of exploded ePub + + + &Explode ePub + + + + :/images/wizard.png:/images/wizard.png + + + + + + + false + + + Rebuild ePub from exploded contents + + + &Rebuild ePub + + + + :/images/exec.png:/images/exec.png + + + + + + + Discard changes + + + &Cancel + + + + :/images/window-close.png:/images/window-close.png + + + + + + + First, explode the epub. Then edit is contents by right clicking on the individual files and selecting the editor of your choice. When you are done, click rebuild epub and the epub in your calibre library will be updated with the changes you have made. + + + true + + + + + + + + + + diff --git a/src/calibre/gui2/tools.py b/src/calibre/gui2/tools.py index 7a516bb4ff..2f0452a773 100644 --- a/src/calibre/gui2/tools.py +++ b/src/calibre/gui2/tools.py @@ -217,6 +217,10 @@ def fetch_scheduled_recipe(arg): if 'output_profile' in ps: recs.append(('output_profile', ps['output_profile'], OptionRecommendation.HIGH)) + if ps['output_profile'] == 'kindle': + recs.append(('no_inline_toc', True, + OptionRecommendation.HIGH)) + lf = load_defaults('look_and_feel') if lf.get('base_font_size', 0.0) != 0.0: recs.append(('base_font_size', lf['base_font_size'],