diff --git a/src/calibre/devices/kobo/driver.py b/src/calibre/devices/kobo/driver.py index a966ebc700..1e1f3cd925 100644 --- a/src/calibre/devices/kobo/driver.py +++ b/src/calibre/devices/kobo/driver.py @@ -3429,7 +3429,12 @@ class KOBOTOUCH(KOBO): if newmi.series is not None: new_series = newmi.series try: - new_series_number = f'{newmi.series_index:g}' + if self.use_series_index_template: + from calibre.ebooks.metadata.book.formatter import SafeFormat + new_series_number = SafeFormat().safe_format( + self.series_index_template, newmi, 'Kobo series number template', newmi) + else: + new_series_number = f'{newmi.series_index:g}' except: new_series_number = None else: @@ -3640,6 +3645,8 @@ class KOBOTOUCH(KOBO): c.add_opt('collections_columns', default='') c.add_opt('use_collections_template', default=False) c.add_opt('collections_template', default='') + c.add_opt('use_series_index_template', default=False) + c.add_opt('series_index_template', default='') c.add_opt('create_collections', default=False) c.add_opt('delete_empty_collections', default=False) c.add_opt('ignore_collections_names', default='') @@ -3986,6 +3993,14 @@ class KOBOTOUCH(KOBO): def collections_template(self): return self.get_pref('collections_template') if self.use_collections_template else '' + @property + def use_series_index_template(self): + return self.get_pref('use_series_index_template') + + @property + def series_index_template(self): + return self.get_pref('series_index_template') if self.use_series_index_template else '' + def get_collections_attributes(self): collections_str = self.collections_columns collections = [x.lower().strip() for x in collections_str.split(',')] if collections_str else [] diff --git a/src/calibre/devices/kobo/kobotouch_config.py b/src/calibre/devices/kobo/kobotouch_config.py index ef8af3e974..f00d4648aa 100644 --- a/src/calibre/devices/kobo/kobotouch_config.py +++ b/src/calibre/devices/kobo/kobotouch_config.py @@ -127,6 +127,8 @@ class KOBOTOUCHConfig(TabbedDeviceConfig): p['collections_columns'] = self.collections_columns p['use_collections_template'] = self.use_collections_template p['collections_template'] = self.collections_template + p['use_series_index_template'] = self.use_series_index_template + p['series_index_template'] = self.series_index_template p['ignore_collections_names'] = self.ignore_collections_names p['delete_empty_collections'] = self.delete_empty_collections @@ -889,6 +891,32 @@ class MetadataGroupBox(DeviceOptionsGroupBox): 'in a series to the same value.'), device.get_pref('force_series_id') ) + self.use_series_index_template_checkbox = create_checkbox( + _('Series number template:'), + _('Use a template to generate what the Kobo displays for the series number.'), + device.get_pref('use_series_index_template') + ) + self.series_index_template_edit = TemplateConfig( + self.use_series_index_template_checkbox.text(), + device.get_pref('series_index_template'), + tooltip='

' + + _('The Kobo can display a series number (book number) ' + 'when books are in a series. To do this, the Kobo uses ' + 'two values, the "series number" (a floating point value) ' + 'and the "series text" (a string). The series number is ' + 'used for sorting. The series text is what is displayed. ' + 'Normally the series text is the same as the series ' + 'number. This option lets you choose a different value ' + 'for the series text.

' + 'A common use is to change the series text to the ' + 'empty string when the series number is zero. This General ' + 'Program Mode template does that: {0}' + 'You can do more complicated things such as have an omnibus ' + 'display "5 to 9". How you do this depends on how you have set ' + 'up the series in calibre.').format( + '

program: if $series_index !=# 0 then $series_index else "" fi
') + + '

' + ) self.update_core_metadata_checkbox = create_checkbox( _('Update metadata on Book Details pages'), _('This will update the metadata in the device database when the device is connected. ' @@ -967,6 +995,9 @@ class MetadataGroupBox(DeviceOptionsGroupBox): hbl.addStretch(1) self.options_layout.addLayout(hbl, line, 0, 1, 4) line += 1 + self.options_layout.addWidget(self.use_series_index_template_checkbox, line, 0, 1, 2) + self.options_layout.addWidget(self.series_index_template_edit, line, 2, 1, 2) + line += 1 self.options_layout.addWidget(self.update_core_metadata_checkbox, line, 0, 1, 4) line += 1 self.options_layout.addWidget(self.update_subtitle_checkbox, line, 0, 1, 2) @@ -990,12 +1021,17 @@ class MetadataGroupBox(DeviceOptionsGroupBox): self.update_core_metadata_checkbox_clicked(device.get_pref('update_core_metadata')) self.update_subtitle_checkbox_clicked(device.get_pref('update_subtitle')) self.update_bookstats_checkbox_clicked(device.get_pref('update_bookstats')) + self.use_series_index_template_checkbox.clicked.connect(self.use_series_index_template_checkbox_clicked) + self.use_series_index_template_checkbox_clicked(device.get_pref('use_series_index_template')) def update_series_checkbox_clicked(self, checked): self.force_series_id_checkbox.setEnabled(checked) if not checked: self.force_series_id_checkbox.setChecked(False) + def use_series_index_template_checkbox_clicked(self, checked): + self.series_index_template_edit.setEnabled(checked) + def update_core_metadata_checkbox_clicked(self, checked): self.update_series_checkbox.setEnabled(not checked) self.force_series_id_checkbox.setEnabled(self.update_series) @@ -1043,6 +1079,14 @@ class MetadataGroupBox(DeviceOptionsGroupBox): def force_series_id(self): return self.update_series and self.force_series_id_checkbox.isChecked() + @property + def use_series_index_template(self): + return self.use_series_index_template_checkbox.isChecked() + + @property + def series_index_template(self): + return self.series_index_template_edit.template + @property def update_core_metadata(self): return self.update_core_metadata_checkbox.isChecked()