diff --git a/src/calibre/ebooks/metadata/mobi.py b/src/calibre/ebooks/metadata/mobi.py
index 4a5911cbfc..4fab134937 100644
--- a/src/calibre/ebooks/metadata/mobi.py
+++ b/src/calibre/ebooks/metadata/mobi.py
@@ -275,7 +275,6 @@ class MetadataUpdater(object):
return StreamSlicer(self.stream, start, stop)
def update(self, mi):
- #print "self.type: %s" % self.type
if self.type != "BOOKMOBI":
raise MobiError("Setting metadata only supported for MOBI files of type 'BOOK'.\n"
"\tThis is a '%s' file of type '%s'" % (self.type[0:4], self.type[4:8]))
diff --git a/src/calibre/gui2/catalog/catalog_epub_mobi.py b/src/calibre/gui2/catalog/catalog_epub_mobi.py
index a22ef3ae9e..2037545bb4 100644
--- a/src/calibre/gui2/catalog/catalog_epub_mobi.py
+++ b/src/calibre/gui2/catalog/catalog_epub_mobi.py
@@ -18,8 +18,9 @@ class PluginWidget(QWidget,Ui_Form):
HELP = _('Options specific to')+' EPUB/MOBI '+_('output')
OPTION_FIELDS = [('exclude_genre','\[[\w ]*\]'),
('exclude_tags','~,'+_('Catalog')),
- ('read_tag','+'),
- ('note_tag','*')]
+ ('note_tag','*'),
+ ('numbers_as_text', False),
+ ('read_tag','+')]
# Output synced to the connected device?
sync_enabled = True
@@ -33,21 +34,30 @@ class PluginWidget(QWidget,Ui_Form):
def initialize(self, name):
self.name = name
- # Restore options from last use here
+ # Update dialog fields from stored options
for opt in self.OPTION_FIELDS:
opt_value = gprefs.get(self.name + '_' + opt[0], opt[1])
- getattr(self, opt[0]).setText(opt_value)
+ if opt[0] == 'numbers_as_text':
+ getattr(self, opt[0]).setChecked(opt_value)
+ else:
+ getattr(self, opt[0]).setText(opt_value)
def options(self):
# Save/return the current options
+ # exclude_genre stores literally
+ # numbers_as_text stores as True/False
+ # others store as lists
opts_dict = {}
for opt in self.OPTION_FIELDS:
- opt_value = unicode(getattr(self, opt[0]).text())
+ if opt[0] == 'numbers_as_text':
+ opt_value = getattr(self,opt[0]).isChecked()
+ else:
+ opt_value = unicode(getattr(self, opt[0]).text())
gprefs.set(self.name + '_' + opt[0], opt_value)
- if opt[0] != 'exclude_genre':
+ if opt[0] == 'exclude_genre' or 'numbers_as_text':
+ opts_dict[opt[0]] = opt_value
+ else:
opt_value = opt_value.split(',')
- opts_dict[opt[0]] = opt_value
-
opts_dict['output_profile'] = [load_defaults('page_setup')['output_profile']]
diff --git a/src/calibre/gui2/catalog/catalog_epub_mobi.ui b/src/calibre/gui2/catalog/catalog_epub_mobi.ui
index e683c479bf..858aec429f 100644
--- a/src/calibre/gui2/catalog/catalog_epub_mobi.ui
+++ b/src/calibre/gui2/catalog/catalog_epub_mobi.ui
@@ -69,6 +69,13 @@
+ -
+
+
+
+
+
+
-
@@ -82,10 +89,10 @@
- -
-
-
-
+
-
+
+
+ Sort numbers as text
diff --git a/src/calibre/library/catalog.py b/src/calibre/library/catalog.py
index 9ed2406dbc..246eb570fe 100644
--- a/src/calibre/library/catalog.py
+++ b/src/calibre/library/catalog.py
@@ -87,7 +87,12 @@ class CSV_XML(CatalogPlugin):
outstr = ''
for (x, field) in enumerate(fields):
item = entry[field]
- if field in ['authors','tags','formats']:
+ if field == 'formats':
+ fmt_list = []
+ for format in item:
+ fmt_list.append(format.partition('.')[2])
+ item = ', '.join(fmt_list)
+ elif field in ['authors','tags']:
item = ', '.join(item)
if x < len(fields) - 1:
if item is not None:
@@ -259,23 +264,29 @@ class EPUB_MOBI(CatalogPlugin):
"--exclude-tags=skip will match 'skip this book' and 'Skip will like this'.\n"
"Default: '%default'\n"
"Applies to: ePub, MOBI output formats")),
- Option('--read-tag',
- default='+',
- dest='read_tag',
- help=_("Tag indicating book has been read.\n" "Default: '%default'\n"
- "Applies to: ePub, MOBI output formats")),
Option('--note-tag',
default='*',
dest='note_tag',
help=_("Tag prefix for user notes, e.g. '*Jeff might enjoy reading this'.\n"
"Default: '%default'\n"
"Applies to: ePub, MOBI output formats")),
+ Option('--numbers-as-text',
+ default=False,
+ dest='numbers_as_text',
+ help=_("Sort titles with leading numbers as text, e.g.,\n'2001: A Space Odyssey' sorts as \n'Two Thousand One: A Space Odyssey'.\n"
+ "Default: '%default'\n"
+ "Applies to: ePub, MOBI output formats")),
Option('--output-profile',
default=None,
dest='output_profile',
help=_("Specifies the output profile. In some cases, an output profile is required to optimize the catalog for the device. For example, 'kindle' or 'kindle_dx' creates a structured Table of Contents with Sections and Articles.\n"
"Default: '%default'\n"
- "Applies to: ePub, MOBI output formats"))
+ "Applies to: ePub, MOBI output formats")),
+ Option('--read-tag',
+ default='+',
+ dest='read_tag',
+ help=_("Tag indicating book has been read.\n" "Default: '%default'\n"
+ "Applies to: ePub, MOBI output formats")),
]
class NumberToText(object):
@@ -798,7 +809,6 @@ class EPUB_MOBI(CatalogPlugin):
os.path.join(self.catalogPath, file[0]))
def fetchBooksByTitle(self):
-
self.opts.log.info(self.updateProgressFullStep("fetchBooksByTitle()"))
# Get the database as a dictionary
@@ -1104,15 +1114,15 @@ class EPUB_MOBI(CatalogPlugin):
# Loop through the books by title
for book in self.booksByTitle:
- if book['title_sort'][0].upper() != current_letter :
+ if self.letter_or_symbol(book['title_sort'][0]) != current_letter :
# Start a new letter
- current_letter = book['title_sort'][0].upper()
+ current_letter = self.letter_or_symbol(book['title_sort'][0])
pIndexTag = Tag(soup, "p")
pIndexTag['class'] = "letter_index"
aTag = Tag(soup, "a")
- aTag['name'] = "%stitles" % book['title_sort'][0].upper()
+ aTag['name'] = "%s" % self.letter_or_symbol(book['title_sort'][0])
pIndexTag.insert(0,aTag)
- pIndexTag.insert(1,NavigableString(book['title_sort'][0].upper()))
+ pIndexTag.insert(1,NavigableString(self.letter_or_symbol(book['title_sort'][0])))
divTag.insert(dtc,pIndexTag)
dtc += 1
@@ -1716,19 +1726,19 @@ class EPUB_MOBI(CatalogPlugin):
books_by_letter = []
# Loop over the titles, find start of each letter, add description_preview_count books
- current_letter = self.booksByTitle[0]['title_sort'][0].upper()
+ current_letter = self.letter_or_symbol(self.booksByTitle[0]['title_sort'][0])
title_letters = [current_letter]
current_book_list = []
current_book = ""
for book in self.booksByTitle:
- if book['title_sort'][0].upper() != current_letter:
+ if self.letter_or_symbol(book['title_sort'][0]) != current_letter:
# Save the old list
book_list = " • ".join(current_book_list)
short_description = self.generateShortDescription(self.formatNCXText(book_list))
books_by_letter.append(short_description)
# Start the new list
- current_letter = book['title_sort'][0].upper()
+ current_letter = self.letter_or_symbol(book['title_sort'][0])
title_letters.append(current_letter)
current_book = book['title']
current_book_list = [book['title']]
@@ -1743,7 +1753,6 @@ class EPUB_MOBI(CatalogPlugin):
short_description = self.generateShortDescription(self.formatNCXText(book_list))
books_by_letter.append(short_description)
-
# Add *article* entries for each populated title letter
for (i,books) in enumerate(books_by_letter):
navPointByLetterTag = Tag(soup, 'navPoint')
@@ -1753,11 +1762,11 @@ class EPUB_MOBI(CatalogPlugin):
self.playOrder += 1
navLabelTag = Tag(soup, 'navLabel')
textTag = Tag(soup, 'text')
- textTag.insert(0, NavigableString("Books beginning with '%s'" % (title_letters[i].upper())))
+ textTag.insert(0, NavigableString("Titles beginning with %s" % (title_letters[i])))
navLabelTag.insert(0, textTag)
navPointByLetterTag.insert(0,navLabelTag)
contentTag = Tag(soup, 'content')
- contentTag['src'] = "content/%s.html#%stitles" % (output, title_letters[i].upper())
+ contentTag['src'] = "content/%s.html#%s" % (output, title_letters[i])
navPointByLetterTag.insert(1,contentTag)
if self.generateForKindle:
@@ -1990,7 +1999,6 @@ class EPUB_MOBI(CatalogPlugin):
tokens[0] += ','
return ' '.join(tokens)
-
def convertHTMLEntities(self, s):
matches = re.findall("\d+;", s)
if len(matches) > 0:
@@ -2294,22 +2302,27 @@ class EPUB_MOBI(CatalogPlugin):
def generateSortTitle(self, title):
# Convert the actual title to a string suitable for sorting.
- # Convert numbers to strings, ignore leading stop words
- # The 21-Day Consciousness Cleanse
- # Scan for numbers in each word clump.
+ # Ignore leading stop words
+ # Optionally convert leading numbers to strings
from calibre.ebooks.metadata import title_sort
title_words = title_sort(title).split()
translated = []
for (i,word) in enumerate(title_words):
- # Initial numbers translated to text equivalent
- if i==0 and re.search('[0-9]+',word):
- translated.append(EPUB_MOBI.NumberToText(word).text)
+ # Leading numbers optionally translated to text equivalent
+ if i==0:
+ if self.opts.numbers_as_text and re.search('[0-9]+',word):
+ translated.append(EPUB_MOBI.NumberToText(word).text.capitalize())
+ else:
+ if re.search('[0-9]+',word):
+ # Coerce standard-width strings for numbers for value sorting
+ word = '%10.2f' % float(re.sub('[^\d\.]','',word))
+ translated.append(word)
else:
if re.search('[0-9]+',word):
# Coerce standard-width strings for numbers
- word = '%03d' % int(re.sub('\D','',word))
+ word = '%10.2f' % float(re.sub('[^\d\.]','',word))
translated.append(word)
return ' '.join(translated)
@@ -2338,6 +2351,12 @@ class EPUB_MOBI(CatalogPlugin):
except RuntimeError:
self.opts.log.error("generateThumbnail(): RuntimeError with %s" % title['title'])
+ def letter_or_symbol(self,char):
+ if not re.search('[a-zA-Z]',char):
+ return 'Symbols'
+ else:
+ return char
+
def processSpecialTags(self, tags, this_title, opts):
tag_list = []
for tag in tags:
diff --git a/src/calibre/library/cli.py b/src/calibre/library/cli.py
index cf29106684..0d9665de8a 100644
--- a/src/calibre/library/cli.py
+++ b/src/calibre/library/cli.py
@@ -670,8 +670,6 @@ def command_catalog(args, dbpath):
print
print >>sys.stderr, _('Error: You must specify a catalog output file')
return 1
- if opts.verbose:
- log("library.cli:command_catalog dispatching to plugin %s" % plugin.name)
if opts.ids:
opts.ids = [int(id) for id in opts.ids.split(',')]