Kobo driver: Add support for new firmware with the series list on the device

Merge branch 'master' of https://github.com/davidfor/calibre
This commit is contained in:
Kovid Goyal 2020-03-03 17:45:50 +05:30
commit 477d9ef560
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 55 additions and 14 deletions

View File

@ -70,6 +70,7 @@ class Book(Book_):
self.can_put_on_shelves = True self.can_put_on_shelves = True
self.kobo_series = None self.kobo_series = None
self.kobo_series_number = None # Kobo stores the series number as string. And it can have a leading "#". self.kobo_series_number = None # Kobo stores the series number as string. And it can have a leading "#".
self.kobo_series_id = None
self.kobo_subtitle = None self.kobo_subtitle = None
if thumbnail_name is not None: if thumbnail_name is not None:
@ -84,6 +85,10 @@ class Book(Book_):
# If we don't have a content Id, we don't know what type it is. # If we don't have a content Id, we don't know what type it is.
return self.contentID and self.contentID.startswith("file") return self.contentID and self.contentID.startswith("file")
@property
def has_kobo_series(self):
return self.kobo_series is not None
@property @property
def is_purchased_kepub(self): def is_purchased_kepub(self):
return self.contentID and not self.contentID.startswith("file") return self.contentID and not self.contentID.startswith("file")
@ -102,6 +107,8 @@ class Book(Book_):
fmt('Content ID', self.contentID) fmt('Content ID', self.contentID)
if self.kobo_series: if self.kobo_series:
fmt('Kobo Series', self.kobo_series + ' #%s'%self.kobo_series_number) fmt('Kobo Series', self.kobo_series + ' #%s'%self.kobo_series_number)
if self.kobo_series_id:
fmt('Kobo Series ID', self.kobo_series_id)
if self.kobo_subtitle: if self.kobo_subtitle:
fmt('Subtitle', self.kobo_subtitle) fmt('Subtitle', self.kobo_subtitle)
if self.mime: if self.mime:

View File

@ -83,7 +83,7 @@ class KOBO(USBMS):
dbversion = 0 dbversion = 0
fwversion = (0,0,0) fwversion = (0,0,0)
supported_dbversion = 156 supported_dbversion = 158
has_kepubs = False has_kepubs = False
supported_platforms = ['windows', 'osx', 'linux'] supported_platforms = ['windows', 'osx', 'linux']
@ -1349,7 +1349,7 @@ class KOBOTOUCH(KOBO):
' Based on the existing Kobo driver by %s.') % KOBO.author ' Based on the existing Kobo driver by %s.') % KOBO.author
# icon = I('devices/kobotouch.jpg') # icon = I('devices/kobotouch.jpg')
supported_dbversion = 157 supported_dbversion = 158
min_supported_dbversion = 53 min_supported_dbversion = 53
min_dbversion_series = 65 min_dbversion_series = 65
min_dbversion_externalid = 65 min_dbversion_externalid = 65
@ -1357,11 +1357,12 @@ class KOBOTOUCH(KOBO):
min_dbversion_images_on_sdcard = 77 min_dbversion_images_on_sdcard = 77
min_dbversion_activity = 77 min_dbversion_activity = 77
min_dbversion_keywords = 82 min_dbversion_keywords = 82
min_dbversion_seriesid = 136
# Starting with firmware version 3.19.x, the last number appears to be is a # Starting with firmware version 3.19.x, the last number appears to be is a
# build number. A number will be recorded here but it can be safely ignored # build number. A number will be recorded here but it can be safely ignored
# when testing the firmware version. # when testing the firmware version.
max_supported_fwversion = (4, 19, 14114) max_supported_fwversion = (4, 20, 14601)
# The following document firwmare versions where new function or devices were added. # The following document firwmare versions where new function or devices were added.
# Not all are used, but this feels a good place to record it. # Not all are used, but this feels a good place to record it.
min_fwversion_shelves = (2, 0, 0) min_fwversion_shelves = (2, 0, 0)
@ -1377,11 +1378,13 @@ class KOBOTOUCH(KOBO):
min_librah20_fwversion = (4, 16, 13337) # "Reviewers" release. min_librah20_fwversion = (4, 16, 13337) # "Reviewers" release.
min_fwversion_epub_location = (4, 17, 13651) # ePub reading location without full contentid. min_fwversion_epub_location = (4, 17, 13651) # ePub reading location without full contentid.
min_fwversion_dropbox = (4, 18, 13737) # The Forma only at this point. min_fwversion_dropbox = (4, 18, 13737) # The Forma only at this point.
min_fwversion_serieslist = (4, 20, 14601) # Series list needs the SeriesID to be set.
has_kepubs = True has_kepubs = True
booklist_class = KTCollectionsBookList booklist_class = KTCollectionsBookList
book_class = Book book_class = Book
kobo_series_dict = {}
MAX_PATH_LEN = 185 # 250 - (len(" - N3_LIBRARY_SHELF.parsed") + len("F:\.kobo\images\")) MAX_PATH_LEN = 185 # 250 - (len(" - N3_LIBRARY_SHELF.parsed") + len("F:\.kobo\images\"))
KOBO_EXTRA_CSSFILE = 'kobo_extra.css' KOBO_EXTRA_CSSFILE = 'kobo_extra.css'
@ -1610,7 +1613,8 @@ class KOBOTOUCH(KOBO):
bl_cache[b.lpath] = idx bl_cache[b.lpath] = idx
def update_booklist(prefix, path, ContentID, ContentType, MimeType, ImageID, def update_booklist(prefix, path, ContentID, ContentType, MimeType, ImageID,
title, authors, DateCreated, Description, Publisher, series, seriesnumber, title, authors, DateCreated, Description, Publisher,
series, seriesnumber, SeriesID, SeriesNumberFloat,
ISBN, Language, Subtitle, ISBN, Language, Subtitle,
readstatus, expired, favouritesindex, accessibility, isdownloaded, readstatus, expired, favouritesindex, accessibility, isdownloaded,
userid, bookshelves userid, bookshelves
@ -1747,10 +1751,16 @@ class KOBOTOUCH(KOBO):
bl[idx].kobo_metadata = kobo_metadata bl[idx].kobo_metadata = kobo_metadata
bl[idx].kobo_series = series bl[idx].kobo_series = series
bl[idx].kobo_series_number = seriesnumber bl[idx].kobo_series_number = seriesnumber
bl[idx].kobo_series_id = SeriesID
bl[idx].kobo_subtitle = Subtitle bl[idx].kobo_subtitle = Subtitle
bl[idx].can_put_on_shelves = allow_shelves bl[idx].can_put_on_shelves = allow_shelves
bl[idx].mime = MimeType bl[idx].mime = MimeType
if not bl[idx].is_sideloaded and bl[idx].has_kobo_series and SeriesID is not None:
if show_debug:
debug_print('KoboTouch:update_booklist - Have purchased kepub with series, saving SeriesID=', SeriesID)
self.kobo_series_dict[series] = SeriesID
if lpath in playlist_map: if lpath in playlist_map:
bl[idx].device_collections = playlist_map.get(lpath,[]) bl[idx].device_collections = playlist_map.get(lpath,[])
bl[idx].current_shelves = bookshelves bl[idx].current_shelves = bookshelves
@ -1800,10 +1810,16 @@ class KOBOTOUCH(KOBO):
book.kobo_metadata = kobo_metadata book.kobo_metadata = kobo_metadata
book.kobo_series = series book.kobo_series = series
book.kobo_series_number = seriesnumber book.kobo_series_number = seriesnumber
book.kobo_series_id = SeriesID
book.kobo_subtitle = Subtitle book.kobo_subtitle = Subtitle
book.can_put_on_shelves = allow_shelves book.can_put_on_shelves = allow_shelves
# debug_print('KoboTouch:update_booklist - title=', title, 'book.device_collections', book.device_collections) # debug_print('KoboTouch:update_booklist - title=', title, 'book.device_collections', book.device_collections)
if not book.is_sideloaded and book.has_kobo_series and SeriesID is not None:
if show_debug:
debug_print('KoboTouch:update_booklist - Have purchased kepub with series, saving SeriesID=', SeriesID)
self.kobo_series_dict[series] = SeriesID
if bl.add_book(book, replace_metadata=False): if bl.add_book(book, replace_metadata=False):
changed = True changed = True
if show_debug: if show_debug:
@ -1863,6 +1879,10 @@ class KOBOTOUCH(KOBO):
columns += ", Series, SeriesNumber, ___UserID, ExternalId, Subtitle" columns += ", Series, SeriesNumber, ___UserID, ExternalId, Subtitle"
else: else:
columns += ', null as Series, null as SeriesNumber, ___UserID, null as ExternalId, null as Subtitle' columns += ', null as Series, null as SeriesNumber, ___UserID, null as ExternalId, null as Subtitle'
if self.supports_series_list:
columns += ", SeriesID, SeriesNumberFloat"
else:
columns += ', null as SeriesID, null as SeriesNumberFloat'
where_clause = '' where_clause = ''
if self.supports_kobo_archive() or self.supports_overdrive(): if self.supports_kobo_archive() or self.supports_overdrive():
@ -1957,7 +1977,8 @@ class KOBOTOUCH(KOBO):
prefix = self._card_a_prefix if oncard == 'carda' else self._main_prefix prefix = self._card_a_prefix if oncard == 'carda' else self._main_prefix
changed = update_booklist(prefix, path, row['ContentID'], row['ContentType'], row['MimeType'], row['ImageId'], changed = update_booklist(prefix, path, row['ContentID'], row['ContentType'], row['MimeType'], row['ImageId'],
row['Title'], row['Attribution'], row['DateCreated'], row['Description'], row['Publisher'], row['Title'], row['Attribution'], row['DateCreated'], row['Description'], row['Publisher'],
row['Series'], row['SeriesNumber'], row['ISBN'], row['Language'], row['Subtitle'], row['Series'], row['SeriesNumber'], row['SeriesID'], row['SeriesNumberFloat'],
row['ISBN'], row['Language'], row['Subtitle'],
row['ReadStatus'], row['___ExpirationStatus'], row['ReadStatus'], row['___ExpirationStatus'],
int(row['FavouritesIndex']), row['Accessibility'], row['IsDownloaded'], int(row['FavouritesIndex']), row['Accessibility'], row['IsDownloaded'],
row['___UserID'], bookshelves row['___UserID'], bookshelves
@ -1972,6 +1993,7 @@ class KOBOTOUCH(KOBO):
self.dump_bookshelves(connection) self.dump_bookshelves(connection)
else: else:
debug_print("KoboTouch:books - automatically managing metadata") debug_print("KoboTouch:books - automatically managing metadata")
debug_print("KoboTouch:books - self.kobo_series_dict=", self.kobo_series_dict)
# Remove books that are no longer in the filesystem. Cache contains # Remove books that are no longer in the filesystem. Cache contains
# indices into the booklist if book not in filesystem, None otherwise # indices into the booklist if book not in filesystem, None otherwise
# Do the operation in reverse order so indices remain valid # Do the operation in reverse order so indices remain valid
@ -3127,7 +3149,6 @@ class KOBOTOUCH(KOBO):
kobo_series_number = None kobo_series_number = None
series_number_changed = not (kobo_series_number == newmi.series_index) series_number_changed = not (kobo_series_number == newmi.series_index)
if series_changed or series_number_changed:
if newmi.series is not None: if newmi.series is not None:
new_series = newmi.series new_series = newmi.series
try: try:
@ -3138,10 +3159,19 @@ class KOBOTOUCH(KOBO):
new_series = None new_series = None
new_series_number = None new_series_number = None
if series_changed or series_number_changed:
update_values.append(new_series) update_values.append(new_series)
set_clause += ', Series = ? ' set_clause += ', Series = ? '
update_values.append(new_series_number) update_values.append(new_series_number)
set_clause += ', SeriesNumber = ? ' set_clause += ', SeriesNumber = ? '
if self.supports_series_list and book.is_sideloaded:
series_id = self.kobo_series_dict.get(new_series, new_series)
if not book.kobo_series_id == series_id or series_changed or series_number_changed:
update_values.append(series_id)
set_clause += ', SeriesID = ? '
update_values.append(new_series_number)
set_clause += ', SeriesNumberFloat = ? '
debug_print("KoboTouch:set_core_metadata Setting SeriesID - new_series='%s', series_id='%s'" % (new_series, series_id))
if not series_only: if not series_only:
if not (newmi.title == kobo_metadata.title): if not (newmi.title == kobo_metadata.title):
@ -3537,6 +3567,10 @@ class KOBOTOUCH(KOBO):
def supports_series(self): def supports_series(self):
return self.dbversion >= self.min_dbversion_series return self.dbversion >= self.min_dbversion_series
@property
def supports_series_list(self):
return self.dbversion >= self.min_dbversion_seriesid and self.fwversion >= self.min_fwversion_serieslist
def supports_kobo_archive(self): def supports_kobo_archive(self):
return self.dbversion >= self.min_dbversion_archive return self.dbversion >= self.min_dbversion_archive