mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Fix #1044619 (When connected to itunes and set to device won't sort by author) and add a link ot the catalog help in the catalog dialog
This commit is contained in:
commit
36939fbfe0
@ -13,7 +13,8 @@ from calibre.constants import isosx, iswindows
|
||||
from calibre.devices.errors import OpenFeedback, UserFeedback
|
||||
from calibre.devices.usbms.deviceconfig import DeviceConfig
|
||||
from calibre.devices.interface import DevicePlugin
|
||||
from calibre.ebooks.metadata import authors_to_string, MetaInformation, title_sort
|
||||
from calibre.ebooks.metadata import (author_to_author_sort, authors_to_string,
|
||||
MetaInformation, title_sort)
|
||||
from calibre.ebooks.metadata.book.base import Metadata
|
||||
from calibre.utils.config import config_dir, dynamic, prefs
|
||||
from calibre.utils.date import now, parse_date
|
||||
@ -3478,6 +3479,7 @@ class Book(Metadata):
|
||||
'''
|
||||
def __init__(self,title,author):
|
||||
Metadata.__init__(self, title, authors=author.split(' & '))
|
||||
self.author_sort = author_to_author_sort(author)
|
||||
|
||||
@property
|
||||
def title_sorter(self):
|
||||
|
@ -67,7 +67,7 @@ class GenerateCatalogAction(InterfaceAction):
|
||||
# jobs.results is a list - the first entry is the intended title for the dialog
|
||||
# Subsequent strings are error messages
|
||||
dialog_title = job.result.pop(0)
|
||||
if re.match('warning:', job.result[0].lower()):
|
||||
if re.search('warning', job.result[0].lower()):
|
||||
msg = _("Catalog generation complete, with warnings.")
|
||||
warning_dialog(self.gui, dialog_title, msg, det_msg='\n'.join(job.result), show=True)
|
||||
else:
|
||||
|
@ -6,17 +6,19 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
from copy import copy
|
||||
import re, sys
|
||||
|
||||
from functools import partial
|
||||
|
||||
from calibre.ebooks.conversion.config import load_defaults
|
||||
from calibre.gui2 import gprefs, question_dialog
|
||||
from calibre.gui2 import gprefs, open_url, question_dialog
|
||||
from calibre.utils.icu import sort_key
|
||||
|
||||
from catalog_epub_mobi_ui import Ui_Form
|
||||
from PyQt4.Qt import (Qt, QAbstractItemView, QCheckBox, QComboBox,
|
||||
QDoubleSpinBox, QIcon, QLineEdit, QObject, QRadioButton, QSize, QSizePolicy,
|
||||
QTableWidget, QTableWidgetItem, QToolButton, QVBoxLayout, QWidget,
|
||||
QTableWidget, QTableWidgetItem, QTextEdit, QToolButton, QUrl,
|
||||
QVBoxLayout, QWidget,
|
||||
SIGNAL)
|
||||
|
||||
class PluginWidget(QWidget,Ui_Form):
|
||||
@ -44,6 +46,7 @@ class PluginWidget(QWidget,Ui_Form):
|
||||
LineEditControls = []
|
||||
RadioButtonControls = []
|
||||
TableWidgetControls = []
|
||||
TextEditControls = []
|
||||
|
||||
for item in self.__dict__:
|
||||
if type(self.__dict__[item]) is QCheckBox:
|
||||
@ -58,6 +61,8 @@ class PluginWidget(QWidget,Ui_Form):
|
||||
RadioButtonControls.append(str(self.__dict__[item].objectName()))
|
||||
elif type(self.__dict__[item]) is QTableWidget:
|
||||
TableWidgetControls.append(str(self.__dict__[item].objectName()))
|
||||
elif type(self.__dict__[item]) is QTextEdit:
|
||||
TextEditControls.append(str(self.__dict__[item].objectName()))
|
||||
|
||||
option_fields = zip(CheckBoxControls,
|
||||
[True for i in CheckBoxControls],
|
||||
@ -72,20 +77,23 @@ class PluginWidget(QWidget,Ui_Form):
|
||||
# LineEditControls
|
||||
option_fields += zip(['exclude_genre'],['\[.+\]|\+'],['line_edit'])
|
||||
|
||||
# TextEditControls
|
||||
#option_fields += zip(['exclude_genre_results'],['excluded genres will appear here'],['text_edit'])
|
||||
|
||||
# SpinBoxControls
|
||||
option_fields += zip(['thumb_width'],[1.00],['spin_box'])
|
||||
|
||||
# Exclusion rules
|
||||
option_fields += zip(['exclusion_rules_tw','exclusion_rules_tw'],
|
||||
option_fields += zip(['exclusion_rules_tw'],
|
||||
[{'ordinal':0,
|
||||
'enabled':True,
|
||||
'name':'Catalogs',
|
||||
'field':'Tags',
|
||||
'pattern':'Catalog'},],
|
||||
['table_widget','table_widget'])
|
||||
['table_widget'])
|
||||
|
||||
# Prefix rules
|
||||
option_fields += zip(['prefix_rules_tw','prefix_rules_tw','prefix_rules_tw'],
|
||||
option_fields += zip(['prefix_rules_tw','prefix_rules_tw'],
|
||||
[{'ordinal':0,
|
||||
'enabled':True,
|
||||
'name':'Read book',
|
||||
@ -98,7 +106,7 @@ class PluginWidget(QWidget,Ui_Form):
|
||||
'field':'Tags',
|
||||
'pattern':'Wishlist',
|
||||
'prefix':u'\u00d7'},],
|
||||
['table_widget','table_widget','table_widget'])
|
||||
['table_widget','table_widget'])
|
||||
|
||||
self.OPTION_FIELDS = option_fields
|
||||
|
||||
@ -110,13 +118,13 @@ class PluginWidget(QWidget,Ui_Form):
|
||||
'''
|
||||
rule_set = []
|
||||
for stored_rule in opt_value:
|
||||
rule = copy(stored_rule)
|
||||
rule = stored_rule.copy()
|
||||
# Skip disabled and incomplete rules
|
||||
if not rule['enabled']:
|
||||
continue
|
||||
elif not rule['field'] or not rule['pattern']:
|
||||
continue
|
||||
elif 'prefix' in rule and not rule['prefix']:
|
||||
elif 'prefix' in rule and rule['prefix'] is None:
|
||||
continue
|
||||
else:
|
||||
if rule['field'] != 'Tags':
|
||||
@ -130,12 +138,58 @@ class PluginWidget(QWidget,Ui_Form):
|
||||
pr = (rule['name'],rule['field'],rule['pattern'],rule['prefix'])
|
||||
else:
|
||||
pr = (rule['name'],rule['field'],rule['pattern'])
|
||||
|
||||
rule_set.append(pr)
|
||||
opt_value = tuple(rule_set)
|
||||
# Strip off the trailing '_tw'
|
||||
opts_dict[c_name[:-3]] = opt_value
|
||||
|
||||
def fetchEligibleCustomFields(self):
|
||||
def exclude_genre_changed(self, regex):
|
||||
""" Dynamically compute excluded genres.
|
||||
|
||||
Run exclude_genre regex against db.all_tags() to show excluded tags.
|
||||
PROVISIONAL CODE, NEEDS TESTING
|
||||
|
||||
Args:
|
||||
regex (QLineEdit.text()): regex to compile, compute
|
||||
|
||||
Output:
|
||||
self.exclude_genre_results (QLabel): updated to show tags to be excluded as genres
|
||||
"""
|
||||
results = _('No genres will be excluded')
|
||||
if not regex:
|
||||
self.exclude_genre_results.clear()
|
||||
self.exclude_genre_results.setText(results)
|
||||
return
|
||||
|
||||
try:
|
||||
pattern = re.compile((str(regex)))
|
||||
except:
|
||||
results = _("regex error: %s") % sys.exc_info()[1]
|
||||
else:
|
||||
excluded_tags = []
|
||||
for tag in self.all_tags:
|
||||
hit = pattern.search(tag)
|
||||
if hit:
|
||||
excluded_tags.append(hit.string)
|
||||
if excluded_tags:
|
||||
if set(excluded_tags) == set(self.all_tags):
|
||||
results = _("All genres will be excluded")
|
||||
else:
|
||||
results = ', '.join(sorted(excluded_tags))
|
||||
finally:
|
||||
if self.DEBUG:
|
||||
print(results)
|
||||
self.exclude_genre_results.clear()
|
||||
self.exclude_genre_results.setText(results)
|
||||
|
||||
def exclude_genre_reset(self):
|
||||
for default in self.OPTION_FIELDS:
|
||||
if default[0] == 'exclude_genre':
|
||||
self.exclude_genre.setText(default[1])
|
||||
break
|
||||
|
||||
def fetch_eligible_custom_fields(self):
|
||||
self.all_custom_fields = self.db.custom_field_keys()
|
||||
custom_fields = {}
|
||||
custom_fields['Tags'] = {'field':'tag', 'datatype':u'text'}
|
||||
@ -146,28 +200,42 @@ class PluginWidget(QWidget,Ui_Form):
|
||||
'datatype':field_md['datatype']}
|
||||
self.eligible_custom_fields = custom_fields
|
||||
|
||||
def generate_descriptions_changed(self, enabled):
|
||||
'''
|
||||
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)
|
||||
|
||||
def initialize(self, name, db):
|
||||
'''
|
||||
|
||||
CheckBoxControls (c_type: check_box):
|
||||
['generate_titles','generate_series','generate_genres',
|
||||
'generate_recently_added','generate_descriptions','include_hr']
|
||||
'generate_recently_added','generate_descriptions','include_hr']
|
||||
ComboBoxControls (c_type: combo_box):
|
||||
['exclude_source_field','header_note_source_field',
|
||||
'merge_source_field']
|
||||
'merge_source_field']
|
||||
LineEditControls (c_type: line_edit):
|
||||
['exclude_genre']
|
||||
RadioButtonControls (c_type: radio_button):
|
||||
['merge_before','merge_after']
|
||||
['merge_before','merge_after','generate_new_cover', 'use_existing_cover']
|
||||
SpinBoxControls (c_type: spin_box):
|
||||
['thumb_width']
|
||||
TableWidgetControls (c_type: table_widget):
|
||||
['exclusion_rules_tw','prefix_rules_tw']
|
||||
TextEditControls (c_type: text_edit):
|
||||
['exclude_genre_results']
|
||||
|
||||
'''
|
||||
self.name = name
|
||||
self.db = db
|
||||
self.fetchEligibleCustomFields()
|
||||
self.all_tags = db.all_tags()
|
||||
self.fetch_eligible_custom_fields()
|
||||
self.populate_combo_boxes()
|
||||
|
||||
# Update dialog fields from stored options
|
||||
@ -200,9 +268,16 @@ class PluginWidget(QWidget,Ui_Form):
|
||||
if opt_value not in prefix_rules:
|
||||
prefix_rules.append(opt_value)
|
||||
|
||||
# Add icon to the reset button
|
||||
# Add icon to the reset button, hook textChanged signal
|
||||
self.reset_exclude_genres_tb.setIcon(QIcon(I('trash.png')))
|
||||
self.reset_exclude_genres_tb.clicked.connect(self.reset_exclude_genres)
|
||||
self.reset_exclude_genres_tb.clicked.connect(self.exclude_genre_reset)
|
||||
|
||||
# Hook textChanged event for exclude_genre QLineEdit
|
||||
self.exclude_genre.textChanged.connect(self.exclude_genre_changed)
|
||||
|
||||
# Hook Descriptions checkbox for related options, init
|
||||
self.generate_descriptions.clicked.connect(self.generate_descriptions_changed)
|
||||
self.generate_descriptions_changed(self.generate_descriptions.isChecked())
|
||||
|
||||
# Init self.merge_source_field_name
|
||||
self.merge_source_field_name = ''
|
||||
@ -226,6 +301,9 @@ class PluginWidget(QWidget,Ui_Form):
|
||||
self.prefix_rules_table = PrefixRules(self.prefix_rules_gb,
|
||||
"prefix_rules_tw",prefix_rules, self.eligible_custom_fields,self.db)
|
||||
|
||||
# Initialize excluded genres preview
|
||||
self.exclude_genre_changed(unicode(getattr(self, 'exclude_genre').text()).strip())
|
||||
|
||||
def options(self):
|
||||
# Save/return the current options
|
||||
# exclude_genre stores literally
|
||||
@ -275,16 +353,21 @@ class PluginWidget(QWidget,Ui_Form):
|
||||
elif self.merge_after.isChecked():
|
||||
checked = 'after'
|
||||
include_hr = self.include_hr.isChecked()
|
||||
opts_dict['merge_comments'] = "%s:%s:%s" % \
|
||||
opts_dict['merge_comments_rule'] = "%s:%s:%s" % \
|
||||
(self.merge_source_field_name, checked, include_hr)
|
||||
|
||||
opts_dict['header_note_source_field'] = self.header_note_source_field_name
|
||||
|
||||
# Fix up exclude_genre regex if blank. Assume blank = no exclusions
|
||||
if opts_dict['exclude_genre'] == '':
|
||||
opts_dict['exclude_genre'] = 'a^'
|
||||
|
||||
# Append the output profile
|
||||
try:
|
||||
opts_dict['output_profile'] = [load_defaults('page_setup')['output_profile']]
|
||||
except:
|
||||
opts_dict['output_profile'] = ['default']
|
||||
|
||||
if self.DEBUG:
|
||||
print "opts_dict"
|
||||
for opt in sorted(opts_dict.keys(), key=sort_key):
|
||||
@ -377,11 +460,11 @@ class PluginWidget(QWidget,Ui_Form):
|
||||
self.merge_after.setEnabled(False)
|
||||
self.include_hr.setEnabled(False)
|
||||
|
||||
def reset_exclude_genres(self):
|
||||
for default in self.OPTION_FIELDS:
|
||||
if default[0] == 'exclude_genre':
|
||||
self.exclude_genre.setText(default[1])
|
||||
break
|
||||
def show_help(self):
|
||||
'''
|
||||
Display help file
|
||||
'''
|
||||
open_url(QUrl('http://manual.calibre-ebook.com/catalogs.html'))
|
||||
|
||||
class CheckableTableWidgetItem(QTableWidgetItem):
|
||||
'''
|
||||
|
@ -6,7 +6,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>650</width>
|
||||
<width>658</width>
|
||||
<height>603</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -41,151 +41,74 @@
|
||||
<string>Included sections</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="generate_genres">
|
||||
<property name="text">
|
||||
<string>Books by &Genre</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QCheckBox" name="generate_recently_added">
|
||||
<property name="text">
|
||||
<string>Recently &Added</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QCheckBox" name="generate_descriptions">
|
||||
<property name="text">
|
||||
<string>&Descriptions</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QCheckBox" name="generate_series">
|
||||
<property name="text">
|
||||
<string>Books by &Series</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="generate_titles">
|
||||
<property name="text">
|
||||
<string>Books by &Title</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="generate_authors">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Books by Author</string>
|
||||
<string>&Authors</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QCheckBox" name="generate_titles">
|
||||
<property name="text">
|
||||
<string>&Titles</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QCheckBox" name="generate_series">
|
||||
<property name="text">
|
||||
<string>&Series</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="generate_genres">
|
||||
<property name="text">
|
||||
<string>&Genres</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<widget class="QCheckBox" name="generate_recently_added">
|
||||
<property name="text">
|
||||
<string>&Recently Added</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="3">
|
||||
<widget class="QCheckBox" name="generate_descriptions">
|
||||
<property name="text">
|
||||
<string>&Descriptions</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="excludedGenres">
|
||||
<widget class="QGroupBox" name="prefix_rules_gb">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>A regular expression describing genres to be excluded from the generated catalog. Genres are derived from the tags applied to your books.
|
||||
The default pattern \[.+\]|\+ excludes tags of the form [tag], e.g., [Test book], and '+', the default tag for a read book.</string>
|
||||
<string>The first matching prefix rule applies a prefix to book listings in the generated catalog.</string>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Excluded genres</string>
|
||||
<string>Prefixes</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_3">
|
||||
<property name="fieldGrowthPolicy">
|
||||
<enum>QFormLayout::FieldsStayAtSizeHint</enum>
|
||||
</property>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>-1</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>175</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Tags to &exclude</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::AutoText</enum>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>exclude_genre</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="exclude_genre">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string extracomment="Default: \[[\w]*\]"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="reset_exclude_genres_tb">
|
||||
<property name="toolTip">
|
||||
<string>Reset to default</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
@ -218,22 +141,148 @@ The default pattern \[.+\]|\+ excludes tags of the form [tag], e.g., [Test book]
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="prefix_rules_gb">
|
||||
<widget class="QGroupBox" name="excludedGenres">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>The first matching prefix rule applies a prefix to book listings in the generated catalog.</string>
|
||||
<string>A regular expression describing genres to be excluded from the generated catalog. Genres are derived from the tags applied to your books.
|
||||
The default pattern \[.+\]|\+ excludes tags of the form [tag], e.g., [Test book], and '+', the default tag for a read book.</string>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Prefixes</string>
|
||||
<string>Excluded genres</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6"/>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>175</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Tags to &exclude (regex):</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::AutoText</enum>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>exclude_genre</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="exclude_genre">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string extracomment="Default: \[[\w]*\]"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QToolButton" name="reset_exclude_genres_tb">
|
||||
<property name="toolTip">
|
||||
<string>Reset to default</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>175</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Results of regex:</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::AutoText</enum>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>exclude_genre</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="exclude_genre_results">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Tags that will be excluded as genres</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::PlainText</enum>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
@ -255,142 +304,9 @@ The default pattern \[.+\]|\+ excludes tags of the form [tag], e.g., [Test book]
|
||||
<property name="title">
|
||||
<string>Other options</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_4">
|
||||
<property name="fieldGrowthPolicy">
|
||||
<enum>QFormLayout::FieldsStayAtSizeHint</enum>
|
||||
</property>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>175</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Thumb width</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>merge_source_field</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="thumb_width">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>137</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Size hint for cover thumbnails included in Descriptions section.</string>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string> inch</string>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>2.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>&Extra note</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>header_note_source_field</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="header_note_source_field">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Custom column source for text to include in Description section.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>175</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Merge with Comments</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>merge_source_field</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="2" column="1">
|
||||
<layout class="QHBoxLayout" name="merge_with_comments_hl">
|
||||
<item>
|
||||
<widget class="QComboBox" name="merge_source_field">
|
||||
<property name="minimumSize">
|
||||
@ -419,6 +335,9 @@ The default pattern \[.+\]|\+ excludes tags of the form [tag], e.g., [Test book]
|
||||
<property name="text">
|
||||
<string>&Before</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string>merge_options_bg</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
@ -429,6 +348,9 @@ The default pattern \[.+\]|\+ excludes tags of the form [tag], e.g., [Test book]
|
||||
<property name="text">
|
||||
<string>&After</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string>merge_options_bg</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
@ -444,7 +366,196 @@ The default pattern \[.+\]|\+ excludes tags of the form [tag], e.g., [Test book]
|
||||
<string>Separate Comments metadata and additional content with a horizontal rule.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Separator</string>
|
||||
<string>Include &Separator</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>175</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Merge with Comments:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>merge_source_field</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>175</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Catalog cover:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<layout class="QHBoxLayout" name="replace_cover_hl">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="generate_new_cover">
|
||||
<property name="text">
|
||||
<string>Generate new cover</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string>cover_options_bg</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="use_existing_cover">
|
||||
<property name="text">
|
||||
<string>Use existing cover</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string>cover_options_bg</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="spacer_label">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>E&xtra Description note:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>header_note_source_field</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QComboBox" name="header_note_source_field">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Custom column source for text to include in Description section.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Thumb width:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>merge_source_field</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="thumb_width">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Size hint for cover thumbnails included in Descriptions section.</string>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string> inch</string>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>2.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -457,4 +568,8 @@ The default pattern \[.+\]|\+ excludes tags of the form [tag], e.g., [Test book]
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
<buttongroups>
|
||||
<buttongroup name="cover_options_bg"/>
|
||||
<buttongroup name="merge_options_bg"/>
|
||||
</buttongroups>
|
||||
</ui>
|
||||
|
@ -10,7 +10,7 @@ import os, sys, importlib
|
||||
|
||||
from calibre.customize.ui import config
|
||||
from calibre.gui2.dialogs.catalog_ui import Ui_Dialog
|
||||
from calibre.gui2 import dynamic, ResizableDialog
|
||||
from calibre.gui2 import dynamic, ResizableDialog, info_dialog
|
||||
from calibre.customize.ui import catalog_plugins
|
||||
|
||||
class Catalog(ResizableDialog, Ui_Dialog):
|
||||
@ -22,7 +22,6 @@ class Catalog(ResizableDialog, Ui_Dialog):
|
||||
from PyQt4.uic import compileUi
|
||||
|
||||
ResizableDialog.__init__(self, parent)
|
||||
|
||||
self.dbspec, self.ids = dbspec, ids
|
||||
|
||||
# Display the number of books we've been passed
|
||||
@ -115,6 +114,7 @@ class Catalog(ResizableDialog, Ui_Dialog):
|
||||
|
||||
self.format.currentIndexChanged.connect(self.show_plugin_tab)
|
||||
self.buttonBox.button(self.buttonBox.Apply).clicked.connect(self.apply)
|
||||
self.buttonBox.button(self.buttonBox.Help).clicked.connect(self.help)
|
||||
self.show_plugin_tab(None)
|
||||
|
||||
geom = dynamic.get('catalog_window_geom', None)
|
||||
@ -129,6 +129,10 @@ class Catalog(ResizableDialog, Ui_Dialog):
|
||||
if cf in pw.formats:
|
||||
self.tabs.addTab(pw, pw.TITLE)
|
||||
break
|
||||
if hasattr(self.tabs.widget(1),'show_help'):
|
||||
self.buttonBox.button(self.buttonBox.Help).setVisible(True)
|
||||
else:
|
||||
self.buttonBox.button(self.buttonBox.Help).setVisible(False)
|
||||
|
||||
def format_changed(self, idx):
|
||||
cf = unicode(self.format.currentText())
|
||||
@ -165,6 +169,29 @@ class Catalog(ResizableDialog, Ui_Dialog):
|
||||
self.save_catalog_settings()
|
||||
return ResizableDialog.accept(self)
|
||||
|
||||
def help(self):
|
||||
'''
|
||||
To add help functionality for a specific format:
|
||||
In gui2.catalog.catalog_<format>.py, add the following:
|
||||
from calibre.gui2 import open_url
|
||||
from PyQt4.Qt import QUrl
|
||||
|
||||
In the PluginWidget() class, add this method:
|
||||
def show_help(self):
|
||||
url = 'file:///' + P('catalog/help_<format>.html')
|
||||
open_url(QUrl(url))
|
||||
|
||||
Create the help file at resources/catalog/help_<format>.html
|
||||
'''
|
||||
if self.tabs.count() > 1 and hasattr(self.tabs.widget(1),'show_help'):
|
||||
try:
|
||||
self.tabs.widget(1).show_help()
|
||||
except:
|
||||
info_dialog(self, _('No help available'),
|
||||
_('No help available for this output format.'),
|
||||
show_copy_button=False,
|
||||
show=True)
|
||||
|
||||
def reject(self):
|
||||
dynamic.set('catalog_window_geom', bytearray(self.saveGeometry()))
|
||||
ResizableDialog.reject(self)
|
||||
|
@ -14,7 +14,7 @@
|
||||
<string>Generate catalog</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset resource="../../../../resources/images.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/images/lt.png</normaloff>:/images/lt.png</iconset>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
@ -37,7 +37,7 @@
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
<set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -54,8 +54,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>666</width>
|
||||
<height>599</height>
|
||||
<width>650</width>
|
||||
<height>575</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
|
@ -17,4 +17,6 @@ FIELDS = ['all', 'title', 'title_sort', 'author_sort', 'authors', 'comments',
|
||||
TEMPLATE_ALLOWED_FIELDS = [ 'author_sort', 'authors', 'id', 'isbn', 'pubdate', 'title_sort',
|
||||
'publisher', 'series_index', 'series', 'tags', 'timestamp', 'title', 'uuid' ]
|
||||
|
||||
class AuthorSortMismatchException(Exception): pass
|
||||
class EmptyCatalogException(Exception): pass
|
||||
|
||||
|
@ -7,13 +7,14 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2012, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import os
|
||||
import os, shutil, sys, time
|
||||
from collections import namedtuple
|
||||
|
||||
from calibre import strftime
|
||||
from calibre.customize import CatalogPlugin
|
||||
from calibre.customize.conversion import OptionRecommendation, DummyReporter
|
||||
from calibre.ebooks import calibre_cover
|
||||
from calibre.library.catalogs import AuthorSortMismatchException, EmptyCatalogException
|
||||
from calibre.ptempfile import PersistentTemporaryFile
|
||||
|
||||
Option = namedtuple('Option', 'option, default, dest, action, help')
|
||||
@ -120,9 +121,9 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
help=_("Custom field containing note text to insert in Description header.\n"
|
||||
"Default: '%default'\n"
|
||||
"Applies to: AZW3, ePub, MOBI output formats")),
|
||||
Option('--merge-comments',
|
||||
Option('--merge-comments-rule',
|
||||
default='::',
|
||||
dest='merge_comments',
|
||||
dest='merge_comments_rule',
|
||||
action = None,
|
||||
help=_("#<custom field>:[before|after]:[True|False] specifying:\n"
|
||||
" <custom field> Custom field containing notes to merge with Comments\n"
|
||||
@ -146,6 +147,13 @@ 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('--use-existing-cover',
|
||||
default=False,
|
||||
dest='use_existing_cover',
|
||||
action = 'store_true',
|
||||
help=_("Replace existing cover when generating the catalog.\n"
|
||||
"Default: '%default'\n"
|
||||
"Applies to: AZW3, ePub, MOBI output formats")),
|
||||
Option('--thumb-width',
|
||||
default='1.0',
|
||||
dest='thumb_width',
|
||||
@ -182,8 +190,8 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
else:
|
||||
op = "kindle"
|
||||
|
||||
opts.descriptionClip = 380 if op.endswith('dx') or 'kindle' not in op else 100
|
||||
opts.authorClip = 100 if op.endswith('dx') or 'kindle' not in op else 60
|
||||
opts.description_clip = 380 if op.endswith('dx') or 'kindle' not in op else 100
|
||||
opts.author_clip = 100 if op.endswith('dx') or 'kindle' not in op else 60
|
||||
opts.output_profile = op
|
||||
|
||||
opts.basename = "Catalog"
|
||||
@ -198,11 +206,12 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
(self.name,self.fmt,'for %s ' % opts.output_profile if opts.output_profile else '',
|
||||
'CLI' if opts.cli_environment else 'GUI'))
|
||||
|
||||
# If exclude_genre is blank, assume user wants all genre tags included
|
||||
# If exclude_genre is blank, assume user wants all tags as genres
|
||||
if opts.exclude_genre.strip() == '':
|
||||
opts.exclude_genre = '\[^.\]'
|
||||
build_log.append(" converting empty exclude_genre to '\[^.\]'")
|
||||
|
||||
#opts.exclude_genre = '\[^.\]'
|
||||
#build_log.append(" converting empty exclude_genre to '\[^.\]'")
|
||||
opts.exclude_genre = 'a^'
|
||||
build_log.append(" converting empty exclude_genre to 'a^'")
|
||||
if opts.connected_device['is_device_connected'] and \
|
||||
opts.connected_device['kind'] == 'device':
|
||||
if opts.connected_device['serial']:
|
||||
@ -304,13 +313,13 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
keys.sort()
|
||||
build_log.append(" opts:")
|
||||
for key in keys:
|
||||
if key in ['catalog_title','authorClip','connected_kindle','descriptionClip',
|
||||
if key in ['catalog_title','author_clip','connected_kindle','description_clip',
|
||||
'exclude_book_marker','exclude_genre','exclude_tags',
|
||||
'exclusion_rules',
|
||||
'header_note_source_field','merge_comments',
|
||||
'exclusion_rules', 'fmt',
|
||||
'header_note_source_field','merge_comments_rule',
|
||||
'output_profile','prefix_rules','read_book_marker',
|
||||
'search_text','sort_by','sort_descriptions_by_author','sync',
|
||||
'thumb_width','wishlist_tag']:
|
||||
'thumb_width','use_existing_cover','wishlist_tag']:
|
||||
build_log.append(" %s: %s" % (key, repr(opts_dict[key])))
|
||||
|
||||
if opts.verbose:
|
||||
@ -323,26 +332,30 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
|
||||
if opts.verbose:
|
||||
log.info(" Begin catalog source generation")
|
||||
catalog.createDirectoryStructure()
|
||||
catalog.copyResources()
|
||||
catalog.calculateThumbnailSize()
|
||||
catalog_source_built = catalog.buildSources()
|
||||
|
||||
if opts.verbose:
|
||||
if catalog_source_built:
|
||||
try:
|
||||
catalog_source_built = catalog.build_sources()
|
||||
if opts.verbose:
|
||||
log.info(" Completed catalog source generation\n")
|
||||
else:
|
||||
log.error(" *** Terminated catalog generation, check log for details ***")
|
||||
except (AuthorSortMismatchException, EmptyCatalogException), e:
|
||||
log.error(" *** Terminated catalog generation: %s ***" % e)
|
||||
except:
|
||||
log.error(" unhandled exception in catalog generator")
|
||||
raise
|
||||
|
||||
if catalog_source_built:
|
||||
else:
|
||||
recommendations = []
|
||||
recommendations.append(('remove_fake_margins', False,
|
||||
OptionRecommendation.HIGH))
|
||||
recommendations.append(('comments', '', OptionRecommendation.HIGH))
|
||||
|
||||
# >>> Use to debug generated catalog code before conversion <<<
|
||||
if False:
|
||||
setattr(opts,'debug_pipeline',os.path.expanduser("~/Desktop/Catalog debug"))
|
||||
"""
|
||||
>>> Use to debug generated catalog code before pipeline conversion <<<
|
||||
"""
|
||||
GENERATE_DEBUG_EPUB = False
|
||||
if GENERATE_DEBUG_EPUB:
|
||||
catalog_debug_path = os.path.join(os.path.expanduser('~'),'Desktop','Catalog debug')
|
||||
setattr(opts,'debug_pipeline',os.path.expanduser(catalog_debug_path))
|
||||
|
||||
dp = getattr(opts, 'debug_pipeline', None)
|
||||
if dp is not None:
|
||||
@ -357,9 +370,9 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
recommendations.append(('book_producer',opts.output_profile,
|
||||
OptionRecommendation.HIGH))
|
||||
|
||||
# If cover exists, use it
|
||||
# Use existing cover or generate new cover
|
||||
cpath = None
|
||||
generate_new_cover = False
|
||||
existing_cover = False
|
||||
try:
|
||||
search_text = 'title:"%s" author:%s' % (
|
||||
opts.catalog_title.replace('"', '\\"'), 'calibre')
|
||||
@ -367,19 +380,18 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
if matches:
|
||||
cpath = db.cover(matches[0], index_is_id=True, as_path=True)
|
||||
if cpath and os.path.exists(cpath):
|
||||
recommendations.append(('cover', cpath,
|
||||
OptionRecommendation.HIGH))
|
||||
log.info("using existing cover")
|
||||
else:
|
||||
log.info("no existing cover, generating new cover")
|
||||
generate_new_cover = True
|
||||
else:
|
||||
log.info("no existing cover, generating new cover")
|
||||
generate_new_cover = True
|
||||
existing_cover = True
|
||||
except:
|
||||
pass
|
||||
|
||||
if generate_new_cover:
|
||||
if self.opts.use_existing_cover and not existing_cover:
|
||||
log.warning("no existing catalog cover found")
|
||||
|
||||
if self.opts.use_existing_cover and existing_cover:
|
||||
recommendations.append(('cover', cpath, OptionRecommendation.HIGH))
|
||||
log.info("using existing catalog cover")
|
||||
else:
|
||||
log.info("replacing catalog cover")
|
||||
new_cover_path = PersistentTemporaryFile(suffix='.jpg')
|
||||
new_cover = calibre_cover(opts.catalog_title.replace('"', '\\"'), 'calibre')
|
||||
new_cover_path.write(new_cover)
|
||||
@ -388,7 +400,7 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
|
||||
# Run ebook-convert
|
||||
from calibre.ebooks.conversion.plumber import Plumber
|
||||
plumber = Plumber(os.path.join(catalog.catalogPath,
|
||||
plumber = Plumber(os.path.join(catalog.catalog_path,
|
||||
opts.basename + '.opf'), path_to_output, log, report_progress=notification,
|
||||
abort_after_input_dump=False)
|
||||
plumber.merge_ui_recommendations(recommendations)
|
||||
@ -399,6 +411,13 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
except:
|
||||
pass
|
||||
|
||||
if GENERATE_DEBUG_EPUB:
|
||||
from calibre.ebooks.tweak import zip_rebuilder
|
||||
input_path = os.path.join(catalog_debug_path,'input')
|
||||
shutil.copy(P('catalog/mimetype'),input_path)
|
||||
shutil.copytree(P('catalog/META-INF'),os.path.join(input_path,'META-INF'))
|
||||
zip_rebuilder(input_path, os.path.join(catalog_debug_path,'input.epub'))
|
||||
|
||||
# returns to gui2.actions.catalog:catalog_generated()
|
||||
return catalog.error
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user