GwR catalog 1.0 revisions

This commit is contained in:
GRiker 2011-01-17 08:53:18 -07:00
parent 46119745cb
commit 9013a5d97d
3 changed files with 279 additions and 328 deletions

View File

@ -0,0 +1,39 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
__license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
'''
Available fields:
{title} Title of the book
{series} Series name
{series_index} Number of the book in the series
{rating} Rating
{rating_parens} Rating, in parentheses
{pubyear} Year the book was published
{pubyear_parens} Year the book was published, in parentheses
'''
# Books by Author
by_authors_normal_title_template = '{title} {pubyear_parens}'
by_authors_series_title_template = '[{series_index}] {title} {pubyear_parens}'
# Books by Title
by_titles_normal_title_template = '{title}'
by_titles_series_title_template = '{title} ({series} [{series_index}])'
# Books by Series
by_series_title_template = '[{series_index}] {title} {pubyear_parens}'
# Books by Genre
by_genres_normal_title_template = '{title} {pubyear_parens}'
by_genres_series_title_template = '{series_index}. {title} {pubyear_parens}'
# Recently Added
by_recently_added_normal_title_template = '{title}'
by_recently_added_series_title_template = '{title} ({series} [{series_index}])'
# By Month added
by_month_added_normal_title_template = '{title} {pubyear_parens}'
by_month_added_series_title_template = '[{series_index}] {title} {pubyear_parens}'

View File

@ -5,11 +5,11 @@ __license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>' __copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
import os, shutil import re, os, shutil
from PyQt4.Qt import QModelIndex from PyQt4.Qt import QModelIndex
from calibre.gui2 import error_dialog, choose_dir from calibre.gui2 import choose_dir, error_dialog, info_dialog, warning_dialog
from calibre.gui2.tools import generate_catalog from calibre.gui2.tools import generate_catalog
from calibre.utils.config import dynamic from calibre.utils.config import dynamic
from calibre.gui2.actions import InterfaceAction from calibre.gui2.actions import InterfaceAction
@ -55,10 +55,16 @@ class GenerateCatalogAction(InterfaceAction):
def catalog_generated(self, job): def catalog_generated(self, job):
if job.result: if job.result:
# Error during catalog generation # Problems during catalog generation
return error_dialog(self.gui, _('Catalog generation terminated'), dialog_title = job.result.pop(0)
job.result, if re.match('warning:', job.result[0].lower()):
show=True) job.result.append("Catalog generation complete.")
warning_dialog(self.gui, dialog_title, '\n'.join(job.result), show=True)
else:
job.result.append("Catalog generation terminated.")
error_dialog(self.gui, dialog_title,'\n'.join(job.result),show=True)
return
if job.failed: if job.failed:
return self.gui.job_exception(job) return self.gui.job_exception(job)
id = self.gui.library_view.model().add_catalog(job.catalog_file_path, job.catalog_title) id = self.gui.library_view.model().add_catalog(job.catalog_file_path, job.catalog_title)

View File

@ -546,9 +546,9 @@ class EPUB_MOBI(CatalogPlugin):
name = 'Catalog_EPUB_MOBI' name = 'Catalog_EPUB_MOBI'
description = 'EPUB/MOBI catalog generator' description = 'EPUB/MOBI catalog generator'
supported_platforms = ['windows', 'osx', 'linux'] supported_platforms = ['windows', 'osx', 'linux']
minimum_calibre_version = (0, 6, 34) minimum_calibre_version = (0, 7, 40)
author = 'Greg Riker' author = 'Greg Riker'
version = (0, 0, 1) version = (1, 0, 0)
file_types = set(['epub','mobi']) file_types = set(['epub','mobi'])
THUMB_SMALLEST = "1.0" THUMB_SMALLEST = "1.0"
@ -900,15 +900,7 @@ class EPUB_MOBI(CatalogPlugin):
''' '''
Generates catalog source files from calibre database Generates catalog source files from calibre database
Implementation notes Flow of control:
- 'Marker tags' in a book's metadata are used to flag special conditions:
(Defaults)
'~' : Do not catalog this book
'+' : Mark this book as read (check mark) in lists
'*' : Display trailing text as 'Note: <text>' in top frame next to cover
'[<source>] : Source of content (e.g., Amazon, Project Gutenberg). Do not create genre
- Program flow
gui2.actions.catalog:generate_catalog() gui2.actions.catalog:generate_catalog()
gui2.tools:generate_catalog() or library.cli:command_catalog() gui2.tools:generate_catalog() or library.cli:command_catalog()
called from gui2.convert.gui_conversion:gui_catalog() called from gui2.convert.gui_conversion:gui_catalog()
@ -953,7 +945,7 @@ class EPUB_MOBI(CatalogPlugin):
self.__creator = opts.creator self.__creator = opts.creator
self.__db = db self.__db = db
self.__descriptionClip = opts.descriptionClip self.__descriptionClip = opts.descriptionClip
self.__error = None self.__error = []
self.__generateForKindle = True if (self.opts.fmt == 'mobi' and \ self.__generateForKindle = True if (self.opts.fmt == 'mobi' and \
self.opts.output_profile and \ self.opts.output_profile and \
self.opts.output_profile.startswith("kindle")) else False self.opts.output_profile.startswith("kindle")) else False
@ -1033,6 +1025,22 @@ class EPUB_MOBI(CatalogPlugin):
# +1 thumbs # +1 thumbs
self.__totalSteps += 3 self.__totalSteps += 3
# Load section list templates
templates = ['by_authors_normal_title_template',
'by_authors_series_title_template',
'by_titles_normal_title_template',
'by_titles_series_title_template',
'by_series_title_template',
'by_genres_normal_title_template',
'by_genres_series_title_template',
'by_recently_added_normal_title_template',
'by_recently_added_series_title_template',
'by_month_added_normal_title_template',
'by_month_added_series_title_template']
execfile(P(os.path.join('catalog','section_list_templates.py')),locals())
for t in templates:
setattr(self,t,eval(t))
# Accessors # Accessors
if True: if True:
''' '''
@ -1420,26 +1428,12 @@ class EPUB_MOBI(CatalogPlugin):
''' '''
self.updateProgressFullStep("Sorting database") self.updateProgressFullStep("Sorting database")
'''
# Sort titles case-insensitive, by author
self.booksByAuthor = sorted(self.booksByTitle,
key=lambda x:(x['author_sort'].upper(), x['author_sort'].upper()))
'''
self.booksByAuthor = list(self.booksByTitle) self.booksByAuthor = list(self.booksByTitle)
self.booksByAuthor.sort(self.author_compare) self.booksByAuthor = sorted(self.booksByAuthor, key=self.booksByAuthorSorter_author)
# for book in self.booksByAuthor:
if False and self.verbose: # print "{0:<30} {1:<30} {2:<30}".format(book['title'],book['author'],book['author_sort'])
self.opts.log.info("fetchBooksByAuthor(): %d books" % len(self.booksByAuthor)) # print
self.opts.log.info(" %-30s %-20s %s" % ('title', 'series', 'series_index')) # stop
for title in self.booksByAuthor:
self.opts.log.info((u" %-30s %-20s%5s " % \
(title['title'][:30],
title['series'][:20] if title['series'] else '',
title['series_index'],
)).encode('utf-8'))
raise SystemExit
# Build the unique_authors set from existing data # Build the unique_authors set from existing data
authors = [(record['author'], record['author_sort'].capitalize()) for record in self.booksByAuthor] authors = [(record['author'], record['author_sort'].capitalize()) for record in self.booksByAuthor]
@ -1457,16 +1451,17 @@ class EPUB_MOBI(CatalogPlugin):
multiple_authors = True multiple_authors = True
if author != current_author and i: if author != current_author and i:
# Warn, exit if friendly matches previous, but sort doesn't # Exit if author matches previous, but author_sort doesn't match
if author[0] == current_author[0]: if author[0] == current_author[0]:
error_msg = _(''' error_msg = _('''
\n*** Metadata error *** Inconsistent Author Sort values for Author '{0}', unable to continue building catalog.\n
Inconsistent Author Sort values for Author '{0}', unable to continue building catalog.
Select all books by '{0}', apply correct Author Sort value in Edit Metadata dialog, Select all books by '{0}', apply correct Author Sort value in Edit Metadata dialog,
then rebuild the catalog.\n''').format(author[0]) then rebuild the catalog.\n''').format(author[0])
self.opts.log.warn('\n*** Metadata error ***')
self.opts.log.warn(error_msg) self.opts.log.warn(error_msg)
self.error = error_msg
self.error.append('Metadata error')
self.error.append(error_msg)
return False return False
# New author, save the previous author/sort/count # New author, save the previous author/sort/count
@ -1496,16 +1491,8 @@ then rebuild the catalog.\n''').format(author[0])
return True return True
def fetchBooksByTitle(self): def fetchBooksByTitle(self):
self.updateProgressFullStep("Fetching database") self.updateProgressFullStep("Fetching database")
# Get the database as a dictionary
# Sort by title
# Search is a string like this:
# not tag:<exclude_tag> author:"Riker"
# So we need to merge opts.exclude_tag with opts.search_text
# not tag:"~" author:"Riker"
self.opts.sort_by = 'title' self.opts.sort_by = 'title'
# Merge opts.exclude_tags with opts.search_text # Merge opts.exclude_tags with opts.search_text
@ -1528,7 +1515,6 @@ then rebuild the catalog.\n''').format(author[0])
else: else:
self.opts.search_text = search_phrase self.opts.search_text = search_phrase
#print "fetchBooksByTitle(): opts.search_text: %s" % self.opts.search_text
# Fetch the database as a dictionary # Fetch the database as a dictionary
data = self.plugin.search_sort_db(self.db, self.opts) data = self.plugin.search_sort_db(self.db, self.opts)
data = self.processExclusions(data) data = self.processExclusions(data)
@ -1536,8 +1522,6 @@ then rebuild the catalog.\n''').format(author[0])
# Populate this_title{} from data[{},{}] # Populate this_title{} from data[{},{}]
titles = [] titles = []
for record in data: for record in data:
if False:
print "available record metadata:\n%s" % sorted(record.keys())
this_title = {} this_title = {}
this_title['id'] = record['id'] this_title['id'] = record['id']
@ -1547,7 +1531,6 @@ then rebuild the catalog.\n''').format(author[0])
if record['series']: if record['series']:
this_title['series'] = record['series'] this_title['series'] = record['series']
this_title['series_index'] = record['series_index'] this_title['series_index'] = record['series_index']
this_title['title'] = self.generateSeriesTitle(this_title)
else: else:
this_title['series'] = None this_title['series'] = None
this_title['series_index'] = 0.0 this_title['series_index'] = 0.0
@ -1572,7 +1555,12 @@ then rebuild the catalog.\n''').format(author[0])
this_title['publisher'] = re.sub('&', '&amp;', record['publisher']) this_title['publisher'] = re.sub('&', '&amp;', record['publisher'])
this_title['rating'] = record['rating'] if record['rating'] else 0 this_title['rating'] = record['rating'] if record['rating'] else 0
this_title['date'] = strftime(u'%B %Y', record['pubdate'].timetuple())
if re.match('0100-01-01',str(record['pubdate'].date())):
this_title['date'] = None
else:
this_title['date'] = strftime(u'%B %Y', record['pubdate'].timetuple())
this_title['timestamp'] = record['timestamp'] this_title['timestamp'] = record['timestamp']
if record['comments']: if record['comments']:
@ -1646,7 +1634,7 @@ then rebuild the catalog.\n''').format(author[0])
title['title_sort'][0:40])).decode('mac-roman')) title['title_sort'][0:40])).decode('mac-roman'))
return True return True
else: else:
self.error = _("No books found to catalog.\nCheck 'Excluded books' criteria in E-book options.") self.error.append( _("No books found to catalog.\nCheck 'Excluded books' criteria in E-book options."))
return False return False
def fetchBookmarks(self): def fetchBookmarks(self):
@ -1748,13 +1736,12 @@ then rebuild the catalog.\n''').format(author[0])
self.bookmarked_books = {} self.bookmarked_books = {}
def generateHTMLDescriptions(self): def generateHTMLDescriptions(self):
# Write each title to a separate HTML file in contentdir '''
Write each title to a separate HTML file in contentdir
'''
self.updateProgressFullStep("'Descriptions'") self.updateProgressFullStep("'Descriptions'")
for (title_num, title) in enumerate(self.booksByTitle): for (title_num, title) in enumerate(self.booksByTitle):
if False:
self.opts.log.info("%3s: %s - %s" % (title['id'], title['title'], title['author']))
self.updateProgressMicroStep("Description %d of %d" % \ self.updateProgressMicroStep("Description %d of %d" % \
(title_num, len(self.booksByTitle)), (title_num, len(self.booksByTitle)),
float(title_num*100/len(self.booksByTitle))/100) float(title_num*100/len(self.booksByTitle))/100)
@ -1768,8 +1755,9 @@ then rebuild the catalog.\n''').format(author[0])
outfile.close() outfile.close()
def generateHTMLByTitle(self): def generateHTMLByTitle(self):
# Write books by title A-Z to HTML file '''
Write books by title A-Z to HTML file
'''
self.updateProgressFullStep("'Titles'") self.updateProgressFullStep("'Titles'")
soup = self.generateHTMLEmptyHeader("Books By Alpha Title") soup = self.generateHTMLEmptyHeader("Books By Alpha Title")
@ -1807,22 +1795,11 @@ then rebuild the catalog.\n''').format(author[0])
current_letter = "" current_letter = ""
# Re-sort title list without leading series/series_index # Re-sort title list without leading series/series_index
# Incoming title <series> <series_index>: <title>
if not self.useSeriesPrefixInTitlesSection: if not self.useSeriesPrefixInTitlesSection:
nspt = deepcopy(self.booksByTitle) nspt = deepcopy(self.booksByTitle)
for book in nspt: nspt = sorted(nspt, key=lambda x:(x['title_sort'].upper(), x['title_sort'].upper()))
if book['series']:
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()))
self.booksByTitle_noSeriesPrefix = nspt self.booksByTitle_noSeriesPrefix = nspt
if False and self.verbose:
self.opts.log.info("no_series_prefix_titles: %d books" % len(nspt))
self.opts.log.info(" %-40s %-40s" % ('title', 'title_sort'))
for title in nspt:
self.opts.log.info((u" %-40s %-40s" % (title['title'][0:40],
title['title_sort'][0:40])).encode('utf-8'))
# Loop through the books by title # Loop through the books by title
title_list = self.booksByTitle title_list = self.booksByTitle
@ -1878,7 +1855,14 @@ then rebuild the catalog.\n''').format(author[0])
aTag = Tag(soup, "a") aTag = Tag(soup, "a")
if self.opts.generate_descriptions: if self.opts.generate_descriptions:
aTag['href'] = "book_%d.html" % (int(float(book['id']))) aTag['href'] = "book_%d.html" % (int(float(book['id'])))
aTag.insert(0,escape(book['title']))
# Generate the title from the template
args = self.generateFormatArgs(book)
if book['series']:
formatted_title = self.by_titles_series_title_template.format(**args).rstrip()
else:
formatted_title = self.by_titles_normal_title_template.format(**args).rstrip()
aTag.insert(0,NavigableString(escape(formatted_title)))
pBookTag.insert(ptc, aTag) pBookTag.insert(ptc, aTag)
ptc += 1 ptc += 1
@ -1916,7 +1900,9 @@ then rebuild the catalog.\n''').format(author[0])
self.htmlFileList_1.append("content/ByAlphaTitle.html") self.htmlFileList_1.append("content/ByAlphaTitle.html")
def generateHTMLByAuthor(self): def generateHTMLByAuthor(self):
# Write books by author A-Z '''
Write books by author A-Z
'''
self.updateProgressFullStep("'Authors'") self.updateProgressFullStep("'Authors'")
friendly_name = "Authors" friendly_name = "Authors"
@ -1953,7 +1939,8 @@ then rebuild the catalog.\n''').format(author[0])
current_author = '' current_author = ''
current_letter = '' current_letter = ''
current_series = None current_series = None
for book in self.booksByAuthor: for book in sorted(self.booksByAuthor, key = self.booksByAuthorSorter_author_sort):
book_count += 1 book_count += 1
if self.letter_or_symbol(book['author_sort'][0].upper()) != current_letter : if self.letter_or_symbol(book['author_sort'][0].upper()) != current_letter :
# Start a new letter with Index letter # Start a new letter with Index letter
@ -2067,14 +2054,18 @@ then rebuild the catalog.\n''').format(author[0])
aTag = Tag(soup, "a") aTag = Tag(soup, "a")
if self.opts.generate_descriptions: if self.opts.generate_descriptions:
aTag['href'] = "book_%d.html" % (int(float(book['id']))) aTag['href'] = "book_%d.html" % (int(float(book['id'])))
# Use series, series index if avail else title, + year of publication
# Generate the title from the template
args = self.generateFormatArgs(book)
if current_series: if current_series:
aTag.insert(0,'%s (%s)' % (escape(book['title'][len(book['series'])+1:]), #aTag.insert(0,'%s%s' % (escape(book['title'][len(book['series'])+1:]),pubyear))
book['date'].split()[1])) formatted_title = self.by_authors_series_title_template.format(**args).rstrip()
else: else:
aTag.insert(0,'%s (%s)' % (escape(book['title']), #aTag.insert(0,'%s%s' % (escape(book['title']), pubyear))
book['date'].split()[1])) formatted_title = self.by_authors_normal_title_template.format(**args).rstrip()
non_series_books += 1 non_series_books += 1
aTag.insert(0,NavigableString(escape(formatted_title)))
pBookTag.insert(ptc, aTag) pBookTag.insert(ptc, aTag)
ptc += 1 ptc += 1
@ -2111,7 +2102,6 @@ then rebuild the catalog.\n''').format(author[0])
# Add the divTag to the body # Add the divTag to the body
body.insert(btc, divTag) body.insert(btc, divTag)
# Write the generated file to contentdir # Write the generated file to contentdir
outfile_spec = "%s/ByAlphaAuthor.html" % (self.contentDir) outfile_spec = "%s/ByAlphaAuthor.html" % (self.contentDir)
outfile = open(outfile_spec, 'w') outfile = open(outfile_spec, 'w')
@ -2120,13 +2110,15 @@ then rebuild the catalog.\n''').format(author[0])
self.htmlFileList_1.append("content/ByAlphaAuthor.html") self.htmlFileList_1.append("content/ByAlphaAuthor.html")
def generateHTMLByDateAdded(self): def generateHTMLByDateAdded(self):
# Write books by reverse chronological order '''
Write books by reverse chronological order
'''
self.updateProgressFullStep("'Recently Added'") self.updateProgressFullStep("'Recently Added'")
def add_books_to_HTML_by_month(this_months_list, dtc): def add_books_to_HTML_by_month(this_months_list, dtc):
if len(this_months_list): if len(this_months_list):
this_months_list.sort(self.author_compare) this_months_list = sorted(this_months_list, key=self.booksByAuthorSorter_author_sort)
# Create a new month anchor # Create a new month anchor
date_string = strftime(u'%B %Y', current_date.timetuple()) date_string = strftime(u'%B %Y', current_date.timetuple())
@ -2156,16 +2148,6 @@ then rebuild the catalog.\n''').format(author[0])
divTag.insert(dtc,pAuthorTag) divTag.insert(dtc,pAuthorTag)
dtc += 1 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 />
hrTag = Tag(soup,'hr')
hrTag['class'] = "series_divider"
divTag.insert(dtc,hrTag)
dtc += 1
'''
# Check for series # Check for series
if new_entry['series'] and new_entry['series'] != current_series: if new_entry['series'] and new_entry['series'] != current_series:
# Start a new series # Start a new series
@ -2213,11 +2195,15 @@ then rebuild the catalog.\n''').format(author[0])
aTag = Tag(soup, "a") aTag = Tag(soup, "a")
if self.opts.generate_descriptions: if self.opts.generate_descriptions:
aTag['href'] = "book_%d.html" % (int(float(new_entry['id']))) aTag['href'] = "book_%d.html" % (int(float(new_entry['id'])))
# Generate the title from the template
args = self.generateFormatArgs(new_entry)
if current_series: if current_series:
aTag.insert(0,escape(new_entry['title'][len(new_entry['series'])+1:])) formatted_title = self.by_month_added_series_title_template.format(**args).rstrip()
else: else:
aTag.insert(0,escape(new_entry['title'])) formatted_title = self.by_month_added_normal_title_template.format(**args).rstrip()
non_series_books += 1 non_series_books += 1
aTag.insert(0,NavigableString(escape(formatted_title)))
pBookTag.insert(ptc, aTag) pBookTag.insert(ptc, aTag)
ptc += 1 ptc += 1
@ -2265,7 +2251,14 @@ then rebuild the catalog.\n''').format(author[0])
aTag = Tag(soup, "a") aTag = Tag(soup, "a")
if self.opts.generate_descriptions: if self.opts.generate_descriptions:
aTag['href'] = "book_%d.html" % (int(float(new_entry['id']))) aTag['href'] = "book_%d.html" % (int(float(new_entry['id'])))
aTag.insert(0,escape(new_entry['title']))
# Generate the title from the template
args = self.generateFormatArgs(new_entry)
if new_entry['series']:
formatted_title = self.by_recently_added_series_title_template.format(**args).rstrip()
else:
formatted_title = self.by_recently_added_normal_title_template.format(**args).rstrip()
aTag.insert(0,NavigableString(escape(formatted_title)))
pBookTag.insert(ptc, aTag) pBookTag.insert(ptc, aTag)
ptc += 1 ptc += 1
@ -2323,17 +2316,12 @@ then rebuild the catalog.\n''').format(author[0])
divTag = Tag(soup, "div") divTag = Tag(soup, "div")
dtc = 0 dtc = 0
# Add books by date range # >>> Books by date range <<<
if self.useSeriesPrefixInTitlesSection: if self.useSeriesPrefixInTitlesSection:
self.booksByDateRange = sorted(self.booksByTitle, self.booksByDateRange = sorted(self.booksByTitle,
key=lambda x:(x['timestamp'], x['timestamp']),reverse=True) key=lambda x:(x['timestamp'], x['timestamp']),reverse=True)
else: else:
nspt = deepcopy(self.booksByTitle) nspt = deepcopy(self.booksByTitle)
for book in nspt:
if book['series']:
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) self.booksByDateRange = sorted(nspt, key=lambda x:(x['timestamp'], x['timestamp']),reverse=True)
date_range_list = [] date_range_list = []
@ -2356,15 +2344,6 @@ then rebuild the catalog.\n''').format(author[0])
dtc = add_books_to_HTML_by_date_range(date_range_list, date_range, dtc) dtc = add_books_to_HTML_by_date_range(date_range_list, date_range, dtc)
date_range_list = [book] 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 <<<< # >>>> Books by month <<<<
# Sort titles case-insensitive for by month using series prefix # Sort titles case-insensitive for by month using series prefix
self.booksByMonth = sorted(self.booksByTitle, self.booksByMonth = sorted(self.booksByTitle,
@ -2395,7 +2374,9 @@ then rebuild the catalog.\n''').format(author[0])
self.htmlFileList_2.append("content/ByDateAdded.html") self.htmlFileList_2.append("content/ByDateAdded.html")
def generateHTMLByDateRead(self): def generateHTMLByDateRead(self):
# Write books by active bookmarks '''
Write books by active bookmarks
'''
friendly_name = 'Recently Read' friendly_name = 'Recently Read'
self.updateProgressFullStep("'%s'" % friendly_name) self.updateProgressFullStep("'%s'" % friendly_name)
if not self.bookmarked_books: if not self.bookmarked_books:
@ -2533,32 +2514,6 @@ then rebuild the catalog.\n''').format(author[0])
self.booksByDateRead = sorted(bookmarked_books, self.booksByDateRead = sorted(bookmarked_books,
key=lambda x:(x['bookmark_timestamp'], x['bookmark_timestamp']),reverse=True) key=lambda x:(x['bookmark_timestamp'], x['bookmark_timestamp']),reverse=True)
'''
# >>>> Recently by date range <<<<
date_range_list = []
today_time = datetime.datetime.utcnow()
today_time.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:
date_range = '%d to %d days ago' % (self.DATE_RANGE[i-1], self.DATE_RANGE[i])
else:
date_range = 'Last %d days' % (self.DATE_RANGE[i])
for book in self.booksByDateRead:
bookmark_time = datetime.datetime.utcfromtimestamp(book['bookmark_timestamp'])
delta = today_time-bookmark_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]
'''
# >>>> Recently read by day <<<< # >>>> Recently read by day <<<<
current_date = datetime.date.fromordinal(1) current_date = datetime.date.fromordinal(1)
todays_list = [] todays_list = []
@ -2713,10 +2668,15 @@ then rebuild the catalog.\n''').format(author[0])
# Use series, series index if avail else just title # 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']))) #aTag.insert(0,'%d. %s &middot; %s' % (book['series_index'],escape(book['title']), ' & '.join(book['authors'])))
# Link to book # Reassert 'date' since this is the result of a new search
aTag.insert(0,'%d. %s (%s)' % (book['series_index'], if re.match('0100-01-01',str(book['pubdate'].date())):
escape(book['title']), book['date'] = None
strftime(u'%Y', book['pubdate'].timetuple()))) else:
book['date'] = strftime(u'%B %Y', book['pubdate'].timetuple())
args = self.generateFormatArgs(book)
formatted_title = self.by_series_title_template.format(**args).rstrip()
aTag.insert(0,NavigableString(escape(formatted_title)))
pBookTag.insert(ptc, aTag) pBookTag.insert(ptc, aTag)
ptc += 1 ptc += 1
@ -2760,10 +2720,11 @@ then rebuild the catalog.\n''').format(author[0])
self.htmlFileList_1.append("content/BySeries.html") self.htmlFileList_1.append("content/BySeries.html")
def generateHTMLByTags(self): def generateHTMLByTags(self):
# Generate individual HTML files for each tag, e.g. Fiction, Nonfiction ... '''
# Note that special tags - ~+*[] - have already been filtered from books[] Generate individual HTML files for each tag, e.g. Fiction, Nonfiction ...
# There may be synonomous tags Note that special tags - have already been filtered from books[]
There may be synonomous tags
'''
self.updateProgressFullStep("'Genres'") self.updateProgressFullStep("'Genres'")
self.genre_tags_dict = self.filterDbTags(self.db.all_tags()) self.genre_tags_dict = self.filterDbTags(self.db.all_tags())
@ -2787,6 +2748,8 @@ then rebuild the catalog.\n''').format(author[0])
this_book['tags'] = book['tags'] this_book['tags'] = book['tags']
this_book['id'] = book['id'] this_book['id'] = book['id']
this_book['series'] = book['series'] this_book['series'] = book['series']
this_book['series_index'] = book['series_index']
this_book['date'] = book['date']
normalized_tag = self.genre_tags_dict[friendly_tag] normalized_tag = self.genre_tags_dict[friendly_tag]
genre_tag_list = [key for genre in genre_list for key in genre] genre_tag_list = [key for genre in genre_list for key in genre]
if normalized_tag in genre_tag_list: if normalized_tag in genre_tag_list:
@ -2843,13 +2806,7 @@ then rebuild the catalog.\n''').format(author[0])
unique_authors.append((current_author[0], current_author[1], books_by_current_author)) unique_authors.append((current_author[0], current_author[1], books_by_current_author))
else: else:
books_by_current_author += 1 books_by_current_author += 1
'''
# Extract the unique entries
unique_authors = []
for author in authors:
if not author in unique_authors:
unique_authors.append(author)
'''
# Write the genre book list as an article # Write the genre book list as an article
titles_spanned = self.generateHTMLByGenre(genre, True if index==0 else False, titles_spanned = self.generateHTMLByGenre(genre, True if index==0 else False,
genre_tag_set[genre], genre_tag_set[genre],
@ -2863,18 +2820,14 @@ then rebuild the catalog.\n''').format(author[0])
'books':genre_tag_set[genre], 'books':genre_tag_set[genre],
'titles_spanned':titles_spanned}) 'titles_spanned':titles_spanned})
if False and self.opts.verbose:
for genre in master_genre_list:
print "genre['tag']: %s" % genre['tag']
for book in genre['books']:
print book['title']
self.genres = master_genre_list self.genres = master_genre_list
def generateThumbnails(self): def generateThumbnails(self):
# Generate a thumbnail per cover. If a current thumbnail exists, skip '''
# If a cover doesn't exist, use default Generate a thumbnail per cover. If a current thumbnail exists, skip
# Return list of active thumbs If a cover doesn't exist, use default
Return list of active thumbs
'''
self.updateProgressFullStep("'Thumbnails'") self.updateProgressFullStep("'Thumbnails'")
thumbs = ['thumbnail_default.jpg'] thumbs = ['thumbnail_default.jpg']
image_dir = "%s/images" % self.catalogPath image_dir = "%s/images" % self.catalogPath
@ -2886,45 +2839,51 @@ then rebuild the catalog.\n''').format(author[0])
thumb_file = 'thumbnail_%d.jpg' % int(title['id']) thumb_file = 'thumbnail_%d.jpg' % int(title['id'])
thumb_generated = True thumb_generated = True
valid_cover = True
try: try:
self.generateThumbnail(title, image_dir, thumb_file)
thumbs.append("thumbnail_%d.jpg" % int(title['id'])) thumbs.append("thumbnail_%d.jpg" % int(title['id']))
self.generateThumbnail(title, image_dir, thumb_file)
except: except:
if 'cover' in title and os.path.exists(title['cover']):
valid_cover = False
self.opts.log.warn(" *** Invalid cover file for '%s' ***" % (title['title']))
if not self.error:
self.error.append('Invalid cover files')
self.error.append("Warning: invalid cover file for '%s', default cover substituted.\n" % (title['title']))
thumb_generated = False thumb_generated = False
if not thumb_generated: if not thumb_generated:
# Use default cover self.opts.log.warn(" using default cover for '%s'" % (title['title']))
if False and self.verbose:
self.opts.log.warn(" using default cover for '%s'" % \
(title['title']))
# Check to make sure default is current # Check to make sure default is current
# Check to see if thumbnail exists # Check to see if thumbnail exists
thumb_fp = "%s/thumbnail_default.jpg" % (image_dir) default_thumb_fp = os.path.join(image_dir,"thumbnail_default.jpg")
cover = "%s/DefaultCover.png" % (self.catalogPath) cover = os.path.join(self.catalogPath, "DefaultCover.png")
if not os.path.exists(cover): if not os.path.exists(cover):
shutil.copyfile(I('book.png'), cover) shutil.copyfile(I('book.png'), cover)
if os.path.isfile(thumb_fp): if os.path.isfile(default_thumb_fp):
# Check to see if default cover is newer than thumbnail # Check to see if default cover is newer than thumbnail
# os.path.getmtime() = modified time # os.path.getmtime() = modified time
# os.path.ctime() = creation time # os.path.ctime() = creation time
cover_timestamp = os.path.getmtime(cover) cover_timestamp = os.path.getmtime(cover)
thumb_timestamp = os.path.getmtime(thumb_fp) thumb_timestamp = os.path.getmtime(default_thumb_fp)
if thumb_timestamp < cover_timestamp: if thumb_timestamp < cover_timestamp:
if False and self.verbose: if False and self.verbose:
self.opts.log.warn("updating thumbnail_default for %s" % title['title']) self.opts.log.warn("updating thumbnail_default for %s" % title['title'])
#title['cover'] = "%s/DefaultCover.jpg" % self.catalogPath #title['cover'] = os.path.join(self.catalogPath,"DefaultCover.jpg")
title['cover'] = cover title['cover'] = cover
self.generateThumbnail(title, image_dir, "thumbnail_default.jpg") self.generateThumbnail(title, image_dir,
"thumbnail_default.jpg" if valid_cover else thumb_file)
else: else:
if False and self.verbose: if False and self.verbose:
self.opts.log.warn(" generating new thumbnail_default.jpg") self.opts.log.warn(" generating new thumbnail_default.jpg")
#title['cover'] = "%s/DefaultCover.jpg" % self.catalogPath #title['cover'] = os.path.join(self.catalogPath,"DefaultCover.jpg")
title['cover'] = cover title['cover'] = cover
self.generateThumbnail(title, image_dir, "thumbnail_default.jpg") self.generateThumbnail(title, image_dir,
"thumbnail_default.jpg" if valid_cover else thumb_file)
# Write the thumb_width to the file validating cache contents
# Write thumb_width to the file, validating cache contents
# Allows detection of aborted catalog builds # Allows detection of aborted catalog builds
with ZipFile(self.__archive_path, mode='a') as zfw: with ZipFile(self.__archive_path, mode='a') as zfw:
zfw.writestr('thumb_width', self.opts.thumb_width) zfw.writestr('thumb_width', self.opts.thumb_width)
@ -3162,15 +3121,17 @@ then rebuild the catalog.\n''').format(author[0])
navLabelTag = Tag(ncx_soup, "navLabel") navLabelTag = Tag(ncx_soup, "navLabel")
textTag = Tag(ncx_soup, "text") textTag = Tag(ncx_soup, "text")
if book['series']: if book['series']:
tokens = list(book['title'].partition(':')) series_index = str(book['series_index'])
if series_index.endswith('.0'):
series_index = series_index[:-2]
if self.generateForKindle: if self.generateForKindle:
# Don't include Author for Kindle # Don't include Author for Kindle
textTag.insert(0, NavigableString(self.formatNCXText('%s (%s)' % \ textTag.insert(0, NavigableString(self.formatNCXText('%s (%s [%s])' %
(tokens[2].strip(), tokens[0]), dest='title'))) (book['title'], book['series'], series_index), dest='title')))
else: else:
# Include Author for non-Kindle # Include Author for non-Kindle
textTag.insert(0, NavigableString(self.formatNCXText('%s &middot; %s (%s)' % \ textTag.insert(0, NavigableString(self.formatNCXText('%s (%s [%s]) &middot; %s ' %
(tokens[2].strip(), book['author'], tokens[0]), dest='title'))) (book['title'], book['series'], series_index, book['author']), dest='title')))
else: else:
if self.generateForKindle: if self.generateForKindle:
# Don't include Author for Kindle # Don't include Author for Kindle
@ -3725,43 +3686,6 @@ then rebuild the catalog.\n''').format(author[0])
add_to_master_date_range_list(current_titles_list) add_to_master_date_range_list(current_titles_list)
current_titles_list = [book['title']] current_titles_list = [book['title']]
'''
# Add *article* entries for each populated date range
# master_date_range_list{}: [0]:titles list [1]:datestr
for books_by_date_range in master_date_range_list:
navPointByDateRangeTag = Tag(soup, 'navPoint')
navPointByDateRangeTag['class'] = "article"
navPointByDateRangeTag['id'] = "%s-ID" % books_by_date_range[1].replace(' ','')
navPointTag['playOrder'] = self.playOrder
self.playOrder += 1
navLabelTag = Tag(soup, 'navLabel')
textTag = Tag(soup, 'text')
textTag.insert(0, NavigableString(books_by_date_range[1]))
navLabelTag.insert(0, textTag)
navPointByDateRangeTag.insert(0,navLabelTag)
contentTag = Tag(soup, 'content')
contentTag['src'] = "%s#bdr_%s" % (HTML_file,
books_by_date_range[1].replace(' ',''))
navPointByDateRangeTag.insert(1,contentTag)
if self.generateForKindle:
cmTag = Tag(soup, '%s' % 'calibre:meta')
cmTag['name'] = "description"
cmTag.insert(0, NavigableString(books_by_date_range[0]))
navPointByDateRangeTag.insert(2, cmTag)
cmTag = Tag(soup, '%s' % 'calibre:meta')
cmTag['name'] = "author"
navStr = '%d titles' % books_by_date_range[2] if books_by_date_range[2] > 1 else \
'%d title' % books_by_date_range[2]
cmTag.insert(0, NavigableString(navStr))
navPointByDateRangeTag.insert(3, cmTag)
navPointTag.insert(nptc, navPointByDateRangeTag)
nptc += 1
'''
# Create an NCX article entry for each populated day # Create an NCX article entry for each populated day
# Loop over the booksByDate list, find start of each month, # Loop over the booksByDate list, find start of each month,
# add description_preview_count titles # add description_preview_count titles
@ -3944,7 +3868,8 @@ then rebuild the catalog.\n''').format(author[0])
outfile = open("%s/%s.ncx" % (self.catalogPath, self.basename), 'w') outfile = open("%s/%s.ncx" % (self.catalogPath, self.basename), 'w')
outfile.write(self.ncxSoup.prettify()) outfile.write(self.ncxSoup.prettify())
# Helpers
# --------------- Helpers ---------------
def author_to_author_sort(self, author): def author_to_author_sort(self, author):
tokens = author.split() tokens = author.split()
tokens = tokens[-1:] + tokens[:-1] tokens = tokens[-1:] + tokens[:-1]
@ -3952,45 +3877,39 @@ then rebuild the catalog.\n''').format(author[0])
tokens[0] += ',' tokens[0] += ','
return ' '.join(tokens).capitalize() return ' '.join(tokens).capitalize()
def author_compare(self,x,y): def booksByAuthorSorter_author_sort(self, book):
# Return -1 if x<y '''
# Return 0 if x==y Sort non-series books before series books
# Return 1 if x>y '''
if not book['series']:
# Different authors - sort by author_sort key = '%s %s' % (book['author_sort'],
if x['author_sort'].capitalize() > y['author_sort'].capitalize(): book['title_sort'].capitalize())
return 1
elif x['author_sort'].capitalize() < y['author_sort'].capitalize():
return -1
else: else:
# Same author index = book['series_index']
if x['series'] != y['series']: integer = int(index)
# One title is a series, the other is not fraction = index-integer
if not x['series']: series_index = '%04d%s' % (integer, str('%0.4f' % fraction).lstrip('0'))
# Sort regular titles < series titles key = '%s ~%s %s' % (book['author_sort'],
return -1 self.generateSortTitle(book['series']),
elif not y['series']: series_index)
return 1 return key
# Different series def booksByAuthorSorter_author(self, book):
if x['title_sort'].lstrip() > y['title_sort'].lstrip(): '''
return 1 Sort non-series books before series books
else: '''
return -1 if not book['series']:
else: key = '%s %s' % (self.author_to_author_sort(book['author']),
# Same series book['title_sort'].capitalize())
if x['series'] == y['series']: else:
if float(x['series_index']) > float(y['series_index']): index = book['series_index']
return 1 integer = int(index)
elif float(x['series_index']) < float(y['series_index']): fraction = index-integer
return -1 series_index = '%04d%s' % (integer, str('%0.4f' % fraction).lstrip('0'))
else: key = '%s ~%s %s' % (self.author_to_author_sort(book['author']),
return 0 self.generateSortTitle(book['series']),
else: series_index)
if x['series'] > y['series']: return key
return 1
else:
return -1
def calculateThumbnailSize(self): def calculateThumbnailSize(self):
''' Calculate thumbnail dimensions based on device DPI. Scale Kindle by 50% ''' ''' Calculate thumbnail dimensions based on device DPI. Scale Kindle by 50% '''
@ -4155,6 +4074,20 @@ then rebuild the catalog.\n''').format(author[0])
# Strip white space to '' # Strip white space to ''
return re.sub("\W","", author) return re.sub("\W","", author)
def generateFormatArgs(self, book):
series_index = str(book['series_index'])
if series_index.endswith('.0'):
series_index = series_index[:-2]
args = dict(
title = book['title'],
series = book['series'],
series_index = series_index,
rating = self.generateRatingString(book),
rating_parens = '(%s)' % self.generateRatingString(book) if 'rating' in book else '',
pubyear = book['date'].split()[1] if book['date'] else '',
pubyear_parens = "(%s)" % book['date'].split()[1] if book['date'] else '')
return args
def generateHTMLByGenre(self, genre, section_head, books, outfile): def generateHTMLByGenre(self, genre, section_head, books, outfile):
# Write an HTML file of this genre's book list # Write an HTML file of this genre's book list
# Return a list with [(first_author, first_book), (last_author, last_book)] # Return a list with [(first_author, first_book), (last_author, last_book)]
@ -4201,16 +4134,6 @@ then rebuild the catalog.\n''').format(author[0])
divTag.insert(dtc,pAuthorTag) divTag.insert(dtc,pAuthorTag)
dtc += 1 dtc += 1
'''
# Insert an <hr /> between non-series and series
if not current_series and non_series_books and book['series']:
# Insert an <hr />
hrTag = Tag(soup,'hr')
hrTag['class'] = "series_divider"
divTag.insert(dtc,hrTag)
dtc += 1
'''
# Check for series # Check for series
if book['series'] and book['series'] != current_series: if book['series'] and book['series'] != current_series:
# Start a new series # Start a new series
@ -4235,17 +4158,6 @@ then rebuild the catalog.\n''').format(author[0])
pBookTag = Tag(soup, "p") pBookTag = Tag(soup, "p")
ptc = 0 ptc = 0
'''
# This if clause does not display MISSING_SYMBOL for wishlist items
# If this is the wishlist_tag genre, don't show missing symbols
# normalized_wishlist_tag = self.genre_tags_dict[self.opts.wishlist_tag]
if self.opts.wishlist_tag in book['tags'] and \
self.genre_tags_dict[self.opts.wishlist_tag] != genre:
pBookTag['class'] = "wishlist_item"
pBookTag.insert(ptc,NavigableString(self.MISSING_SYMBOL))
ptc += 1
'''
# book with read|reading|unread symbol or wishlist item # book with read|reading|unread symbol or wishlist item
if self.opts.wishlist_tag in book.get('tags', []): if self.opts.wishlist_tag in book.get('tags', []):
pBookTag['class'] = "wishlist_item" pBookTag['class'] = "wishlist_item"
@ -4271,12 +4183,18 @@ then rebuild the catalog.\n''').format(author[0])
aTag = Tag(soup, "a") aTag = Tag(soup, "a")
if self.opts.generate_descriptions: if self.opts.generate_descriptions:
aTag['href'] = "book_%d.html" % (int(float(book['id']))) aTag['href'] = "book_%d.html" % (int(float(book['id'])))
# Use series, series index if avail else just title
# Generate the title from the template
args = self.generateFormatArgs(book)
if current_series: if current_series:
aTag.insert(0,escape(book['title'][len(book['series'])+1:])) #aTag.insert(0,escape(book['title'][len(book['series'])+1:]))
formatted_title = self.by_genres_series_title_template.format(**args).rstrip()
else: else:
aTag.insert(0,escape(book['title'])) #aTag.insert(0,escape(book['title']))
formatted_title = self.by_genres_normal_title_template.format(**args).rstrip()
non_series_books += 1 non_series_books += 1
aTag.insert(0,NavigableString(escape(formatted_title)))
pBookTag.insert(ptc, aTag) pBookTag.insert(ptc, aTag)
ptc += 1 ptc += 1
@ -4322,36 +4240,21 @@ then rebuild the catalog.\n''').format(author[0])
xmlns=XHTML_NS, xmlns=XHTML_NS,
) )
generated_html = P('catalog/template.xhtml', generated_html = P(os.path.join('catalog','template.xhtml'),
data=True).decode('utf-8').format(**args) data=True).decode('utf-8').format(**args)
generated_html = substitute_entites(generated_html) generated_html = substitute_entites(generated_html)
return BeautifulSoup(generated_html) return BeautifulSoup(generated_html)
if False:
print "title metadata:\n%s" % ', '.join(sorted(book.keys()))
if False:
for item in sorted(book.keys()):
try:
print "%s: %s%s" % (item, book[item][:50], '...' if len(book[item])>50 else '')
except:
print "%s: %s" % (item, book[item])
# Generate the template arguments # Generate the template arguments
css = P('catalog/stylesheet.css', data=True).decode('utf-8') css = P(os.path.join('catalog','stylesheet.css'), data=True).decode('utf-8')
title_str = escape(book['title']) title_str = title = escape(book['title'])
series = ''
# Title/series series_index = ''
if book['series']: if book['series']:
series_id, _, title = book['title'].partition(':')
title = escape(title.strip())
series = escape(book['series']) series = escape(book['series'])
series_index = str(book['series_index']) series_index = str(book['series_index'])
if series_index.endswith('.0'): if series_index.endswith('.0'):
series_index = series_index[:-2] series_index = series_index[:-2]
else:
title = escape(book['title'])
series = ''
series_index = ''
# Author, author_prefix (read|reading|none symbol or missing symbol) # Author, author_prefix (read|reading|none symbol or missing symbol)
author = book['author'] author = book['author']
@ -4392,7 +4295,10 @@ then rebuild the catalog.\n''').format(author[0])
# Date of publication # Date of publication
pubdate = book['date'] pubdate = book['date']
pubmonth, pubyear = pubdate.split(' ') if pubdate:
pubmonth, pubyear = pubdate.split(' ')
else:
pubmonth = pubyear = ''
# Thumb # Thumb
_soup = BeautifulSoup('<html>',selfClosingTags=['img']) _soup = BeautifulSoup('<html>',selfClosingTags=['img'])
@ -4525,7 +4431,7 @@ then rebuild the catalog.\n''').format(author[0])
def generateMastheadImage(self, out_path): def generateMastheadImage(self, out_path):
from calibre.ebooks.conversion.config import load_defaults from calibre.ebooks.conversion.config import load_defaults
from calibre.utils.fonts import fontconfig from calibre.utils.fonts import fontconfig
font_path = default_font = P('fonts/liberation/LiberationSerif-Bold.ttf') font_path = default_font = P(os.path.join('fonts','liberation','LiberationSerif-Bold.ttf'))
recs = load_defaults('mobi_output') recs = load_defaults('mobi_output')
masthead_font_family = recs.get('masthead_font', 'Default') masthead_font_family = recs.get('masthead_font', 'Default')
@ -4562,16 +4468,15 @@ then rebuild the catalog.\n''').format(author[0])
draw.text((left, top), text, fill=(0,0,0), font=font) draw.text((left, top), text, fill=(0,0,0), font=font)
img.save(open(out_path, 'wb'), 'GIF') img.save(open(out_path, 'wb'), 'GIF')
def generateSeriesTitle(self, title): def generateRatingString(self, book):
if float(title['series_index']) - int(title['series_index']): rating = ''
series_title = '%s %4.2f: %s' % (title['series'], if 'rating' in book:
title['series_index'], stars = int(book['rating']) / 2
title['title']) if stars:
else: star_string = self.FULL_RATING_SYMBOL * stars
series_title = '%s %d: %s' % (title['series'], empty_stars = self.EMPTY_RATING_SYMBOL * (5 - stars)
title['series_index'], rating = '%s%s' % (star_string,empty_stars)
title['title']) return rating
return series_title
def generateShortDescription(self, description, dest=None): def generateShortDescription(self, description, dest=None):
# Truncate the description, on word boundaries if necessary # Truncate the description, on word boundaries if necessary
@ -4610,9 +4515,11 @@ then rebuild the catalog.\n''').format(author[0])
raise RuntimeError raise RuntimeError
def generateSortTitle(self, title): def generateSortTitle(self, title):
# Generate a string suitable for sorting from the title '''
# Ignore leading stop words Generate a string suitable for sorting from the title
# Optionally convert leading numbers to strings Ignore leading stop words
Optionally convert leading numbers to strings
'''
from calibre.ebooks.metadata import title_sort from calibre.ebooks.metadata import title_sort
# Strip stop words # Strip stop words
@ -4912,10 +4819,10 @@ then rebuild the catalog.\n''').format(author[0])
class NotImplementedError: class NotImplementedError:
def __init__(self, error): def __init__(self, error):
self.error = error self.error.append(error)
def logerror(self): def logerror(self):
self.opts.log.info('%s not implemented' % self.error) self.opts.log.info('%s not implemented' % error)
def run(self, path_to_output, opts, db, notification=DummyReporter()): def run(self, path_to_output, opts, db, notification=DummyReporter()):
opts.log = log opts.log = log
@ -4982,11 +4889,12 @@ then rebuild the catalog.\n''').format(author[0])
if opts_dict['ids']: if opts_dict['ids']:
build_log.append(" book count: %d" % len(opts_dict['ids'])) build_log.append(" book count: %d" % len(opts_dict['ids']))
sections_list = ['Authors']
''' '''
sections_list = []
if opts.generate_authors: if opts.generate_authors:
sections_list.append('Authors') sections_list.append('Authors')
''' '''
sections_list = ['Authors']
if opts.generate_titles: if opts.generate_titles:
sections_list.append('Titles') sections_list.append('Titles')
if opts.generate_genres: if opts.generate_genres:
@ -5042,7 +4950,7 @@ then rebuild the catalog.\n''').format(author[0])
if catalog_source_built: if catalog_source_built:
log.info(" Completed catalog source generation\n") log.info(" Completed catalog source generation\n")
else: else:
log.warn(" No database hits with supplied criteria") log.warn(" *** Errors during catalog generation, check log for details ***")
if catalog_source_built: if catalog_source_built:
recommendations = [] recommendations = []
@ -5072,8 +4980,6 @@ then rebuild the catalog.\n''').format(author[0])
abort_after_input_dump=False) abort_after_input_dump=False)
plumber.merge_ui_recommendations(recommendations) plumber.merge_ui_recommendations(recommendations)
plumber.run() plumber.run()
# returns to gui2.actions.catalog:catalog_generated()
return None # returns to gui2.actions.catalog:catalog_generated()
else: return catalog.error
# returns to gui2.actions.catalog:catalog_generated()
return catalog.error