mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Catalog: Fix #1035191 (Catalog, double entries in toc for titles starting with umlauts). Also fixes #1035372 (regression that broke generating catalogs when a device is connected)
This commit is contained in:
commit
85b2cf0be2
@ -83,7 +83,7 @@ p.author_index {
|
|||||||
font-size:large;
|
font-size:large;
|
||||||
font-weight:bold;
|
font-weight:bold;
|
||||||
text-align:left;
|
text-align:left;
|
||||||
margin-top:0px;
|
margin-top:0.25px;
|
||||||
margin-bottom:-2px;
|
margin-bottom:-2px;
|
||||||
text-indent: 0em;
|
text-indent: 0em;
|
||||||
}
|
}
|
||||||
|
@ -545,9 +545,9 @@ class GenericRulesTable(QTableWidget):
|
|||||||
first = rows[0].row() + 1
|
first = rows[0].row() + 1
|
||||||
last = rows[-1].row() + 1
|
last = rows[-1].row() + 1
|
||||||
|
|
||||||
message = '<p>Are you sure you want to delete rule %d?' % first
|
message = _('Are you sure you want to delete rule %d?') % first
|
||||||
if len(rows) > 1:
|
if len(rows) > 1:
|
||||||
message = '<p>Are you sure you want to delete rules %d-%d?' % (first, last)
|
message = _('Are you sure you want to delete rules %d-%d?') % (first, last)
|
||||||
if not question_dialog(self, _('Are you sure?'), message, show_copy_button=False):
|
if not question_dialog(self, _('Are you sure?'), message, show_copy_button=False):
|
||||||
return
|
return
|
||||||
first_sel_row = self.currentRow()
|
first_sel_row = self.currentRow()
|
||||||
@ -652,9 +652,9 @@ class GenericRulesTable(QTableWidget):
|
|||||||
class ExclusionRules(GenericRulesTable):
|
class ExclusionRules(GenericRulesTable):
|
||||||
|
|
||||||
COLUMNS = { 'ENABLED':{'ordinal': 0, 'name': ''},
|
COLUMNS = { 'ENABLED':{'ordinal': 0, 'name': ''},
|
||||||
'NAME': {'ordinal': 1, 'name': 'Name'},
|
'NAME': {'ordinal': 1, 'name': _('Name')},
|
||||||
'FIELD': {'ordinal': 2, 'name': 'Field'},
|
'FIELD': {'ordinal': 2, 'name': _('Field')},
|
||||||
'PATTERN': {'ordinal': 3, 'name': 'Value'},}
|
'PATTERN': {'ordinal': 3, 'name': _('Value')},}
|
||||||
|
|
||||||
def __init__(self, parent_gb_hl, object_name, rules, eligible_custom_fields, db):
|
def __init__(self, parent_gb_hl, object_name, rules, eligible_custom_fields, db):
|
||||||
super(ExclusionRules, self).__init__(parent_gb_hl, object_name, rules, eligible_custom_fields, db)
|
super(ExclusionRules, self).__init__(parent_gb_hl, object_name, rules, eligible_custom_fields, db)
|
||||||
@ -760,15 +760,15 @@ class ExclusionRules(GenericRulesTable):
|
|||||||
elif source_field == 'Tags':
|
elif source_field == 'Tags':
|
||||||
values = sorted(self.db.all_tags(), key=sort_key)
|
values = sorted(self.db.all_tags(), key=sort_key)
|
||||||
else:
|
else:
|
||||||
if self.eligible_custom_fields[source_field]['datatype'] in ['enumeration', 'text']:
|
if self.eligible_custom_fields[unicode(source_field)]['datatype'] in ['enumeration', 'text']:
|
||||||
values = self.db.all_custom(self.db.field_metadata.key_to_label(
|
values = self.db.all_custom(self.db.field_metadata.key_to_label(
|
||||||
self.eligible_custom_fields[source_field]['field']))
|
self.eligible_custom_fields[unicode(source_field)]['field']))
|
||||||
values = sorted(values, key=sort_key)
|
values = sorted(values, key=sort_key)
|
||||||
elif self.eligible_custom_fields[source_field]['datatype'] in ['bool']:
|
elif self.eligible_custom_fields[unicode(source_field)]['datatype'] in ['bool']:
|
||||||
values = ['True','False','unspecified']
|
values = ['True','False','unspecified']
|
||||||
elif self.eligible_custom_fields[source_field]['datatype'] in ['composite']:
|
elif self.eligible_custom_fields[unicode(source_field)]['datatype'] in ['composite']:
|
||||||
values = ['any value','unspecified']
|
values = ['any value','unspecified']
|
||||||
elif self.eligible_custom_fields[source_field]['datatype'] in ['datetime']:
|
elif self.eligible_custom_fields[unicode(source_field)]['datatype'] in ['datetime']:
|
||||||
values = ['any date','unspecified']
|
values = ['any date','unspecified']
|
||||||
|
|
||||||
values_combo = ComboBox(self, values, pattern)
|
values_combo = ComboBox(self, values, pattern)
|
||||||
@ -777,10 +777,10 @@ class ExclusionRules(GenericRulesTable):
|
|||||||
class PrefixRules(GenericRulesTable):
|
class PrefixRules(GenericRulesTable):
|
||||||
|
|
||||||
COLUMNS = { 'ENABLED':{'ordinal': 0, 'name': ''},
|
COLUMNS = { 'ENABLED':{'ordinal': 0, 'name': ''},
|
||||||
'NAME': {'ordinal': 1, 'name': 'Name'},
|
'NAME': {'ordinal': 1, 'name': _('Name')},
|
||||||
'PREFIX': {'ordinal': 2, 'name': 'Prefix'},
|
'PREFIX': {'ordinal': 2, 'name': _('Prefix')},
|
||||||
'FIELD': {'ordinal': 3, 'name': 'Field'},
|
'FIELD': {'ordinal': 3, 'name': _('Field')},
|
||||||
'PATTERN':{'ordinal': 4, 'name': 'Value'},}
|
'PATTERN':{'ordinal': 4, 'name': _('Value')},}
|
||||||
|
|
||||||
def __init__(self, parent_gb_hl, object_name, rules, eligible_custom_fields, db):
|
def __init__(self, parent_gb_hl, object_name, rules, eligible_custom_fields, db):
|
||||||
super(PrefixRules, self).__init__(parent_gb_hl, object_name, rules, eligible_custom_fields, db)
|
super(PrefixRules, self).__init__(parent_gb_hl, object_name, rules, eligible_custom_fields, db)
|
||||||
@ -1035,15 +1035,15 @@ class PrefixRules(GenericRulesTable):
|
|||||||
elif source_field == 'Tags':
|
elif source_field == 'Tags':
|
||||||
values = sorted(self.db.all_tags(), key=sort_key)
|
values = sorted(self.db.all_tags(), key=sort_key)
|
||||||
else:
|
else:
|
||||||
if self.eligible_custom_fields[source_field]['datatype'] in ['enumeration', 'text']:
|
if self.eligible_custom_fields[unicode(source_field)]['datatype'] in ['enumeration', 'text']:
|
||||||
values = self.db.all_custom(self.db.field_metadata.key_to_label(
|
values = self.db.all_custom(self.db.field_metadata.key_to_label(
|
||||||
self.eligible_custom_fields[source_field]['field']))
|
self.eligible_custom_fields[unicode(source_field)]['field']))
|
||||||
values = sorted(values, key=sort_key)
|
values = sorted(values, key=sort_key)
|
||||||
elif self.eligible_custom_fields[source_field]['datatype'] in ['bool']:
|
elif self.eligible_custom_fields[unicode(source_field)]['datatype'] in ['bool']:
|
||||||
values = ['True','False','unspecified']
|
values = ['True','False','unspecified']
|
||||||
elif self.eligible_custom_fields[source_field]['datatype'] in ['composite']:
|
elif self.eligible_custom_fields[unicode(source_field)]['datatype'] in ['composite']:
|
||||||
values = ['any value','unspecified']
|
values = ['any value','unspecified']
|
||||||
elif self.eligible_custom_fields[source_field]['datatype'] in ['datetime']:
|
elif self.eligible_custom_fields[unicode(source_field)]['datatype'] in ['datetime']:
|
||||||
values = ['any date','unspecified']
|
values = ['any date','unspecified']
|
||||||
|
|
||||||
values_combo = ComboBox(self, values, pattern)
|
values_combo = ComboBox(self, values, pattern)
|
||||||
|
@ -174,14 +174,14 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
if op is None:
|
if op is None:
|
||||||
op = 'default'
|
op = 'default'
|
||||||
|
|
||||||
if opts.connected_device['name'] and \
|
if opts.connected_device['name'] and 'kindle' in opts.connected_device['name'].lower():
|
||||||
opts.connected_device['short_name'] in ['kindle','kindle dx']:
|
|
||||||
opts.connected_kindle = True
|
opts.connected_kindle = True
|
||||||
if opts.connected_device['serial'] and \
|
if opts.connected_device['serial'] and \
|
||||||
opts.connected_device['serial'][:4] in ['B004','B005']:
|
opts.connected_device['serial'][:4] in ['B004','B005']:
|
||||||
op = "kindle_dx"
|
op = "kindle_dx"
|
||||||
else:
|
else:
|
||||||
op = "kindle"
|
op = "kindle"
|
||||||
|
|
||||||
opts.descriptionClip = 380 if op.endswith('dx') or 'kindle' not in op else 100
|
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
|
opts.authorClip = 100 if op.endswith('dx') or 'kindle' not in op else 60
|
||||||
opts.output_profile = op
|
opts.output_profile = op
|
||||||
@ -385,9 +385,6 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
new_cover_path.close()
|
new_cover_path.close()
|
||||||
recommendations.append(('cover', new_cover_path.name, OptionRecommendation.HIGH))
|
recommendations.append(('cover', new_cover_path.name, OptionRecommendation.HIGH))
|
||||||
|
|
||||||
if opts.verbose:
|
|
||||||
log.info("Invoking Plumber with recommendations:\n %s" % recommendations)
|
|
||||||
|
|
||||||
# Run ebook-convert
|
# Run ebook-convert
|
||||||
from calibre.ebooks.conversion.plumber import Plumber
|
from calibre.ebooks.conversion.plumber import Plumber
|
||||||
plumber = Plumber(os.path.join(catalog.catalogPath,
|
plumber = Plumber(os.path.join(catalog.catalogPath,
|
||||||
|
@ -15,7 +15,7 @@ from calibre.ptempfile import PersistentTemporaryDirectory
|
|||||||
from calibre.utils.config import config_dir
|
from calibre.utils.config import config_dir
|
||||||
from calibre.utils.date import format_date, is_date_undefined, now as nowf
|
from calibre.utils.date import format_date, is_date_undefined, now as nowf
|
||||||
from calibre.utils.filenames import ascii_text
|
from calibre.utils.filenames import ascii_text
|
||||||
from calibre.utils.icu import capitalize, sort_key
|
from calibre.utils.icu import capitalize, collation_order, sort_key
|
||||||
from calibre.utils.magick.draw import thumbnail
|
from calibre.utils.magick.draw import thumbnail
|
||||||
from calibre.utils.zipfile import ZipFile
|
from calibre.utils.zipfile import ZipFile
|
||||||
|
|
||||||
@ -517,19 +517,19 @@ class CatalogBuilder(object):
|
|||||||
self.generateOPF()
|
self.generateOPF()
|
||||||
self.generateNCXHeader()
|
self.generateNCXHeader()
|
||||||
if self.opts.generate_authors:
|
if self.opts.generate_authors:
|
||||||
self.generateNCXByAuthor("Authors")
|
self.generateNCXByAuthor(_("Authors"))
|
||||||
if self.opts.generate_titles:
|
if self.opts.generate_titles:
|
||||||
self.generateNCXByTitle("Titles")
|
self.generateNCXByTitle(_("Titles"))
|
||||||
if self.opts.generate_series:
|
if self.opts.generate_series:
|
||||||
self.generateNCXBySeries("Series")
|
self.generateNCXBySeries(_("Series"))
|
||||||
if self.opts.generate_genres:
|
if self.opts.generate_genres:
|
||||||
self.generateNCXByGenre("Genres")
|
self.generateNCXByGenre(_("Genres"))
|
||||||
if self.opts.generate_recently_added:
|
if self.opts.generate_recently_added:
|
||||||
self.generateNCXByDateAdded("Recently Added")
|
self.generateNCXByDateAdded(_("Recently Added"))
|
||||||
if self.generateRecentlyRead:
|
if self.generateRecentlyRead:
|
||||||
self.generateNCXByDateRead("Recently Read")
|
self.generateNCXByDateRead(_("Recently Read"))
|
||||||
if self.opts.generate_descriptions:
|
if self.opts.generate_descriptions:
|
||||||
self.generateNCXDescriptions("Descriptions")
|
self.generateNCXDescriptions(_("Descriptions"))
|
||||||
|
|
||||||
self.writeNCX()
|
self.writeNCX()
|
||||||
return True
|
return True
|
||||||
@ -673,7 +673,8 @@ Author '{0}':
|
|||||||
for record in data:
|
for record in data:
|
||||||
matched = list(set(record['tags']) & set(exclude_tags))
|
matched = list(set(record['tags']) & set(exclude_tags))
|
||||||
if matched :
|
if matched :
|
||||||
self.opts.log.info(" - %s (Exclusion rule Tags: '%s')" % (record['title'], str(matched[0])))
|
self.opts.log.info(" - %s by %s (Exclusion rule Tags: '%s')" %
|
||||||
|
(record['title'], record['authors'][0], str(matched[0])))
|
||||||
|
|
||||||
search_phrase = ''
|
search_phrase = ''
|
||||||
if exclude_tags:
|
if exclude_tags:
|
||||||
@ -960,7 +961,7 @@ Author '{0}':
|
|||||||
aTag['id'] = "bytitle"
|
aTag['id'] = "bytitle"
|
||||||
pTag.insert(ptc,aTag)
|
pTag.insert(ptc,aTag)
|
||||||
ptc += 1
|
ptc += 1
|
||||||
pTag.insert(ptc,NavigableString('Titles'))
|
pTag.insert(ptc,NavigableString(_('Titles')))
|
||||||
|
|
||||||
body.insert(btc,pTag)
|
body.insert(btc,pTag)
|
||||||
btc += 1
|
btc += 1
|
||||||
@ -976,6 +977,9 @@ Author '{0}':
|
|||||||
nspt = sorted(nspt, key=lambda x: sort_key(x['title_sort'].upper()))
|
nspt = sorted(nspt, key=lambda x: sort_key(x['title_sort'].upper()))
|
||||||
self.booksByTitle_noSeriesPrefix = nspt
|
self.booksByTitle_noSeriesPrefix = nspt
|
||||||
|
|
||||||
|
# Establish initial letter equivalencies
|
||||||
|
sort_equivalents = self.establish_equivalencies(self.booksByTitle, key='title_sort')
|
||||||
|
|
||||||
# Loop through the books by title
|
# Loop through the books by title
|
||||||
# Generate one divRunningTag per initial letter for the purposes of
|
# Generate one divRunningTag per initial letter for the purposes of
|
||||||
# minimizing widows and orphans on readers that can handle large
|
# minimizing widows and orphans on readers that can handle large
|
||||||
@ -985,8 +989,8 @@ Author '{0}':
|
|||||||
title_list = self.booksByTitle_noSeriesPrefix
|
title_list = self.booksByTitle_noSeriesPrefix
|
||||||
drtc = 0
|
drtc = 0
|
||||||
divRunningTag = None
|
divRunningTag = None
|
||||||
for book in title_list:
|
for idx, book in enumerate(title_list):
|
||||||
if self.letter_or_symbol(book['title_sort'][0]) != current_letter :
|
if self.letter_or_symbol(sort_equivalents[idx]) != current_letter:
|
||||||
# Start a new letter
|
# Start a new letter
|
||||||
if drtc and divRunningTag is not None:
|
if drtc and divRunningTag is not None:
|
||||||
divTag.insert(dtc, divRunningTag)
|
divTag.insert(dtc, divRunningTag)
|
||||||
@ -998,13 +1002,15 @@ Author '{0}':
|
|||||||
pIndexTag = Tag(soup, "p")
|
pIndexTag = Tag(soup, "p")
|
||||||
pIndexTag['class'] = "author_title_letter_index"
|
pIndexTag['class'] = "author_title_letter_index"
|
||||||
aTag = Tag(soup, "a")
|
aTag = Tag(soup, "a")
|
||||||
current_letter = self.letter_or_symbol(book['title_sort'][0])
|
current_letter = self.letter_or_symbol(sort_equivalents[idx])
|
||||||
if current_letter == self.SYMBOLS:
|
if current_letter == self.SYMBOLS:
|
||||||
aTag['id'] = self.SYMBOLS
|
aTag['id'] = self.SYMBOLS + "_titles"
|
||||||
|
pIndexTag.insert(0,aTag)
|
||||||
|
pIndexTag.insert(1,NavigableString(self.SYMBOLS))
|
||||||
else:
|
else:
|
||||||
aTag['id'] = "%s" % self.generateUnicodeName(current_letter)
|
aTag['id'] = self.generateUnicodeName(current_letter) + "_titles"
|
||||||
pIndexTag.insert(0,aTag)
|
pIndexTag.insert(0,aTag)
|
||||||
pIndexTag.insert(1,NavigableString(self.letter_or_symbol(book['title_sort'][0])))
|
pIndexTag.insert(1,NavigableString(sort_equivalents[idx]))
|
||||||
divRunningTag.insert(dtc,pIndexTag)
|
divRunningTag.insert(dtc,pIndexTag)
|
||||||
drtc += 1
|
drtc += 1
|
||||||
|
|
||||||
@ -1079,7 +1085,7 @@ Author '{0}':
|
|||||||
'''
|
'''
|
||||||
self.updateProgressFullStep("'Authors'")
|
self.updateProgressFullStep("'Authors'")
|
||||||
|
|
||||||
friendly_name = "Authors"
|
friendly_name = _("Authors")
|
||||||
|
|
||||||
soup = self.generateHTMLEmptyHeader(friendly_name)
|
soup = self.generateHTMLEmptyHeader(friendly_name)
|
||||||
body = soup.find('body')
|
body = soup.find('body')
|
||||||
@ -1100,11 +1106,14 @@ Author '{0}':
|
|||||||
current_author = ''
|
current_author = ''
|
||||||
current_letter = ''
|
current_letter = ''
|
||||||
current_series = None
|
current_series = None
|
||||||
#for book in sorted(self.booksByAuthor, key = self.booksByAuthorSorter_author_sort):
|
# Establish initial letter equivalencies
|
||||||
for book in self.booksByAuthor:
|
sort_equivalents = self.establish_equivalencies(self.booksByAuthor,key='author_sort')
|
||||||
|
|
||||||
|
#for book in sorted(self.booksByAuthor, key = self.booksByAuthorSorter_author_sort):
|
||||||
|
#for book in self.booksByAuthor:
|
||||||
|
for idx, book in enumerate(self.booksByAuthor):
|
||||||
book_count += 1
|
book_count += 1
|
||||||
if self.letter_or_symbol(book['author_sort'][0].upper()) != current_letter :
|
if self.letter_or_symbol(sort_equivalents[idx]) != current_letter :
|
||||||
# Start a new letter with Index letter
|
# Start a new letter with Index letter
|
||||||
if divOpeningTag is not None:
|
if divOpeningTag is not None:
|
||||||
divTag.insert(dtc, divOpeningTag)
|
divTag.insert(dtc, divOpeningTag)
|
||||||
@ -1124,13 +1133,16 @@ Author '{0}':
|
|||||||
pIndexTag = Tag(soup, "p")
|
pIndexTag = Tag(soup, "p")
|
||||||
pIndexTag['class'] = "author_title_letter_index"
|
pIndexTag['class'] = "author_title_letter_index"
|
||||||
aTag = Tag(soup, "a")
|
aTag = Tag(soup, "a")
|
||||||
current_letter = self.letter_or_symbol(book['author_sort'][0].upper())
|
#current_letter = self.letter_or_symbol(book['author_sort'][0].upper())
|
||||||
|
current_letter = self.letter_or_symbol(sort_equivalents[idx])
|
||||||
if current_letter == self.SYMBOLS:
|
if current_letter == self.SYMBOLS:
|
||||||
aTag['id'] = self.SYMBOLS + '_authors'
|
aTag['id'] = self.SYMBOLS + '_authors'
|
||||||
|
pIndexTag.insert(0,aTag)
|
||||||
|
pIndexTag.insert(1,NavigableString(self.SYMBOLS))
|
||||||
else:
|
else:
|
||||||
aTag['id'] = "%s_authors" % self.generateUnicodeName(current_letter)
|
aTag['id'] = self.generateUnicodeName(current_letter) + '_authors'
|
||||||
pIndexTag.insert(0,aTag)
|
pIndexTag.insert(0,aTag)
|
||||||
pIndexTag.insert(1,NavigableString(self.letter_or_symbol(book['author_sort'][0].upper())))
|
pIndexTag.insert(1,NavigableString(sort_equivalents[idx]))
|
||||||
divOpeningTag.insert(dotc,pIndexTag)
|
divOpeningTag.insert(dotc,pIndexTag)
|
||||||
dotc += 1
|
dotc += 1
|
||||||
|
|
||||||
@ -1180,7 +1192,7 @@ Author '{0}':
|
|||||||
if self.opts.generate_series:
|
if self.opts.generate_series:
|
||||||
aTag = Tag(soup,'a')
|
aTag = Tag(soup,'a')
|
||||||
aTag['href'] = "%s.html#%s_series" % ('BySeries',
|
aTag['href'] = "%s.html#%s_series" % ('BySeries',
|
||||||
re.sub('\W','',book['series']).lower())
|
re.sub('\s','',book['series']).lower())
|
||||||
aTag.insert(0, book['series'])
|
aTag.insert(0, book['series'])
|
||||||
pSeriesTag.insert(0, aTag)
|
pSeriesTag.insert(0, aTag)
|
||||||
else:
|
else:
|
||||||
@ -1282,7 +1294,7 @@ Author '{0}':
|
|||||||
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 = sorted(this_months_list, key=self.booksByAuthorSorter_author_sort)
|
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())
|
||||||
@ -1307,7 +1319,7 @@ Author '{0}':
|
|||||||
pAuthorTag['class'] = "author_index"
|
pAuthorTag['class'] = "author_index"
|
||||||
aTag = Tag(soup, "a")
|
aTag = Tag(soup, "a")
|
||||||
if self.opts.generate_authors:
|
if self.opts.generate_authors:
|
||||||
aTag['id'] = "%s" % self.generateAuthorAnchor(current_author)
|
aTag['href'] = "%s.html#%s" % ("ByAlphaAuthor", self.generateAuthorAnchor(current_author))
|
||||||
aTag.insert(0,NavigableString(current_author))
|
aTag.insert(0,NavigableString(current_author))
|
||||||
pAuthorTag.insert(0,aTag)
|
pAuthorTag.insert(0,aTag)
|
||||||
divTag.insert(dtc,pAuthorTag)
|
divTag.insert(dtc,pAuthorTag)
|
||||||
@ -1425,7 +1437,7 @@ Author '{0}':
|
|||||||
dtc += 1
|
dtc += 1
|
||||||
return dtc
|
return dtc
|
||||||
|
|
||||||
friendly_name = "Recently Added"
|
friendly_name = _("Recently Added")
|
||||||
|
|
||||||
soup = self.generateHTMLEmptyHeader(friendly_name)
|
soup = self.generateHTMLEmptyHeader(friendly_name)
|
||||||
body = soup.find('body')
|
body = soup.find('body')
|
||||||
@ -1518,7 +1530,7 @@ Author '{0}':
|
|||||||
'''
|
'''
|
||||||
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:
|
||||||
return
|
return
|
||||||
@ -1710,6 +1722,8 @@ Author '{0}':
|
|||||||
|
|
||||||
# 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)
|
||||||
|
|
||||||
|
# Remove exclusions
|
||||||
self.booksBySeries = self.processExclusions(data)
|
self.booksBySeries = self.processExclusions(data)
|
||||||
|
|
||||||
if not self.booksBySeries:
|
if not self.booksBySeries:
|
||||||
@ -1717,24 +1731,25 @@ Author '{0}':
|
|||||||
self.opts.log(" no series found in selected books, cancelling series generation")
|
self.opts.log(" no series found in selected books, cancelling series generation")
|
||||||
return
|
return
|
||||||
|
|
||||||
friendly_name = "Series"
|
# Generate series_sort
|
||||||
|
for book in self.booksBySeries:
|
||||||
|
book['series_sort'] = self.generateSortTitle(book['series'])
|
||||||
|
|
||||||
|
friendly_name = _("Series")
|
||||||
|
|
||||||
soup = self.generateHTMLEmptyHeader(friendly_name)
|
soup = self.generateHTMLEmptyHeader(friendly_name)
|
||||||
body = soup.find('body')
|
body = soup.find('body')
|
||||||
|
|
||||||
btc = 0
|
btc = 0
|
||||||
|
|
||||||
# Insert section tag
|
pTag = Tag(soup, "p")
|
||||||
|
pTag['style'] = 'display:none'
|
||||||
|
ptc = 0
|
||||||
aTag = Tag(soup,'a')
|
aTag = Tag(soup,'a')
|
||||||
aTag['name'] = 'section_start'
|
aTag['id'] = 'section_start'
|
||||||
body.insert(btc, aTag)
|
pTag.insert(ptc, aTag)
|
||||||
btc += 1
|
ptc += 1
|
||||||
|
body.insert(btc, pTag)
|
||||||
# Insert the anchor
|
|
||||||
aTag = Tag(soup, "a")
|
|
||||||
anchor_name = friendly_name.lower()
|
|
||||||
aTag['name'] = anchor_name.replace(" ","")
|
|
||||||
body.insert(btc, aTag)
|
|
||||||
btc += 1
|
btc += 1
|
||||||
|
|
||||||
divTag = Tag(soup, "div")
|
divTag = Tag(soup, "div")
|
||||||
@ -1742,23 +1757,29 @@ Author '{0}':
|
|||||||
current_letter = ""
|
current_letter = ""
|
||||||
current_series = None
|
current_series = None
|
||||||
|
|
||||||
|
# Establish initial letter equivalencies
|
||||||
|
sort_equivalents = self.establish_equivalencies(self.booksBySeries, key='series_sort')
|
||||||
|
|
||||||
# Loop through booksBySeries
|
# Loop through booksBySeries
|
||||||
series_count = 0
|
series_count = 0
|
||||||
for book in self.booksBySeries:
|
for idx, book in enumerate(self.booksBySeries):
|
||||||
# Check for initial letter change
|
# Check for initial letter change
|
||||||
sort_title = self.generateSortTitle(book['series'])
|
if self.letter_or_symbol(sort_equivalents[idx]) != current_letter :
|
||||||
if self.letter_or_symbol(sort_title[0].upper()) != current_letter :
|
|
||||||
# Start a new letter with Index letter
|
# Start a new letter with Index letter
|
||||||
current_letter = self.letter_or_symbol(sort_title[0].upper())
|
current_letter = self.letter_or_symbol(sort_equivalents[idx])
|
||||||
pIndexTag = Tag(soup, "p")
|
pIndexTag = Tag(soup, "p")
|
||||||
pIndexTag['class'] = "series_letter_index"
|
pIndexTag['class'] = "series_letter_index"
|
||||||
aTag = Tag(soup, "a")
|
aTag = Tag(soup, "a")
|
||||||
aTag['name'] = "%s_series" % self.letter_or_symbol(current_letter)
|
if current_letter == self.SYMBOLS:
|
||||||
pIndexTag.insert(0,aTag)
|
aTag['id'] = self.SYMBOLS + "_series"
|
||||||
pIndexTag.insert(1,NavigableString(self.letter_or_symbol(sort_title[0].upper())))
|
pIndexTag.insert(0,aTag)
|
||||||
|
pIndexTag.insert(1,NavigableString(self.SYMBOLS))
|
||||||
|
else:
|
||||||
|
aTag['id'] = self.generateUnicodeName(current_letter) + "_series"
|
||||||
|
pIndexTag.insert(0,aTag)
|
||||||
|
pIndexTag.insert(1,NavigableString(sort_equivalents[idx]))
|
||||||
divTag.insert(dtc,pIndexTag)
|
divTag.insert(dtc,pIndexTag)
|
||||||
dtc += 1
|
dtc += 1
|
||||||
|
|
||||||
# Check for series change
|
# Check for series change
|
||||||
if book['series'] != current_series:
|
if book['series'] != current_series:
|
||||||
# Start a new series
|
# Start a new series
|
||||||
@ -1767,7 +1788,10 @@ Author '{0}':
|
|||||||
pSeriesTag = Tag(soup,'p')
|
pSeriesTag = Tag(soup,'p')
|
||||||
pSeriesTag['class'] = "series"
|
pSeriesTag['class'] = "series"
|
||||||
aTag = Tag(soup, 'a')
|
aTag = Tag(soup, 'a')
|
||||||
aTag['name'] = "%s_series" % re.sub('\W','',book['series']).lower()
|
if self.letter_or_symbol(book['series']):
|
||||||
|
aTag['id'] = "symbol_%s_series" % re.sub('\W','',book['series']).lower()
|
||||||
|
else:
|
||||||
|
aTag['id'] = "%s_series" % re.sub('\W','',book['series']).lower()
|
||||||
pSeriesTag.insert(0,aTag)
|
pSeriesTag.insert(0,aTag)
|
||||||
pSeriesTag.insert(1,NavigableString('%s' % book['series']))
|
pSeriesTag.insert(1,NavigableString('%s' % book['series']))
|
||||||
divTag.insert(dtc,pSeriesTag)
|
divTag.insert(dtc,pSeriesTag)
|
||||||
@ -1830,7 +1854,7 @@ Author '{0}':
|
|||||||
pTag['class'] = 'title'
|
pTag['class'] = 'title'
|
||||||
aTag = Tag(soup, "a")
|
aTag = Tag(soup, "a")
|
||||||
anchor_name = friendly_name.lower()
|
anchor_name = friendly_name.lower()
|
||||||
aTag['name'] = anchor_name.replace(" ","")
|
aTag['id'] = anchor_name.replace(" ","")
|
||||||
pTag.insert(0,aTag)
|
pTag.insert(0,aTag)
|
||||||
#h2Tag.insert(1,NavigableString('%s (%d)' % (friendly_name, series_count)))
|
#h2Tag.insert(1,NavigableString('%s (%d)' % (friendly_name, series_count)))
|
||||||
pTag.insert(1,NavigableString('%s' % friendly_name))
|
pTag.insert(1,NavigableString('%s' % friendly_name))
|
||||||
@ -1984,7 +2008,7 @@ Author '{0}':
|
|||||||
thumb_generated = False
|
thumb_generated = False
|
||||||
|
|
||||||
if not thumb_generated:
|
if not thumb_generated:
|
||||||
self.opts.log.warn(" using default cover for '%s' (%d)" % (title['title'], title['id']))
|
self.opts.log.warn(" using default cover for '%s' (%d)" % (title['title'], title['id']))
|
||||||
# Confirm thumb exists, default is current
|
# Confirm thumb exists, default is current
|
||||||
default_thumb_fp = os.path.join(image_dir,"thumbnail_default.jpg")
|
default_thumb_fp = os.path.join(image_dir,"thumbnail_default.jpg")
|
||||||
cover = os.path.join(self.catalogPath, "DefaultCover.png")
|
cover = os.path.join(self.catalogPath, "DefaultCover.png")
|
||||||
@ -2376,22 +2400,30 @@ Author '{0}':
|
|||||||
nptc += 1
|
nptc += 1
|
||||||
|
|
||||||
series_by_letter = []
|
series_by_letter = []
|
||||||
|
# Establish initial letter equivalencies
|
||||||
|
sort_equivalents = self.establish_equivalencies(self.booksBySeries, key='series_sort')
|
||||||
|
|
||||||
# Loop over the series titles, find start of each letter, add description_preview_count books
|
# Loop over the series titles, find start of each letter, add description_preview_count books
|
||||||
# Special switch for using different title list
|
# Special switch for using different title list
|
||||||
|
|
||||||
title_list = self.booksBySeries
|
title_list = self.booksBySeries
|
||||||
current_letter = self.letter_or_symbol(self.generateSortTitle(title_list[0]['series'])[0])
|
|
||||||
|
# Prime the pump
|
||||||
|
current_letter = self.letter_or_symbol(sort_equivalents[0])
|
||||||
|
|
||||||
title_letters = [current_letter]
|
title_letters = [current_letter]
|
||||||
current_series_list = []
|
current_series_list = []
|
||||||
current_series = ""
|
current_series = ""
|
||||||
for book in title_list:
|
for idx, book in enumerate(title_list):
|
||||||
sort_title = self.generateSortTitle(book['series'])
|
sort_title = self.generateSortTitle(book['series'])
|
||||||
if self.letter_or_symbol(sort_title[0]) != current_letter:
|
sort_title_equivalent = self.establish_equivalencies([sort_title])[0]
|
||||||
|
if self.letter_or_symbol(sort_equivalents[idx]) != current_letter:
|
||||||
|
|
||||||
# Save the old list
|
# Save the old list
|
||||||
add_to_series_by_letter(current_series_list)
|
add_to_series_by_letter(current_series_list)
|
||||||
|
|
||||||
# Start the new list
|
# Start the new list
|
||||||
current_letter = self.letter_or_symbol(sort_title[0])
|
current_letter = self.letter_or_symbol(sort_equivalents[idx])
|
||||||
title_letters.append(current_letter)
|
title_letters.append(current_letter)
|
||||||
current_series = book['series']
|
current_series = book['series']
|
||||||
current_series_list = [book['series']]
|
current_series_list = [book['series']]
|
||||||
@ -2413,12 +2445,17 @@ Author '{0}':
|
|||||||
self.playOrder += 1
|
self.playOrder += 1
|
||||||
navLabelTag = Tag(soup, 'navLabel')
|
navLabelTag = Tag(soup, 'navLabel')
|
||||||
textTag = Tag(soup, 'text')
|
textTag = Tag(soup, 'text')
|
||||||
textTag.insert(0, NavigableString(u"Series beginning with %s" % \
|
textTag.insert(0, NavigableString(_(u"Series beginning with %s") % \
|
||||||
(title_letters[i] if len(title_letters[i])>1 else "'" + title_letters[i] + "'")))
|
(title_letters[i] if len(title_letters[i])>1 else "'" + title_letters[i] + "'")))
|
||||||
navLabelTag.insert(0, textTag)
|
navLabelTag.insert(0, textTag)
|
||||||
navPointByLetterTag.insert(0,navLabelTag)
|
navPointByLetterTag.insert(0,navLabelTag)
|
||||||
contentTag = Tag(soup, 'content')
|
contentTag = Tag(soup, 'content')
|
||||||
contentTag['src'] = "content/%s.html#%s_series" % (output, title_letters[i])
|
#contentTag['src'] = "content/%s.html#%s_series" % (output, title_letters[i])
|
||||||
|
if title_letters[i] == self.SYMBOLS:
|
||||||
|
contentTag['src'] = "content/%s.html#%s_series" % (output, self.SYMBOLS)
|
||||||
|
else:
|
||||||
|
contentTag['src'] = "content/%s.html#%s_series" % (output, self.generateUnicodeName(title_letters[i]))
|
||||||
|
|
||||||
navPointByLetterTag.insert(1,contentTag)
|
navPointByLetterTag.insert(1,contentTag)
|
||||||
|
|
||||||
if self.generateForKindle:
|
if self.generateForKindle:
|
||||||
@ -2469,23 +2506,31 @@ Author '{0}':
|
|||||||
|
|
||||||
books_by_letter = []
|
books_by_letter = []
|
||||||
|
|
||||||
|
# Establish initial letter equivalencies
|
||||||
|
sort_equivalents = self.establish_equivalencies(self.booksByTitle, key='title_sort')
|
||||||
|
|
||||||
# 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
|
||||||
# Special switch for using different title list
|
# Special switch for using different title list
|
||||||
if self.useSeriesPrefixInTitlesSection:
|
if self.useSeriesPrefixInTitlesSection:
|
||||||
title_list = self.booksByTitle
|
title_list = self.booksByTitle
|
||||||
else:
|
else:
|
||||||
title_list = self.booksByTitle_noSeriesPrefix
|
title_list = self.booksByTitle_noSeriesPrefix
|
||||||
current_letter = self.letter_or_symbol(title_list[0]['title_sort'][0])
|
|
||||||
|
# Prime the list
|
||||||
|
current_letter = self.letter_or_symbol(sort_equivalents[0])
|
||||||
title_letters = [current_letter]
|
title_letters = [current_letter]
|
||||||
current_book_list = []
|
current_book_list = []
|
||||||
current_book = ""
|
current_book = ""
|
||||||
for book in title_list:
|
for idx, book in enumerate(title_list):
|
||||||
if self.letter_or_symbol(book['title_sort'][0]) != current_letter:
|
#if self.letter_or_symbol(book['title_sort'][0]) != current_letter:
|
||||||
|
if self.letter_or_symbol(sort_equivalents[idx]) != 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)
|
||||||
|
|
||||||
# Start the new list
|
# Start the new list
|
||||||
current_letter = self.letter_or_symbol(book['title_sort'][0])
|
#current_letter = self.letter_or_symbol(book['title_sort'][0])
|
||||||
|
current_letter = self.letter_or_symbol(sort_equivalents[idx])
|
||||||
title_letters.append(current_letter)
|
title_letters.append(current_letter)
|
||||||
current_book = book['title']
|
current_book = book['title']
|
||||||
current_book_list = [book['title']]
|
current_book_list = [book['title']]
|
||||||
@ -2507,15 +2552,15 @@ Author '{0}':
|
|||||||
self.playOrder += 1
|
self.playOrder += 1
|
||||||
navLabelTag = Tag(soup, 'navLabel')
|
navLabelTag = Tag(soup, 'navLabel')
|
||||||
textTag = Tag(soup, 'text')
|
textTag = Tag(soup, 'text')
|
||||||
textTag.insert(0, NavigableString(u"Titles beginning with %s" % \
|
textTag.insert(0, NavigableString(_(u"Titles beginning with %s") % \
|
||||||
(title_letters[i] if len(title_letters[i])>1 else "'" + title_letters[i] + "'")))
|
(title_letters[i] if len(title_letters[i])>1 else "'" + title_letters[i] + "'")))
|
||||||
navLabelTag.insert(0, textTag)
|
navLabelTag.insert(0, textTag)
|
||||||
navPointByLetterTag.insert(0,navLabelTag)
|
navPointByLetterTag.insert(0,navLabelTag)
|
||||||
contentTag = Tag(soup, 'content')
|
contentTag = Tag(soup, 'content')
|
||||||
if title_letters[i] == self.SYMBOLS:
|
if title_letters[i] == self.SYMBOLS:
|
||||||
contentTag['src'] = "content/%s.html#%s" % (output, title_letters[i])
|
contentTag['src'] = "content/%s.html#%s_titles" % (output, self.SYMBOLS)
|
||||||
else:
|
else:
|
||||||
contentTag['src'] = "content/%s.html#%s" % (output, self.generateUnicodeName(title_letters[i]))
|
contentTag['src'] = "content/%s.html#%s_titles" % (output, self.generateUnicodeName(title_letters[i]))
|
||||||
navPointByLetterTag.insert(1,contentTag)
|
navPointByLetterTag.insert(1,contentTag)
|
||||||
|
|
||||||
if self.generateForKindle:
|
if self.generateForKindle:
|
||||||
@ -2570,17 +2615,22 @@ Author '{0}':
|
|||||||
# Loop over the sorted_authors list, find start of each letter,
|
# Loop over the sorted_authors list, find start of each letter,
|
||||||
# add description_preview_count artists
|
# add description_preview_count artists
|
||||||
# self.authors[0]:friendly [1]:author_sort [2]:book_count
|
# self.authors[0]:friendly [1]:author_sort [2]:book_count
|
||||||
|
# (<friendly name>, author_sort, book_count)
|
||||||
|
|
||||||
|
# Need to extract a list of author_sort, generate sort_equivalents from that
|
||||||
|
sort_equivalents = self.establish_equivalencies([x[1] for x in self.authors])
|
||||||
|
|
||||||
master_author_list = []
|
master_author_list = []
|
||||||
# self.authors[0][1][0] = Initial letter of author_sort[0]
|
# Prime the pump
|
||||||
current_letter = self.letter_or_symbol(self.authors[0][1][0])
|
current_letter = self.letter_or_symbol(sort_equivalents[0])
|
||||||
current_author_list = []
|
current_author_list = []
|
||||||
for author in self.authors:
|
for idx, author in enumerate(self.authors):
|
||||||
if self.letter_or_symbol(author[1][0]) != current_letter:
|
if self.letter_or_symbol(sort_equivalents[idx]) != current_letter:
|
||||||
# Save the old list
|
# Save the old list
|
||||||
add_to_author_list(current_author_list, current_letter)
|
add_to_author_list(current_author_list, current_letter)
|
||||||
|
|
||||||
# Start the new list
|
# Start the new list
|
||||||
current_letter = self.letter_or_symbol(author[1][0])
|
current_letter = self.letter_or_symbol(sort_equivalents[idx])
|
||||||
current_author_list = [author[0]]
|
current_author_list = [author[0]]
|
||||||
else:
|
else:
|
||||||
if len(current_author_list) < self.descriptionClip:
|
if len(current_author_list) < self.descriptionClip:
|
||||||
@ -2599,7 +2649,7 @@ Author '{0}':
|
|||||||
self.playOrder += 1
|
self.playOrder += 1
|
||||||
navLabelTag = Tag(soup, 'navLabel')
|
navLabelTag = Tag(soup, 'navLabel')
|
||||||
textTag = Tag(soup, 'text')
|
textTag = Tag(soup, 'text')
|
||||||
textTag.insert(0, NavigableString("Authors beginning with '%s'" % (authors_by_letter[1])))
|
textTag.insert(0, NavigableString(_("Authors beginning with '%s'") % (authors_by_letter[1])))
|
||||||
navLabelTag.insert(0, textTag)
|
navLabelTag.insert(0, textTag)
|
||||||
navPointByLetterTag.insert(0,navLabelTag)
|
navPointByLetterTag.insert(0,navLabelTag)
|
||||||
contentTag = Tag(soup, 'content')
|
contentTag = Tag(soup, 'content')
|
||||||
@ -3177,6 +3227,46 @@ Author '{0}':
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def establish_equivalencies(self, item_list, key=None):
|
||||||
|
# Filter for leading letter equivalencies
|
||||||
|
|
||||||
|
# Hack to force the cataloged leading letter to be
|
||||||
|
# an unadorned character if the accented version sorts before the unaccented
|
||||||
|
exceptions = {
|
||||||
|
u'Ä':u'A',
|
||||||
|
u'Ö':u'O',
|
||||||
|
u'Ü':u'U'
|
||||||
|
}
|
||||||
|
|
||||||
|
if key is not None:
|
||||||
|
sort_field = key
|
||||||
|
|
||||||
|
cl_list = [None] * len(item_list)
|
||||||
|
last_ordnum = 0
|
||||||
|
|
||||||
|
for idx, item in enumerate(item_list):
|
||||||
|
if key:
|
||||||
|
c = item[sort_field]
|
||||||
|
else:
|
||||||
|
c = item
|
||||||
|
|
||||||
|
ordnum, ordlen = collation_order(c)
|
||||||
|
if last_ordnum != ordnum:
|
||||||
|
last_c = icu_upper(c[0:ordlen])
|
||||||
|
if last_c in exceptions.keys():
|
||||||
|
last_c = exceptions[unicode(last_c)]
|
||||||
|
last_ordnum = ordnum
|
||||||
|
cl_list[idx] = last_c
|
||||||
|
|
||||||
|
if False:
|
||||||
|
if key:
|
||||||
|
for idx, item in enumerate(item_list):
|
||||||
|
print("%s %s" % (cl_list[idx],item[sort_field]))
|
||||||
|
else:
|
||||||
|
print("%s %s" % (cl_list[0], item))
|
||||||
|
|
||||||
|
return cl_list
|
||||||
|
|
||||||
def filterDbTags(self, tags):
|
def filterDbTags(self, tags):
|
||||||
# Remove the special marker tags from the database's tag list,
|
# Remove the special marker tags from the database's tag list,
|
||||||
# return sorted list of normalized genre tags
|
# return sorted list of normalized genre tags
|
||||||
@ -3458,11 +3548,11 @@ Author '{0}':
|
|||||||
author = book['author']
|
author = book['author']
|
||||||
|
|
||||||
if book['prefix']:
|
if book['prefix']:
|
||||||
author_prefix = book['prefix'] + " by "
|
author_prefix = book['prefix'] + ' ' + _("by ")
|
||||||
elif self.opts.connected_kindle and book['id'] in self.bookmarked_books:
|
elif self.opts.connected_kindle and book['id'] in self.bookmarked_books:
|
||||||
author_prefix = self.READING_SYMBOL + " by "
|
author_prefix = self.READING_SYMBOL + ' ' + _("by ")
|
||||||
else:
|
else:
|
||||||
author_prefix = "by "
|
author_prefix = _("by ")
|
||||||
|
|
||||||
# Genres
|
# Genres
|
||||||
genres = ''
|
genres = ''
|
||||||
@ -3551,8 +3641,12 @@ Author '{0}':
|
|||||||
if aTag:
|
if aTag:
|
||||||
if book['series']:
|
if book['series']:
|
||||||
if self.opts.generate_series:
|
if self.opts.generate_series:
|
||||||
aTag['href'] = "%s.html#%s_series" % ('BySeries',
|
if self.letter_or_symbol(book['series']):
|
||||||
|
aTag['href'] = "%s.html#symbol_%s_series" % ('BySeries',
|
||||||
re.sub('\W','',book['series']).lower())
|
re.sub('\W','',book['series']).lower())
|
||||||
|
else:
|
||||||
|
aTag['href'] = "%s.html#%s_series" % ('BySeries',
|
||||||
|
re.sub('\s','',book['series']).lower())
|
||||||
else:
|
else:
|
||||||
aTag.extract()
|
aTag.extract()
|
||||||
|
|
||||||
@ -4045,7 +4139,7 @@ Author '{0}':
|
|||||||
re.IGNORECASE) is not None:
|
re.IGNORECASE) is not None:
|
||||||
if self.opts.verbose:
|
if self.opts.verbose:
|
||||||
field_md = self.db.metadata_for_field(field)
|
field_md = self.db.metadata_for_field(field)
|
||||||
self.opts.log.info(" - %s (Exclusion rule '%s': %s:%s)" %
|
self.opts.log.info(" - %s (Exclusion rule '%s': %s:%s)" %
|
||||||
(record['title'], field_md['name'], field,pat))
|
(record['title'], field_md['name'], field,pat))
|
||||||
exclusion_set.append(record)
|
exclusion_set.append(record)
|
||||||
if record in filtered_data_set:
|
if record in filtered_data_set:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user