GwR update author lists, fix EXTH output

This commit is contained in:
GRiker 2010-02-11 07:15:55 -07:00
parent 845acb192f
commit b817c151b5
3 changed files with 137 additions and 54 deletions

View File

@ -79,3 +79,9 @@ p.unread_book {
text-indent:-2em; text-indent:-2em;
} }
hr.series_divider {
width:50%;
margin-left:1em;
margin-top:0em;
margin-bottom:0em;
}

View File

@ -105,11 +105,12 @@ class MetadataUpdater(object):
have_exth = self.have_exth = (flags & 0x40) != 0 have_exth = self.have_exth = (flags & 0x40) != 0
self.cover_record = self.thumbnail_record = None self.cover_record = self.thumbnail_record = None
self.timestamp = None self.timestamp = None
self.pdbrecords = self.get_pdbrecords() self.pdbrecords = self.get_pdbrecords()
self.original_exth_records = {}
if not have_exth: if not have_exth:
self.create_exth() self.create_exth()
else:
# Fetch timestamp, cover_record, thumbnail_record # Fetch timestamp, cover_record, thumbnail_record
self.fetchEXTHFields() self.fetchEXTHFields()
@ -131,6 +132,8 @@ class MetadataUpdater(object):
content = exth[pos + 8: pos + size] content = exth[pos + 8: pos + size]
pos += size pos += size
self.original_exth_records[id] = content
if id == 106: if id == 106:
self.timestamp = content self.timestamp = content
elif id == 201: elif id == 201:
@ -284,6 +287,10 @@ class MetadataUpdater(object):
return StreamSlicer(self.stream, start, stop) return StreamSlicer(self.stream, start, stop)
def update(self, mi): def update(self, mi):
def pop_exth_record(exth_id):
if exth_id in self.original_exth_records:
self.original_exth_records.pop(exth_id)
if self.type != "BOOKMOBI": if self.type != "BOOKMOBI":
raise MobiError("Setting metadata only supported for MOBI files of type 'BOOK'.\n" 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])) "\tThis is a '%s' file of type '%s'" % (self.type[0:4], self.type[4:8]))
@ -298,35 +305,53 @@ class MetadataUpdater(object):
if mi.author_sort and pas: if mi.author_sort and pas:
authors = mi.author_sort authors = mi.author_sort
recs.append((100, authors.encode(self.codec, 'replace'))) recs.append((100, authors.encode(self.codec, 'replace')))
pop_exth_record(100)
elif mi.authors: elif mi.authors:
authors = '; '.join(mi.authors) authors = '; '.join(mi.authors)
recs.append((100, authors.encode(self.codec, 'replace'))) recs.append((100, authors.encode(self.codec, 'replace')))
pop_exth_record(100)
if mi.publisher: if mi.publisher:
recs.append((101, mi.publisher.encode(self.codec, 'replace'))) recs.append((101, mi.publisher.encode(self.codec, 'replace')))
pop_exth_record(101)
if mi.comments: if mi.comments:
recs.append((103, mi.comments.encode(self.codec, 'replace'))) recs.append((103, mi.comments.encode(self.codec, 'replace')))
pop_exth_record(103)
if mi.isbn: if mi.isbn:
recs.append((104, mi.isbn.encode(self.codec, 'replace'))) recs.append((104, mi.isbn.encode(self.codec, 'replace')))
pop_exth_record(104)
if mi.tags: if mi.tags:
subjects = '; '.join(mi.tags) subjects = '; '.join(mi.tags)
recs.append((105, subjects.encode(self.codec, 'replace'))) recs.append((105, subjects.encode(self.codec, 'replace')))
pop_exth_record(105)
if mi.pubdate: if mi.pubdate:
recs.append((106, str(mi.pubdate).encode(self.codec, 'replace'))) recs.append((106, str(mi.pubdate).encode(self.codec, 'replace')))
pop_exth_record(106)
elif mi.timestamp: elif mi.timestamp:
recs.append((106, str(mi.timestamp).encode(self.codec, 'replace'))) recs.append((106, str(mi.timestamp).encode(self.codec, 'replace')))
pop_exth_record(106)
elif self.timestamp: elif self.timestamp:
recs.append((106, self.timestamp)) recs.append((106, self.timestamp))
pop_exth_record(106)
else: else:
recs.append((106, str(datetime.now()).encode(self.codec, 'replace'))) recs.append((106, str(datetime.now()).encode(self.codec, 'replace')))
pop_exth_record(106)
if self.cover_record is not None: if self.cover_record is not None:
recs.append((201, pack('>I', self.cover_rindex))) recs.append((201, pack('>I', self.cover_rindex)))
recs.append((203, pack('>I', 0))) recs.append((203, pack('>I', 0)))
pop_exth_record(201)
pop_exth_record(203)
if self.thumbnail_record is not None: if self.thumbnail_record is not None:
recs.append((202, pack('>I', self.thumbnail_rindex))) recs.append((202, pack('>I', self.thumbnail_rindex)))
pop_exth_record(202)
if getattr(self, 'encryption_type', -1) != 0: if getattr(self, 'encryption_type', -1) != 0:
raise MobiError('Setting metadata in DRMed MOBI files is not supported.') raise MobiError('Setting metadata in DRMed MOBI files is not supported.')
# Restore any original EXTH fields that weren't modified/updated
for id in sorted(self.original_exth_records):
recs.append((id, self.original_exth_records[id]))
recs = sorted(recs, key=lambda x:(x[0],x[0]))
exth = StringIO() exth = StringIO()
for code, data in recs: for code, data in recs:
exth.write(pack('>II', code, len(data) + 8)) exth.write(pack('>II', code, len(data) + 8))

View File

@ -941,12 +941,23 @@ class EPUB_MOBI(CatalogPlugin):
this_title['series_index'] = 0.0 this_title['series_index'] = 0.0
this_title['title_sort'] = self.generateSortTitle(this_title['title']) this_title['title_sort'] = self.generateSortTitle(this_title['title'])
if 'authors' in record and record['authors'] is not None: if 'authors' in record and record['authors']:
this_title['author'] = " & ".join(record['authors']) this_title['author'] = " & ".join(record['authors'])
else: else:
this_title['author'] = 'Unknown' this_title['author'] = 'Unknown'
this_title['author_sort'] = record['author_sort'].title() if len(record['author_sort'].strip()) \
'''
this_title['author_sort_original'] = record['author_sort']
author_sort = record['author_sort'] if len(record['author_sort'].strip()) \
else self.author_to_author_sort(this_title['author']) else self.author_to_author_sort(this_title['author'])
author_sort = author_sort[0].upper() + author_sort[1:]
this_title['author_sort'] = author_sort
'''
if 'author_sort' in record and record['author_sort'].strip():
this_title['author_sort'] = record['author_sort']
else:
this_title['author_sort'] = self.author_to_author_sort(this_title['author'])
this_title['id'] = record['id'] this_title['id'] = record['id']
if record['publisher']: if record['publisher']:
this_title['publisher'] = re.sub('&', '&', record['publisher']) this_title['publisher'] = re.sub('&', '&', record['publisher'])
@ -996,37 +1007,6 @@ class EPUB_MOBI(CatalogPlugin):
def fetchBooksByAuthor(self): def fetchBooksByAuthor(self):
# Generate a list of titles sorted by author from the database # Generate a list of titles sorted by author from the database
def author_compare(x,y):
# Return -1 if x<y
# Return 0 if x==y
# Return 1 if x>y
# Different authors - sort by author_sort
if x['author_sort'] > y['author_sort']:
return 1
elif x['author_sort'] < y['author_sort']:
return -1
else:
# Same author
if x['series'] != y['series']:
# Different series
if x['title_sort'].lstrip() > y['title_sort'].lstrip():
return 1
else:
return -1
else:
# Same series
if x['series'] == y['series']:
if float(x['series_index']) > float(y['series_index']):
return 1
elif float(x['series_index']) < float(y['series_index']):
return -1
else:
return 0
else:
if x['series'] > y['series']:
return 1
else:
return -1
self.updateProgressFullStep("Sorting database") self.updateProgressFullStep("Sorting database")
@ -1037,13 +1017,13 @@ class EPUB_MOBI(CatalogPlugin):
''' '''
self.booksByAuthor = list(self.booksByTitle) self.booksByAuthor = list(self.booksByTitle)
self.booksByAuthor.sort(author_compare) self.booksByAuthor.sort(self.author_compare)
if False and self.verbose: if False and self.verbose:
self.opts.log.info("fetchBooksByAuthor(): %d books" % len(self.booksByAuthor)) self.opts.log.info("fetchBooksByAuthor(): %d books" % len(self.booksByAuthor))
self.opts.log.info(" %-30s %-20s %s" % ('title', 'title_sort','series', 'series_index')) self.opts.log.info(" %-30s %-20s %s" % ('title', 'series', 'series_index'))
for title in self.booksByAuthor: for title in self.booksByAuthor:
self.opts.log.info((u" %-30s %-20s %-20s%5s " % \ self.opts.log.info((u" %-30s %-20s%5s " % \
(title['title'][:30], (title['title'][:30],
title['series'][:20] if title['series'] else '', title['series'][:20] if title['series'] else '',
title['series_index'], title['series_index'],
@ -1051,7 +1031,7 @@ class EPUB_MOBI(CatalogPlugin):
raise SystemExit raise SystemExit
# Build the unique_authors set from existing data # Build the unique_authors set from existing data
authors = [(record['author'], record['author_sort']) for record in self.booksByAuthor] authors = [(record['author'], record['author_sort'].capitalize()) for record in self.booksByAuthor]
# authors[] contains a list of all book authors, with multiple entries for multiple books by author # authors[] contains a list of all book authors, with multiple entries for multiple books by author
# authors[]: (([0]:friendly [1]:sort)) # authors[]: (([0]:friendly [1]:sort))
@ -1417,7 +1397,7 @@ class EPUB_MOBI(CatalogPlugin):
book_count = 0 book_count = 0
for book in self.booksByAuthor: for book in self.booksByAuthor:
book_count += 1 book_count += 1
if book['author_sort'][0].upper() != current_letter : if self.letter_or_symbol(book['author_sort'][0].upper()) != current_letter :
''' '''
# Start a new letter - anchor only, hidden # Start a new letter - anchor only, hidden
current_letter = book['author_sort'][0].upper() current_letter = book['author_sort'][0].upper()
@ -1427,19 +1407,21 @@ class EPUB_MOBI(CatalogPlugin):
dtc += 1 dtc += 1
''' '''
# Start a new letter with Index letter # Start a new letter with Index letter
current_letter = book['author_sort'][0].upper() current_letter = self.letter_or_symbol(book['author_sort'][0].upper())
pIndexTag = Tag(soup, "p") pIndexTag = Tag(soup, "p")
pIndexTag['class'] = "letter_index" pIndexTag['class'] = "letter_index"
aTag = Tag(soup, "a") aTag = Tag(soup, "a")
aTag['name'] = "%sauthors" % current_letter aTag['name'] = "%sauthors" % self.letter_or_symbol(current_letter)
pIndexTag.insert(0,aTag) pIndexTag.insert(0,aTag)
pIndexTag.insert(1,NavigableString(book['author_sort'][0].upper())) pIndexTag.insert(1,NavigableString(self.letter_or_symbol(book['author_sort'][0].upper())))
divTag.insert(dtc,pIndexTag) divTag.insert(dtc,pIndexTag)
dtc += 1 dtc += 1
if book['author'] != current_author: if book['author'] != current_author:
# Start a new author # Start a new author
current_author = book['author'] current_author = book['author']
non_series_books = 0
current_series = None
pAuthorTag = Tag(soup, "p") pAuthorTag = Tag(soup, "p")
pAuthorTag['class'] = "author_index" pAuthorTag['class'] = "author_index"
emTag = Tag(soup, "em") emTag = Tag(soup, "em")
@ -1451,6 +1433,14 @@ class EPUB_MOBI(CatalogPlugin):
divTag.insert(dtc,pAuthorTag) divTag.insert(dtc,pAuthorTag)
dtc += 1 dtc += 1
# Insert an <hr /> between non-series and series
if not current_series and non_series_books and book['series']:
# Insert an <hr />
hrTag = Tag(soup,'hr')
hrTag['class'] = "series_divider"
divTag.insert(dtc,hrTag)
dtc += 1
# Check for series # Check for series
if book['series'] and book['series'] != current_series: if book['series'] and book['series'] != current_series:
# Start a new series # Start a new series
@ -1486,6 +1476,7 @@ class EPUB_MOBI(CatalogPlugin):
aTag.insert(0,escape(book['title'][len(book['series'])+1:])) aTag.insert(0,escape(book['title'][len(book['series'])+1:]))
else: else:
aTag.insert(0,escape(book['title'])) aTag.insert(0,escape(book['title']))
non_series_books += 1
pBookTag.insert(ptc, aTag) pBookTag.insert(ptc, aTag)
ptc += 1 ptc += 1
@ -1522,12 +1513,11 @@ class EPUB_MOBI(CatalogPlugin):
def add_books_to_HTML(this_months_list, dtc): def add_books_to_HTML(this_months_list, dtc):
if len(this_months_list): if len(this_months_list):
date_string = strftime(u'%B %Y', current_date.timetuple())
this_months_list = sorted(this_months_list, this_months_list.sort(self.author_compare)
key=lambda x:(x['title_sort'], x['title_sort']))
this_months_list = sorted(this_months_list,
key=lambda x:(x['author_sort'], x['author_sort']))
# Create a new month anchor # Create a new month anchor
date_string = strftime(u'%B %Y', current_date.timetuple())
pIndexTag = Tag(soup, "p") pIndexTag = Tag(soup, "p")
pIndexTag['class'] = "date_index" pIndexTag['class'] = "date_index"
aTag = Tag(soup, "a") aTag = Tag(soup, "a")
@ -1543,6 +1533,8 @@ class EPUB_MOBI(CatalogPlugin):
if new_entry['author'] != current_author: if new_entry['author'] != current_author:
# Start a new author # Start a new author
current_author = new_entry['author'] current_author = new_entry['author']
non_series_books = 0
current_series = None
pAuthorTag = Tag(soup, "p") pAuthorTag = Tag(soup, "p")
pAuthorTag['class'] = "author_index" pAuthorTag['class'] = "author_index"
emTag = Tag(soup, "em") emTag = Tag(soup, "em")
@ -1554,6 +1546,14 @@ class EPUB_MOBI(CatalogPlugin):
divTag.insert(dtc,pAuthorTag) divTag.insert(dtc,pAuthorTag)
dtc += 1 dtc += 1
# Insert an <hr /> between non-series and series
if not current_series and non_series_books and new_entry['series']:
# Insert an <hr />
hrTag = Tag(soup,'hr')
hrTag['class'] = "series_divider"
divTag.insert(dtc,hrTag)
dtc += 1
# Check for series # Check for series
if new_entry['series'] and new_entry['series'] != current_series: if new_entry['series'] and new_entry['series'] != current_series:
# Start a new series # Start a new series
@ -1588,6 +1588,7 @@ class EPUB_MOBI(CatalogPlugin):
aTag.insert(0,escape(new_entry['title'][len(new_entry['series'])+1:])) aTag.insert(0,escape(new_entry['title'][len(new_entry['series'])+1:]))
else: else:
aTag.insert(0,escape(new_entry['title'])) aTag.insert(0,escape(new_entry['title']))
non_series_books += 1
pBookTag.insert(ptc, aTag) pBookTag.insert(ptc, aTag)
ptc += 1 ptc += 1
@ -1685,7 +1686,7 @@ class EPUB_MOBI(CatalogPlugin):
this_book = {} this_book = {}
this_book['author'] = book['author'] this_book['author'] = book['author']
this_book['title'] = book['title'] this_book['title'] = book['title']
this_book['author_sort'] = book['author_sort'] this_book['author_sort'] = book['author_sort'].capitalize()
this_book['read'] = book['read'] this_book['read'] = book['read']
this_book['id'] = book['id'] this_book['id'] = book['id']
this_book['series'] = book['series'] this_book['series'] = book['series']
@ -2228,15 +2229,15 @@ class EPUB_MOBI(CatalogPlugin):
# self.authors[0]:friendly [1]:author_sort [2]:book_count # self.authors[0]:friendly [1]:author_sort [2]:book_count
master_author_list = [] master_author_list = []
# self.authors[0][1][0] = Initial letter of author_sort[0] # self.authors[0][1][0] = Initial letter of author_sort[0]
current_letter = self.authors[0][1][0] current_letter = self.letter_or_symbol(self.authors[0][1][0])
current_author_list = [] current_author_list = []
for author in self.authors: for author in self.authors:
if author[1][0] != current_letter: if self.letter_or_symbol(author[1][0]) != 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 = author[1][0] current_letter = self.letter_or_symbol(author[1][0])
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:
@ -2496,6 +2497,46 @@ class EPUB_MOBI(CatalogPlugin):
tokens[0] += ',' tokens[0] += ','
return ' '.join(tokens).capitalize() return ' '.join(tokens).capitalize()
def author_compare(self,x,y):
# Return -1 if x<y
# Return 0 if x==y
# Return 1 if x>y
# Different authors - sort by author_sort
if x['author_sort'].capitalize() > y['author_sort'].capitalize():
return 1
elif x['author_sort'].capitalize() < y['author_sort'].capitalize():
return -1
else:
# Same author
if x['series'] != y['series']:
# One title is a series, the other is not
if not x['series']:
# Sort regular titles < series titles
return -1
elif not y['series']:
return 1
# Different series
if x['title_sort'].lstrip() > y['title_sort'].lstrip():
return 1
else:
return -1
else:
# Same series
if x['series'] == y['series']:
if float(x['series_index']) > float(y['series_index']):
return 1
elif float(x['series_index']) < float(y['series_index']):
return -1
else:
return 0
else:
if x['series'] > y['series']:
return 1
else:
return -1
def calculateThumbnailSize(self): def calculateThumbnailSize(self):
''' Calculate thumbnail dimensions based on device DPI. Scale Kindle by 50% ''' ''' Calculate thumbnail dimensions based on device DPI. Scale Kindle by 50% '''
from calibre.customize.ui import output_profiles from calibre.customize.ui import output_profiles
@ -2658,6 +2699,8 @@ class EPUB_MOBI(CatalogPlugin):
if book['author'] != current_author: if book['author'] != current_author:
# Start a new author with link # Start a new author with link
current_author = book['author'] current_author = book['author']
non_series_books = 0
current_series = None
pAuthorTag = Tag(soup, "p") pAuthorTag = Tag(soup, "p")
pAuthorTag['class'] = "author_index" pAuthorTag['class'] = "author_index"
emTag = Tag(soup, "em") emTag = Tag(soup, "em")
@ -2669,6 +2712,14 @@ class EPUB_MOBI(CatalogPlugin):
divTag.insert(dtc,pAuthorTag) divTag.insert(dtc,pAuthorTag)
dtc += 1 dtc += 1
# Insert an <hr /> between non-series and series
if not current_series and non_series_books and book['series']:
# Insert an <hr />
hrTag = Tag(soup,'hr')
hrTag['class'] = "series_divider"
divTag.insert(dtc,hrTag)
dtc += 1
# Check for series # Check for series
if book['series'] and book['series'] != current_series: if book['series'] and book['series'] != current_series:
# Start a new series # Start a new series
@ -2703,6 +2754,7 @@ class EPUB_MOBI(CatalogPlugin):
aTag.insert(0,escape(book['title'][len(book['series'])+1:])) aTag.insert(0,escape(book['title'][len(book['series'])+1:]))
else: else:
aTag.insert(0,escape(book['title'])) aTag.insert(0,escape(book['title']))
non_series_books += 1
pBookTag.insert(ptc, aTag) pBookTag.insert(ptc, aTag)
ptc += 1 ptc += 1