Fix #2100559 [KePubify: Restore 'template for kepubification'](https://bugs.launchpad.net/calibre/+bug/2100559)

This commit is contained in:
Kovid Goyal 2025-02-28 08:57:02 +05:30
parent 882dc07eec
commit 1526cdb906
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 58 additions and 11 deletions

View File

@ -2294,24 +2294,43 @@ class KOBOTOUCH(KOBO):
debug_print(f'KoboTouch:upload_books - {len(files)} books') debug_print(f'KoboTouch:upload_books - {len(files)} books')
debug_print('KoboTouch:upload_books - files=', files) debug_print('KoboTouch:upload_books - files=', files)
modify_epub = self.modifying_epub() or self.get_pref('kepubify') do_kepubify = self.get_pref('kepubify')
def should_modify(name: str) -> bool: template = self.get_pref('template_for_kepubify')
ext = '.' + name.rpartition('.')[-1].lower() modify_css = self.modifying_epub()
return ext == EPUB_EXT and modify_epub entries = tuple(zip(files, names, metadata))
kepubifiable = set()
def should_modify(name: str, mi) -> bool:
mi.kte_calibre_name = name
if not name.lower().endswith(EPUB_EXT):
return False
if do_kepubify:
if not template:
kepubifiable.add(mi.uuid)
return True
from calibre.ebooks.metadata.book.formatter import SafeFormat
kepubify = SafeFormat().safe_format(template, mi, 'Open With template error', mi)
debug_print(f'kepubify_template_result for {mi.title}:', kepubify)
if kepubify is not None and kepubify.startswith('PLUGBOARD TEMPLATE ERROR'):
import sys
print(f'kepubify template: {template} returned error', file=sys.stderr)
kepubifiable.add(mi.uuid)
return True
return kepubify and kepubify != 'false'
return modify_css
self.extra_css, self.extra_sheet = self.get_extra_css() self.extra_css, self.extra_sheet = self.get_extra_css()
modifiable = {x for x in names if should_modify(x)} modifiable = {mi.uuid for _, name, mi in entries if should_modify(name, mi)}
self.files_to_rename_to_kepub = set() self.files_to_rename_to_kepub = set()
if modifiable: if modifiable:
i = 0 i = 0
for idx, (file, n, mi) in enumerate(zip(files, names, metadata)): for idx, (file, n, mi) in enumerate(entries):
if n not in modifiable: if mi.uuid not in modifiable:
continue continue
debug_print('KoboTouch:upload_books: Processing book: {} by {}'.format(mi.title, ' and '.join(mi.authors))) debug_print('KoboTouch:upload_books: Processing book: {} by {}'.format(mi.title, ' and '.join(mi.authors)))
debug_print(f'KoboTouch:upload_books: file={file}, name={n}') debug_print(f'KoboTouch:upload_books: file={file}, name={n}')
self.report_progress(i / float(len(modifiable)), 'Processing book: {} by {}'.format(mi.title, ' and '.join(mi.authors))) self.report_progress(i / float(len(modifiable)), 'Processing book: {} by {}'.format(mi.title, ' and '.join(mi.authors)))
mi.kte_calibre_name = n if mi.uuid in kepubifiable:
if self.get_pref('kepubify'):
self._kepubify(file, n, mi) self._kepubify(file, n, mi)
else: else:
self._modify_epub(file, mi) self._modify_epub(file, mi)
@ -3663,6 +3682,7 @@ class KOBOTOUCH(KOBO):
c.add_opt('bookstats_timetoread_lower_template', default=None) c.add_opt('bookstats_timetoread_lower_template', default=None)
c.add_opt('kepubify', default=True) c.add_opt('kepubify', default=True)
c.add_opt('template_for_kepubify', default=None)
c.add_opt('modify_css', default=False) c.add_opt('modify_css', default=False)
c.add_opt('per_device_css', default='{}') c.add_opt('per_device_css', default='{}')
c.add_opt('override_kobo_replace_existing', default=True) # Overriding the replace behaviour is how the driver has always worked. c.add_opt('override_kobo_replace_existing', default=True) # Overriding the replace behaviour is how the driver has always worked.

View File

@ -155,6 +155,7 @@ class KOBOTOUCHConfig(TabbedDeviceConfig):
p['modify_css'] = self.modify_css p['modify_css'] = self.modify_css
p['per_device_css'] = self.per_device_css p['per_device_css'] = self.per_device_css
p['kepubify'] = self.kepubify p['kepubify'] = self.kepubify
p['template_for_kepubify'] = self.template_for_kepubify
p['override_kobo_replace_existing'] = self.override_kobo_replace_existing p['override_kobo_replace_existing'] = self.override_kobo_replace_existing
p['support_newer_firmware'] = self.support_newer_firmware p['support_newer_firmware'] = self.support_newer_firmware
@ -359,6 +360,20 @@ class BookUploadsGroupBox(DeviceOptionsGroupBox):
' the Kobo viewer. If you would rather use the legacy viewer for EPUB, disable this option.' ' the Kobo viewer. If you would rather use the legacy viewer for EPUB, disable this option.'
), device.get_pref('kepubify')) ), device.get_pref('kepubify'))
self.template_la = la = QLabel('\xa0\xa0' + _('Template to decide conversion:'))
self.kepubify_template_edit = TemplateConfig(
device.get_pref('template_for_kepubify'),
tooltip=_(
'Enter a template to decide if an EPUB book is to be auto converted to KEPUB. '
'If the template returns false or no result, the book will not be '
'converted to KEPUB. For example to only kepubify books that have the tag "as_kepub", use the template: {0}'
' or to only convert books that do not have the tag as_epub, use the template: {1}'
'\n\nIf no template is specified conversion to KEPUB is controlled only by the setting above to use the Kobo viewer. '
'Note that the setting above must be enabled for the template to be checked.'
).format(r'{tags:str_in_list(\,,as_kepub,true,false)}', r'{tags:str_in_list(\,,as_epub,false,true)}')
)
la.setBuddy(self.kepubify_template_edit)
self.override_kobo_replace_existing_checkbox = create_checkbox( self.override_kobo_replace_existing_checkbox = create_checkbox(
_('Do not treat replacements as new books'), _('Do not treat replacements as new books'),
_('When a new book is side-loaded, the Kobo firmware imports details of the book into the internal database. ' _('When a new book is side-loaded, the Kobo firmware imports details of the book into the internal database. '
@ -371,7 +386,14 @@ class BookUploadsGroupBox(DeviceOptionsGroupBox):
) )
self.options_layout.addWidget(self.kepubify_checkbox, 0, 0, 1, 2) self.options_layout.addWidget(self.kepubify_checkbox, 0, 0, 1, 2)
self.options_layout.addWidget(self.override_kobo_replace_existing_checkbox, 1, 0, 1, 2) self.options_layout.addWidget(self.template_la, 1, 0, 1, 1)
self.options_layout.addWidget(self.kepubify_template_edit, 1, 1, 1, 1)
self.options_layout.addWidget(self.override_kobo_replace_existing_checkbox, 2, 0, 1, 2)
self.update_template_state()
self.kepubify_checkbox.toggled.connect(self.update_template_state)
def update_template_state(self):
self.kepubify_template_edit.setEnabled(self.kepubify)
@property @property
def override_kobo_replace_existing(self): def override_kobo_replace_existing(self):
@ -381,6 +403,10 @@ class BookUploadsGroupBox(DeviceOptionsGroupBox):
def kepubify(self): def kepubify(self):
return self.kepubify_checkbox.isChecked() return self.kepubify_checkbox.isChecked()
@property
def template_for_kepubify(self):
return (self.kepubify_template_edit.template or '').strip()
class HyphenationGroupBox(DeviceOptionsGroupBox): class HyphenationGroupBox(DeviceOptionsGroupBox):

View File

@ -553,11 +553,12 @@ def unkepubify_path(path, outpath='', max_workers=0, allow_overwrite=False):
def check_if_css_needs_modification(extra_css: str) -> tuple[bool, bool]: def check_if_css_needs_modification(extra_css: str) -> tuple[bool, bool]:
remove_widows_and_orphans = remove_at_page_rules = False remove_widows_and_orphans = remove_at_page_rules = False
sheet = None
if extra_css: if extra_css:
try: try:
sheet = css_parser().parseString(extra_css) sheet = css_parser().parseString(extra_css)
except Exception: except Exception:
sheet = None pass
else: else:
for rule in sheet.cssRules: for rule in sheet.cssRules:
if rule.type == CSSRule.PAGE_RULE: if rule.type == CSSRule.PAGE_RULE: