GwR revisions for device profile, tweaks to Recently Added

This commit is contained in:
GRiker 2010-02-15 10:38:37 -07:00
parent 4b6e4d9ae4
commit 096e53c484
5 changed files with 323 additions and 63 deletions

View File

@ -23,7 +23,7 @@ def gui_convert(input, output, recommendations, notification=DummyReporter(),
plumber.run() plumber.run()
def gui_catalog(fmt, title, dbspec, ids, out_file_name, sync, fmt_options, def gui_catalog(fmt, title, dbspec, ids, out_file_name, sync, fmt_options, connected_device,
notification=DummyReporter(), log=None): notification=DummyReporter(), log=None):
if log is None: if log is None:
log = Log() log = Log()
@ -44,6 +44,7 @@ def gui_catalog(fmt, title, dbspec, ids, out_file_name, sync, fmt_options,
# Populate opts # Populate opts
# opts.gui_search_text = something # opts.gui_search_text = something
opts.catalog_title = title opts.catalog_title = title
opts.connected_device = connected_device
opts.ids = ids opts.ids = ids
opts.search_text = None opts.search_text = None
opts.sort_by = None opts.sort_by = None

View File

@ -7,7 +7,7 @@ __docformat__ = 'restructuredtext en'
Logic for setting up conversion jobs Logic for setting up conversion jobs
''' '''
import cPickle import cPickle, os
from PyQt4.Qt import QDialog, QProgressDialog, QString, QTimer, SIGNAL from PyQt4.Qt import QDialog, QProgressDialog, QString, QTimer, SIGNAL
@ -236,7 +236,7 @@ def fetch_scheduled_recipe(arg):
return 'gui_convert', args, _('Fetch news from ')+arg['title'], fmt.upper(), [pt] return 'gui_convert', args, _('Fetch news from ')+arg['title'], fmt.upper(), [pt]
def generate_catalog(parent, dbspec, ids): def generate_catalog(parent, dbspec, ids, device):
from calibre.gui2.dialogs.catalog import Catalog from calibre.gui2.dialogs.catalog import Catalog
# Build the Catalog dialog in gui2.dialogs.catalog # Build the Catalog dialog in gui2.dialogs.catalog
@ -248,6 +248,21 @@ def generate_catalog(parent, dbspec, ids):
# Create the output file # Create the output file
out = PersistentTemporaryFile(suffix='_catalog_out.'+d.catalog_format.lower()) out = PersistentTemporaryFile(suffix='_catalog_out.'+d.catalog_format.lower())
# Profile the connected device
# Parallel initialization in calibre.library.cli:command_catalog()
connected_device = { 'storage':None,'serial':None,'name':None}
if device:
storage = []
if device._main_prefix:
storage.append(os.path.join(device._main_prefix, device.EBOOK_DIR_MAIN))
if device._card_a_prefix:
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,
'name':device.gui_name}
# These args are passed inline to gui2.convert.gui_conversion:gui_catalog
args = [ args = [
d.catalog_format, d.catalog_format,
d.catalog_title, d.catalog_title,
@ -255,12 +270,13 @@ def generate_catalog(parent, dbspec, ids):
ids, ids,
out.name, out.name,
d.catalog_sync, d.catalog_sync,
d.fmt_options d.fmt_options,
connected_device
] ]
out.close() out.close()
# This returns to gui2.ui:generate_catalog() # This returns to gui2.ui:generate_catalog()
# Which then calls gui2.convert.gui_conversion:gui_catalog() # Which then calls gui2.convert.gui_conversion:gui_catalog() with the args inline
return 'gui_catalog', args, _('Generate catalog'), out.name, d.catalog_sync, \ return 'gui_catalog', args, _('Generate catalog'), out.name, d.catalog_sync, \
d.catalog_title d.catalog_title

View File

@ -1379,7 +1379,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
show=True) show=True)
# Calling gui2.tools:generate_catalog() # Calling gui2.tools:generate_catalog()
ret = generate_catalog(self, dbspec, ids) ret = generate_catalog(self, dbspec, ids, self.device_manager.device)
if ret is None: if ret is None:
return return

View File

@ -1,7 +1,8 @@
import os, re, shutil, htmlentitydefs import datetime, htmlentitydefs, os, re, shutil, time, traceback
from collections import namedtuple from collections import namedtuple
from datetime import date from copy import deepcopy
from xml.sax.saxutils import escape from xml.sax.saxutils import escape
from calibre import filesystem_encoding, prints, prepare_string_for_xml, strftime from calibre import filesystem_encoding, prints, prepare_string_for_xml, strftime
@ -533,10 +534,11 @@ class EPUB_MOBI(CatalogPlugin):
catalog.copyResources() catalog.copyResources()
catalog.buildSources() catalog.buildSources()
''' '''
# A single number creates 'Last x days' only.
# Number of discrete steps to catalog creation # Multiple numbers create 'Last x days', 'x to y days ago' ...
# current_step = 0.0 # e.g, [7,15,30,60], [30]
# total_steps = 10.0 # [] = No date ranges added
DATE_RANGE=[30]
# basename output file basename # basename output file basename
# creator dc:creator in OPF metadata # creator dc:creator in OPF metadata
@ -551,10 +553,12 @@ class EPUB_MOBI(CatalogPlugin):
report_progress=DummyReporter(), report_progress=DummyReporter(),
stylesheet="content/stylesheet.css"): stylesheet="content/stylesheet.css"):
self.__opts = opts self.__opts = opts
self.__authorClip = opts.authorClip
self.__authors = None self.__authors = None
self.__basename = opts.basename self.__basename = opts.basename
self.__booksByAuthor = None self.__booksByAuthor = None
self.__booksByTitle = None self.__booksByTitle = None
self.__booksByTitle_noSeriesPrefix = None
self.__catalogPath = PersistentTemporaryDirectory("_epub_mobi_catalog", prefix='') self.__catalogPath = PersistentTemporaryDirectory("_epub_mobi_catalog", prefix='')
self.__contentDir = os.path.join(self.catalogPath, "content") self.__contentDir = os.path.join(self.catalogPath, "content")
self.__currentStep = 0.0 self.__currentStep = 0.0
@ -581,6 +585,7 @@ class EPUB_MOBI(CatalogPlugin):
self.__thumbHeight = 0 self.__thumbHeight = 0
self.__title = opts.catalog_title self.__title = opts.catalog_title
self.__totalSteps = 11.0 self.__totalSteps = 11.0
self.__useSeriesPrefixInTitlesSection = False
self.__verbose = opts.verbose self.__verbose = opts.verbose
# Tweak build steps based on optional sections. 1 call for HTML, 1 for NCX # Tweak build steps based on optional sections. 1 call for HTML, 1 for NCX
@ -600,6 +605,13 @@ class EPUB_MOBI(CatalogPlugin):
return property(fget=fget, fset=fset) return property(fget=fget, fset=fset)
''' '''
@dynamic_property
def authorClip(self):
def fget(self):
return self.__authorClip
def fset(self, val):
self.__authorClip = val
return property(fget=fget, fset=fset)
@dynamic_property @dynamic_property
def authors(self): def authors(self):
def fget(self): def fget(self):
@ -629,6 +641,13 @@ class EPUB_MOBI(CatalogPlugin):
self.__booksByTitle = val self.__booksByTitle = val
return property(fget=fget, fset=fset) return property(fget=fget, fset=fset)
@dynamic_property @dynamic_property
def booksByTitle_noSeriesPrefix(self):
def fget(self):
return self.__booksByTitle_noSeriesPrefix
def fset(self, val):
self.__booksByTitle_noSeriesPrefix = val
return property(fget=fget, fset=fset)
@dynamic_property
def catalogPath(self): def catalogPath(self):
def fget(self): def fget(self):
return self.__catalogPath return self.__catalogPath
@ -799,6 +818,13 @@ class EPUB_MOBI(CatalogPlugin):
return self.__totalSteps return self.__totalSteps
return property(fget=fget) return property(fget=fget)
@dynamic_property @dynamic_property
def useSeriesPrefixInTitlesSection(self):
def fget(self):
return self.__useSeriesPrefixInTitlesSection
def fset(self, val):
self.__useSeriesPrefixInTitlesSection = val
return property(fget=fget, fset=fset)
@dynamic_property
def verbose(self): def verbose(self):
def fget(self): def fget(self):
return self.__verbose return self.__verbose
@ -971,7 +997,7 @@ class EPUB_MOBI(CatalogPlugin):
for token in p.contents: for token in p.contents:
if token.string is not None: if token.string is not None:
tokens.append(token.string) tokens.append(token.string)
this_title['short_description'] = self.generateShortDescription(' '.join(tokens)) this_title['short_description'] = self.generateShortDescription(' '.join(tokens), dest="description")
else: else:
this_title['description'] = None this_title['description'] = None
this_title['short_description'] = None this_title['short_description'] = None
@ -1109,10 +1135,10 @@ class EPUB_MOBI(CatalogPlugin):
# title<br />series series_index # title<br />series series_index
brTag = Tag(soup,'br') brTag = Tag(soup,'br')
title_tokens = title['title'].split(': ') title_tokens = title['title'].split(': ')
emTag.insert(0, NavigableString(title_tokens[1])) emTag.insert(0, escape(NavigableString(title_tokens[1])))
emTag.insert(1, brTag) emTag.insert(1, brTag)
smallTag = Tag(soup,'small') smallTag = Tag(soup,'small')
smallTag.insert(0,NavigableString(title_tokens[0])) smallTag.insert(0, escape(NavigableString(title_tokens[0])))
emTag.insert(2, smallTag) emTag.insert(2, smallTag)
else: else:
emTag.insert(0, NavigableString(escape(title['title']))) emTag.insert(0, NavigableString(escape(title['title'])))
@ -1287,8 +1313,29 @@ class EPUB_MOBI(CatalogPlugin):
dtc = 0 dtc = 0
current_letter = "" current_letter = ""
# 2/14/10 7:11 AM Experimental: 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])
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
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
for book in self.booksByTitle: title_list = self.booksByTitle
if not self.useSeriesPrefixInTitlesSection:
title_list = self.booksByTitle_noSeriesPrefix
for book in title_list:
if self.letter_or_symbol(book['title_sort'][0]) != current_letter : if self.letter_or_symbol(book['title_sort'][0]) != current_letter :
# Start a new letter # Start a new letter
current_letter = self.letter_or_symbol(book['title_sort'][0]) current_letter = self.letter_or_symbol(book['title_sort'][0])
@ -1513,7 +1560,7 @@ class EPUB_MOBI(CatalogPlugin):
# 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(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.sort(self.author_compare)
@ -1598,10 +1645,56 @@ class EPUB_MOBI(CatalogPlugin):
dtc += 1 dtc += 1
return dtc return dtc
def add_books_to_HTML_by_date_range(date_range_list, date_range, dtc):
if len(date_range_list):
pIndexTag = Tag(soup, "p")
pIndexTag['class'] = "date_index"
aTag = Tag(soup, "a")
aTag['name'] = date_range.replace(' ','')
pIndexTag.insert(0,aTag)
pIndexTag.insert(1,NavigableString(date_range))
divTag.insert(dtc,pIndexTag)
dtc += 1
# Sort titles case-insensitive for new_entry in date_range_list:
self.booksByDate = sorted(self.booksByTitle, # Add books
key=lambda x:(x['timestamp'], x['timestamp']),reverse=True) pBookTag = Tag(soup, "p")
ptc = 0
# Prefix book with read/unread symbol
if new_entry['read']:
# check mark
pBookTag.insert(ptc,NavigableString(self.READ_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(new_entry['id'])))
aTag.insert(0,escape(new_entry['title']))
pBookTag.insert(ptc, aTag)
ptc += 1
# Dot
pBookTag.insert(ptc, NavigableString(" &middot; "))
ptc += 1
# Link to author
emTag = Tag(soup, "em")
aTag = Tag(soup, "a")
aTag['href'] = "%s.html#%s" % ("ByAlphaAuthor", self.generateAuthorAnchor(new_entry['author']))
aTag.insert(0, NavigableString(new_entry['author']))
emTag.insert(0,aTag)
pBookTag.insert(ptc, emTag)
ptc += 1
divTag.insert(dtc, pBookTag)
dtc += 1
return dtc
friendly_name = "Recently Added" friendly_name = "Recently Added"
@ -1640,20 +1733,63 @@ class EPUB_MOBI(CatalogPlugin):
divTag = Tag(soup, "div") divTag = Tag(soup, "div")
dtc = 0 dtc = 0
current_date = date.fromordinal(1) # Add books by date range
if self.useSeriesPrefixInTitlesSection:
self.booksByDateRange = sorted(self.booksByTitle,
key=lambda x:(x['timestamp'], x['timestamp']),reverse=True)
else:
nspt = deepcopy(self.booksByTitle)
for book in nspt:
if book['series']:
tokens = book['title'].split(': ')
book['title'] = '%s (%s)' % (tokens[1], tokens[0])
book['title_sort'] = self.generateSortTitle(book['title'])
self.booksByDateRange = sorted(nspt, key=lambda x:(x['timestamp'], x['timestamp']),reverse=True)
today = datetime.datetime.now()
date_range_list = []
today_time = datetime.datetime(today.year, today.month, today.day)
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.booksByDateRange:
book_time = datetime.datetime(book['timestamp'].year, book['timestamp'].month, book['timestamp'].day)
if (today_time-book_time).days <= date_range_limit:
#print "generateHTMLByDateAdded: %s added %d days ago" % (book['title'], (today_time-book_time).days)
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')
divTag.insert(dtc,hrTag)
dtc += 1
# Sort titles case-insensitive for by month using series prefix
self.booksByMonth = sorted(self.booksByTitle,
key=lambda x:(x['timestamp'], x['timestamp']),reverse=True)
# Loop through books by date # Loop through books by date
current_date = datetime.date.fromordinal(1)
this_months_list = [] this_months_list = []
for book in self.booksByDate: for book in self.booksByMonth:
if book['timestamp'].month != current_date.month or \ if book['timestamp'].month != current_date.month or \
book['timestamp'].year != current_date.year: book['timestamp'].year != current_date.year:
dtc = add_books_to_HTML(this_months_list, dtc) dtc = add_books_to_HTML_by_month(this_months_list, dtc)
this_months_list = [] this_months_list = []
current_date = book['timestamp'].date() current_date = book['timestamp'].date()
this_months_list.append(book) this_months_list.append(book)
# Add the last month's list # Add the last month's list
add_books_to_HTML(this_months_list, dtc) add_books_to_HTML_by_month(this_months_list, dtc)
# Add the divTag to the body # Add the divTag to the body
body.insert(btc, divTag) body.insert(btc, divTag)
@ -2055,6 +2191,7 @@ class EPUB_MOBI(CatalogPlugin):
# Loop over the titles # Loop over the titles
sort_descriptions_by = self.booksByAuthor if self.opts.sort_descriptions_by_author \ sort_descriptions_by = self.booksByAuthor if self.opts.sort_descriptions_by_author \
else self.booksByTitle else self.booksByTitle
for book in sort_descriptions_by: for book in sort_descriptions_by:
navPointVolumeTag = Tag(ncx_soup, 'navPoint') navPointVolumeTag = Tag(ncx_soup, 'navPoint')
navPointVolumeTag['class'] = "article" navPointVolumeTag['class'] = "article"
@ -2065,9 +2202,9 @@ class EPUB_MOBI(CatalogPlugin):
textTag = Tag(ncx_soup, "text") textTag = Tag(ncx_soup, "text")
if book['series']: if book['series']:
tokens = book['title'].split(': ') tokens = book['title'].split(': ')
textTag.insert(0, NavigableString(self.formatNCXText('%s (%s)' % (tokens[1], tokens[0])))) textTag.insert(0, NavigableString(self.formatNCXText('%s (%s)' % (tokens[1], tokens[0]), dest='title')))
else: else:
textTag.insert(0, NavigableString(self.formatNCXText(book['title']))) textTag.insert(0, NavigableString(self.formatNCXText(book['title'], dest='title')))
navLabelTag.insert(0,textTag) navLabelTag.insert(0,textTag)
navPointVolumeTag.insert(0,navLabelTag) navPointVolumeTag.insert(0,navLabelTag)
@ -2079,10 +2216,10 @@ class EPUB_MOBI(CatalogPlugin):
# Add the author tag # Add the author tag
cmTag = Tag(ncx_soup, '%s' % 'calibre:meta') cmTag = Tag(ncx_soup, '%s' % 'calibre:meta')
cmTag['name'] = "author" cmTag['name'] = "author"
navStr = '%s | %s' % (self.formatNCXText(book['author']), navStr = '%s | %s' % (self.formatNCXText(book['author'], dest='author'),
book['date'].split()[1]) book['date'].split()[1])
if 'tags' in book: if 'tags' in book:
navStr += ' | %s' % self.formatNCXText(' &middot; '.join(sorted(book['tags']))) navStr = self.formatNCXText(navStr + ' | ' + ' &middot; '.join(sorted(book['tags'])), dest='author')
cmTag.insert(0, NavigableString(navStr)) cmTag.insert(0, NavigableString(navStr))
navPointVolumeTag.insert(2, cmTag) navPointVolumeTag.insert(2, cmTag)
@ -2090,7 +2227,7 @@ class EPUB_MOBI(CatalogPlugin):
if book['short_description']: if book['short_description']:
cmTag = Tag(ncx_soup, '%s' % 'calibre:meta') cmTag = Tag(ncx_soup, '%s' % 'calibre:meta')
cmTag['name'] = "description" cmTag['name'] = "description"
cmTag.insert(0, NavigableString(self.formatNCXText(book['short_description']))) cmTag.insert(0, NavigableString(self.formatNCXText(book['short_description'], dest='description')))
navPointVolumeTag.insert(3, cmTag) navPointVolumeTag.insert(3, cmTag)
# Add this volume to the section tag # Add this volume to the section tag
@ -2108,7 +2245,7 @@ class EPUB_MOBI(CatalogPlugin):
def add_to_books_by_letter(current_book_list): def add_to_books_by_letter(current_book_list):
current_book_list = " &bull; ".join(current_book_list) current_book_list = " &bull; ".join(current_book_list)
current_book_list = self.generateShortDescription(self.formatNCXText(current_book_list)) current_book_list = self.formatNCXText(current_book_list, dest="description")
books_by_letter.append(current_book_list) books_by_letter.append(current_book_list)
soup = self.ncxSoup soup = self.ncxSoup
@ -2137,11 +2274,16 @@ class EPUB_MOBI(CatalogPlugin):
books_by_letter = [] books_by_letter = []
# Loop over the titles, find start of each letter, add description_preview_count books # Loop over the titles, find start of each letter, add description_preview_count books
current_letter = self.letter_or_symbol(self.booksByTitle[0]['title_sort'][0]) # Special switch for using different title list
if self.useSeriesPrefixInTitlesSection:
title_list = self.booksByTitle
else:
title_list = self.booksByTitle_noSeriesPrefix
current_letter = self.letter_or_symbol(title_list[0]['title_sort'][0])
title_letters = [current_letter] title_letters = [current_letter]
current_book_list = [] current_book_list = []
current_book = "" current_book = ""
for book in self.booksByTitle: for book in title_list:
if self.letter_or_symbol(book['title_sort'][0]) != current_letter: if self.letter_or_symbol(book['title_sort'][0]) != current_letter:
# Save the old list # Save the old list
add_to_books_by_letter(current_book_list) add_to_books_by_letter(current_book_list)
@ -2180,7 +2322,7 @@ class EPUB_MOBI(CatalogPlugin):
if self.generateForKindle: if self.generateForKindle:
cmTag = Tag(soup, '%s' % 'calibre:meta') cmTag = Tag(soup, '%s' % 'calibre:meta')
cmTag['name'] = "description" cmTag['name'] = "description"
cmTag.insert(0, NavigableString(self.formatNCXText(books))) cmTag.insert(0, NavigableString(self.formatNCXText(books, dest='description')))
navPointByLetterTag.insert(2, cmTag) navPointByLetterTag.insert(2, cmTag)
navPointTag.insert(nptc, navPointByLetterTag) navPointTag.insert(nptc, navPointByLetterTag)
@ -2197,7 +2339,7 @@ class EPUB_MOBI(CatalogPlugin):
def add_to_author_list(current_author_list, current_letter): def add_to_author_list(current_author_list, current_letter):
current_author_list = " &bull; ".join(current_author_list) current_author_list = " &bull; ".join(current_author_list)
current_author_list = self.generateShortDescription(self.formatNCXText(current_author_list)) current_author_list = self.formatNCXText(current_author_list, dest="description")
master_author_list.append((current_author_list, current_letter)) master_author_list.append((current_author_list, current_letter))
soup = self.ncxSoup soup = self.ncxSoup
@ -2287,9 +2429,15 @@ class EPUB_MOBI(CatalogPlugin):
def add_to_master_month_list(current_titles_list): def add_to_master_month_list(current_titles_list):
book_count = len(current_titles_list) book_count = len(current_titles_list)
current_titles_list = " &bull; ".join(current_titles_list) current_titles_list = " &bull; ".join(current_titles_list)
current_titles_list = self.generateShortDescription(self.formatNCXText(current_titles_list)) current_titles_list = self.formatNCXText(current_titles_list, dest='description')
master_month_list.append((current_titles_list, current_date, book_count)) master_month_list.append((current_titles_list, current_date, book_count))
def add_to_master_date_range_list(current_titles_list):
book_count = len(current_titles_list)
current_titles_list = " &bull; ".join(current_titles_list)
current_titles_list = self.formatNCXText(current_titles_list, dest='description')
master_date_range_list.append((current_titles_list, date_range, book_count))
soup = self.ncxSoup soup = self.ncxSoup
HTML_file = "content/ByDateAdded.html" HTML_file = "content/ByDateAdded.html"
body = soup.find("navPoint") body = soup.find("navPoint")
@ -2315,15 +2463,74 @@ class EPUB_MOBI(CatalogPlugin):
navPointTag.insert(nptc, contentTag) navPointTag.insert(nptc, contentTag)
nptc += 1 nptc += 1
# Create an NCX article entry for each date range
current_titles_list = []
master_date_range_list = []
today = datetime.datetime.now()
today_time = datetime.datetime(today.year, today.month, today.day)
for (i,date) in enumerate(self.DATE_RANGE):
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])
date_range_limit = self.DATE_RANGE[i]
for book in self.booksByDateRange:
book_time = datetime.datetime(book['timestamp'].year, book['timestamp'].month, book['timestamp'].day)
if (today_time-book_time).days <= date_range_limit:
#print "generateNCXByDateAdded: %s added %d days ago" % (book['title'], (today_time-book_time).days)
current_titles_list.append(book['title'])
else:
break
if current_titles_list:
add_to_master_date_range_list(current_titles_list)
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#%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 month # Create an NCX article entry for each populated month
# 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
# master_month_list(list,date,count) # master_month_list(list,date,count)
current_titles_list = [] current_titles_list = []
master_month_list = [] master_month_list = []
current_date = self.booksByDate[0]['timestamp'] current_date = self.booksByMonth[0]['timestamp']
for book in self.booksByDate: for book in self.booksByMonth:
if book['timestamp'].month != current_date.month or \ if book['timestamp'].month != current_date.month or \
book['timestamp'].year != current_date.year: book['timestamp'].year != current_date.year:
# Save the old lists # Save the old lists
@ -2432,7 +2639,7 @@ class EPUB_MOBI(CatalogPlugin):
if self.genre_tags_dict[friendly_tag] == genre['tag']: if self.genre_tags_dict[friendly_tag] == genre['tag']:
normalized_tag = self.genre_tags_dict[friendly_tag] normalized_tag = self.genre_tags_dict[friendly_tag]
break break
textTag.insert(0, self.formatNCXText(NavigableString(friendly_tag))) textTag.insert(0, self.formatNCXText(NavigableString(friendly_tag), dest='description'))
navLabelTag.insert(0,textTag) navLabelTag.insert(0,textTag)
navPointVolumeTag.insert(0,navLabelTag) navPointVolumeTag.insert(0,navLabelTag)
contentTag = Tag(ncx_soup, "content") contentTag = Tag(ncx_soup, "content")
@ -2463,15 +2670,15 @@ class EPUB_MOBI(CatalogPlugin):
title_range = "%s -\n%s" % (genre['titles_spanned'][0][1], genre['titles_spanned'][1][1]) title_range = "%s -\n%s" % (genre['titles_spanned'][0][1], genre['titles_spanned'][1][1])
else: else:
title_range = "%s" % (genre['titles_spanned'][0][1]) title_range = "%s" % (genre['titles_spanned'][0][1])
cmTag.insert(0, NavigableString(self.formatNCXText(title_range))) cmTag.insert(0, NavigableString(self.formatNCXText(title_range, dest='description')))
else: else:
# Form 2: title &bull; title &bull; title ... # Form 2: title &bull; title &bull; title ...
titles = [] titles = []
for title in genre['books']: for title in genre['books']:
titles.append(title['title']) titles.append(title['title'])
titles = sorted(titles, key=lambda x:(self.generateSortTitle(x),self.generateSortTitle(x))) titles = sorted(titles, key=lambda x:(self.generateSortTitle(x),self.generateSortTitle(x)))
titles_list = self.generateShortDescription(u" &bull; ".join(titles)) titles_list = self.generateShortDescription(u" &bull; ".join(titles), dest="description")
cmTag.insert(0, NavigableString(self.formatNCXText(titles_list))) cmTag.insert(0, NavigableString(self.formatNCXText(titles_list, dest='description')))
navPointVolumeTag.insert(3, cmTag) navPointVolumeTag.insert(3, cmTag)
@ -2652,7 +2859,7 @@ class EPUB_MOBI(CatalogPlugin):
return genre_tags_dict return genre_tags_dict
def formatNCXText(self, description): def formatNCXText(self, description, dest=None):
# Kindle TOC descriptions won't render certain characters # Kindle TOC descriptions won't render certain characters
# Fix up # Fix up
massaged = unicode(BeautifulStoneSoup(description, convertEntities=BeautifulStoneSoup.HTML_ENTITIES)) massaged = unicode(BeautifulStoneSoup(description, convertEntities=BeautifulStoneSoup.HTML_ENTITIES))
@ -2660,7 +2867,11 @@ class EPUB_MOBI(CatalogPlugin):
# Replace '&' with '&#38;' # Replace '&' with '&#38;'
massaged = re.sub("&","&#38;", massaged) massaged = re.sub("&","&#38;", massaged)
return massaged.strip() if massaged.strip() and dest:
#print traceback.print_stack(limit=3)
return self.generateShortDescription(massaged.strip(), dest=dest)
else:
return None
def generateAuthorAnchor(self, author): def generateAuthorAnchor(self, author):
# Strip white space to '' # Strip white space to ''
@ -2928,27 +3139,41 @@ class EPUB_MOBI(CatalogPlugin):
title['title']) title['title'])
return series_title return series_title
def generateShortDescription(self, description): def generateShortDescription(self, description, dest=None):
# Truncate the description to description_clip, on word boundaries if necessary # Truncate the description, on word boundaries if necessary
if not description: # Possible destinations:
return None # description NCX summary
# title NCX title
# author NCX author
if not self.descriptionClip: def shortDescription(description, limit):
return description
if len(description) < self.descriptionClip:
return description
# Start adding words until we reach description_clip
short_description = "" short_description = ""
words = description.split() words = description.split()
for word in words: for word in words:
short_description += word + " " short_description += word + " "
if len(short_description) > self.descriptionClip: if len(short_description) > limit:
short_description += "..." short_description += "..."
return short_description return short_description
return short_description if not description:
return None
if dest == 'title':
# No truncation for titles, let the device deal with it
return description
elif dest == 'author':
if self.authorClip and len(description) < self.authorClip:
return description
else:
return shortDescription(description, self.authorClip)
elif dest == 'description':
if self.descriptionClip and len(description) < self.descriptionClip:
return description
else:
return shortDescription(description, self.descriptionClip)
else:
print " returning description with unspecified destination '%s'" % description
raise RuntimeError
def generateSortTitle(self, title): def generateSortTitle(self, title):
# Convert the actual title to a string suitable for sorting. # Convert the actual title to a string suitable for sorting.
@ -3172,12 +3397,17 @@ class EPUB_MOBI(CatalogPlugin):
# Add local options # Add local options
opts.creator = "calibre" opts.creator = "calibre"
# Finalize output_profile
op = self.opts.output_profile op = self.opts.output_profile
if op is None: if op is None:
op = 'default' op = 'default'
if opts.connected_device['name'] and 'kindle' in opts.connected_device['name'].lower():
op = "kindle_dx" if opts.connected_device['serial'][:4] in ['B004','B005'] else 'kindle'
opts.descriptionClip = 380 if op.endswith('dx') or 'kindle' not in op else 100
opts.authorClip = 100 if op.endswith('dx') or 'kindle' not in op else 60
self.opts.output_profile = op self.opts.output_profile = op
opts.descriptionClip = 380 if op.endswith('dx') or 'kindle' not in op else 90
opts.basename = "Catalog" opts.basename = "Catalog"
opts.cli_environment = not hasattr(opts,'sync') opts.cli_environment = not hasattr(opts,'sync')
# GwR *** hardwired to sort by author, could be an option if passed in opts # GwR *** hardwired to sort by author, could be an option if passed in opts
@ -3205,13 +3435,22 @@ class EPUB_MOBI(CatalogPlugin):
opts.exclude_genre = '\[^.\]' opts.exclude_genre = '\[^.\]'
log(" converting empty exclude_genre to '\[^.\]'") log(" converting empty exclude_genre to '\[^.\]'")
if opts.connected_device['name']:
log(" connected_device: '%s' #%s%s " % (opts.connected_device['name'],
opts.connected_device['serial'][0:4],
'x' * (len(opts.connected_device['serial']) - 4)))
for storage in opts.connected_device['storage']:
if storage:
log(" mount point: %s" % storage)
# for book in opts.connected_device['books']:
# log("%s: %s" % (book.title, book.path))
# Display opts # Display opts
keys = opts_dict.keys() keys = opts_dict.keys()
keys.sort() keys.sort()
log(" opts:") log(" opts:")
for key in keys: for key in keys:
if key in ['catalog_title','exclude_genre','exclude_tags', if key in ['catalog_title','authorClip','descriptionClip','exclude_genre','exclude_tags',
'note_tag','numbers_as_text','read_tag', 'note_tag','numbers_as_text','read_tag',
'search_text','sort_by','sort_descriptions_by_author','sync']: 'search_text','sort_by','sort_descriptions_by_author','sync']:
log(" %s: %s" % (key, opts_dict[key])) log(" %s: %s" % (key, opts_dict[key]))

View File

@ -673,6 +673,10 @@ def command_catalog(args, dbpath):
if opts.ids: if opts.ids:
opts.ids = [int(id) for id in opts.ids.split(',')] opts.ids = [int(id) for id in opts.ids.split(',')]
# No support for connected device in CLI environment
# Parallel initialization in calibre.gui2.tools:generate_catalog()
opts.connected_device = {'storage':None,'serial':None,'name':None}
with plugin: with plugin:
plugin.run(args[1], opts, get_db(dbpath, opts)) plugin.run(args[1], opts, get_db(dbpath, opts))
return 0 return 0