From 096e53c4840056c72ebdf9efbba1e70526925a94 Mon Sep 17 00:00:00 2001 From: GRiker Date: Mon, 15 Feb 2010 10:38:37 -0700 Subject: [PATCH] GwR revisions for device profile, tweaks to Recently Added --- src/calibre/gui2/convert/gui_conversion.py | 3 +- src/calibre/gui2/tools.py | 24 +- src/calibre/gui2/ui.py | 2 +- src/calibre/library/catalog.py | 353 +++++++++++++++++---- src/calibre/library/cli.py | 4 + 5 files changed, 323 insertions(+), 63 deletions(-) diff --git a/src/calibre/gui2/convert/gui_conversion.py b/src/calibre/gui2/convert/gui_conversion.py index d035a0ff93..148dc328ad 100644 --- a/src/calibre/gui2/convert/gui_conversion.py +++ b/src/calibre/gui2/convert/gui_conversion.py @@ -23,7 +23,7 @@ def gui_convert(input, output, recommendations, notification=DummyReporter(), 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): if log is None: log = Log() @@ -44,6 +44,7 @@ def gui_catalog(fmt, title, dbspec, ids, out_file_name, sync, fmt_options, # Populate opts # opts.gui_search_text = something opts.catalog_title = title + opts.connected_device = connected_device opts.ids = ids opts.search_text = None opts.sort_by = None diff --git a/src/calibre/gui2/tools.py b/src/calibre/gui2/tools.py index bd34f84821..38b0a6d663 100644 --- a/src/calibre/gui2/tools.py +++ b/src/calibre/gui2/tools.py @@ -7,7 +7,7 @@ __docformat__ = 'restructuredtext en' Logic for setting up conversion jobs ''' -import cPickle +import cPickle, os 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] -def generate_catalog(parent, dbspec, ids): +def generate_catalog(parent, dbspec, ids, device): from calibre.gui2.dialogs.catalog import Catalog # Build the Catalog dialog in gui2.dialogs.catalog @@ -248,6 +248,21 @@ def generate_catalog(parent, dbspec, ids): # Create the output file 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 = [ d.catalog_format, d.catalog_title, @@ -255,12 +270,13 @@ def generate_catalog(parent, dbspec, ids): ids, out.name, d.catalog_sync, - d.fmt_options + d.fmt_options, + connected_device ] out.close() # 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, \ d.catalog_title diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index f3b5e439a3..c16b868b34 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -1379,7 +1379,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): show=True) # 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: return diff --git a/src/calibre/library/catalog.py b/src/calibre/library/catalog.py index 540ba65cc5..77e1e51e17 100644 --- a/src/calibre/library/catalog.py +++ b/src/calibre/library/catalog.py @@ -1,7 +1,8 @@ -import os, re, shutil, htmlentitydefs +import datetime, htmlentitydefs, os, re, shutil, time, traceback from collections import namedtuple -from datetime import date +from copy import deepcopy + from xml.sax.saxutils import escape from calibre import filesystem_encoding, prints, prepare_string_for_xml, strftime @@ -533,10 +534,11 @@ class EPUB_MOBI(CatalogPlugin): catalog.copyResources() catalog.buildSources() ''' - - # Number of discrete steps to catalog creation -# current_step = 0.0 -# total_steps = 10.0 + # A single number creates 'Last x days' only. + # Multiple numbers create 'Last x days', 'x to y days ago' ... + # e.g, [7,15,30,60], [30] + # [] = No date ranges added + DATE_RANGE=[30] # basename output file basename # creator dc:creator in OPF metadata @@ -551,10 +553,12 @@ class EPUB_MOBI(CatalogPlugin): report_progress=DummyReporter(), stylesheet="content/stylesheet.css"): self.__opts = opts + self.__authorClip = opts.authorClip self.__authors = None self.__basename = opts.basename self.__booksByAuthor = None self.__booksByTitle = None + self.__booksByTitle_noSeriesPrefix = None self.__catalogPath = PersistentTemporaryDirectory("_epub_mobi_catalog", prefix='') self.__contentDir = os.path.join(self.catalogPath, "content") self.__currentStep = 0.0 @@ -581,6 +585,7 @@ class EPUB_MOBI(CatalogPlugin): self.__thumbHeight = 0 self.__title = opts.catalog_title self.__totalSteps = 11.0 + self.__useSeriesPrefixInTitlesSection = False self.__verbose = opts.verbose # 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) ''' + @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 def authors(self): def fget(self): @@ -629,6 +641,13 @@ class EPUB_MOBI(CatalogPlugin): self.__booksByTitle = val return property(fget=fget, fset=fset) @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 fget(self): return self.__catalogPath @@ -799,6 +818,13 @@ class EPUB_MOBI(CatalogPlugin): return self.__totalSteps return property(fget=fget) @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 fget(self): return self.__verbose @@ -971,7 +997,7 @@ class EPUB_MOBI(CatalogPlugin): for token in p.contents: if token.string is not None: tokens.append(token.string) - this_title['short_description'] = self.generateShortDescription(' '.join(tokens)) + this_title['short_description'] = self.generateShortDescription(' '.join(tokens), dest="description") else: this_title['description'] = None this_title['short_description'] = None @@ -1109,10 +1135,10 @@ class EPUB_MOBI(CatalogPlugin): # title
series series_index brTag = Tag(soup,'br') title_tokens = title['title'].split(': ') - emTag.insert(0, NavigableString(title_tokens[1])) + emTag.insert(0, escape(NavigableString(title_tokens[1]))) emTag.insert(1, brTag) smallTag = Tag(soup,'small') - smallTag.insert(0,NavigableString(title_tokens[0])) + smallTag.insert(0, escape(NavigableString(title_tokens[0]))) emTag.insert(2, smallTag) else: emTag.insert(0, NavigableString(escape(title['title']))) @@ -1287,8 +1313,29 @@ class EPUB_MOBI(CatalogPlugin): dtc = 0 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 - 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 : # Start a new letter current_letter = self.letter_or_symbol(book['title_sort'][0]) @@ -1513,7 +1560,7 @@ class EPUB_MOBI(CatalogPlugin): # Write books by reverse chronological order 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): this_months_list.sort(self.author_compare) @@ -1598,10 +1645,56 @@ class EPUB_MOBI(CatalogPlugin): dtc += 1 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 - self.booksByDate = sorted(self.booksByTitle, - key=lambda x:(x['timestamp'], x['timestamp']),reverse=True) + for new_entry in date_range_list: + # Add books + 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(" · ")) + 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" @@ -1640,20 +1733,63 @@ class EPUB_MOBI(CatalogPlugin): divTag = Tag(soup, "div") 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
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 + current_date = datetime.date.fromordinal(1) this_months_list = [] - for book in self.booksByDate: + for book in self.booksByMonth: if book['timestamp'].month != current_date.month or \ 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 = [] current_date = book['timestamp'].date() this_months_list.append(book) # 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 body.insert(btc, divTag) @@ -2055,6 +2191,7 @@ class EPUB_MOBI(CatalogPlugin): # Loop over the titles sort_descriptions_by = self.booksByAuthor if self.opts.sort_descriptions_by_author \ else self.booksByTitle + for book in sort_descriptions_by: navPointVolumeTag = Tag(ncx_soup, 'navPoint') navPointVolumeTag['class'] = "article" @@ -2065,9 +2202,9 @@ class EPUB_MOBI(CatalogPlugin): textTag = Tag(ncx_soup, "text") if book['series']: 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: - textTag.insert(0, NavigableString(self.formatNCXText(book['title']))) + textTag.insert(0, NavigableString(self.formatNCXText(book['title'], dest='title'))) navLabelTag.insert(0,textTag) navPointVolumeTag.insert(0,navLabelTag) @@ -2079,10 +2216,10 @@ class EPUB_MOBI(CatalogPlugin): # Add the author tag cmTag = Tag(ncx_soup, '%s' % 'calibre:meta') cmTag['name'] = "author" - navStr = '%s | %s' % (self.formatNCXText(book['author']), + navStr = '%s | %s' % (self.formatNCXText(book['author'], dest='author'), book['date'].split()[1]) if 'tags' in book: - navStr += ' | %s' % self.formatNCXText(' · '.join(sorted(book['tags']))) + navStr = self.formatNCXText(navStr + ' | ' + ' · '.join(sorted(book['tags'])), dest='author') cmTag.insert(0, NavigableString(navStr)) navPointVolumeTag.insert(2, cmTag) @@ -2090,7 +2227,7 @@ class EPUB_MOBI(CatalogPlugin): if book['short_description']: cmTag = Tag(ncx_soup, '%s' % 'calibre:meta') 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) # Add this volume to the section tag @@ -2108,7 +2245,7 @@ class EPUB_MOBI(CatalogPlugin): def add_to_books_by_letter(current_book_list): current_book_list = " • ".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) soup = self.ncxSoup @@ -2137,11 +2274,16 @@ class EPUB_MOBI(CatalogPlugin): books_by_letter = [] # 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] current_book_list = [] current_book = "" - for book in self.booksByTitle: + for book in title_list: if self.letter_or_symbol(book['title_sort'][0]) != current_letter: # Save the old list add_to_books_by_letter(current_book_list) @@ -2180,7 +2322,7 @@ class EPUB_MOBI(CatalogPlugin): if self.generateForKindle: cmTag = Tag(soup, '%s' % 'calibre:meta') cmTag['name'] = "description" - cmTag.insert(0, NavigableString(self.formatNCXText(books))) + cmTag.insert(0, NavigableString(self.formatNCXText(books, dest='description'))) navPointByLetterTag.insert(2, cmTag) navPointTag.insert(nptc, navPointByLetterTag) @@ -2197,7 +2339,7 @@ class EPUB_MOBI(CatalogPlugin): def add_to_author_list(current_author_list, current_letter): current_author_list = " • ".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)) soup = self.ncxSoup @@ -2287,9 +2429,15 @@ class EPUB_MOBI(CatalogPlugin): def add_to_master_month_list(current_titles_list): book_count = len(current_titles_list) current_titles_list = " • ".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)) + def add_to_master_date_range_list(current_titles_list): + book_count = len(current_titles_list) + current_titles_list = " • ".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 HTML_file = "content/ByDateAdded.html" body = soup.find("navPoint") @@ -2315,15 +2463,74 @@ class EPUB_MOBI(CatalogPlugin): navPointTag.insert(nptc, contentTag) 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 # Loop over the booksByDate list, find start of each month, # add description_preview_count titles # master_month_list(list,date,count) current_titles_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 \ book['timestamp'].year != current_date.year: # Save the old lists @@ -2432,7 +2639,7 @@ class EPUB_MOBI(CatalogPlugin): if self.genre_tags_dict[friendly_tag] == genre['tag']: normalized_tag = self.genre_tags_dict[friendly_tag] break - textTag.insert(0, self.formatNCXText(NavigableString(friendly_tag))) + textTag.insert(0, self.formatNCXText(NavigableString(friendly_tag), dest='description')) navLabelTag.insert(0,textTag) navPointVolumeTag.insert(0,navLabelTag) 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]) else: 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: # Form 2: title • title • title ... titles = [] for title in genre['books']: titles.append(title['title']) titles = sorted(titles, key=lambda x:(self.generateSortTitle(x),self.generateSortTitle(x))) - titles_list = self.generateShortDescription(u" • ".join(titles)) - cmTag.insert(0, NavigableString(self.formatNCXText(titles_list))) + titles_list = self.generateShortDescription(u" • ".join(titles), dest="description") + cmTag.insert(0, NavigableString(self.formatNCXText(titles_list, dest='description'))) navPointVolumeTag.insert(3, cmTag) @@ -2652,7 +2859,7 @@ class EPUB_MOBI(CatalogPlugin): return genre_tags_dict - def formatNCXText(self, description): + def formatNCXText(self, description, dest=None): # Kindle TOC descriptions won't render certain characters # Fix up massaged = unicode(BeautifulStoneSoup(description, convertEntities=BeautifulStoneSoup.HTML_ENTITIES)) @@ -2660,7 +2867,11 @@ class EPUB_MOBI(CatalogPlugin): # Replace '&' with '&' massaged = re.sub("&","&", 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): # Strip white space to '' @@ -2928,27 +3139,41 @@ class EPUB_MOBI(CatalogPlugin): title['title']) return series_title - def generateShortDescription(self, description): - # Truncate the description to description_clip, on word boundaries if necessary + def generateShortDescription(self, description, dest=None): + # Truncate the description, on word boundaries if necessary + # Possible destinations: + # description NCX summary + # title NCX title + # author NCX author + + def shortDescription(description, limit): + short_description = "" + words = description.split() + for word in words: + short_description += word + " " + if len(short_description) > limit: + short_description += "..." + return short_description + if not description: return None - if not self.descriptionClip: + if dest == 'title': + # No truncation for titles, let the device deal with it return description - - if len(description) < self.descriptionClip: - return description - - # Start adding words until we reach description_clip - short_description = "" - words = description.split() - for word in words: - short_description += word + " " - if len(short_description) > self.descriptionClip: - short_description += "..." - return short_description - - return short_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): # Convert the actual title to a string suitable for sorting. @@ -3172,12 +3397,17 @@ class EPUB_MOBI(CatalogPlugin): # Add local options opts.creator = "calibre" + + # Finalize output_profile op = self.opts.output_profile if op is None: 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 - opts.descriptionClip = 380 if op.endswith('dx') or 'kindle' not in op else 90 opts.basename = "Catalog" opts.cli_environment = not hasattr(opts,'sync') # 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 = '\[^.\]' 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 keys = opts_dict.keys() keys.sort() log(" opts:") - 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', 'search_text','sort_by','sort_descriptions_by_author','sync']: log(" %s: %s" % (key, opts_dict[key])) diff --git a/src/calibre/library/cli.py b/src/calibre/library/cli.py index 0d9665de8a..9dfa2c17a6 100644 --- a/src/calibre/library/cli.py +++ b/src/calibre/library/cli.py @@ -673,6 +673,10 @@ def command_catalog(args, dbpath): if opts.ids: 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: plugin.run(args[1], opts, get_db(dbpath, opts)) return 0