GwR catalog UI revisions

This commit is contained in:
GRiker 2010-12-23 12:49:53 -07:00
parent 3c254aca3f
commit 230d92dcb5
7 changed files with 1114 additions and 275 deletions

View File

@ -108,6 +108,13 @@ p.date_read {
text-indent:-6em;
}
hr.annotations_divider {
width:50%;
margin-left:1em;
margin-top:0em;
margin-bottom:0em;
}
hr.description_divider {
width:90%;
margin-left:5%;
@ -117,18 +124,20 @@ hr.description_divider {
border-left: solid white 0px;
}
hr.annotations_divider {
width:50%;
margin-left:1em;
margin-top:0em;
margin-bottom:0em;
hr.merged_comments_divider {
width:80%;
margin-left:10%;
border-top: solid white 0px;
border-right: solid white 0px;
border-bottom: dotted grey 2px;
border-left: solid white 0px;
}
td.publisher, td.date {
font-weight:bold;
text-align:center;
}
td.rating {
td.rating, td.notes {
text-align: center;
}
td.thumbnail img {

View File

@ -57,7 +57,7 @@ class GenerateCatalogAction(InterfaceAction):
if job.result:
# Search terms nulled catalog results
return error_dialog(self.gui, _('No books found'),
_("No books to catalog\nCheck exclude tags"),
_("No books to catalog\nCheck exclusion criteria"),
show=True)
if job.failed:
return self.gui.job_exception(job)

View File

@ -17,18 +17,55 @@ class PluginWidget(QWidget,Ui_Form):
TITLE = _('E-book options')
HELP = _('Options specific to')+' EPUB/MOBI '+_('output')
OPTION_FIELDS = [('exclude_genre','\[.+\]'),
('exclude_tags','~,'+_('Catalog')),
('generate_titles', True),
('generate_series', True),
('generate_recently_added', True),
('note_tag','*'),
('numbers_as_text', False),
('read_pattern','+'),
('read_source_field_cb','Tag'),
('wishlist_tag','Wishlist'),
]
CheckBoxControls = [
'generate_titles',
'generate_series',
'generate_genres',
'generate_recently_added',
'generate_descriptions',
'include_hr'
]
ComboBoxControls = [
'read_source_field',
'exclude_source_field',
'header_note_source_field',
'merge_source_field'
]
LineEditControls = [
'exclude_genre',
'exclude_pattern',
'exclude_tags',
'read_pattern',
'wishlist_tag'
]
RadioButtonControls = [
'merge_before',
'merge_after'
]
SpinBoxControls = [
'thumb_width'
]
OPTION_FIELDS = zip(CheckBoxControls,
[True for i in CheckBoxControls],
['check_box' for i in CheckBoxControls])
OPTION_FIELDS += zip(ComboBoxControls,
[None for i in ComboBoxControls],
['combo_box' for i in ComboBoxControls])
OPTION_FIELDS += zip(RadioButtonControls,
[None for i in RadioButtonControls],
['radio_button' for i in RadioButtonControls])
# LineEditControls
OPTION_FIELDS += zip(['exclude_genre'],['\[.+\]'],['line_edit'])
OPTION_FIELDS += zip(['exclude_pattern'],[None],['line_edit'])
OPTION_FIELDS += zip(['exclude_tags'],['~,'+_('Catalog')],['line_edit'])
OPTION_FIELDS += zip(['read_pattern'],['+'],['line_edit'])
OPTION_FIELDS += zip(['wishlist_tag'],['Wishlist'],['line_edit'])
# SpinBoxControls
OPTION_FIELDS += zip(['thumb_width'],[1.00],['spin_box'])
# Output synced to the connected device?
sync_enabled = True
@ -42,105 +79,203 @@ class PluginWidget(QWidget,Ui_Form):
def initialize(self, name, db):
self.name = name
# Populate the 'Read book' source fields
all_custom_fields = db.custom_field_keys()
custom_fields = {}
custom_fields['Tag'] = {'field':'tag', 'datatype':u'text'}
for custom_field in all_custom_fields:
field_md = db.metadata_for_field(custom_field)
if field_md['datatype'] in ['bool','composite','datetime','text']:
custom_fields[field_md['name']] = {'field':custom_field,
'datatype':field_md['datatype']}
# Add the sorted eligible fields to the combo box
for cf in sorted(custom_fields):
self.read_source_field_cb.addItem(cf)
self.read_source_fields = custom_fields
self.read_source_field_cb.currentIndexChanged.connect(self.read_source_field_changed)
self.db = db
self.populateComboBoxes()
# Update dialog fields from stored options
for opt in self.OPTION_FIELDS:
opt_value = gprefs.get(self.name + '_' + opt[0], opt[1])
if opt[0] in [
'generate_recently_added',
'generate_series',
'generate_titles',
'numbers_as_text',
]:
getattr(self, opt[0]).setChecked(opt_value)
c_name, c_def, c_type = opt
opt_value = gprefs.get(self.name + '_' + c_name, c_def)
if c_type in ['check_box']:
getattr(self, c_name).setChecked(eval(str(opt_value)))
elif c_type in ['combo_box'] and opt_value is not None:
# *** Test this code with combo boxes ***
#index = self.read_source_field.findText(opt_value)
index = getattr(self,c_name).findText(opt_value)
if index == -1 and c_name == 'read_source_field':
index = self.read_source_field.findText('Tag')
#self.read_source_field.setCurrentIndex(index)
getattr(self,c_name).setCurrentIndex(index)
elif c_type in ['line_edit']:
getattr(self, c_name).setText(opt_value)
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))
# Combo box
elif opt[0] in ['read_source_field_cb']:
# Look for last-stored combo box value
index = self.read_source_field_cb.findText(opt_value)
if index == -1:
index = self.read_source_field_cb.findText('Tag')
self.read_source_field_cb.setCurrentIndex(index)
# Text fields
else:
getattr(self, opt[0]).setText(opt_value)
# Init self.read_source_field
cs = unicode(self.read_source_field_cb.currentText())
# Init self.read_source_field_name
cs = unicode(self.read_source_field.currentText())
read_source_spec = self.read_source_fields[cs]
self.read_source_field = read_source_spec['field']
self.read_source_field_name = read_source_spec['field']
# Init self.exclude_source_field_name
self.exclude_source_field_name = ''
cs = unicode(self.exclude_source_field.currentText())
if cs > '':
exclude_source_spec = self.exclude_source_fields[cs]
self.exclude_source_field_name = exclude_source_spec['field']
# Init self.merge_source_field_name
self.merge_source_field_name = ''
cs = unicode(self.merge_source_field.currentText())
if cs > '':
merge_source_spec = self.merge_source_fields[cs]
self.merge_source_field_name = merge_source_spec['field']
# Init self.header_note_source_field_name
self.header_note_source_field_name = ''
cs = unicode(self.header_note_source_field.currentText())
if cs > '':
header_note_source_spec = self.header_note_source_fields[cs]
self.header_note_source_field_name = header_note_source_spec['field']
# Hook changes to thumb_width
self.thumb_width.valueChanged.connect(self.thumb_width_changed)
def options(self):
# Save/return the current options
# exclude_genre stores literally
# generate_titles, generate_recently_added, numbers_as_text stores as True/False
# others store as lists
opts_dict = {}
# Save values to gprefs
for opt in self.OPTION_FIELDS:
# Save values to gprefs
if opt[0] in [
'generate_recently_added',
'generate_series',
'generate_titles',
'numbers_as_text',
]:
opt_value = getattr(self,opt[0]).isChecked()
c_name, c_def, c_type = opt
if c_type in ['check_box', 'radio_button']:
opt_value = getattr(self, c_name).isChecked()
elif c_type in ['combo_box']:
opt_value = unicode(getattr(self,c_name).currentText())
elif c_type in ['line_edit']:
opt_value = unicode(getattr(self, c_name).text())
elif c_type in ['spin_box']:
opt_value = unicode(getattr(self, c_name).cleanText())
gprefs.set(self.name + '_' + c_name, opt_value)
# Combo box uses .currentText()
elif opt[0] in ['read_source_field_cb']:
opt_value = unicode(getattr(self, opt[0]).currentText())
# text fields use .text()
# Construct opts object
if c_name == 'exclude_tags':
# store as list
opts_dict[c_name] = opt_value.split(',')
else:
opt_value = unicode(getattr(self, opt[0]).text())
gprefs.set(self.name + '_' + opt[0], opt_value)
opts_dict[c_name] = opt_value
# Construct opts
if opt[0] in [
'exclude_genre',
'generate_recently_added',
'generate_series',
'generate_titles',
'numbers_as_text',
]:
opts_dict[opt[0]] = opt_value
else:
opts_dict[opt[0]] = opt_value.split(',')
# Generate markers for hybrids
opts_dict['read_book_marker'] = "%s:%s" % (self.read_source_field_name,
self.read_pattern.text())
opts_dict['exclude_book_marker'] = "%s:%s" % (self.exclude_source_field_name,
self.exclude_pattern.text())
# Generate read_book_marker
opts_dict['read_book_marker'] = "%s:%s" % (self.read_source_field, self.read_pattern.text())
# Generate specs for merge_comments, header_note_source_field
checked = ''
if self.merge_before.isChecked():
checked = 'before'
elif self.merge_after.isChecked():
checked = 'after'
include_hr = self.include_hr.isChecked()
opts_dict['merge_comments'] = "%s:%s:%s" % \
(self.merge_source_field_name, checked, include_hr)
opts_dict['header_note_source_field'] = self.header_note_source_field_name
# Append the output profile
opts_dict['output_profile'] = [load_defaults('page_setup')['output_profile']]
if False:
print "opts_dict"
for opt in sorted(opts_dict.keys()):
print " %s: %s" % (opt, repr(opts_dict[opt]))
return opts_dict
def populateComboBoxes(self):
# Custom column types declared in
# gui2.preferences.create_custom_column:CreateCustomColumn()
# As of 0.7.34:
# bool Yes/No
# comments Long text, like comments, not shown in tag browser
# composite Column built from other columns
# datetime Date
# enumeration Text, but with a fixed set of permitted values
# float Floating point numbers
# int Integers
# rating Ratings, shown with stars
# series Text column for keeping series-like information
# text Column shown in the tag browser
# *text Comma-separated text, like tags, shown in tag browser
all_custom_fields = self.db.custom_field_keys()
# Populate the 'Read book' hybrid
custom_fields = {}
custom_fields['Tag'] = {'field':'tag', 'datatype':u'text'}
for custom_field in all_custom_fields:
field_md = self.db.metadata_for_field(custom_field)
if field_md['datatype'] in ['bool','composite','datetime','enumeration','text']:
custom_fields[field_md['name']] = {'field':custom_field,
'datatype':field_md['datatype']}
# Add the sorted eligible fields to the combo box
for cf in sorted(custom_fields):
self.read_source_field.addItem(cf)
self.read_source_fields = custom_fields
self.read_source_field.currentIndexChanged.connect(self.read_source_field_changed)
# Populate the 'Excluded books' hybrid
custom_fields = {}
for custom_field in all_custom_fields:
field_md = self.db.metadata_for_field(custom_field)
if field_md['datatype'] in ['bool','composite','datetime','enumeration','text']:
custom_fields[field_md['name']] = {'field':custom_field,
'datatype':field_md['datatype']}
# Blank field first
self.exclude_source_field.addItem('')
# Add the sorted eligible fields to the combo box
for cf in sorted(custom_fields):
self.exclude_source_field.addItem(cf)
self.exclude_source_fields = custom_fields
self.exclude_source_field.currentIndexChanged.connect(self.exclude_source_field_changed)
# Populate the 'Header note' combo box
custom_fields = {}
for custom_field in all_custom_fields:
field_md = self.db.metadata_for_field(custom_field)
if field_md['datatype'] in ['composite','datetime','enumeration','text']:
custom_fields[field_md['name']] = {'field':custom_field,
'datatype':field_md['datatype']}
# Blank field first
self.header_note_source_field.addItem('')
# Add the sorted eligible fields to the combo box
for cf in sorted(custom_fields):
self.header_note_source_field.addItem(cf)
self.header_note_source_fields = custom_fields
self.header_note_source_field.currentIndexChanged.connect(self.header_note_source_field_changed)
# Populate the 'Merge with Comments' combo box
custom_fields = {}
for custom_field in all_custom_fields:
field_md = self.db.metadata_for_field(custom_field)
if field_md['datatype'] in ['text','comments']:
custom_fields[field_md['name']] = {'field':custom_field,
'datatype':field_md['datatype']}
# Blank field first
self.merge_source_field.addItem('')
# Add the sorted eligible fields to the combo box
for cf in sorted(custom_fields):
self.merge_source_field.addItem(cf)
self.merge_source_fields = custom_fields
self.merge_source_field.currentIndexChanged.connect(self.merge_source_field_changed)
self.merge_before.setEnabled(False)
self.merge_after.setEnabled(False)
self.include_hr.setEnabled(False)
def read_source_field_changed(self,new_index):
'''
Process changes in the read_source_field combo box
Currently using QLineEdit for all field types
Possible to modify to switch QWidget type
'''
new_source = str(self.read_source_field_cb.currentText())
new_source = str(self.read_source_field.currentText())
read_source_spec = self.read_source_fields[str(new_source)]
self.read_source_field = read_source_spec['field']
self.read_source_field_name = read_source_spec['field']
# Change pattern input widget to match the source field datatype
if read_source_spec['datatype'] in ['bool','composite','datetime','text']:
@ -152,3 +287,62 @@ class PluginWidget(QWidget,Ui_Form):
self.read_pattern = dw
self.read_spec_hl.addWidget(dw)
def exclude_source_field_changed(self,new_index):
'''
Process changes in the exclude_source_field combo box
Currently using QLineEdit for all field types
Possible to modify to switch QWidget type
'''
new_source = str(self.exclude_source_field.currentText())
self.exclude_source_field_name = new_source
if new_source > '':
exclude_source_spec = self.exclude_source_fields[str(new_source)]
self.exclude_source_field_name = exclude_source_spec['field']
# Change pattern input widget to match the source field datatype
if exclude_source_spec['datatype'] in ['bool','composite','datetime','text']:
if not isinstance(self.exclude_pattern, QLineEdit):
self.exclude_spec_hl.removeWidget(self.exclude_pattern)
dw = QLineEdit(self)
dw.setObjectName('exclude_pattern')
dw.setToolTip('Exclusion pattern')
self.exclude_pattern = dw
self.exclude_spec_hl.addWidget(dw)
else:
self.exclude_pattern.setText('')
def header_note_source_field_changed(self,new_index):
'''
Process changes in the header_note_source_field combo box
'''
new_source = str(self.header_note_source_field.currentText())
self.header_note_source_field_name = new_source
if new_source > '':
header_note_source_spec = self.header_note_source_fields[str(new_source)]
self.header_note_source_field_name = header_note_source_spec['field']
def merge_source_field_changed(self,new_index):
'''
Process changes in the header_note_source_field combo box
'''
new_source = str(self.merge_source_field.currentText())
self.merge_source_field_name = new_source
if new_source > '':
merge_source_spec = self.merge_source_fields[str(new_source)]
self.merge_source_field_name = merge_source_spec['field']
if not self.merge_before.isChecked() and not self.merge_after.isChecked():
self.merge_after.setChecked(True)
self.merge_before.setEnabled(True)
self.merge_after.setEnabled(True)
self.include_hr.setEnabled(True)
else:
self.merge_before.setEnabled(False)
self.merge_after.setEnabled(False)
self.include_hr.setEnabled(False)
def thumb_width_changed(self,new_value):
'''
Process changes in the thumb_width spin box
'''
pass

View File

@ -6,163 +6,653 @@
<rect>
<x>0</x>
<y>0</y>
<width>627</width>
<height>549</height>
<width>650</width>
<height>582</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>'Don't include this book' tag:</string>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="includedSections">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="exclude_tags">
<property name="toolTip">
<string extracomment="Default: ~,Catalog"/>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Additional note tag prefix:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="note_tag">
<property name="toolTip">
<string extracomment="Default: *"/>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLineEdit" name="exclude_genre">
<property name="toolTip">
<string extracomment="Default: \[[\w]*\]"/>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Regex pattern describing tags to exclude as genres:</string>
</property>
<property name="textFormat">
<enum>Qt::LogText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Regex tips:
- The default regex - \[.+\] - excludes genre tags of the form [tag], e.g., [Amazon Freebie]
- A regex pattern of a single dot excludes all genre tags, generating no Genre Section</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="8" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<property name="minimumSize">
<size>
<width>20</width>
<height>40</height>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item row="10" column="0">
<widget class="QCheckBox" name="generate_titles">
<property name="text">
<string>Include 'Titles' Section</string>
<property name="toolTip">
<string>Sections to include in generated catalog. A minimal catalog includes 'Books by Author'.</string>
</property>
<property name="title">
<string>Included sections (Books by Author included by default)</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QCheckBox" name="generate_titles">
<property name="text">
<string>Books by Title</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="generate_series">
<property name="text">
<string>Books by Series</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QCheckBox" name="generate_recently_added">
<property name="text">
<string>Recently Added</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="generate_genres">
<property name="text">
<string>Books by Genre</string>
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QCheckBox" name="generate_descriptions">
<property name="text">
<string>Descriptions</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="12" column="0">
<widget class="QCheckBox" name="generate_recently_added">
<property name="text">
<string>Include 'Recently Added' Section</string>
<item>
<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>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Lucida Grande'; font-size:13pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Default pattern &lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Courier New,courier';&quot;&gt;\[.+\]&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;excludes tags of the form [&lt;span style=&quot; font-style:italic;&quot;&gt;tag&lt;/span&gt;]&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="title">
<string>Excluded genres</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>
</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>
</layout>
</item>
</layout>
</widget>
</item>
<item row="13" column="0">
<widget class="QCheckBox" name="numbers_as_text">
<property name="text">
<string>Sort numbers as text</string>
<item>
<widget class="QGroupBox" name="excludedBooks">
<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>Exclude matching books from generated catalog</string>
</property>
<property name="title">
<string>Excluded books</string>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<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="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="exclude_tags">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Lucida Grande'; font-size:13pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Comma-separated list of tags to exclude.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Default:&lt;/span&gt;&lt;span style=&quot; font-family:'Courier New,courier'; font-size:12pt;&quot;&gt; ~,Catalog&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0" colspan="2">
<layout class="QHBoxLayout" name="exclude_spec_hl">
<item>
<widget class="QLabel" name="label_7">
<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>Column/value</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="exclude_source_field">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Column containing exclusion criteria</string>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToMinimumContentsLengthWithIcon</enum>
</property>
<property name="minimumContentsLength">
<number>18</number>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="exclude_pattern">
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Exclusion pattern</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item row="11" column="0">
<widget class="QCheckBox" name="generate_series">
<property name="text">
<string>Include 'Series' Section</string>
<item>
<widget class="QGroupBox" name="readBooks">
<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>Matching books will be displayed with ✓</string>
</property>
<property name="title">
<string>Read books</string>
</property>
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="0" colspan="2">
<layout class="QHBoxLayout" name="read_spec_hl">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<item>
<widget class="QLabel" name="label_3">
<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>Column/value</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="read_source_field">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Column containing 'read' status</string>
</property>
<property name="statusTip">
<string/>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToMinimumContentsLengthWithIcon</enum>
</property>
<property name="minimumContentsLength">
<number>18</number>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="read_pattern">
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>'read book' pattern</string>
</property>
<property name="statusTip">
<string/>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="wishlist_tag"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Wishlist tag:</string>
<item>
<widget class="QGroupBox" name="otherOptions">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="2" column="1">
<layout class="QHBoxLayout" name="read_spec_hl">
<property name="sizeConstraint">
<enum>QLayout::SetMinimumSize</enum>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<item>
<widget class="QComboBox" name="read_source_field_cb">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Source column for read book</string>
</property>
<property name="statusTip">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="read_pattern">
<property name="toolTip">
<string>Pattern for read book</string>
</property>
<property name="statusTip">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Books marked as read:</string>
<property name="title">
<string>Other options</string>
</property>
<layout class="QFormLayout" name="formLayout_4">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::FieldsStayAtSizeHint</enum>
</property>
<item row="1" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_5">
<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="toolTip">
<string/>
</property>
<property name="text">
<string>Wishlist tag</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="wishlist_tag">
<property name="toolTip">
<string>Wishlist items will be displayed with ✕</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_4">
<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>Thumbnail width</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</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="toolTip">
<string>Size hint for cover thumbnails included in Descriptions</string>
</property>
<property name="suffix">
<string>&quot;</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>
</layout>
</item>
<item row="3" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLabel" name="label_6">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<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>Header note</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</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="toolTip">
<string>Column containing header note</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="4" 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>
</widget>
</item>
<item>
<widget class="QComboBox" name="merge_source_field">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Column containing additional content to merge</string>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="merge_before">
<property name="toolTip">
<string>Merge before Comments</string>
</property>
<property name="text">
<string>Before</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="merge_after">
<property name="toolTip">
<string>Merge after Comments</string>
</property>
<property name="text">
<string>After</string>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="include_hr">
<property name="toolTip">
<string>Separate with horizontal rule</string>
</property>
<property name="text">
<string>&lt;hr /&gt;</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>579</width>
<height>411</height>
<width>650</width>
<height>575</height>
</rect>
</property>
<property name="windowTitle">

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>611</width>
<height>514</height>
<width>674</width>
<height>660</height>
</rect>
</property>
<property name="windowTitle">
@ -33,6 +33,18 @@
</item>
<item row="1" column="0" colspan="2">
<widget class="QTabWidget" name="tabs">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>650</width>
<height>575</height>
</size>
</property>
<property name="currentIndex">
<number>0</number>
</property>

View File

@ -550,6 +550,13 @@ class EPUB_MOBI(CatalogPlugin):
"of the conversion process a bug is occurring.\n"
"Default: '%default'None\n"
"Applies to: ePub, MOBI output formats")),
Option('--exclude-book-marker',
default=':',
dest='exclude_book_marker',
action = None,
help=_("field:pattern specifying custom field/contents indicating book should be excluded.\n"
"Default: '%default'\n"
"Applies to ePub, MOBI output formats")),
Option('--exclude-genre',
default='\[.+\]',
dest='exclude_genre',
@ -585,6 +592,23 @@ class EPUB_MOBI(CatalogPlugin):
help=_("Include 'Recently Added' section in catalog.\n"
"Default: '%default'\n"
"Applies to: ePub, MOBI output formats")),
Option('--header-note-source-field',
default='',
dest='header_note_source_field',
action = None,
help=_("Custom field containing note text to insert in Description header.\n"
"Default: '%default'\n"
"Applies to: ePub, MOBI output formats")),
Option('--merge-comments',
default='::',
dest='merge_comments',
action = None,
help=_("<custom field>:[before|after]:[True|False] specifying:\n"
" <custom field> Custom field containing notes to merge with Comments\n"
" [before|after] Placement of notes with respect to Comments\n"
" [True|False] - A horizontal rule is inserted between notes and Comments\n"
"Default: '%default'\n"
"Applies to ePub, MOBI output formats")),
Option('--note-tag',
default='*',
dest='note_tag',
@ -845,6 +869,7 @@ class EPUB_MOBI(CatalogPlugin):
catalog.copyResources()
catalog.buildSources()
'''
# A single number creates 'Last x days' only.
# Multiple numbers create 'Last x days', 'x to y days ago' ...
# e.g, [7,15,30,60], [30]
@ -889,6 +914,7 @@ class EPUB_MOBI(CatalogPlugin):
and self.generateForKindle \
else False
self.__genres = None
self.genres = []
self.__genre_tags_dict = None
self.__htmlFileList = []
self.__markerTags = self.getMarkerTags()
@ -900,13 +926,15 @@ class EPUB_MOBI(CatalogPlugin):
self.__progressString = ''
f, _, p = opts.read_book_marker.partition(':')
self.__read_book_marker = {'field':f, 'pattern':p}
f, p, hr = self.opts.merge_comments.split(':')
self.__merge_comments = {'field':f, 'position':p, 'hr':hr}
self.__reporter = report_progress
self.__stylesheet = stylesheet
self.__thumbs = None
self.__thumbWidth = 0
self.__thumbHeight = 0
self.__title = opts.catalog_title
self.__totalSteps = 11.0
self.__totalSteps = 8.0
self.__useSeriesPrefixInTitlesSection = False
self.__verbose = opts.verbose
@ -916,17 +944,36 @@ class EPUB_MOBI(CatalogPlugin):
self.__output_profile = profile
break
# Confirm/create thumbs archive
# Confirm/create thumbs archive.
if not os.path.exists(self.__cache_dir):
self.opts.log.info(" creating new thumb cache '%s'" % self.__cache_dir)
os.makedirs(self.__cache_dir)
if not os.path.exists(self.__archive_path):
self.opts.log.info(" creating thumbnail archive")
self.opts.log.info(' creating thumbnail archive, thumb_width: %1.2f"' %
float(self.opts.thumb_width))
zfw = ZipFile(self.__archive_path, mode='w')
zfw.writestr("Catalog Thumbs Archive",'')
zfw.comment = "thumb_width: %1.2f" % float(self.opts.thumb_width)
zfw.close()
else:
self.opts.log.info(" existing thumb cache at '%s'" % self.__archive_path)
with closing(ZipFile(self.__archive_path, mode='r')) as zfr:
try:
cached_thumb_width = float(zfr.comment[len('thumb_width: '):])
except:
cached_thumb_width = "0.0"
if float(cached_thumb_width) != float(self.opts.thumb_width):
self.opts.log.info(" invalidating cache at '%s'" % self.__archive_path)
self.opts.log.info(' thumb_width: %1.2f" => %1.2f"' %
(float(cached_thumb_width),float(self.opts.thumb_width)))
os.remove(self.__archive_path)
zfw = ZipFile(self.__archive_path, mode='w')
zfw.writestr("Catalog Thumbs Archive",'')
zfw.comment = "thumb_width: %1.2f" % float(self.opts.thumb_width)
zfw.close()
else:
self.opts.log.info(' existing thumb cache at %s, cached_thumb_width: %1.2f"' %
(self.__archive_path, float(cached_thumb_width)))
# Tweak build steps based on optional sections: 1 call for HTML, 1 for NCX
if self.opts.generate_titles:
@ -937,6 +984,9 @@ class EPUB_MOBI(CatalogPlugin):
self.__totalSteps += 2
if self.opts.generate_series:
self.__totalSteps += 2
if self.opts.generate_descriptions:
# +1 thumbs
self.__totalSteps += 3
# Accessors
if True:
@ -1246,7 +1296,8 @@ class EPUB_MOBI(CatalogPlugin):
return False
self.fetchBooksByAuthor()
self.fetchBookmarks()
self.generateHTMLDescriptions()
if self.opts.generate_descriptions:
self.generateHTMLDescriptions()
self.generateHTMLByAuthor()
if self.opts.generate_titles:
self.generateHTMLByTitle()
@ -1256,10 +1307,10 @@ class EPUB_MOBI(CatalogPlugin):
self.generateHTMLByDateAdded()
if self.generateRecentlyRead:
self.generateHTMLByDateRead()
self.generateHTMLByTags()
self.generateThumbnails()
if self.opts.generate_genres:
self.generateHTMLByTags()
if self.opts.generate_descriptions:
self.generateThumbnails()
self.generateOPF()
self.generateNCXHeader()
self.generateNCXByAuthor("Authors")
@ -1271,8 +1322,11 @@ class EPUB_MOBI(CatalogPlugin):
self.generateNCXByDateAdded("Recently Added")
if self.generateRecentlyRead:
self.generateNCXByDateRead("Recently Read")
self.generateNCXByGenre("Genres")
self.generateNCXDescriptions("Descriptions")
if self.opts.generate_genres:
self.generateNCXByGenre("Genres")
if self.opts.generate_descriptions:
self.generateNCXDescriptions("Descriptions")
self.writeNCX()
return True
@ -1340,6 +1394,7 @@ class EPUB_MOBI(CatalogPlugin):
#print "fetchBooksByTitle(): opts.search_text: %s" % self.opts.search_text
# Fetch the database as a dictionary
data = self.plugin.search_sort_db(self.db, self.opts)
data = self.processExclusions(data)
# Populate this_title{} from data[{},{}]
titles = []
@ -1388,6 +1443,8 @@ class EPUB_MOBI(CatalogPlugin):
record['comments'] = record['comments'][:ad_offset]
this_title['description'] = self.markdownComments(record['comments'])
# Create short description
paras = BeautifulSoup(this_title['description']).findAll('p')
tokens = []
for p in paras:
@ -1399,6 +1456,10 @@ class EPUB_MOBI(CatalogPlugin):
this_title['description'] = None
this_title['short_description'] = None
# Merge with custom field/value
if self.__merge_comments['field']:
this_title['description'] = self.mergeComments(this_title)
if record['cover']:
this_title['cover'] = re.sub('&amp;', '&', record['cover'])
@ -1413,6 +1474,14 @@ class EPUB_MOBI(CatalogPlugin):
formats.append(self.convertHTMLEntities(format))
this_title['formats'] = formats
# Add user notes to be displayed in header
if self.opts.header_note_source_field:
notes = self.__db.get_field(record['id'],
self.opts.header_note_source_field,
index_is_id=True)
if notes:
this_title['notes'] = notes
titles.append(this_title)
# Re-sort based on title_sort
@ -1712,7 +1781,8 @@ class EPUB_MOBI(CatalogPlugin):
for tag in title.get('tags', []):
aTag = Tag(soup,'a')
#print "aTag: %s" % "Genre_%s.html" % re.sub("\W","",tag.lower())
aTag['href'] = "Genre_%s.html" % re.sub("\W","",tag.lower())
if self.opts.generate_genres:
aTag['href'] = "Genre_%s.html" % re.sub("\W","",tag.lower())
aTag.insert(0,escape(NavigableString(tag)))
emTag = Tag(soup, "em")
emTag.insert(0, aTag)
@ -1771,7 +1841,6 @@ class EPUB_MOBI(CatalogPlugin):
#ratingLabel = body.find('td',text="Rating").replaceWith("Unrated")
ratingTag.insert(0,NavigableString('<br/>'))
# Insert user notes or remove Notes label. Notes > 1 line will push formatting down
if 'notes' in title:
notesTag = body.find(attrs={'class':'notes'})
@ -1894,7 +1963,8 @@ class EPUB_MOBI(CatalogPlugin):
# Link to book
aTag = Tag(soup, "a")
aTag['href'] = "book_%d.html" % (int(float(book['id'])))
if self.opts.generate_descriptions:
aTag['href'] = "book_%d.html" % (int(float(book['id'])))
aTag.insert(0,escape(book['title']))
pBookTag.insert(ptc, aTag)
ptc += 1
@ -2067,8 +2137,9 @@ class EPUB_MOBI(CatalogPlugin):
ptc += 1
aTag = Tag(soup, "a")
aTag['href'] = "book_%d.html" % (int(float(book['id'])))
# Use series, series index if avail else just title, + year of publication
if self.opts.generate_descriptions:
aTag['href'] = "book_%d.html" % (int(float(book['id'])))
# Use series, series index if avail else title, + year of publication
if current_series:
aTag.insert(0,'%s (%s)' % (escape(book['title'][len(book['series'])+1:]),
book['date'].split()[1]))
@ -2079,7 +2150,6 @@ class EPUB_MOBI(CatalogPlugin):
pBookTag.insert(ptc, aTag)
ptc += 1
divTag.insert(dtc, pBookTag)
dtc += 1
@ -2200,7 +2270,8 @@ class EPUB_MOBI(CatalogPlugin):
ptc += 1
aTag = Tag(soup, "a")
aTag['href'] = "book_%d.html" % (int(float(new_entry['id'])))
if self.opts.generate_descriptions:
aTag['href'] = "book_%d.html" % (int(float(new_entry['id'])))
if current_series:
aTag.insert(0,escape(new_entry['title'][len(new_entry['series'])+1:]))
else:
@ -2251,7 +2322,8 @@ class EPUB_MOBI(CatalogPlugin):
ptc += 1
aTag = Tag(soup, "a")
aTag['href'] = "book_%d.html" % (int(float(new_entry['id'])))
if self.opts.generate_descriptions:
aTag['href'] = "book_%d.html" % (int(float(new_entry['id'])))
aTag.insert(0,escape(new_entry['title']))
pBookTag.insert(ptc, aTag)
ptc += 1
@ -2411,7 +2483,8 @@ class EPUB_MOBI(CatalogPlugin):
ptc += 1
aTag = Tag(soup, "a")
aTag['href'] = "book_%d.html" % (int(float(new_entry['id'])))
if self.opts.generate_descriptions:
aTag['href'] = "book_%d.html" % (int(float(new_entry['id'])))
aTag.insert(0,escape(new_entry['title']))
pBookTag.insert(ptc, aTag)
ptc += 1
@ -2458,7 +2531,8 @@ class EPUB_MOBI(CatalogPlugin):
ptc += 1
aTag = Tag(soup, "a")
aTag['href'] = "book_%d.html" % (int(float(new_entry['id'])))
if self.opts.generate_descriptions:
aTag['href'] = "book_%d.html" % (int(float(new_entry['id'])))
aTag.insert(0,escape(new_entry['title']))
pBookTag.insert(ptc, aTag)
ptc += 1
@ -2699,7 +2773,8 @@ class EPUB_MOBI(CatalogPlugin):
ptc += 1
aTag = Tag(soup, "a")
aTag['href'] = "book_%d.html" % (int(float(book['id'])))
if self.opts.generate_descriptions:
aTag['href'] = "book_%d.html" % (int(float(book['id'])))
# Use series, series index if avail else just title
#aTag.insert(0,'%d. %s &middot; %s' % (book['series_index'],escape(book['title']), ' & '.join(book['authors'])))
@ -2983,18 +3058,20 @@ class EPUB_MOBI(CatalogPlugin):
manifest.insert(mtc, itemTag)
mtc += 1
# Write the thumbnail images to the manifest
for thumb in self.thumbs:
itemTag = Tag(soup, "item")
itemTag['href'] = "images/%s" % (thumb)
end = thumb.find('.jpg')
itemTag['id'] = "%s-image" % thumb[:end]
itemTag['media-type'] = 'image/jpeg'
manifest.insert(mtc, itemTag)
mtc += 1
# Write the thumbnail images, descriptions to the manifest
sort_descriptions_by = []
if self.opts.generate_descriptions:
for thumb in self.thumbs:
itemTag = Tag(soup, "item")
itemTag['href'] = "images/%s" % (thumb)
end = thumb.find('.jpg')
itemTag['id'] = "%s-image" % thumb[:end]
itemTag['media-type'] = 'image/jpeg'
manifest.insert(mtc, itemTag)
mtc += 1
# HTML files - add books to manifest and spine
sort_descriptions_by = self.booksByAuthor if self.opts.sort_descriptions_by_author \
# HTML files - add descriptions to manifest and spine
sort_descriptions_by = self.booksByAuthor if self.opts.sort_descriptions_by_author \
else self.booksByTitle
# Add html_files to manifest and spine
@ -3970,15 +4047,15 @@ class EPUB_MOBI(CatalogPlugin):
from calibre.customize.ui import output_profiles
for x in output_profiles():
if x.short_name == self.opts.output_profile:
# .9" width aspect ratio: 3:4
self.thumbWidth = int(x.dpi * 1)
self.thumbHeight = int(self.thumbWidth * 1.33)
# aspect ratio: 3:4
self.thumbWidth = x.dpi * float(self.opts.thumb_width)
self.thumbHeight = self.thumbWidth * 1.33
if 'kindle' in x.short_name and self.opts.fmt == 'mobi':
# Kindle DPI appears to be off by a factor of 2
self.thumbWidth = int(self.thumbWidth/2)
self.thumbHeight = int(self.thumbHeight/2)
self.thumbWidth = self.thumbWidth/2
self.thumbHeight = self.thumbHeight/2
break
if False and self.verbose:
if True and self.verbose:
self.opts.log(" DPI = %d; thumbnail dimensions: %d x %d" % \
(x.dpi, self.thumbWidth, self.thumbHeight))
@ -4238,7 +4315,8 @@ class EPUB_MOBI(CatalogPlugin):
# Add the book title
aTag = Tag(soup, "a")
aTag['href'] = "book_%d.html" % (int(float(book['id'])))
if self.opts.generate_descriptions:
aTag['href'] = "book_%d.html" % (int(float(book['id'])))
# Use series, series index if avail else just title
if current_series:
aTag.insert(0,escape(book['title'][len(book['series'])+1:]))
@ -4460,7 +4538,9 @@ class EPUB_MOBI(CatalogPlugin):
# Leading numbers optionally translated to text equivalent
# Capitalize leading sort word
if i==0:
if self.opts.numbers_as_text and re.match('[0-9]+',word[0]):
# *** Keep this code in case we need to restore numbers_as_text ***
if False:
#if self.opts.numbers_as_text and re.match('[0-9]+',word[0]):
translated.append(EPUB_MOBI.NumberToText(word).text.capitalize())
else:
if re.match('[0-9]+',word[0]):
@ -4540,7 +4620,6 @@ class EPUB_MOBI(CatalogPlugin):
''' Return a list of special marker tags to be excluded from genre list '''
markerTags = []
markerTags.extend(self.opts.exclude_tags.split(','))
markerTags.extend(self.opts.note_tag.split(','))
return markerTags
def letter_or_symbol(self,char):
@ -4663,13 +4742,63 @@ class EPUB_MOBI(CatalogPlugin):
return result.renderContents(encoding=None)
def mergeComments(self, record):
'''
merge ['description'] with custom field contents to be displayed in Descriptions
'''
merged = ''
if record['description']:
addendum = self.__db.get_field(record['id'],
self.__merge_comments['field'],
index_is_id=True)
include_hr = eval(self.__merge_comments['hr'])
if self.__merge_comments['position'] == 'before':
merged = addendum
if include_hr:
merged += '<hr class="merged_comments_divider"/>'
else:
merged += '\n'
merged += record['description']
else:
merged = record['description']
if include_hr:
merged += '<hr class="merged_comments_divider"/>'
else:
merged += '\n'
merged += addendum
else:
# Return the custom field contents
merged = self.__db.get_field(record['id'],
self.__merge_comments['field'],
index_is_id=True)
return merged
def processExclusions(self, data_set):
'''
Remove excluded entries
'''
field, pat = self.opts.exclude_book_marker.split(':')
if pat == '':
return data_set
filtered_data_set = []
for record in data_set:
field_contents = self.__db.get_field(record['id'],
field,
index_is_id=True)
if field_contents:
if re.search(pat, unicode(field_contents),
re.IGNORECASE) is not None:
continue
filtered_data_set.append(record)
return filtered_data_set
def processSpecialTags(self, tags, this_title, opts):
tag_list = []
for tag in tags:
tag = self.convertHTMLEntities(tag)
if tag.startswith(opts.note_tag):
this_title['notes'] = tag[len(self.opts.note_tag):]
elif re.search(opts.exclude_genre, tag):
if re.search(opts.exclude_genre, tag):
continue
elif self.__read_book_marker['field'] == 'tag' and \
tag == self.__read_book_marker['pattern']:
@ -4767,13 +4896,16 @@ class EPUB_MOBI(CatalogPlugin):
if opts_dict['ids']:
build_log.append(" book count: %d" % len(opts_dict['ids']))
sections_list = ['Descriptions','Authors']
sections_list = ['Authors']
if opts.generate_titles:
sections_list.append('Titles')
if opts.generate_recently_added:
sections_list.append('Recently Added')
if not opts.exclude_genre.strip() == '.':
if opts.generate_genres:
sections_list.append('Genres')
if opts.generate_descriptions:
sections_list.append('Descriptions')
build_log.append(u" Sections: %s" % ', '.join(sections_list))
# Display opts
@ -4782,11 +4914,12 @@ class EPUB_MOBI(CatalogPlugin):
build_log.append(" opts:")
for key in keys:
if key in ['catalog_title','authorClip','connected_kindle','descriptionClip',
'exclude_genre','exclude_tags','note_tag','numbers_as_text',
'exclude_book_marker','exclude_genre','exclude_tags',
'header_note_source_field','merge_comments',
'output_profile','read_book_marker',
'search_text','sort_by','sort_descriptions_by_author','sync',
'wishlist_tag']:
build_log.append(" %s: %s" % (key, opts_dict[key]))
'thumb_width','wishlist_tag']:
build_log.append(" %s: %s" % (key, repr(opts_dict[key])))
if opts.verbose:
log('\n'.join(line for line in build_log))
@ -4801,6 +4934,7 @@ class EPUB_MOBI(CatalogPlugin):
catalog.copyResources()
catalog.calculateThumbnailSize()
catalog_source_built = catalog.buildSources()
if opts.verbose:
if catalog_source_built:
log.info(" Completed catalog source generation\n")