mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-08 18:54:09 -04:00
Catalog generation: Fixed improper title display in catalog when title contains ':'. Added 'ondevice' field to CSV/XML catalog output (only with connected device|folder|iTunes). Added optional 'Series' section to generated catalogs with hyperlinks between books and series. Tweaks to catalog formatting
This commit is contained in:
commit
336db024ae
@ -6,7 +6,7 @@ p.title {
|
||||
text-align:center;
|
||||
font-style:italic;
|
||||
font-size:xx-large;
|
||||
border-bottom: solid black 4px;
|
||||
border-bottom: solid black 2px;
|
||||
}
|
||||
|
||||
p.author {
|
||||
@ -17,6 +17,15 @@ p.author {
|
||||
font-size:large;
|
||||
}
|
||||
|
||||
p.author_index {
|
||||
font-size:large;
|
||||
font-weight:bold;
|
||||
text-align:left;
|
||||
margin-top:0px;
|
||||
margin-bottom:-2px;
|
||||
text-indent: 0em;
|
||||
}
|
||||
|
||||
p.tags {
|
||||
margin-top:0em;
|
||||
margin-bottom:0em;
|
||||
@ -47,19 +56,12 @@ p.letter_index {
|
||||
margin-bottom:0px;
|
||||
}
|
||||
|
||||
p.author_index {
|
||||
font-size:large;
|
||||
text-align:left;
|
||||
margin-top:0px;
|
||||
margin-bottom:0px;
|
||||
text-indent: 0em;
|
||||
}
|
||||
|
||||
p.series {
|
||||
text-align: left;
|
||||
margin-top:0px;
|
||||
font-style:italic;
|
||||
margin-top:2px;
|
||||
margin-bottom:0px;
|
||||
margin-left:2em;
|
||||
text-align:left;
|
||||
text-indent:-2em;
|
||||
}
|
||||
|
||||
@ -87,11 +89,13 @@ p.date_read {
|
||||
text-indent:-6em;
|
||||
}
|
||||
|
||||
hr.series_divider {
|
||||
width:50%;
|
||||
margin-left:1em;
|
||||
margin-top:0em;
|
||||
margin-bottom:0em;
|
||||
hr.description_divider {
|
||||
width:90%;
|
||||
margin-left:5%;
|
||||
border-top: solid white 0px;
|
||||
border-right: solid white 0px;
|
||||
border-bottom: solid black 1px;
|
||||
border-left: solid white 0px;
|
||||
}
|
||||
|
||||
hr.annotations_divider {
|
||||
|
@ -294,7 +294,7 @@ class CatalogPlugin(Plugin): # {{{
|
||||
# Return a list of requested fields, with opts.sort_by first
|
||||
all_fields = set(
|
||||
['author_sort','authors','comments','cover','formats',
|
||||
'id','isbn','pubdate','publisher','rating',
|
||||
'id','isbn','ondevice','pubdate','publisher','rating',
|
||||
'series_index','series','size','tags','timestamp',
|
||||
'title','uuid'])
|
||||
|
||||
@ -306,6 +306,9 @@ class CatalogPlugin(Plugin): # {{{
|
||||
else:
|
||||
fields = list(all_fields)
|
||||
|
||||
if not opts.connected_device['is_device_connected'] and 'ondevice' in fields:
|
||||
fields.pop(int(fields.index('ondevice')))
|
||||
|
||||
fields.sort()
|
||||
if opts.sort_by and opts.sort_by in fields:
|
||||
fields.insert(0,fields.pop(int(fields.index(opts.sort_by))))
|
||||
|
@ -2303,9 +2303,9 @@ class ITUNES(DriverBase):
|
||||
# Delete existing from Device|Books, add to self.update_list
|
||||
# for deletion from booklist[0] during add_books_to_metadata
|
||||
for book in self.cached_books:
|
||||
if self.cached_books[book]['uuid'] == metadata.uuid and \
|
||||
self.cached_books[book]['title'] == metadata.title and \
|
||||
self.cached_books[book]['author'] == metadata.authors[0]:
|
||||
if self.cached_books[book]['uuid'] == metadata.uuid or \
|
||||
(self.cached_books[book]['title'] == metadata.title and \
|
||||
self.cached_books[book]['author'] == metadata.authors[0]):
|
||||
self.update_list.append(self.cached_books[book])
|
||||
self._remove_from_device(self.cached_books[book])
|
||||
if DEBUG:
|
||||
@ -2322,9 +2322,9 @@ class ITUNES(DriverBase):
|
||||
# Delete existing from Library|Books, add to self.update_list
|
||||
# for deletion from booklist[0] during add_books_to_metadata
|
||||
for book in self.cached_books:
|
||||
if self.cached_books[book]['uuid'] == metadata.uuid and \
|
||||
self.cached_books[book]['title'] == metadata.title and \
|
||||
self.cached_books[book]['author'] == metadata.authors[0]:
|
||||
if self.cached_books[book]['uuid'] == metadata.uuid or \
|
||||
(self.cached_books[book]['title'] == metadata.title and \
|
||||
self.cached_books[book]['author'] == metadata.authors[0]):
|
||||
self.update_list.append(self.cached_books[book])
|
||||
self._remove_from_iTunes(self.cached_books[book])
|
||||
if DEBUG:
|
||||
@ -2488,7 +2488,7 @@ class ITUNES(DriverBase):
|
||||
zf_opf.close()
|
||||
|
||||
# If 'News' in tags, tweak the title/author for friendlier display in iBooks
|
||||
if _('News') in metadata.tags:
|
||||
if _('News') or _('Catalog') in metadata.tags:
|
||||
if metadata.title.find('[') > 0:
|
||||
metadata.title = metadata.title[:metadata.title.find('[')-1]
|
||||
date_as_author = '%s, %s %s, %s' % (strftime('%A'), strftime('%B'), strftime('%d').lstrip('0'), strftime('%Y'))
|
||||
|
@ -26,14 +26,18 @@ class GenerateCatalogAction(InterfaceAction):
|
||||
rows = xrange(self.gui.library_view.model().rowCount(QModelIndex()))
|
||||
ids = map(self.gui.library_view.model().id, rows)
|
||||
|
||||
dbspec = None
|
||||
if not ids:
|
||||
return error_dialog(self.gui, _('No books selected'),
|
||||
_('No books selected to generate catalog for'),
|
||||
show=True)
|
||||
|
||||
db = self.gui.library_view.model().db
|
||||
dbspec = {}
|
||||
for id in ids:
|
||||
dbspec[id] = {'ondevice': db.ondevice(id, index_is_id=True)}
|
||||
|
||||
# Calling gui2.tools:generate_catalog()
|
||||
ret = generate_catalog(self.gui, dbspec, ids, self.gui.device_manager.device)
|
||||
ret = generate_catalog(self.gui, dbspec, ids, self.gui.device_manager)
|
||||
if ret is None:
|
||||
return
|
||||
|
||||
|
@ -19,6 +19,7 @@ class PluginWidget(QWidget,Ui_Form):
|
||||
OPTION_FIELDS = [('exclude_genre','\[.+\]'),
|
||||
('exclude_tags','~,'+_('Catalog')),
|
||||
('generate_titles', True),
|
||||
('generate_series', True),
|
||||
('generate_recently_added', True),
|
||||
('note_tag','*'),
|
||||
('numbers_as_text', False),
|
||||
@ -40,7 +41,7 @@ class PluginWidget(QWidget,Ui_Form):
|
||||
# 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 ['numbers_as_text','generate_titles','generate_recently_added']:
|
||||
if opt[0] in ['numbers_as_text','generate_titles','generate_series','generate_recently_added']:
|
||||
getattr(self, opt[0]).setChecked(opt_value)
|
||||
else:
|
||||
getattr(self, opt[0]).setText(opt_value)
|
||||
@ -52,13 +53,13 @@ class PluginWidget(QWidget,Ui_Form):
|
||||
# others store as lists
|
||||
opts_dict = {}
|
||||
for opt in self.OPTION_FIELDS:
|
||||
if opt[0] in ['numbers_as_text','generate_titles','generate_recently_added']:
|
||||
if opt[0] in ['numbers_as_text','generate_titles','generate_series','generate_recently_added']:
|
||||
opt_value = getattr(self,opt[0]).isChecked()
|
||||
else:
|
||||
opt_value = unicode(getattr(self, opt[0]).text())
|
||||
gprefs.set(self.name + '_' + opt[0], opt_value)
|
||||
|
||||
if opt[0] in ['exclude_genre','numbers_as_text','generate_titles','generate_recently_added']:
|
||||
if opt[0] in ['exclude_genre','numbers_as_text','generate_titles','generate_series','generate_recently_added']:
|
||||
opts_dict[opt[0]] = opt_value
|
||||
else:
|
||||
opts_dict[opt[0]] = opt_value.split(',')
|
||||
|
@ -108,20 +108,27 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<item row="10" column="0">
|
||||
<widget class="QCheckBox" name="generate_recently_added">
|
||||
<property name="text">
|
||||
<string>Include 'Recently Added' Section</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="0">
|
||||
<item row="11" column="0">
|
||||
<widget class="QCheckBox" name="numbers_as_text">
|
||||
<property name="text">
|
||||
<string>Sort numbers as text</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<widget class="QCheckBox" name="generate_series">
|
||||
<property name="text">
|
||||
<string>Include 'Series' Section</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
|
@ -29,6 +29,7 @@ def gui_catalog(fmt, title, dbspec, ids, out_file_name, sync, fmt_options, conne
|
||||
log = Log()
|
||||
from calibre.library import db
|
||||
db = db()
|
||||
db.catalog_plugin_on_device_temp_mapping = dbspec
|
||||
|
||||
# Create a minimal OptionParser that we can append to
|
||||
parser = OptionParser()
|
||||
|
@ -238,7 +238,7 @@ def fetch_scheduled_recipe(arg):
|
||||
|
||||
return 'gui_convert', args, _('Fetch news from ')+arg['title'], fmt.upper(), [pt]
|
||||
|
||||
def generate_catalog(parent, dbspec, ids, device):
|
||||
def generate_catalog(parent, dbspec, ids, device_manager):
|
||||
from calibre.gui2.dialogs.catalog import Catalog
|
||||
|
||||
# Build the Catalog dialog in gui2.dialogs.catalog
|
||||
@ -252,9 +252,18 @@ def generate_catalog(parent, dbspec, ids, device):
|
||||
|
||||
# Profile the connected device
|
||||
# Parallel initialization in calibre.library.cli:command_catalog()
|
||||
connected_device = { 'storage':None,'serial':None,'save_template':None,'name':None}
|
||||
connected_device = {
|
||||
'is_device_connected': device_manager.is_device_connected,
|
||||
'kind': device_manager.connected_device_kind,
|
||||
'name': None,
|
||||
'save_template': None,
|
||||
'serial': None,
|
||||
'storage': None
|
||||
}
|
||||
|
||||
if device:
|
||||
if device_manager.is_device_connected:
|
||||
device = device_manager.device
|
||||
connected_device['name'] = device.gui_name
|
||||
try:
|
||||
storage = []
|
||||
if device._main_prefix:
|
||||
@ -263,11 +272,10 @@ def generate_catalog(parent, dbspec, ids, device):
|
||||
storage.append(os.path.join(device._card_a_prefix, device.EBOOK_DIR_CARD_A))
|
||||
if device._card_b_prefix:
|
||||
storage.append(os.path.join(device._card_b_prefix, device.EBOOK_DIR_CARD_B))
|
||||
connected_device = { 'storage': storage,
|
||||
'serial': device.detected_device.serial if \
|
||||
hasattr(device.detected_device,'serial') else None,
|
||||
'save_template': device.save_template(),
|
||||
'name': device.gui_name}
|
||||
connected_device['storage'] = storage
|
||||
connected_device['serial'] = device.detected_device.serial if \
|
||||
hasattr(device.detected_device,'serial') else None
|
||||
connected_device['save_template'] = device.save_template()
|
||||
except:
|
||||
pass
|
||||
|
||||
|
@ -20,7 +20,7 @@ from calibre.utils.date import isoformat, now as nowf
|
||||
from calibre.utils.logging import default_log as log
|
||||
|
||||
FIELDS = ['all', 'author_sort', 'authors', 'comments',
|
||||
'cover', 'formats', 'id', 'isbn', 'pubdate', 'publisher', 'rating',
|
||||
'cover', 'formats', 'id', 'isbn', 'ondevice', 'pubdate', 'publisher', 'rating',
|
||||
'series_index', 'series', 'size', 'tags', 'timestamp', 'title',
|
||||
'uuid']
|
||||
|
||||
@ -67,6 +67,8 @@ class CSV_XML(CatalogPlugin):
|
||||
if opts.verbose:
|
||||
opts_dict = vars(opts)
|
||||
log("%s(): Generating %s" % (self.name,self.fmt))
|
||||
if opts.connected_device['is_device_connected']:
|
||||
log(" connected_device: %s" % opts.connected_device['name'])
|
||||
if opts_dict['search_text']:
|
||||
log(" --search='%s'" % opts_dict['search_text'])
|
||||
|
||||
@ -81,7 +83,6 @@ class CSV_XML(CatalogPlugin):
|
||||
else:
|
||||
log(" Fields: %s" % opts_dict['fields'])
|
||||
|
||||
|
||||
# If a list of ids are provided, don't use search_text
|
||||
if opts.ids:
|
||||
opts.search_text = None
|
||||
@ -95,6 +96,11 @@ class CSV_XML(CatalogPlugin):
|
||||
# Get the requested output fields as a list
|
||||
fields = self.get_output_fields(opts)
|
||||
|
||||
# If connected device, add 'On Device' values to data
|
||||
if opts.connected_device['is_device_connected'] and 'ondevice' in fields:
|
||||
for entry in data:
|
||||
entry['ondevice'] = db.catalog_plugin_on_device_temp_mapping[entry['id']]['ondevice']
|
||||
|
||||
if self.fmt == 'csv':
|
||||
outfile = codecs.open(path_to_output, 'w', 'utf8')
|
||||
|
||||
@ -140,10 +146,10 @@ class CSV_XML(CatalogPlugin):
|
||||
root.append(record)
|
||||
|
||||
for field in ('id', 'uuid', 'title', 'publisher', 'rating', 'size',
|
||||
'isbn'):
|
||||
'isbn','ondevice'):
|
||||
if field in fields:
|
||||
val = r[field]
|
||||
if val is None:
|
||||
if not val:
|
||||
continue
|
||||
if not isinstance(val, (str, unicode)):
|
||||
val = unicode(val)
|
||||
@ -561,6 +567,13 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
help=_("Include 'Titles' section in catalog.\n"
|
||||
"Default: '%default'\n"
|
||||
"Applies to: ePub, MOBI output formats")),
|
||||
Option('--generate-series',
|
||||
default=False,
|
||||
dest='generate_series',
|
||||
action = 'store_true',
|
||||
help=_("Include 'Series' section in catalog.\n"
|
||||
"Default: '%default'\n"
|
||||
"Applies to: ePub, MOBI output formats")),
|
||||
Option('--generate-recently-added',
|
||||
default=False,
|
||||
dest='generate_recently_added',
|
||||
@ -886,8 +899,12 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
self.__totalSteps += 2
|
||||
if self.generateRecentlyRead:
|
||||
self.__totalSteps += 2
|
||||
if self.opts.generate_series:
|
||||
self.__totalSteps += 2
|
||||
|
||||
|
||||
# Accessors
|
||||
if True:
|
||||
'''
|
||||
@dynamic_property
|
||||
def xxxx(self):
|
||||
@ -897,7 +914,6 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
self.__ = val
|
||||
return property(fget=fget, fset=fset)
|
||||
'''
|
||||
|
||||
@dynamic_property
|
||||
def authorClip(self):
|
||||
def fget(self):
|
||||
@ -1196,6 +1212,8 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
self.generateHTMLByAuthor()
|
||||
if self.opts.generate_titles:
|
||||
self.generateHTMLByTitle()
|
||||
if self.opts.generate_series:
|
||||
self.generateHTMLBySeries()
|
||||
if self.opts.generate_recently_added:
|
||||
self.generateHTMLByDateAdded()
|
||||
if self.generateRecentlyRead:
|
||||
@ -1206,15 +1224,17 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
|
||||
self.generateOPF()
|
||||
self.generateNCXHeader()
|
||||
self.generateNCXDescriptions("Descriptions")
|
||||
self.generateNCXByAuthor("Authors")
|
||||
if self.opts.generate_titles:
|
||||
self.generateNCXByTitle("Titles")
|
||||
if self.opts.generate_series:
|
||||
self.generateNCXBySeries("Series")
|
||||
if self.opts.generate_recently_added:
|
||||
self.generateNCXByDateAdded("Recently Added")
|
||||
if self.generateRecentlyRead:
|
||||
self.generateNCXByDateRead("Recently Read")
|
||||
self.generateNCXByGenre("Genres")
|
||||
self.generateNCXDescriptions("Descriptions")
|
||||
self.writeNCX()
|
||||
return True
|
||||
|
||||
@ -1569,9 +1589,22 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
emTag = Tag(soup, "em")
|
||||
if title['series']:
|
||||
# title<br />series series_index
|
||||
if self.opts.generate_series:
|
||||
brTag = Tag(soup,'br')
|
||||
title_tokens = title['title'].split(': ')
|
||||
emTag.insert(0, escape(NavigableString(title_tokens[1])))
|
||||
title_tokens = list(title['title'].partition(':'))
|
||||
emTag.insert(0, escape(NavigableString(title_tokens[2].strip())))
|
||||
emTag.insert(1, brTag)
|
||||
smallTag = Tag(soup,'small')
|
||||
aTag = Tag(soup,'a')
|
||||
aTag['href'] = "%s.html#%s_series" % ('BySeries',
|
||||
re.sub('\W','',title['series']).lower())
|
||||
aTag.insert(0, title_tokens[0])
|
||||
smallTag.insert(0, aTag)
|
||||
emTag.insert(2, smallTag)
|
||||
else:
|
||||
brTag = Tag(soup,'br')
|
||||
title_tokens = list(title['title'].partition(':'))
|
||||
emTag.insert(0, escape(NavigableString(title_tokens[2].strip())))
|
||||
emTag.insert(1, brTag)
|
||||
smallTag = Tag(soup,'small')
|
||||
smallTag.insert(0, escape(NavigableString(title_tokens[0])))
|
||||
@ -1724,17 +1757,17 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
body.insert(btc, aTag)
|
||||
btc += 1
|
||||
|
||||
'''
|
||||
if not self.__generateForKindle:
|
||||
# We don't need this because the Kindle shows section titles
|
||||
#<h2><a name="byalphatitle" id="byalphatitle"></a>By Title</h2>
|
||||
h2Tag = Tag(soup, "h2")
|
||||
pTag = Tag(soup, "p")
|
||||
pTag['class'] = 'title'
|
||||
aTag = Tag(soup, "a")
|
||||
aTag['name'] = "bytitle"
|
||||
h2Tag.insert(0,aTag)
|
||||
h2Tag.insert(1,NavigableString('By Title (%d)' % len(self.booksByTitle)))
|
||||
body.insert(btc,h2Tag)
|
||||
pTag.insert(0,aTag)
|
||||
pTag.insert(1,NavigableString('Titles'))
|
||||
body.insert(btc,pTag)
|
||||
btc += 1
|
||||
'''
|
||||
|
||||
# <p class="letter_index">
|
||||
# <p class="book_title">
|
||||
@ -1742,13 +1775,13 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
dtc = 0
|
||||
current_letter = ""
|
||||
|
||||
# 2/14/10 7:11 AM Experimental: re-sort title list without leading series/series_index
|
||||
# Re-sort title list without leading series/series_index
|
||||
if not self.useSeriesPrefixInTitlesSection:
|
||||
nspt = deepcopy(self.booksByTitle)
|
||||
for book in nspt:
|
||||
if book['series']:
|
||||
tokens = book['title'].split(': ')
|
||||
book['title'] = '%s (%s)' % (tokens[1], tokens[0])
|
||||
tokens = book['title'].partition(':')
|
||||
book['title'] = '%s (%s)' % (tokens[2].strip(), tokens[0])
|
||||
book['title_sort'] = self.generateSortTitle(book['title'])
|
||||
nspt = sorted(nspt,
|
||||
key=lambda x:(x['title_sort'].upper(), x['title_sort'].upper()))
|
||||
@ -1835,7 +1868,7 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
# Write books by author A-Z
|
||||
self.updateProgressFullStep("'Authors'")
|
||||
|
||||
friendly_name = "By Author"
|
||||
friendly_name = "Authors"
|
||||
|
||||
soup = self.generateHTMLEmptyHeader(friendly_name)
|
||||
body = soup.find('body')
|
||||
@ -1906,15 +1939,14 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
current_series = None
|
||||
pAuthorTag = Tag(soup, "p")
|
||||
pAuthorTag['class'] = "author_index"
|
||||
emTag = Tag(soup, "em")
|
||||
aTag = Tag(soup, "a")
|
||||
aTag['name'] = "%s" % self.generateAuthorAnchor(current_author)
|
||||
aTag.insert(0,NavigableString(current_author))
|
||||
emTag.insert(0,aTag)
|
||||
pAuthorTag.insert(0,emTag)
|
||||
pAuthorTag.insert(0,aTag)
|
||||
divTag.insert(dtc,pAuthorTag)
|
||||
dtc += 1
|
||||
|
||||
'''
|
||||
# Insert an <hr /> between non-series and series
|
||||
if not current_series and non_series_books and book['series']:
|
||||
# Insert an <hr />
|
||||
@ -1922,6 +1954,7 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
hrTag['class'] = "series_divider"
|
||||
divTag.insert(dtc,hrTag)
|
||||
dtc += 1
|
||||
'''
|
||||
|
||||
# Check for series
|
||||
if book['series'] and book['series'] != current_series:
|
||||
@ -1929,7 +1962,18 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
current_series = book['series']
|
||||
pSeriesTag = Tag(soup,'p')
|
||||
pSeriesTag['class'] = "series"
|
||||
pSeriesTag.insert(0,NavigableString(self.NOT_READ_SYMBOL + book['series']))
|
||||
|
||||
if self.opts.generate_series:
|
||||
aTag = Tag(soup,'a')
|
||||
aTag['href'] = "%s.html#%s_series" % ('BySeries',
|
||||
re.sub('\W','',book['series']).lower())
|
||||
aTag.insert(0, book['series'])
|
||||
#pSeriesTag.insert(0, NavigableString(self.NOT_READ_SYMBOL))
|
||||
pSeriesTag.insert(0, aTag)
|
||||
else:
|
||||
#pSeriesTag.insert(0,NavigableString(self.NOT_READ_SYMBOL + '%s' % book['series']))
|
||||
pSeriesTag.insert(0,NavigableString('%s' % book['series']))
|
||||
|
||||
divTag.insert(dtc,pSeriesTag)
|
||||
dtc += 1
|
||||
if current_series and not book['series']:
|
||||
@ -1957,30 +2001,34 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
|
||||
aTag = Tag(soup, "a")
|
||||
aTag['href'] = "book_%d.html" % (int(float(book['id'])))
|
||||
# Use series, series index if avail else just title
|
||||
# Use series, series index if avail else just title, + year of publication
|
||||
if current_series:
|
||||
aTag.insert(0,escape(book['title'][len(book['series'])+1:]))
|
||||
aTag.insert(0,'%s (%s)' % (escape(book['title'][len(book['series'])+1:]),
|
||||
book['date'].split()[1]))
|
||||
else:
|
||||
aTag.insert(0,escape(book['title']))
|
||||
aTag.insert(0,'%s (%s)' % (escape(book['title']),
|
||||
book['date'].split()[1]))
|
||||
non_series_books += 1
|
||||
pBookTag.insert(ptc, aTag)
|
||||
ptc += 1
|
||||
|
||||
|
||||
divTag.insert(dtc, pBookTag)
|
||||
dtc += 1
|
||||
|
||||
'''
|
||||
if not self.__generateForKindle:
|
||||
# Insert the <h2> tag with book_count at the head
|
||||
#<h2><a name="byalphaauthor" id="byalphaauthor"></a>By Author</h2>
|
||||
h2Tag = Tag(soup, "h2")
|
||||
pTag = Tag(soup, "p")
|
||||
pTag['class'] = 'title'
|
||||
aTag = Tag(soup, "a")
|
||||
anchor_name = friendly_name.lower()
|
||||
aTag['name'] = anchor_name.replace(" ","")
|
||||
h2Tag.insert(0,aTag)
|
||||
h2Tag.insert(1,NavigableString('%s (%d)' % (friendly_name, book_count)))
|
||||
body.insert(btc,h2Tag)
|
||||
pTag.insert(0,aTag)
|
||||
#h2Tag.insert(1,NavigableString('%s (%d)' % (friendly_name, book_count)))
|
||||
pTag.insert(1,NavigableString('%s' % (friendly_name)))
|
||||
body.insert(btc,pTag)
|
||||
btc += 1
|
||||
'''
|
||||
|
||||
# Add the divTag to the body
|
||||
body.insert(btc, divTag)
|
||||
@ -2023,15 +2071,14 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
current_series = None
|
||||
pAuthorTag = Tag(soup, "p")
|
||||
pAuthorTag['class'] = "author_index"
|
||||
emTag = Tag(soup, "em")
|
||||
aTag = Tag(soup, "a")
|
||||
aTag['name'] = "%s" % self.generateAuthorAnchor(current_author)
|
||||
aTag.insert(0,NavigableString(current_author))
|
||||
emTag.insert(0,aTag)
|
||||
pAuthorTag.insert(0,emTag)
|
||||
pAuthorTag.insert(0,aTag)
|
||||
divTag.insert(dtc,pAuthorTag)
|
||||
dtc += 1
|
||||
|
||||
'''
|
||||
# Insert an <hr /> between non-series and series
|
||||
if not current_series and non_series_books and new_entry['series']:
|
||||
# Insert an <hr />
|
||||
@ -2039,6 +2086,7 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
hrTag['class'] = "series_divider"
|
||||
divTag.insert(dtc,hrTag)
|
||||
dtc += 1
|
||||
'''
|
||||
|
||||
# Check for series
|
||||
if new_entry['series'] and new_entry['series'] != current_series:
|
||||
@ -2046,7 +2094,14 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
current_series = new_entry['series']
|
||||
pSeriesTag = Tag(soup,'p')
|
||||
pSeriesTag['class'] = "series"
|
||||
pSeriesTag.insert(0,NavigableString(self.NOT_READ_SYMBOL + new_entry['series']))
|
||||
if self.opts.generate_series:
|
||||
aTag = Tag(soup,'a')
|
||||
aTag['href'] = "%s.html#%s_series" % ('BySeries',
|
||||
re.sub('\W','',new_entry['series']).lower())
|
||||
aTag.insert(0, new_entry['series'])
|
||||
pSeriesTag.insert(0, aTag)
|
||||
else:
|
||||
pSeriesTag.insert(0,NavigableString('%s' % new_entry['series']))
|
||||
divTag.insert(dtc,pSeriesTag)
|
||||
dtc += 1
|
||||
if current_series and not new_entry['series']:
|
||||
@ -2160,18 +2215,18 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
aTag['name'] = anchor_name.replace(" ","")
|
||||
body.insert(btc, aTag)
|
||||
btc += 1
|
||||
'''
|
||||
# We don't need this because the kindle inserts section titles
|
||||
|
||||
if not self.__generateForKindle:
|
||||
#<h2><a name="byalphaauthor" id="byalphaauthor"></a>By Author</h2>
|
||||
h2Tag = Tag(soup, "h2")
|
||||
pTag = Tag(soup, "p")
|
||||
pTag['class'] = 'title'
|
||||
aTag = Tag(soup, "a")
|
||||
anchor_name = friendly_name.lower()
|
||||
aTag['name'] = anchor_name.replace(" ","")
|
||||
h2Tag.insert(0,aTag)
|
||||
h2Tag.insert(1,NavigableString('%s' % friendly_name))
|
||||
body.insert(btc,h2Tag)
|
||||
pTag.insert(0,aTag)
|
||||
pTag.insert(1,NavigableString('%s' % friendly_name))
|
||||
body.insert(btc,pTag)
|
||||
btc += 1
|
||||
'''
|
||||
|
||||
# <p class="letter_index">
|
||||
# <p class="author_index">
|
||||
@ -2186,14 +2241,13 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
nspt = deepcopy(self.booksByTitle)
|
||||
for book in nspt:
|
||||
if book['series']:
|
||||
tokens = book['title'].split(': ')
|
||||
book['title'] = '%s (%s)' % (tokens[1], tokens[0])
|
||||
tokens = book['title'].partition(':')
|
||||
book['title'] = '%s (%s)' % (tokens[2].strip(), tokens[0])
|
||||
book['title_sort'] = self.generateSortTitle(book['title'])
|
||||
self.booksByDateRange = sorted(nspt, key=lambda x:(x['timestamp'], x['timestamp']),reverse=True)
|
||||
|
||||
date_range_list = []
|
||||
today_time = nowf().replace(hour=23, minute=59, second=59)
|
||||
books_added_in_date_range = False
|
||||
for (i, date) in enumerate(self.DATE_RANGE):
|
||||
date_range_limit = self.DATE_RANGE[i]
|
||||
if i:
|
||||
@ -2206,18 +2260,20 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
delta = today_time-book_time
|
||||
if delta.days <= date_range_limit:
|
||||
date_range_list.append(book)
|
||||
books_added_in_date_range = True
|
||||
else:
|
||||
break
|
||||
|
||||
dtc = add_books_to_HTML_by_date_range(date_range_list, date_range, dtc)
|
||||
date_range_list = [book]
|
||||
|
||||
'''
|
||||
if books_added_in_date_range:
|
||||
# Add an <hr> separating date ranges from months
|
||||
hrTag = Tag(soup,'hr')
|
||||
hrTag['class'] = "description_divider"
|
||||
divTag.insert(dtc,hrTag)
|
||||
dtc += 1
|
||||
'''
|
||||
|
||||
# >>>> Books by month <<<<
|
||||
# Sort titles case-insensitive for by month using series prefix
|
||||
@ -2437,6 +2493,174 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
outfile.close()
|
||||
self.htmlFileList.append("content/ByDateRead.html")
|
||||
|
||||
def generateHTMLBySeries(self):
|
||||
'''
|
||||
Generate a list of series
|
||||
'''
|
||||
self.updateProgressFullStep("Fetching series")
|
||||
|
||||
self.opts.sort_by = 'series'
|
||||
|
||||
# Merge opts.exclude_tags with opts.search_text
|
||||
# Updated to use exact match syntax
|
||||
empty_exclude_tags = False if len(self.opts.exclude_tags) else True
|
||||
search_phrase = 'series:true '
|
||||
if not empty_exclude_tags:
|
||||
exclude_tags = self.opts.exclude_tags.split(',')
|
||||
search_terms = []
|
||||
for tag in exclude_tags:
|
||||
search_terms.append("tag:=%s" % tag)
|
||||
search_phrase += "not (%s)" % " or ".join(search_terms)
|
||||
|
||||
# If a list of ids are provided, don't use search_text
|
||||
if self.opts.ids:
|
||||
self.opts.search_text = search_phrase
|
||||
else:
|
||||
if self.opts.search_text:
|
||||
self.opts.search_text += " " + search_phrase
|
||||
else:
|
||||
self.opts.search_text = search_phrase
|
||||
|
||||
# Fetch the database as a dictionary
|
||||
self.booksBySeries = self.plugin.search_sort_db(self.db, self.opts)
|
||||
|
||||
friendly_name = "Series"
|
||||
|
||||
soup = self.generateHTMLEmptyHeader(friendly_name)
|
||||
body = soup.find('body')
|
||||
|
||||
btc = 0
|
||||
|
||||
# Insert section tag
|
||||
aTag = Tag(soup,'a')
|
||||
aTag['name'] = 'section_start'
|
||||
body.insert(btc, aTag)
|
||||
btc += 1
|
||||
|
||||
# Insert the anchor
|
||||
aTag = Tag(soup, "a")
|
||||
anchor_name = friendly_name.lower()
|
||||
aTag['name'] = anchor_name.replace(" ","")
|
||||
body.insert(btc, aTag)
|
||||
btc += 1
|
||||
|
||||
# <p class="letter_index">
|
||||
# <p class="author_index">
|
||||
divTag = Tag(soup, "div")
|
||||
dtc = 0
|
||||
current_letter = ""
|
||||
current_series = None
|
||||
|
||||
# Loop through booksBySeries
|
||||
series_count = 0
|
||||
for book in self.booksBySeries:
|
||||
# Check for initial letter change
|
||||
sort_title = self.generateSortTitle(book['series'])
|
||||
if self.letter_or_symbol(sort_title[0].upper()) != current_letter :
|
||||
'''
|
||||
# Start a new letter - anchor only, hidden
|
||||
current_letter = book['author_sort'][0].upper()
|
||||
aTag = Tag(soup, "a")
|
||||
aTag['name'] = "%sseries" % current_letter
|
||||
divTag.insert(dtc, aTag)
|
||||
dtc += 1
|
||||
'''
|
||||
# Start a new letter with Index letter
|
||||
current_letter = self.letter_or_symbol(sort_title[0].upper())
|
||||
pIndexTag = Tag(soup, "p")
|
||||
pIndexTag['class'] = "letter_index"
|
||||
aTag = Tag(soup, "a")
|
||||
aTag['name'] = "%s_series" % self.letter_or_symbol(current_letter)
|
||||
pIndexTag.insert(0,aTag)
|
||||
pIndexTag.insert(1,NavigableString(self.letter_or_symbol(sort_title[0].upper())))
|
||||
divTag.insert(dtc,pIndexTag)
|
||||
dtc += 1
|
||||
|
||||
# Check for series change
|
||||
if book['series'] != current_series:
|
||||
# Start a new series
|
||||
series_count += 1
|
||||
current_series = book['series']
|
||||
pSeriesTag = Tag(soup,'p')
|
||||
pSeriesTag['class'] = "series"
|
||||
aTag = Tag(soup, 'a')
|
||||
aTag['name'] = "%s_series" % re.sub('\W','',book['series']).lower()
|
||||
pSeriesTag.insert(0,aTag)
|
||||
pSeriesTag.insert(1,NavigableString(self.NOT_READ_SYMBOL + '%s' % book['series']))
|
||||
divTag.insert(dtc,pSeriesTag)
|
||||
dtc += 1
|
||||
|
||||
# Add books
|
||||
pBookTag = Tag(soup, "p")
|
||||
ptc = 0
|
||||
|
||||
# book with read/reading/unread symbol
|
||||
if 'read' in book and book['read']:
|
||||
# check mark
|
||||
pBookTag.insert(ptc,NavigableString(self.READ_SYMBOL))
|
||||
pBookTag['class'] = "read_book"
|
||||
ptc += 1
|
||||
elif book['id'] in self.bookmarked_books:
|
||||
pBookTag.insert(ptc,NavigableString(self.READING_SYMBOL))
|
||||
pBookTag['class'] = "read_book"
|
||||
ptc += 1
|
||||
else:
|
||||
# hidden check mark
|
||||
pBookTag['class'] = "unread_book"
|
||||
pBookTag.insert(ptc,NavigableString(self.NOT_READ_SYMBOL))
|
||||
ptc += 1
|
||||
|
||||
aTag = Tag(soup, "a")
|
||||
aTag['href'] = "book_%d.html" % (int(float(book['id'])))
|
||||
# Use series, series index if avail else just title
|
||||
#aTag.insert(0,'%d. %s · %s' % (book['series_index'],escape(book['title']), ' & '.join(book['authors'])))
|
||||
|
||||
# Link to book
|
||||
aTag.insert(0,'%d. %s (%s)' % (book['series_index'],
|
||||
escape(book['title']),
|
||||
strftime(u'%Y', book['pubdate'].timetuple())))
|
||||
pBookTag.insert(ptc, aTag)
|
||||
ptc += 1
|
||||
|
||||
# ·
|
||||
pBookTag.insert(ptc, NavigableString(' · '))
|
||||
ptc += 1
|
||||
|
||||
# Link to author
|
||||
aTag = Tag(soup, "a")
|
||||
aTag['href'] = "%s.html#%s" % ("ByAlphaAuthor",
|
||||
self.generateAuthorAnchor(escape(' & '.join(book['authors']))))
|
||||
aTag.insert(0, NavigableString(' & '.join(book['authors'])))
|
||||
pBookTag.insert(ptc, aTag)
|
||||
ptc += 1
|
||||
|
||||
divTag.insert(dtc, pBookTag)
|
||||
dtc += 1
|
||||
|
||||
if not self.__generateForKindle:
|
||||
# Insert the <h2> tag with book_count at the head
|
||||
#<h2><a name="byseries" id="byseries"></a>By Series</h2>
|
||||
pTag = Tag(soup, "p")
|
||||
pTag['class'] = 'title'
|
||||
aTag = Tag(soup, "a")
|
||||
anchor_name = friendly_name.lower()
|
||||
aTag['name'] = anchor_name.replace(" ","")
|
||||
pTag.insert(0,aTag)
|
||||
#h2Tag.insert(1,NavigableString('%s (%d)' % (friendly_name, series_count)))
|
||||
pTag.insert(1,NavigableString('%s' % friendly_name))
|
||||
body.insert(btc,pTag)
|
||||
btc += 1
|
||||
|
||||
# Add the divTag to the body
|
||||
body.insert(btc, divTag)
|
||||
|
||||
# Write the generated file to contentdir
|
||||
outfile_spec = "%s/BySeries.html" % (self.contentDir)
|
||||
outfile = open(outfile_spec, 'w')
|
||||
outfile.write(soup.prettify())
|
||||
outfile.close()
|
||||
self.htmlFileList.append("content/BySeries.html")
|
||||
|
||||
def generateHTMLByTags(self):
|
||||
# Generate individual HTML files for each tag, e.g. Fiction, Nonfiction ...
|
||||
# Note that special tags - ~+*[] - have already been filtered from books[]
|
||||
@ -2683,22 +2907,7 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
# HTML files - add books to manifest and spine
|
||||
sort_descriptions_by = self.booksByAuthor if self.opts.sort_descriptions_by_author \
|
||||
else self.booksByTitle
|
||||
for book in sort_descriptions_by:
|
||||
# manifest
|
||||
itemTag = Tag(soup, "item")
|
||||
itemTag['href'] = "content/book_%d.html" % int(book['id'])
|
||||
itemTag['id'] = "book%d" % int(book['id'])
|
||||
itemTag['media-type'] = "application/xhtml+xml"
|
||||
manifest.insert(mtc, itemTag)
|
||||
mtc += 1
|
||||
|
||||
# spine
|
||||
itemrefTag = Tag(soup, "itemref")
|
||||
itemrefTag['idref'] = "book%d" % int(book['id'])
|
||||
spine.insert(stc, itemrefTag)
|
||||
stc += 1
|
||||
|
||||
# Add other html_files to manifest and spine
|
||||
# Add html_files to manifest and spine
|
||||
|
||||
for file in self.htmlFileList:
|
||||
itemTag = Tag(soup, "item")
|
||||
@ -2734,6 +2943,21 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
spine.insert(stc, itemrefTag)
|
||||
stc += 1
|
||||
|
||||
for book in sort_descriptions_by:
|
||||
# manifest
|
||||
itemTag = Tag(soup, "item")
|
||||
itemTag['href'] = "content/book_%d.html" % int(book['id'])
|
||||
itemTag['id'] = "book%d" % int(book['id'])
|
||||
itemTag['media-type'] = "application/xhtml+xml"
|
||||
manifest.insert(mtc, itemTag)
|
||||
mtc += 1
|
||||
|
||||
# spine
|
||||
itemrefTag = Tag(soup, "itemref")
|
||||
itemrefTag['idref'] = "book%d" % int(book['id'])
|
||||
spine.insert(stc, itemrefTag)
|
||||
stc += 1
|
||||
|
||||
# Guide
|
||||
referenceTag = Tag(soup, "reference")
|
||||
referenceTag['type'] = 'masthead'
|
||||
@ -2769,7 +2993,8 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
navLabelTag.insert(0, textTag)
|
||||
navPointTag.insert(0, navLabelTag)
|
||||
contentTag = Tag(soup, 'content')
|
||||
contentTag['src'] = "content/book_%d.html" % int(self.booksByTitle[0]['id'])
|
||||
#contentTag['src'] = "content/book_%d.html" % int(self.booksByTitle[0]['id'])
|
||||
contentTag['src'] = "content/ByAlphaAuthor.html"
|
||||
navPointTag.insert(1, contentTag)
|
||||
cmiTag = Tag(soup, '%s' % 'calibre:meta-img')
|
||||
cmiTag['name'] = "mastheadImage"
|
||||
@ -2821,15 +3046,15 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
navLabelTag = Tag(ncx_soup, "navLabel")
|
||||
textTag = Tag(ncx_soup, "text")
|
||||
if book['series']:
|
||||
tokens = book['title'].split(': ')
|
||||
tokens = list(book['title'].partition(':'))
|
||||
if self.generateForKindle:
|
||||
# Don't include Author for Kindle
|
||||
textTag.insert(0, NavigableString(self.formatNCXText('%s (%s)' % \
|
||||
(tokens[1], tokens[0]), dest='title')))
|
||||
(tokens[2].strip(), tokens[0]), dest='title')))
|
||||
else:
|
||||
# Include Author for non-Kindle
|
||||
textTag.insert(0, NavigableString(self.formatNCXText('%s · %s (%s)' % \
|
||||
(tokens[1], book['author'], tokens[0]), dest='title')))
|
||||
(tokens[2].strip(), book['author'], tokens[0]), dest='title')))
|
||||
else:
|
||||
if self.generateForKindle:
|
||||
# Don't include Author for Kindle
|
||||
@ -2882,6 +3107,98 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
|
||||
self.ncxSoup = ncx_soup
|
||||
|
||||
def generateNCXBySeries(self, tocTitle):
|
||||
self.updateProgressFullStep("NCX 'Series'")
|
||||
|
||||
def add_to_series_by_letter(current_series_list):
|
||||
current_series_list = " • ".join(current_series_list)
|
||||
current_series_list = self.formatNCXText(current_series_list, dest="description")
|
||||
series_by_letter.append(current_series_list)
|
||||
|
||||
soup = self.ncxSoup
|
||||
output = "BySeries"
|
||||
body = soup.find("navPoint")
|
||||
btc = len(body.contents)
|
||||
|
||||
# --- Construct the 'Books By Series' section ---
|
||||
navPointTag = Tag(soup, 'navPoint')
|
||||
navPointTag['class'] = "section"
|
||||
navPointTag['id'] = "byseries-ID"
|
||||
navPointTag['playOrder'] = self.playOrder
|
||||
self.playOrder += 1
|
||||
navLabelTag = Tag(soup, 'navLabel')
|
||||
textTag = Tag(soup, 'text')
|
||||
textTag.insert(0, NavigableString(tocTitle))
|
||||
navLabelTag.insert(0, textTag)
|
||||
nptc = 0
|
||||
navPointTag.insert(nptc, navLabelTag)
|
||||
nptc += 1
|
||||
contentTag = Tag(soup,"content")
|
||||
contentTag['src'] = "content/%s.html#section_start" % (output)
|
||||
navPointTag.insert(nptc, contentTag)
|
||||
nptc += 1
|
||||
|
||||
series_by_letter = []
|
||||
|
||||
# Loop over the series titles, find start of each letter, add description_preview_count books
|
||||
# Special switch for using different title list
|
||||
title_list = self.booksBySeries
|
||||
current_letter = self.letter_or_symbol(title_list[0]['series'][0])
|
||||
title_letters = [current_letter]
|
||||
current_series_list = []
|
||||
current_series = ""
|
||||
for book in title_list:
|
||||
sort_title = self.generateSortTitle(book['series'])
|
||||
if self.letter_or_symbol(sort_title[0]) != current_letter:
|
||||
# Save the old list
|
||||
add_to_series_by_letter(current_series_list)
|
||||
|
||||
# Start the new list
|
||||
current_letter = self.letter_or_symbol(sort_title[0])
|
||||
title_letters.append(current_letter)
|
||||
current_series = book['series']
|
||||
current_series_list = [book['series']]
|
||||
else:
|
||||
if len(current_series_list) < self.descriptionClip and \
|
||||
book['series'] != current_series :
|
||||
current_series = book['series']
|
||||
current_series_list.append(book['series'])
|
||||
|
||||
# Add the last book list
|
||||
add_to_series_by_letter(current_series_list)
|
||||
|
||||
# Add *article* entries for each populated series title letter
|
||||
for (i,books) in enumerate(series_by_letter):
|
||||
navPointByLetterTag = Tag(soup, 'navPoint')
|
||||
navPointByLetterTag['class'] = "article"
|
||||
navPointByLetterTag['id'] = "%sSeries-ID" % (title_letters[i].upper())
|
||||
navPointTag['playOrder'] = self.playOrder
|
||||
self.playOrder += 1
|
||||
navLabelTag = Tag(soup, 'navLabel')
|
||||
textTag = Tag(soup, 'text')
|
||||
textTag.insert(0, NavigableString(u"Series beginning with %s" % \
|
||||
(title_letters[i] if len(title_letters[i])>1 else "'" + title_letters[i] + "'")))
|
||||
navLabelTag.insert(0, textTag)
|
||||
navPointByLetterTag.insert(0,navLabelTag)
|
||||
contentTag = Tag(soup, 'content')
|
||||
contentTag['src'] = "content/%s.html#%s_series" % (output, title_letters[i])
|
||||
navPointByLetterTag.insert(1,contentTag)
|
||||
|
||||
if self.generateForKindle:
|
||||
cmTag = Tag(soup, '%s' % 'calibre:meta')
|
||||
cmTag['name'] = "description"
|
||||
cmTag.insert(0, NavigableString(self.formatNCXText(books, dest='description')))
|
||||
navPointByLetterTag.insert(2, cmTag)
|
||||
|
||||
navPointTag.insert(nptc, navPointByLetterTag)
|
||||
nptc += 1
|
||||
|
||||
# Add this section to the body
|
||||
body.insert(btc, navPointTag)
|
||||
btc += 1
|
||||
|
||||
self.ncxSoup = soup
|
||||
|
||||
def generateNCXByTitle(self, tocTitle):
|
||||
self.updateProgressFullStep("NCX 'Titles'")
|
||||
|
||||
@ -3713,7 +4030,7 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
btc += 1
|
||||
|
||||
titleTag = body.find(attrs={'class':'title'})
|
||||
titleTag.insert(0,NavigableString('<b><i>%s</i></b>' % escape(self.getFriendlyGenreTag(genre))))
|
||||
titleTag.insert(0,NavigableString('%s' % escape(self.getFriendlyGenreTag(genre))))
|
||||
|
||||
# Insert the books by author list
|
||||
divTag = body.find(attrs={'class':'authors'})
|
||||
@ -3729,15 +4046,14 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
current_series = None
|
||||
pAuthorTag = Tag(soup, "p")
|
||||
pAuthorTag['class'] = "author_index"
|
||||
emTag = Tag(soup, "em")
|
||||
aTag = Tag(soup, "a")
|
||||
aTag['href'] = "%s.html#%s" % ("ByAlphaAuthor", self.generateAuthorAnchor(book['author']))
|
||||
aTag.insert(0, book['author'])
|
||||
emTag.insert(0,aTag)
|
||||
pAuthorTag.insert(0,emTag)
|
||||
pAuthorTag.insert(0,aTag)
|
||||
divTag.insert(dtc,pAuthorTag)
|
||||
dtc += 1
|
||||
|
||||
'''
|
||||
# Insert an <hr /> between non-series and series
|
||||
if not current_series and non_series_books and book['series']:
|
||||
# Insert an <hr />
|
||||
@ -3745,6 +4061,7 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
hrTag['class'] = "series_divider"
|
||||
divTag.insert(dtc,hrTag)
|
||||
dtc += 1
|
||||
'''
|
||||
|
||||
# Check for series
|
||||
if book['series'] and book['series'] != current_series:
|
||||
@ -3752,7 +4069,14 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
current_series = book['series']
|
||||
pSeriesTag = Tag(soup,'p')
|
||||
pSeriesTag['class'] = "series"
|
||||
pSeriesTag.insert(0,NavigableString(self.NOT_READ_SYMBOL + book['series']))
|
||||
if self.opts.generate_series:
|
||||
aTag = Tag(soup,'a')
|
||||
aTag['href'] = "%s.html#%s_series" % ('BySeries',
|
||||
re.sub('\W','',book['series']).lower())
|
||||
aTag.insert(0, book['series'])
|
||||
pSeriesTag.insert(0, aTag)
|
||||
else:
|
||||
pSeriesTag.insert(0,NavigableString('%s' % book['series']))
|
||||
divTag.insert(dtc,pSeriesTag)
|
||||
dtc += 1
|
||||
|
||||
@ -3809,7 +4133,7 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
def generateHTMLDescriptionHeader(self, title):
|
||||
|
||||
title_border = '' if self.opts.fmt == 'epub' else \
|
||||
'<div class="hr"><blockquote><hr/></blockquote></div>'
|
||||
'<hr class="description_divider"/>'
|
||||
header = '''
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:calibre="http://calibre.kovidgoyal.net/2009/metadata">
|
||||
@ -3855,7 +4179,7 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
<td> </td>
|
||||
</tr>
|
||||
</table>
|
||||
<blockquote><hr/></blockquote>
|
||||
<hr class="description_divider" />
|
||||
<div class="description"></div>
|
||||
</body>
|
||||
</html>
|
||||
@ -3897,7 +4221,7 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
</head>
|
||||
<body>
|
||||
<p class="title"></p>
|
||||
<div class="hr"><blockquote><hr/></blockquote></div>
|
||||
<!--div class="hr"><blockquote><hr/></blockquote></div-->
|
||||
<div class="authors"></div>
|
||||
</body>
|
||||
</html>
|
||||
@ -4049,6 +4373,12 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
except:
|
||||
self.opts.log.error("generateThumbnail(): Error with %s" % title['title'])
|
||||
|
||||
def getFriendlyGenreTag(self, genre):
|
||||
# Find the first instance of friendly_tag matching genre
|
||||
for friendly_tag in self.genre_tags_dict:
|
||||
if self.genre_tags_dict[friendly_tag] == genre:
|
||||
return friendly_tag
|
||||
|
||||
def getMarkerTags(self):
|
||||
''' Return a list of special marker tags to be excluded from genre list '''
|
||||
markerTags = []
|
||||
@ -4063,12 +4393,6 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
else:
|
||||
return char
|
||||
|
||||
def getFriendlyGenreTag(self, genre):
|
||||
# Find the first instance of friendly_tag matching genre
|
||||
for friendly_tag in self.genre_tags_dict:
|
||||
if self.genre_tags_dict[friendly_tag] == genre:
|
||||
return friendly_tag
|
||||
|
||||
def markdownComments(self, comments):
|
||||
'''
|
||||
Convert random comment text to normalized, xml-legal block of <p>s
|
||||
@ -4224,13 +4548,15 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
opts.fmt = self.fmt = path_to_output.rpartition('.')[2]
|
||||
|
||||
# Add local options
|
||||
opts.creator = "calibre"
|
||||
opts.creator = '%s, %s %s, %s' % (strftime('%A'), strftime('%B'), strftime('%d').lstrip('0'), strftime('%Y'))
|
||||
opts.creator_sort_as = '%s %s' % ('calibre', strftime('%Y-%m-%d'))
|
||||
opts.connected_kindle = False
|
||||
|
||||
# Finalize output_profile
|
||||
op = opts.output_profile
|
||||
if op is None:
|
||||
op = 'default'
|
||||
|
||||
if opts.connected_device['name'] and 'kindle' in opts.connected_device['name'].lower():
|
||||
opts.connected_kindle = True
|
||||
if opts.connected_device['serial'] and opts.connected_device['serial'][:4] in ['B004','B005']:
|
||||
@ -4256,7 +4582,8 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
opts.exclude_genre = '\[^.\]'
|
||||
build_log.append(" converting empty exclude_genre to '\[^.\]'")
|
||||
|
||||
if opts.connected_device['name']:
|
||||
if opts.connected_device['is_device_connected'] and \
|
||||
opts.connected_device['kind'] == 'device':
|
||||
if opts.connected_device['serial']:
|
||||
build_log.append(u" connected_device: '%s' #%s%s " % \
|
||||
(opts.connected_device['name'],
|
||||
@ -4267,9 +4594,14 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
build_log.append(u" mount point: %s" % storage)
|
||||
else:
|
||||
build_log.append(u" connected_device: '%s'" % opts.connected_device['name'])
|
||||
try:
|
||||
for storage in opts.connected_device['storage']:
|
||||
if storage:
|
||||
build_log.append(u" mount point: %s" % storage)
|
||||
except:
|
||||
build_log.append(u" (no mount points)")
|
||||
else:
|
||||
build_log.append(u" connected_device: '%s'" % opts.connected_device['name'])
|
||||
|
||||
opts_dict = vars(opts)
|
||||
if opts_dict['ids']:
|
||||
|
@ -674,7 +674,14 @@ def command_catalog(args, dbpath):
|
||||
|
||||
# No support for connected device in CLI environment
|
||||
# Parallel initialization in calibre.gui2.tools:generate_catalog()
|
||||
opts.connected_device = { 'storage':None,'serial':None,'save_template':None,'name':None}
|
||||
opts.connected_device = {
|
||||
'is_device_connected': False,
|
||||
'kind': None,
|
||||
'name': None,
|
||||
'save_template': None,
|
||||
'serial': None,
|
||||
'storage': None,
|
||||
}
|
||||
|
||||
with plugin:
|
||||
plugin.run(args[1], opts, get_db(dbpath, opts))
|
||||
|
Loading…
x
Reference in New Issue
Block a user