Tweak EPUB: Also allow tweaking of HTMLZ files (when both EPUB and HTMLZ are present, EPUB is preferred, can be changed via Preferences->Tweaks).

This commit is contained in:
Kovid Goyal 2012-01-07 23:17:12 +05:30
parent 383f2c62e2
commit 2dd5346104
6 changed files with 71 additions and 26 deletions

View File

@ -476,3 +476,9 @@ save_original_format = True
# how many should be shown, here. # how many should be shown, here.
gui_view_history_size = 15 gui_view_history_size = 15
#: When using the 'Tweak Book' action, which format to prefer
# When tweaking a book that has multiple formats, calibre picks one
# automatically. By default EPUB is preferred to HTMLZ. If you would like to
# prefer HTMLZ to EPUB for tweaking, change this to 'htmlz'
tweak_book_prefer = 'epub'

View File

@ -839,7 +839,7 @@ class ActionCopyToLibrary(InterfaceActionBase):
class ActionTweakEpub(InterfaceActionBase): class ActionTweakEpub(InterfaceActionBase):
name = 'Tweak ePub' name = 'Tweak ePub'
actual_plugin = 'calibre.gui2.actions.tweak_epub:TweakEpubAction' actual_plugin = 'calibre.gui2.actions.tweak_epub:TweakEpubAction'
description = _('Make small tweaks to epub files in your calibre library') description = _('Make small tweaks to epub or htmlz files in your calibre library')
class ActionNextMatch(InterfaceActionBase): class ActionNextMatch(InterfaceActionBase):
name = 'Next Match' name = 'Next Match'

View File

@ -10,12 +10,13 @@ import os
from calibre.gui2 import error_dialog from calibre.gui2 import error_dialog
from calibre.gui2.actions import InterfaceAction from calibre.gui2.actions import InterfaceAction
from calibre.gui2.dialogs.tweak_epub import TweakEpub from calibre.gui2.dialogs.tweak_epub import TweakEpub
from calibre.utils.config import tweaks
class TweakEpubAction(InterfaceAction): class TweakEpubAction(InterfaceAction):
name = 'Tweak ePub' name = 'Tweak ePub'
action_spec = (_('Tweak ePub'), 'trim.png', action_spec = (_('Tweak Book'), 'trim.png',
_('Make small changes to ePub format books'), _('Make small changes to ePub or HTMLZ format books'),
_('T')) _('T'))
dont_add_to = frozenset(['context-menu-device']) dont_add_to = frozenset(['context-menu-device'])
action_type = 'current' action_type = 'current'
@ -26,33 +27,48 @@ class TweakEpubAction(InterfaceAction):
def edit_epub_in_situ(self, *args): def edit_epub_in_situ(self, *args):
row = self.gui.library_view.currentIndex() row = self.gui.library_view.currentIndex()
if not row.isValid(): if not row.isValid():
return error_dialog(self.gui, _('Cannot tweak ePub'), return error_dialog(self.gui, _('Cannot tweak Book'),
_('No book selected'), show=True) _('No book selected'), show=True)
# Confirm 'EPUB' in formats
book_id = self.gui.library_view.model().id(row) book_id = self.gui.library_view.model().id(row)
# Confirm 'EPUB' in formats
try: try:
path_to_epub = self.gui.library_view.model().db.format( path_to_epub = self.gui.library_view.model().db.format(
book_id, 'EPUB', index_is_id=True, as_path=True) book_id, 'EPUB', index_is_id=True, as_path=True)
except: except:
path_to_epub = None path_to_epub = None
if not path_to_epub: # Confirm 'HTMLZ' in formats
return error_dialog(self.gui, _('Cannot tweak ePub'), try:
_('No ePub available. First convert the book to ePub.'), path_to_htmlz = self.gui.library_view.model().db.format(
book_id, 'HTMLZ', index_is_id=True, as_path=True)
except:
path_to_htmlz = None
if not path_to_epub and not path_to_htmlz:
return error_dialog(self.gui, _('Cannot tweak Book'),
_('The book must be in ePub or HTMLZ format to tweak.'
'\n\nFirst convert the book to ePub or HTMLZ.'),
show=True) show=True)
# Launch modal dialog waiting for user to tweak or cancel # Launch modal dialog waiting for user to tweak or cancel
dlg = TweakEpub(self.gui, path_to_epub) if tweaks['tweak_book_prefer'] == 'htmlz':
path_to_book = path_to_htmlz or path_to_epub
else:
path_to_book = path_to_epub or path_to_htmlz
dlg = TweakEpub(self.gui, path_to_book)
if dlg.exec_() == dlg.Accepted: if dlg.exec_() == dlg.Accepted:
self.update_db(book_id, dlg._output) self.update_db(book_id, dlg._output)
dlg.cleanup() dlg.cleanup()
os.remove(path_to_epub) os.remove(path_to_book)
def update_db(self, book_id, rebuilt): def update_db(self, book_id, rebuilt):
''' '''
Update the calibre db with the tweaked epub Update the calibre db with the tweaked epub
''' '''
self.gui.library_view.model().db.add_format(book_id, 'EPUB', fmt = os.path.splitext(rebuilt)[1][1:].upper()
self.gui.library_view.model().db.add_format(book_id, fmt,
open(rebuilt, 'rb'), index_is_id=True) open(rebuilt, 'rb'), index_is_id=True)

View File

@ -7,6 +7,7 @@ __copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
import os, shutil import os, shutil
from itertools import repeat, izip
from calibre.utils.zipfile import ZipFile, ZIP_DEFLATED, ZIP_STORED from calibre.utils.zipfile import ZipFile, ZIP_DEFLATED, ZIP_STORED
from PyQt4.Qt import QDialog from PyQt4.Qt import QDialog
@ -30,9 +31,20 @@ class TweakEpub(QDialog, Ui_Dialog):
self._epub = epub self._epub = epub
self._exploded = None self._exploded = None
self._output = None self._output = None
self.ishtmlz = epub.lower().endswith('.htmlz')
self.rebuilt_name = 'rebuilt.' + ('htmlz' if self.ishtmlz else 'epub')
# Run the dialog setup generated from tweak_epub.ui # Run the dialog setup generated from tweak_epub.ui
self.setupUi(self) self.setupUi(self)
for x, props in [(self, ['windowTitle']), (self.label, ['text'])]+\
list(izip([self.cancel_button, self.explode_button,
self.rebuild_button, self.preview_button],
repeat(['text', 'statusTip', 'toolTip']))):
for prop in props:
val = unicode(getattr(x, prop)())
val = val.format('HTMLZ' if self.ishtmlz else 'ePub')
prop = 'set' + prop[0].upper() + prop[1:]
getattr(x, prop)(val)
self.cancel_button.clicked.connect(self.reject) self.cancel_button.clicked.connect(self.reject)
self.explode_button.clicked.connect(self.explode) self.explode_button.clicked.connect(self.explode)
@ -83,9 +95,11 @@ class TweakEpub(QDialog, Ui_Dialog):
def do_rebuild(self, src): def do_rebuild(self, src):
with ZipFile(src, 'w', compression=ZIP_DEFLATED) as zf: with ZipFile(src, 'w', compression=ZIP_DEFLATED) as zf:
# Write mimetype # Write mimetype
zf.write(os.path.join(self._exploded,'mimetype'), 'mimetype', compress_type=ZIP_STORED) mt = os.path.join(self._exploded, 'mimetype')
if os.path.exists(mt):
zf.write(mt, 'mimetype', compress_type=ZIP_STORED)
# Write everything else # Write everything else
exclude_files = ['.DS_Store','mimetype','iTunesMetadata.plist','rebuilt.epub'] exclude_files = ['.DS_Store','mimetype','iTunesMetadata.plist',self.rebuilt_name]
for root, dirs, files in os.walk(self._exploded): for root, dirs, files in os.walk(self._exploded):
for fn in files: for fn in files:
if fn in exclude_files: if fn in exclude_files:
@ -97,11 +111,11 @@ class TweakEpub(QDialog, Ui_Dialog):
def preview(self): def preview(self):
if not self._exploded: if not self._exploded:
return error_dialog(self, _('Cannot preview'), msg = _('You must first explode the %s before previewing.')
_('You must first explode the epub before previewing.'), msg = msg%('HTMLZ' if self.ishtmlz else 'ePub')
show=True) return error_dialog(self, _('Cannot preview'), msg, show=True)
tf = PersistentTemporaryFile('.epub') tf = PersistentTemporaryFile('.htmlz' if self.ishtmlz else '.epub')
tf.close() tf.close()
self._preview_files.append(tf.name) self._preview_files.append(tf.name)
@ -110,7 +124,7 @@ class TweakEpub(QDialog, Ui_Dialog):
self.gui.iactions['View']._view_file(tf.name) self.gui.iactions['View']._view_file(tf.name)
def rebuild(self, *args): def rebuild(self, *args):
self._output = os.path.join(self._exploded, 'rebuilt.epub') self._output = os.path.join(self._exploded, self.rebuilt_name)
self.do_rebuild(self._output) self.do_rebuild(self._output)
return QDialog.accept(self) return QDialog.accept(self)

View File

@ -14,7 +14,7 @@
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Tweak ePub</string> <string>Tweak {0}</string>
</property> </property>
<property name="sizeGripEnabled"> <property name="sizeGripEnabled">
<bool>false</bool> <bool>false</bool>
@ -26,7 +26,7 @@
<item row="0" column="0" colspan="2"> <item row="0" column="0" colspan="2">
<widget class="QLabel" name="label"> <widget class="QLabel" name="label">
<property name="text"> <property name="text">
<string>&lt;p&gt;Explode the ePub to display contents in a file browser window. To tweak individual files, right-click, then 'Open with...' your editor of choice. When tweaks are complete, close the file browser window &lt;b&gt;and the editor windows you used to edit files in the epub&lt;/b&gt;.&lt;/p&gt;&lt;p&gt;Rebuild the ePub, updating your calibre library.&lt;/p&gt;</string> <string>&lt;p&gt;Explode the {0} to display contents in a file browser window. To tweak individual files, right-click, then 'Open with...' your editor of choice. When tweaks are complete, close the file browser window &lt;b&gt;and the editor windows you used to edit files in the ePub&lt;/b&gt;.&lt;/p&gt;&lt;p&gt;Rebuild the ePub, updating your calibre library.&lt;/p&gt;</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@ -35,11 +35,14 @@
</item> </item>
<item row="1" column="0"> <item row="1" column="0">
<widget class="QPushButton" name="explode_button"> <widget class="QPushButton" name="explode_button">
<property name="toolTip">
<string>Display contents of exploded {0}</string>
</property>
<property name="statusTip"> <property name="statusTip">
<string>Display contents of exploded ePub</string> <string>Display contents of exploded {0}</string>
</property> </property>
<property name="text"> <property name="text">
<string>&amp;Explode ePub</string> <string>&amp;Explode {0}</string>
</property> </property>
<property name="icon"> <property name="icon">
<iconset resource="../../../../resources/images.qrc"> <iconset resource="../../../../resources/images.qrc">
@ -49,6 +52,9 @@
</item> </item>
<item row="3" column="0"> <item row="3" column="0">
<widget class="QPushButton" name="cancel_button"> <widget class="QPushButton" name="cancel_button">
<property name="toolTip">
<string>Discard changes</string>
</property>
<property name="statusTip"> <property name="statusTip">
<string>Discard changes</string> <string>Discard changes</string>
</property> </property>
@ -66,11 +72,14 @@
<property name="enabled"> <property name="enabled">
<bool>false</bool> <bool>false</bool>
</property> </property>
<property name="toolTip">
<string>Rebuild {0} from exploded contents</string>
</property>
<property name="statusTip"> <property name="statusTip">
<string>Rebuild ePub from exploded contents</string> <string>Rebuild {0} from exploded contents</string>
</property> </property>
<property name="text"> <property name="text">
<string>&amp;Rebuild ePub</string> <string>&amp;Rebuild {0}</string>
</property> </property>
<property name="icon"> <property name="icon">
<iconset resource="../../../../resources/images.qrc"> <iconset resource="../../../../resources/images.qrc">
@ -81,7 +90,7 @@
<item row="1" column="1"> <item row="1" column="1">
<widget class="QPushButton" name="preview_button"> <widget class="QPushButton" name="preview_button">
<property name="text"> <property name="text">
<string>&amp;Preview ePub</string> <string>&amp;Preview {0}</string>
</property> </property>
<property name="icon"> <property name="icon">
<iconset resource="../../../../resources/images.qrc"> <iconset resource="../../../../resources/images.qrc">

View File

@ -323,7 +323,7 @@ remove all non-breaking-space entities, or may include false positive matches re
tags, i.e. horizontal rules, and <img> tags are exceptions. Horizontal rules can optionally be specified with styles, if you tags, i.e. horizontal rules, and <img> tags are exceptions. Horizontal rules can optionally be specified with styles, if you
choose to add your own style be sure to include the 'width' setting, otherwise the style information will be discarded. Image choose to add your own style be sure to include the 'width' setting, otherwise the style information will be discarded. Image
tags can used, but |app| does not provide the ability to add the image during conversion, this must be done after the fact using tags can used, but |app| does not provide the ability to add the image during conversion, this must be done after the fact using
the 'Tweak Epub' feature, or Sigil. the 'Tweak Book' feature, or Sigil.
Example image tag (place the image within an 'Images' folder inside the epub after conversion): Example image tag (place the image within an 'Images' folder inside the epub after conversion):
<img style="width:10%" src="../Images/scenebreak.png" /> <img style="width:10%" src="../Images/scenebreak.png" />