mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
EPUB/MOBI Catalogs: Allow saving used settings as presets which can be loaded easily later. Fixes #1155587 ([EHANCEMENT] Save named catalog parameters)
This commit is contained in:
commit
9d90ba326d
@ -12,20 +12,22 @@ from functools import partial
|
||||
|
||||
from calibre.ebooks.conversion.config import load_defaults
|
||||
from calibre.gui2 import gprefs, open_url, question_dialog
|
||||
from calibre.utils.config import JSONConfig
|
||||
from calibre.utils.icu import sort_key
|
||||
|
||||
from catalog_epub_mobi_ui import Ui_Form
|
||||
from PyQt4 import QtGui
|
||||
from PyQt4.Qt import (Qt, QAbstractItemView, QCheckBox, QComboBox,
|
||||
QDoubleSpinBox, QIcon, QLineEdit, QObject, QRadioButton, QSize, QSizePolicy,
|
||||
QTableWidget, QTableWidgetItem, QTextEdit, QToolButton, QUrl,
|
||||
QVBoxLayout, QWidget,
|
||||
QDoubleSpinBox, QIcon, QInputDialog, QLineEdit, QObject, QRadioButton,
|
||||
QSize, QSizePolicy, QTableWidget, QTableWidgetItem, QTextEdit, QToolButton,
|
||||
QUrl, QVBoxLayout, QWidget,
|
||||
SIGNAL)
|
||||
|
||||
class PluginWidget(QWidget,Ui_Form):
|
||||
|
||||
TITLE = _('E-book options')
|
||||
HELP = _('Options specific to')+' AZW3/EPUB/MOBI '+_('output')
|
||||
DEBUG = False
|
||||
DEBUG = True
|
||||
|
||||
# Output synced to the connected device?
|
||||
sync_enabled = True
|
||||
@ -212,8 +214,8 @@ class PluginWidget(QWidget,Ui_Form):
|
||||
else:
|
||||
results = _truncated_results(excluded_tags)
|
||||
finally:
|
||||
if self.DEBUG:
|
||||
print(results)
|
||||
if False and self.DEBUG:
|
||||
print("exclude_genre_changed(): %s" % results)
|
||||
self.exclude_genre_results.clear()
|
||||
self.exclude_genre_results.setText(results)
|
||||
|
||||
@ -239,11 +241,11 @@ class PluginWidget(QWidget,Ui_Form):
|
||||
Toggle Description-related controls
|
||||
'''
|
||||
self.header_note_source_field.setEnabled(enabled)
|
||||
self.thumb_width.setEnabled(enabled)
|
||||
self.merge_source_field.setEnabled(enabled)
|
||||
self.merge_before.setEnabled(enabled)
|
||||
self.merge_after.setEnabled(enabled)
|
||||
self.include_hr.setEnabled(enabled)
|
||||
self.merge_after.setEnabled(enabled)
|
||||
self.merge_before.setEnabled(enabled)
|
||||
self.merge_source_field.setEnabled(enabled)
|
||||
self.thumb_width.setEnabled(enabled)
|
||||
|
||||
def generate_genres_changed(self, enabled):
|
||||
'''
|
||||
@ -263,6 +265,22 @@ class PluginWidget(QWidget,Ui_Form):
|
||||
self.genre_source_field_name = genre_source_spec['field']
|
||||
self.exclude_genre_changed()
|
||||
|
||||
def get_format_and_title(self):
|
||||
current_format = None
|
||||
current_title = None
|
||||
self.parentWidget().blockSignals(True)
|
||||
for peer in self.parentWidget().children():
|
||||
if peer == self:
|
||||
continue
|
||||
elif peer.children():
|
||||
for child in peer.children():
|
||||
if child.objectName() == 'format':
|
||||
current_format = str(child.currentText()).strip()
|
||||
elif child.objectName() == 'title':
|
||||
current_title = str(child.text()).strip()
|
||||
self.parentWidget().blockSignals(False)
|
||||
return current_format, current_title
|
||||
|
||||
def header_note_source_field_changed(self,new_index):
|
||||
'''
|
||||
Process changes in the header_note_source_field combo box
|
||||
@ -374,15 +392,20 @@ class PluginWidget(QWidget,Ui_Form):
|
||||
|
||||
# Initialize exclusion rules
|
||||
self.exclusion_rules_table = ExclusionRules(self.exclusion_rules_gb,
|
||||
"exclusion_rules_tw",exclusion_rules, self.eligible_custom_fields,self.db)
|
||||
"exclusion_rules_tw", exclusion_rules, self.eligible_custom_fields, self.db)
|
||||
|
||||
# Initialize prefix rules
|
||||
self.prefix_rules_table = PrefixRules(self.prefix_rules_gb,
|
||||
"prefix_rules_tw",prefix_rules, self.eligible_custom_fields,self.db)
|
||||
"prefix_rules_tw", prefix_rules, self.eligible_custom_fields, self.db)
|
||||
|
||||
# Initialize excluded genres preview
|
||||
self.exclude_genre_changed()
|
||||
|
||||
# Hook Preset signals
|
||||
self.preset_delete_pb.clicked.connect(self.preset_remove)
|
||||
self.preset_save_pb.clicked.connect(self.preset_save)
|
||||
self.preset_field.currentIndexChanged[str].connect(self.preset_change)
|
||||
|
||||
def merge_source_field_changed(self,new_index):
|
||||
'''
|
||||
Process changes in the merge_source_field combo box
|
||||
@ -404,10 +427,12 @@ class PluginWidget(QWidget,Ui_Form):
|
||||
self.include_hr.setEnabled(False)
|
||||
|
||||
def options(self):
|
||||
# Save/return the current options
|
||||
# exclude_genre stores literally
|
||||
# Section switches store as True/False
|
||||
# others store as lists
|
||||
'''
|
||||
Return, optionally save current options
|
||||
exclude_genre stores literally
|
||||
Section switches store as True/False
|
||||
others store as lists
|
||||
'''
|
||||
|
||||
opts_dict = {}
|
||||
prefix_rules_processed = False
|
||||
@ -469,7 +494,7 @@ class PluginWidget(QWidget,Ui_Form):
|
||||
except:
|
||||
opts_dict['output_profile'] = ['default']
|
||||
|
||||
if self.DEBUG:
|
||||
if False and self.DEBUG:
|
||||
print "opts_dict"
|
||||
for opt in sorted(opts_dict.keys(), key=sort_key):
|
||||
print " %s: %s" % (opt, repr(opts_dict[opt]))
|
||||
@ -544,6 +569,213 @@ class PluginWidget(QWidget,Ui_Form):
|
||||
self.genre_source_fields = custom_fields
|
||||
self.genre_source_field.currentIndexChanged.connect(self.genre_source_field_changed)
|
||||
|
||||
# Populate the Presets combo box
|
||||
self.presets = JSONConfig("catalog_presets")
|
||||
self.preset_field.addItem("")
|
||||
self.preset_field_values = sorted([p for p in self.presets], key=sort_key)
|
||||
self.preset_field.addItems(self.preset_field_values)
|
||||
|
||||
def preset_change(self, item_name):
|
||||
'''
|
||||
Update catalog options from current preset
|
||||
'''
|
||||
if not item_name:
|
||||
return
|
||||
|
||||
current_preset = str(self.preset_field.currentText())
|
||||
options = self.presets[current_preset]
|
||||
|
||||
exclusion_rules = []
|
||||
prefix_rules = []
|
||||
for opt in self.OPTION_FIELDS:
|
||||
c_name, c_def, c_type = opt
|
||||
if c_name == 'preset_field':
|
||||
continue
|
||||
# Ignore extra entries in options for cli invocation
|
||||
if c_name in options:
|
||||
opt_value = options[c_name]
|
||||
else:
|
||||
continue
|
||||
if c_type in ['check_box']:
|
||||
getattr(self, c_name).setChecked(eval(str(opt_value)))
|
||||
if c_name == 'generate_genres':
|
||||
self.genre_source_field.setEnabled(eval(str(opt_value)))
|
||||
elif c_type in ['combo_box']:
|
||||
if opt_value is None:
|
||||
index = 0
|
||||
if c_name == 'genre_source_field':
|
||||
index = self.genre_source_field.findText(_('Tags'))
|
||||
else:
|
||||
index = getattr(self,c_name).findText(opt_value)
|
||||
if index == -1:
|
||||
if c_name == 'read_source_field':
|
||||
index = self.read_source_field.findText(_('Tags'))
|
||||
elif c_name == 'genre_source_field':
|
||||
index = self.genre_source_field.findText(_('Tags'))
|
||||
getattr(self,c_name).setCurrentIndex(index)
|
||||
elif c_type in ['line_edit']:
|
||||
getattr(self, c_name).setText(opt_value if opt_value else '')
|
||||
elif c_type in ['radio_button'] and opt_value is not None:
|
||||
getattr(self, c_name).setChecked(opt_value)
|
||||
elif c_type in ['spin_box']:
|
||||
getattr(self, c_name).setValue(float(opt_value))
|
||||
if c_type == 'table_widget':
|
||||
if c_name == 'exclusion_rules_tw':
|
||||
if opt_value not in exclusion_rules:
|
||||
exclusion_rules.append(opt_value)
|
||||
if c_name == 'prefix_rules_tw':
|
||||
if opt_value not in prefix_rules:
|
||||
prefix_rules.append(opt_value)
|
||||
|
||||
# Reset exclusion rules
|
||||
self.exclusion_rules_table.clearLayout()
|
||||
self.exclusion_rules_table = ExclusionRules(self.exclusion_rules_gb,
|
||||
"exclusion_rules_tw", exclusion_rules, self.eligible_custom_fields, self.db)
|
||||
|
||||
# Reset prefix rules
|
||||
self.prefix_rules_table.clearLayout()
|
||||
self.prefix_rules_table = PrefixRules(self.prefix_rules_gb,
|
||||
"prefix_rules_tw", prefix_rules, self.eligible_custom_fields, self.db)
|
||||
|
||||
# Reset excluded genres preview
|
||||
self.exclude_genre_changed()
|
||||
|
||||
# Reset format and title
|
||||
format = options['format']
|
||||
title = options['catalog_title']
|
||||
self.set_format_and_title(format, title)
|
||||
|
||||
def preset_remove(self):
|
||||
if self.preset_field.currentIndex() == 0:
|
||||
return
|
||||
|
||||
if not question_dialog(self, _("Delete saved catalog preset"),
|
||||
_("The selected saved catalog preset will be deleted. "
|
||||
"Are you sure?")):
|
||||
return
|
||||
|
||||
item_id = self.preset_field.currentIndex()
|
||||
item_name = unicode(self.preset_field.currentText())
|
||||
|
||||
self.preset_field.blockSignals(True)
|
||||
self.preset_field.removeItem(item_id)
|
||||
self.preset_field.blockSignals(False)
|
||||
self.preset_field.setCurrentIndex(0)
|
||||
|
||||
if item_name in self.presets.keys():
|
||||
del(self.presets[item_name])
|
||||
self.presets.commit()
|
||||
|
||||
def preset_save(self):
|
||||
names = ['']
|
||||
names.extend(self.preset_field_values)
|
||||
try:
|
||||
dex = names.index(self.preset_search_name)
|
||||
except:
|
||||
dex = 0
|
||||
name = ''
|
||||
while not name:
|
||||
name, ok = QInputDialog.getItem(self, _('Save catalog preset'),
|
||||
_('Preset name:'), names, dex, True)
|
||||
if not ok:
|
||||
return
|
||||
if not name:
|
||||
error_dialog(self, _("Save catalog preset"),
|
||||
_("You must provide a name."), show=True)
|
||||
new = True
|
||||
name = unicode(name)
|
||||
if name in self.presets.keys():
|
||||
if not question_dialog(self, _("Save catalog preset"),
|
||||
_("That saved preset already exists and will be overwritten. "
|
||||
"Are you sure?")):
|
||||
return
|
||||
new = False
|
||||
|
||||
preset = {}
|
||||
prefix_rules_processed = False
|
||||
exclusion_rules_processed = False
|
||||
|
||||
for opt in self.OPTION_FIELDS:
|
||||
c_name, c_def, c_type = opt
|
||||
if c_name == 'exclusion_rules_tw' and exclusion_rules_processed:
|
||||
continue
|
||||
if c_name == 'prefix_rules_tw' and prefix_rules_processed:
|
||||
continue
|
||||
|
||||
if c_type in ['check_box', 'radio_button']:
|
||||
opt_value = getattr(self, c_name).isChecked()
|
||||
elif c_type in ['combo_box']:
|
||||
if c_name == 'preset_field':
|
||||
continue
|
||||
opt_value = unicode(getattr(self,c_name).currentText()).strip()
|
||||
elif c_type in ['line_edit']:
|
||||
opt_value = unicode(getattr(self, c_name).text()).strip()
|
||||
elif c_type in ['spin_box']:
|
||||
opt_value = unicode(getattr(self, c_name).value())
|
||||
elif c_type in ['table_widget']:
|
||||
if c_name == 'prefix_rules_tw':
|
||||
opt_value = self.prefix_rules_table.get_data()
|
||||
prefix_rules_processed = True
|
||||
if c_name == 'exclusion_rules_tw':
|
||||
opt_value = self.exclusion_rules_table.get_data()
|
||||
exclusion_rules_processed = True
|
||||
|
||||
preset[c_name] = opt_value
|
||||
# Construct cli version of table rules
|
||||
if c_name in ['exclusion_rules_tw','prefix_rules_tw']:
|
||||
self.construct_tw_opts_object(c_name, opt_value, preset)
|
||||
|
||||
format, title = self.get_format_and_title()
|
||||
preset['format'] = format
|
||||
preset['catalog_title'] = title
|
||||
|
||||
# Additional items needed for cli invocation
|
||||
# Generate specs for merge_comments, header_note_source_field, genre_source_field
|
||||
checked = ''
|
||||
if self.merge_before.isChecked():
|
||||
checked = 'before'
|
||||
elif self.merge_after.isChecked():
|
||||
checked = 'after'
|
||||
include_hr = self.include_hr.isChecked()
|
||||
preset['merge_comments_rule'] = "%s:%s:%s" % \
|
||||
(self.merge_source_field_name, checked, include_hr)
|
||||
|
||||
preset['header_note_source_field'] = self.header_note_source_field_name
|
||||
|
||||
preset['genre_source_field'] = self.genre_source_field_name
|
||||
|
||||
# Append the current output profile
|
||||
try:
|
||||
preset['output_profile'] = load_defaults('page_setup')['output_profile']
|
||||
except:
|
||||
preset['output_profile'] = 'default'
|
||||
|
||||
self.presets[name] = preset
|
||||
self.presets.commit()
|
||||
|
||||
if new:
|
||||
self.preset_field.blockSignals(True)
|
||||
self.preset_field.clear()
|
||||
self.preset_field.addItem('')
|
||||
self.preset_field_values = sorted([q for q in self.presets], key=sort_key)
|
||||
self.preset_field.addItems(self.preset_field_values)
|
||||
self.preset_field.blockSignals(False)
|
||||
self.preset_field.setCurrentIndex(self.preset_field.findText(name))
|
||||
|
||||
def set_format_and_title(self, format, title):
|
||||
for peer in self.parentWidget().children():
|
||||
if peer == self:
|
||||
continue
|
||||
elif peer.children():
|
||||
for child in peer.children():
|
||||
if child.objectName() == 'format':
|
||||
index = child.findText(format)
|
||||
child.blockSignals(True)
|
||||
child.setCurrentIndex(index)
|
||||
child.blockSignals(False)
|
||||
elif child.objectName() == 'title':
|
||||
child.setText(title)
|
||||
|
||||
def show_help(self):
|
||||
'''
|
||||
Display help file
|
||||
@ -631,6 +863,7 @@ class GenericRulesTable(QTableWidget):
|
||||
self.last_row_selected = self.currentRow()
|
||||
self.last_rows_selected = self.selectionModel().selectedRows()
|
||||
|
||||
# Add the controls
|
||||
self._init_controls()
|
||||
|
||||
# Hook check_box changes
|
||||
@ -681,6 +914,21 @@ class GenericRulesTable(QTableWidget):
|
||||
# In case table was empty
|
||||
self.horizontalHeader().setStretchLastSection(True)
|
||||
|
||||
def clearLayout(self):
|
||||
if self.layout is not None:
|
||||
old_layout = self.layout
|
||||
|
||||
for child in old_layout.children():
|
||||
for i in reversed(range(child.count())):
|
||||
if child.itemAt(i).widget() is not None:
|
||||
child.itemAt(i).widget().setParent(None)
|
||||
import sip
|
||||
sip.delete(child)
|
||||
|
||||
for i in reversed(range(old_layout.count())):
|
||||
if old_layout.itemAt(i).widget() is not None:
|
||||
old_layout.itemAt(i).widget().setParent(None)
|
||||
|
||||
def delete_row(self):
|
||||
if self.DEBUG:
|
||||
print("%s:delete_row()" % self.objectName())
|
||||
|
@ -20,6 +20,54 @@
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="catalogPresets">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Presets</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_9">
|
||||
<item>
|
||||
<widget class="QComboBox" name="preset_field">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Select catalog preset to load</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="preset_save_pb">
|
||||
<property name="toolTip">
|
||||
<string>Save current catalog settings as preset</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Save</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="preset_delete_pb">
|
||||
<property name="toolTip">
|
||||
<string>Delete current preset</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Delete</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="includedSections">
|
||||
<property name="sizePolicy">
|
||||
@ -46,6 +94,9 @@
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>List of books, sorted by Author</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Authors</string>
|
||||
</property>
|
||||
@ -54,15 +105,21 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="generate_titles">
|
||||
<property name="toolTip">
|
||||
<string>List of books, sorted by Title</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Titles</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="generate_series">
|
||||
<property name="toolTip">
|
||||
<string>List of series books, sorted by Series</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Series</string>
|
||||
</property>
|
||||
@ -72,6 +129,9 @@
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="generate_genres">
|
||||
<property name="toolTip">
|
||||
<string>List of books, sorted by Genre</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Genres</string>
|
||||
</property>
|
||||
@ -80,13 +140,13 @@
|
||||
<item>
|
||||
<widget class="QComboBox" name="genre_source_field">
|
||||
<property name="toolTip">
|
||||
<string>Field containing Genre information</string>
|
||||
<string>Field containing Genres</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<item row="2" column="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="generate_recently_added">
|
||||
@ -96,6 +156,9 @@
|
||||
<height>26</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>List of books, sorted by date added to calibre</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Recently Added</string>
|
||||
</property>
|
||||
@ -103,7 +166,7 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<item row="4" column="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="generate_descriptions">
|
||||
@ -113,6 +176,9 @@
|
||||
<height>26</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Individual descriptions of books with cover thumbs, sorted by author</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Descriptions</string>
|
||||
</property>
|
||||
@ -120,6 +186,41 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="1" rowspan="5">
|
||||
<widget class="Line" name="line_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="Line" name="line_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="Line" name="line_6">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="Line" name="line_7">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="Line" name="line_8">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@ -347,7 +448,7 @@ The default pattern \[.+\]|\+ excludes tags of the form [tag], e.g., [Test book]
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Custom column containing additional content to be merged with Comments metadata.</string>
|
||||
<string>Custom column containing additional content to be merged with Comments metadata in Descriptions section.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -361,7 +462,7 @@ The default pattern \[.+\]|\+ excludes tags of the form [tag], e.g., [Test book]
|
||||
<item>
|
||||
<widget class="QRadioButton" name="merge_before">
|
||||
<property name="toolTip">
|
||||
<string>Merge additional content before Comments metadata.</string>
|
||||
<string>Merge additional content before Comments in Descriptions section.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Before</string>
|
||||
@ -374,7 +475,7 @@ The default pattern \[.+\]|\+ excludes tags of the form [tag], e.g., [Test book]
|
||||
<item>
|
||||
<widget class="QRadioButton" name="merge_after">
|
||||
<property name="toolTip">
|
||||
<string>Merge additional content after Comments metadata.</string>
|
||||
<string>Merge additional content after Comments in Descriptions section.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&After</string>
|
||||
@ -394,7 +495,7 @@ The default pattern \[.+\]|\+ excludes tags of the form [tag], e.g., [Test book]
|
||||
<item>
|
||||
<widget class="QCheckBox" name="include_hr">
|
||||
<property name="toolTip">
|
||||
<string>Separate Comments metadata and additional content with a horizontal rule.</string>
|
||||
<string>Separate Comments metadata and additional content with a horizontal rule in Descriptions section.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Include &Separator</string>
|
||||
@ -514,7 +615,7 @@ The default pattern \[.+\]|\+ excludes tags of the form [tag], e.g., [Test book]
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Custom column source for text to include in Description section.</string>
|
||||
<string>Custom column source for text to include in Descriptions section.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -11,17 +11,18 @@ import os
|
||||
from collections import namedtuple
|
||||
|
||||
from calibre import strftime
|
||||
from calibre.constants import config_dir
|
||||
from calibre.customize import CatalogPlugin
|
||||
from calibre.customize.conversion import OptionRecommendation, DummyReporter
|
||||
from calibre.ebooks import calibre_cover
|
||||
from calibre.library import current_library_name
|
||||
from calibre.library.catalogs import AuthorSortMismatchException, EmptyCatalogException
|
||||
from calibre.ptempfile import PersistentTemporaryFile
|
||||
from calibre.utils.config import JSONConfig
|
||||
from calibre.utils.localization import calibre_langcode_to_name, canonicalize_lang, get_lang
|
||||
|
||||
Option = namedtuple('Option', 'option, default, dest, action, help')
|
||||
|
||||
|
||||
class EPUB_MOBI(CatalogPlugin):
|
||||
'ePub catalog generator'
|
||||
|
||||
@ -162,6 +163,14 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
"When multiple rules are defined, the first matching rule will be used.\n"
|
||||
"Default:\n" + '"' + '%default' + '"' + "\n"
|
||||
"Applies to AZW3, ePub, MOBI output formats")),
|
||||
Option('--preset',
|
||||
default=None,
|
||||
dest='preset',
|
||||
action=None,
|
||||
help=_("Use a named preset created with the GUI Catalog builder.\n"
|
||||
"A preset specifies all settings for building a catalog.\n"
|
||||
"Default: '%default'\n"
|
||||
"Applies to AZW3, ePub, MOBI output formats")),
|
||||
Option('--use-existing-cover',
|
||||
default=False,
|
||||
dest='use_existing_cover',
|
||||
@ -184,6 +193,43 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
from calibre.library.catalogs.epub_mobi_builder import CatalogBuilder
|
||||
from calibre.utils.logging import default_log as log
|
||||
|
||||
# If preset specified from the cli, insert stored options from JSON file
|
||||
if hasattr(opts, 'preset') and opts.preset:
|
||||
available_presets = JSONConfig("catalog_presets")
|
||||
if not opts.preset in available_presets:
|
||||
if available_presets:
|
||||
print(_('Error: Preset "%s" not found.' % opts.preset))
|
||||
print(_('Stored presets: %s' % ', '.join([p for p in sorted(available_presets.keys())])))
|
||||
else:
|
||||
print(_('Error: No stored presets.'))
|
||||
return 1
|
||||
|
||||
# Copy the relevant preset values to the opts object
|
||||
for item in available_presets[opts.preset]:
|
||||
if not item in ['exclusion_rules_tw', 'format', 'prefix_rules_tw']:
|
||||
setattr(opts, item, available_presets[opts.preset][item])
|
||||
|
||||
# Provide an unconnected device
|
||||
opts.connected_device = {
|
||||
'is_device_connected': False,
|
||||
'kind': None,
|
||||
'name': None,
|
||||
'save_template': None,
|
||||
'serial': None,
|
||||
'storage': None,
|
||||
}
|
||||
|
||||
# Convert prefix_rules and exclusion_rules from JSON lists to tuples
|
||||
prs = []
|
||||
for rule in opts.prefix_rules:
|
||||
prs.append(tuple(rule))
|
||||
opts.prefix_rules = tuple(prs)
|
||||
|
||||
ers = []
|
||||
for rule in opts.exclusion_rules:
|
||||
ers.append(tuple(rule))
|
||||
opts.exclusion_rules = tuple(ers)
|
||||
|
||||
opts.log = log
|
||||
opts.fmt = self.fmt = path_to_output.rpartition('.')[2]
|
||||
|
||||
@ -329,15 +375,14 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
log.error("incorrect number of args for --exclusion-rules: %s" % repr(rule))
|
||||
|
||||
# Display opts
|
||||
keys = opts_dict.keys()
|
||||
keys.sort()
|
||||
keys = sorted(opts_dict.keys())
|
||||
build_log.append(" opts:")
|
||||
for key in keys:
|
||||
if key in ['catalog_title', 'author_clip', 'connected_kindle', 'creator',
|
||||
'cross_reference_authors', 'description_clip', 'exclude_book_marker',
|
||||
'exclude_genre', 'exclude_tags', 'exclusion_rules', 'fmt',
|
||||
'genre_source_field', 'header_note_source_field', 'merge_comments_rule',
|
||||
'output_profile', 'prefix_rules', 'read_book_marker',
|
||||
'output_profile', 'prefix_rules', 'preset', 'read_book_marker',
|
||||
'search_text', 'sort_by', 'sort_descriptions_by_author', 'sync',
|
||||
'thumb_width', 'use_existing_cover', 'wishlist_tag']:
|
||||
build_log.append(" %s: %s" % (key, repr(opts_dict[key])))
|
||||
|
@ -1277,7 +1277,6 @@ class CatalogBuilder(object):
|
||||
self.opts.log.info('%s' % _format_tag_list(genre_tags_dict, header="enabled genres"))
|
||||
self.opts.log.info('%s' % _format_tag_list(excluded_tags, header="excluded genres"))
|
||||
|
||||
print("genre_tags_dict: %s" % genre_tags_dict)
|
||||
return genre_tags_dict
|
||||
|
||||
def filter_excluded_genres(self, tags, regex):
|
||||
|
Loading…
x
Reference in New Issue
Block a user