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.
This commit is contained in:
Kovid Goyal 2025-07-17 13:53:51 +05:30
parent aa2aef48f8
commit 6d3af52614
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 53 additions and 36 deletions

View File

@ -13,6 +13,7 @@ import hashlib
import json import json
import os import os
import re import re
from typing import NamedTuple
from calibre import fsync, prints, strftime from calibre import fsync, prints, strftime
from calibre.constants import DEBUG, filesystem_encoding from calibre.constants import DEBUG, filesystem_encoding
@ -366,6 +367,18 @@ class KINDLE(USBMS):
db.add_books([bm.value['path']], ['txt'], [mi]) 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): class KINDLE2(KINDLE):
name = 'Kindle 2/3/4/Touch/PaperWhite/Voyage Device Interface' name = 'Kindle 2/3/4/Touch/PaperWhite/Voyage Device Interface'

View File

@ -86,13 +86,6 @@ class MTP_DEVICE(BASE):
p.defaults['history'] = {} p.defaults['history'] = {}
p.defaults['rules'] = [] p.defaults['rules'] = []
p.defaults['ignored_folders'] = {} p.defaults['ignored_folders'] = {}
p.defaults['apnx'] = {
'send': False,
'method': 'fast',
'custom_column_page_count': None,
'custom_column_method': None,
}
return self._prefs return self._prefs
@property @property
@ -551,10 +544,13 @@ class MTP_DEVICE(BASE):
try: try:
self.upload_cover(parent, relpath, storage, mi, stream) self.upload_cover(parent, relpath, storage, mi, stream)
# Upload the apnx file # Upload the apnx file
if self.is_kindle and self.get_pref('apnx').get('send', False): if self.is_kindle:
name = path[-1].rpartition('.')[0] from calibre.devices.kindle.driver import get_apnx_opts
debug('Uploading APNX file for', name) apnx_opts = get_apnx_opts()
self.upload_apnx(parent, name, storage, mi, infile) 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: except Exception:
import traceback import traceback
traceback.print_exc() traceback.print_exc()
@ -643,7 +639,7 @@ class MTP_DEVICE(BASE):
debug(f'Restored {count} cover thumbnails that were destroyed by Amazon') 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') debug('upload_apnx() called')
from calibre.devices.kindle.apnx import APNXBuilder from calibre.devices.kindle.apnx import APNXBuilder
from calibre.ptempfile import PersistentTemporaryFile from calibre.ptempfile import PersistentTemporaryFile
@ -653,18 +649,17 @@ class MTP_DEVICE(BASE):
apnx_local_file.close() apnx_local_file.close()
try: try:
pref = self.get_pref('apnx')
custom_page_count = 0 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: if cust_col_name:
try: try:
custom_page_count = int(mi.get(cust_col_name, 0)) custom_page_count = int(mi.get(cust_col_name, 0))
except Exception: except Exception:
pass 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: if cust_col_method:
try: try:
method = str(mi.get(cust_col_method)).lower() method = str(mi.get(cust_col_method)).lower()

View File

@ -354,7 +354,10 @@ class FormatRules(QGroupBox):
class APNX(QWidget): # {{{ 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) QWidget.__init__(self)
self.layout = l = QVBoxLayout() self.layout = l = QVBoxLayout()
self.setLayout(l) self.setLayout(l)
@ -362,17 +365,19 @@ class APNX(QWidget): # {{{
self.layout.setAlignment(Qt.AlignTop) self.layout.setAlignment(Qt.AlignTop)
self.send = f1 = QCheckBox(_('Send page number information when sending books')) 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) l.addWidget(f1)
f1.setToolTip(KINDLE2.EXTRA_CUSTOMIZATION_MESSAGE[KINDLE2.OPT_APNX])
label2 = QLabel('<p>' + _('Page count calculation method') + '</p>') label2 = QLabel('<p>' + _('Page count calculation method') + '</p>')
label2.setWordWrap(True) label2.setWordWrap(True)
l.addWidget(label2) l.addWidget(label2)
self.method = f2 = QComboBox(self) self.method = f2 = QComboBox(self)
f2.addItem(_('fast'), 'fast') label2.setToolTip(KINDLE2.EXTRA_CUSTOMIZATION_MESSAGE[KINDLE2.OPT_APNX_METHOD])
f2.addItem(_('accurate'), 'accurate') f2.setToolTip(KINDLE2.EXTRA_CUSTOMIZATION_MESSAGE[KINDLE2.OPT_APNX_METHOD])
f2.addItem(_('page break'), 'pagebreak') for key in sorted(APNXBuilder.generators.keys()):
if (idx := f2.findData(apnx.get('method') or 'fast')) > -1: f2.addItem(key, key)
if (idx := f2.findData(apnx_opts.apnx_method)) > -1:
f2.setCurrentIndex(idx) f2.setCurrentIndex(idx)
l.addWidget(f2) l.addWidget(f2)
@ -380,25 +385,30 @@ class APNX(QWidget): # {{{
label3.setWordWrap(True) label3.setWordWrap(True)
l.addWidget(label3) l.addWidget(label3)
self.column_page_count = f3 = QLineEdit(self) 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) l.addWidget(f3)
label4 = QLabel('<p>' + _('Custom column name to retrieve calculation method from') + '</p>') label4 = QLabel('<p>' + _('Custom column name to retrieve calculation method from') + '</p>')
label4.setWordWrap(True) label4.setWordWrap(True)
l.addWidget(label4) l.addWidget(label4)
self.column_method = f4 = QLineEdit(self) 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(f4)
l.addWidget(QLabel(_('Note that these settings apply to all Kindle devices not just this particular one')))
@property def commit(self):
def apnx(self): from calibre.devices.kindle.driver import KINDLE2
result = { vals = list(KINDLE2.EXTRA_CUSTOMIZATION_DEFAULT)
'send': bool(self.send.isChecked()), vals[KINDLE2.OPT_APNX] = bool(self.send.isChecked())
'method': str(self.method.currentData()).strip(), vals[KINDLE2.OPT_APNX_METHOD] = str(self.method.currentData()).strip()
'custom_column_page_count': str(self.column_page_count.text()).strip(), vals[KINDLE2.OPT_APNX_CUST_COL] = str(self.column_page_count.text()).strip()
'custom_column_method': str(self.column_method.text()).strip(), vals[KINDLE2.OPT_APNX_METHOD_COL] = str(self.column_method.text()).strip()
} p = KINDLE2._configProxy()
return result p['extra_customization'] = vals
# }}} # }}}
@ -472,7 +482,7 @@ class MTPConfig(QTabWidget):
l.setRowStretch(7, 100) l.setRowStretch(7, 100)
if device.is_kindle: 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.addTab(self.apnx_tab, _('Page numbering (APNX)'))
self.igntab = IgnoredDevices(self.device.prefs['history'], self.igntab = IgnoredDevices(self.device.prefs['history'],
@ -563,9 +573,8 @@ class MTPConfig(QTabWidget):
if self.current_ignored_folders != self.initial_ignored_folders: if self.current_ignored_folders != self.initial_ignored_folders:
p['ignored_folders'] = self.current_ignored_folders p['ignored_folders'] = self.current_ignored_folders
p.pop('apnx', None)
if hasattr(self, 'apnx_tab'): if hasattr(self, 'apnx_tab'):
p['apnx'] = self.apnx_tab.apnx self.apnx_tab.commit()
if self.current_device_key is not None: if self.current_device_key is not None:
self.device.prefs[self.current_device_key] = p self.device.prefs[self.current_device_key] = p