mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Catalog: Make sortiing of numbers in title as text optional.
This commit is contained in:
commit
68aeb0c35e
@ -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]))
|
||||
|
@ -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']]
|
||||
|
||||
|
||||
|
@ -69,6 +69,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="exclude_genre">
|
||||
<property name="toolTip">
|
||||
<string extracomment="Tooltip comment here"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
@ -82,10 +89,10 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="exclude_genre">
|
||||
<property name="toolTip">
|
||||
<string extracomment="Tooltip comment here"/>
|
||||
<item row="5" column="0">
|
||||
<widget class="QCheckBox" name="numbers_as_text">
|
||||
<property name="text">
|
||||
<string>Sort numbers as text</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -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:
|
||||
|
@ -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(',')]
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user