From 6d3af526140cc2b5f9595de7afb49b3f4f67fc47 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 17 Jul 2025 13:53:51 +0530 Subject: [PATCH] MTP driver: Use APNX config values from the Kindle plugin This means APNX settings will be shared across all Kindle devices in one place. They will apply the same to both USBMS and MTP based Kindles. --- src/calibre/devices/kindle/driver.py | 13 +++++ src/calibre/devices/mtp/driver.py | 27 +++++----- src/calibre/gui2/device_drivers/mtp_config.py | 49 +++++++++++-------- 3 files changed, 53 insertions(+), 36 deletions(-) diff --git a/src/calibre/devices/kindle/driver.py b/src/calibre/devices/kindle/driver.py index 6e61d322fc..8bc849b17f 100644 --- a/src/calibre/devices/kindle/driver.py +++ b/src/calibre/devices/kindle/driver.py @@ -13,6 +13,7 @@ import hashlib import json import os import re +from typing import NamedTuple from calibre import fsync, prints, strftime from calibre.constants import DEBUG, filesystem_encoding @@ -366,6 +367,18 @@ class KINDLE(USBMS): db.add_books([bm.value['path']], ['txt'], [mi]) +class APNXOpts(NamedTuple): + send_apnx: bool = True + apnx_method: str = 'fast' + custom_col_name: str = '' + method_col_name: str = '' + overwrite: bool = True + + +def get_apnx_opts() -> APNXOpts: + return APNXOpts(*KINDLE2.settings().extra_customization) + + class KINDLE2(KINDLE): name = 'Kindle 2/3/4/Touch/PaperWhite/Voyage Device Interface' diff --git a/src/calibre/devices/mtp/driver.py b/src/calibre/devices/mtp/driver.py index d91c9a72a9..1d08b5af4f 100644 --- a/src/calibre/devices/mtp/driver.py +++ b/src/calibre/devices/mtp/driver.py @@ -86,13 +86,6 @@ class MTP_DEVICE(BASE): p.defaults['history'] = {} p.defaults['rules'] = [] p.defaults['ignored_folders'] = {} - p.defaults['apnx'] = { - 'send': False, - 'method': 'fast', - 'custom_column_page_count': None, - 'custom_column_method': None, - } - return self._prefs @property @@ -551,10 +544,13 @@ class MTP_DEVICE(BASE): try: self.upload_cover(parent, relpath, storage, mi, stream) # Upload the apnx file - if self.is_kindle and self.get_pref('apnx').get('send', False): - name = path[-1].rpartition('.')[0] - debug('Uploading APNX file for', name) - self.upload_apnx(parent, name, storage, mi, infile) + if self.is_kindle: + from calibre.devices.kindle.driver import get_apnx_opts + apnx_opts = get_apnx_opts() + if apnx_opts.send_apnx: + name = path[-1].rpartition('.')[0] + debug('Uploading APNX file for', name) + self.upload_apnx(parent, name, storage, mi, infile, apnx_opts) except Exception: import traceback traceback.print_exc() @@ -643,7 +639,7 @@ class MTP_DEVICE(BASE): debug(f'Restored {count} cover thumbnails that were destroyed by Amazon') # }}} - def upload_apnx(self, parent, name, storage, mi, filepath): + def upload_apnx(self, parent, name, storage, mi, filepath, apnx_opts): debug('upload_apnx() called') from calibre.devices.kindle.apnx import APNXBuilder from calibre.ptempfile import PersistentTemporaryFile @@ -653,18 +649,17 @@ class MTP_DEVICE(BASE): apnx_local_file.close() try: - pref = self.get_pref('apnx') custom_page_count = 0 - cust_col_name = pref.get('custom_column_page_count') + cust_col_name = apnx_opts.custom_col_name if cust_col_name: try: custom_page_count = int(mi.get(cust_col_name, 0)) except Exception: pass - method = pref.get('method', 'fast') + method = apnx_opts.apnx_method - cust_col_method = pref.get('custom_column_method') + cust_col_method = apnx_opts.method_col_name if cust_col_method: try: method = str(mi.get(cust_col_method)).lower() diff --git a/src/calibre/gui2/device_drivers/mtp_config.py b/src/calibre/gui2/device_drivers/mtp_config.py index d0ecbd2de8..1a24595988 100644 --- a/src/calibre/gui2/device_drivers/mtp_config.py +++ b/src/calibre/gui2/device_drivers/mtp_config.py @@ -354,7 +354,10 @@ class FormatRules(QGroupBox): class APNX(QWidget): # {{{ - def __init__(self, apnx): + def __init__(self): + from calibre.devices.kindle.apnx import APNXBuilder + from calibre.devices.kindle.driver import KINDLE2, get_apnx_opts + apnx_opts = get_apnx_opts() QWidget.__init__(self) self.layout = l = QVBoxLayout() self.setLayout(l) @@ -362,17 +365,19 @@ class APNX(QWidget): # {{{ self.layout.setAlignment(Qt.AlignTop) self.send = f1 = QCheckBox(_('Send page number information when sending books')) - f1.setChecked(bool(apnx.get('send'))) + f1.setChecked(bool(apnx_opts.send_apnx)) l.addWidget(f1) + f1.setToolTip(KINDLE2.EXTRA_CUSTOMIZATION_MESSAGE[KINDLE2.OPT_APNX]) label2 = QLabel('

' + _('Page count calculation method') + '

') label2.setWordWrap(True) l.addWidget(label2) self.method = f2 = QComboBox(self) - f2.addItem(_('fast'), 'fast') - f2.addItem(_('accurate'), 'accurate') - f2.addItem(_('page break'), 'pagebreak') - if (idx := f2.findData(apnx.get('method') or 'fast')) > -1: + label2.setToolTip(KINDLE2.EXTRA_CUSTOMIZATION_MESSAGE[KINDLE2.OPT_APNX_METHOD]) + f2.setToolTip(KINDLE2.EXTRA_CUSTOMIZATION_MESSAGE[KINDLE2.OPT_APNX_METHOD]) + for key in sorted(APNXBuilder.generators.keys()): + f2.addItem(key, key) + if (idx := f2.findData(apnx_opts.apnx_method)) > -1: f2.setCurrentIndex(idx) l.addWidget(f2) @@ -380,25 +385,30 @@ class APNX(QWidget): # {{{ label3.setWordWrap(True) l.addWidget(label3) self.column_page_count = f3 = QLineEdit(self) - f3.setText(apnx.get('custom_column_page_count') or '') + f3.setText(apnx_opts.custom_col_name) + label3.setToolTip(KINDLE2.EXTRA_CUSTOMIZATION_MESSAGE[KINDLE2.OPT_APNX_CUST_COL]) + f3.setToolTip(KINDLE2.EXTRA_CUSTOMIZATION_MESSAGE[KINDLE2.OPT_APNX_CUST_COL]) l.addWidget(f3) label4 = QLabel('

' + _('Custom column name to retrieve calculation method from') + '

') label4.setWordWrap(True) l.addWidget(label4) self.column_method = f4 = QLineEdit(self) - f4.setText(apnx.get('custom_column_method') or '') + f4.setText(apnx_opts.method_col_name) + label4.setToolTip(KINDLE2.EXTRA_CUSTOMIZATION_MESSAGE[KINDLE2.OPT_APNX_METHOD_COL]) + f4.setToolTip(KINDLE2.EXTRA_CUSTOMIZATION_MESSAGE[KINDLE2.OPT_APNX_METHOD_COL]) l.addWidget(f4) + l.addWidget(QLabel(_('Note that these settings apply to all Kindle devices not just this particular one'))) - @property - def apnx(self): - result = { - 'send': bool(self.send.isChecked()), - 'method': str(self.method.currentData()).strip(), - 'custom_column_page_count': str(self.column_page_count.text()).strip(), - 'custom_column_method': str(self.column_method.text()).strip(), - } - return result + def commit(self): + from calibre.devices.kindle.driver import KINDLE2 + vals = list(KINDLE2.EXTRA_CUSTOMIZATION_DEFAULT) + vals[KINDLE2.OPT_APNX] = bool(self.send.isChecked()) + vals[KINDLE2.OPT_APNX_METHOD] = str(self.method.currentData()).strip() + vals[KINDLE2.OPT_APNX_CUST_COL] = str(self.column_page_count.text()).strip() + vals[KINDLE2.OPT_APNX_METHOD_COL] = str(self.column_method.text()).strip() + p = KINDLE2._configProxy() + p['extra_customization'] = vals # }}} @@ -472,7 +482,7 @@ class MTPConfig(QTabWidget): l.setRowStretch(7, 100) if device.is_kindle: - self.apnx_tab = APNX(self.get_pref('apnx') or {}) + self.apnx_tab = APNX() self.addTab(self.apnx_tab, _('Page numbering (APNX)')) self.igntab = IgnoredDevices(self.device.prefs['history'], @@ -563,9 +573,8 @@ class MTPConfig(QTabWidget): if self.current_ignored_folders != self.initial_ignored_folders: p['ignored_folders'] = self.current_ignored_folders - p.pop('apnx', None) if hasattr(self, 'apnx_tab'): - p['apnx'] = self.apnx_tab.apnx + self.apnx_tab.commit() if self.current_device_key is not None: self.device.prefs[self.current_device_key] = p