Kobo driver: Add support for new firmware

Kobo driver: Add an option to not maintain bookmarks/read status/etc. when resending a book already on the device.

Fixes #1767589 [New Kobo Glo driver not supported](https://bugs.launchpad.net/calibre/+bug/1767589)
This commit is contained in:
Kovid Goyal 2018-04-28 14:28:31 +05:30
commit 684bbe6dab
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 68 additions and 45 deletions

View File

@ -52,6 +52,13 @@ def qhash(inputstr):
return h
def any_in(haystack, *needles):
for n in needles:
if n in haystack:
return True
return False
class DummyCSSPreProcessor(object):
def __call__(self, data, add_namespace=False):
@ -69,7 +76,7 @@ class KOBO(USBMS):
dbversion = 0
fwversion = (0,0,0)
supported_dbversion = 129
supported_dbversion = 146
has_kepubs = False
supported_platforms = ['windows', 'osx', 'linux']
@ -98,33 +105,33 @@ class KOBO(USBMS):
VIRTUAL_BOOK_EXTENSIONS = frozenset(['kobo', ''])
EXTRA_CUSTOMIZATION_MESSAGE = [
_('The Kobo supports several collections including ')+ 'Read, Closed, Im_Reading. ' +
_('Create tags for automatic management'),
_('Upload covers for books (newer readers)') +
':::'+_('Normally, the Kobo readers get the cover image from the'
' e-book file itself. With this option, calibre will send a '
'separate cover image to the reader, useful if you '
'have modified the cover.'),
_('The Kobo supports several collections including ')+ 'Read, Closed, Im_Reading. ' + _(
'Create tags for automatic management'),
_('Upload covers for books (newer readers)') + ':::'+_(
'Normally, the Kobo readers get the cover image from the'
' e-book file itself. With this option, calibre will send a '
'separate cover image to the reader, useful if you '
'have modified the cover.'),
_('Upload black and white covers'),
_('Show expired books') +
':::'+_('A bug in an earlier version left non kepubs book records'
' in the database. With this option calibre will show the '
'expired records and allow you to delete them with '
'the new delete logic.'),
_('Show Previews') +
':::'+_('Kobo previews are included on the Touch and some other versions'
' by default they are no longer displayed as there is no good reason to '
'see them. Enable if you wish to see/delete them.'),
_('Show Recommendations') +
':::'+_('Kobo now shows recommendations on the device. In some cases these have '
'files but in other cases they are just pointers to the web site to buy. '
'Enable if you wish to see/delete them.'),
_('Attempt to support newer firmware') +
':::'+_('Kobo routinely updates the firmware and the '
'database version. With this option calibre will attempt '
'to perform full read-write functionality - Here be Dragons!! '
'Enable only if you are comfortable with restoring your kobo '
'to factory defaults and testing software'),
_('Show expired books') + ':::'+_(
'A bug in an earlier version left non kepubs book records'
' in the database. With this option calibre will show the '
'expired records and allow you to delete them with '
'the new delete logic.'),
_('Show Previews') + ':::'+_(
'Kobo previews are included on the Touch and some other versions'
' by default they are no longer displayed as there is no good reason to '
'see them. Enable if you wish to see/delete them.'),
_('Show Recommendations') + ':::'+_(
'Kobo now shows recommendations on the device. In some cases these have '
'files but in other cases they are just pointers to the web site to buy. '
'Enable if you wish to see/delete them.'),
_('Attempt to support newer firmware') + ':::'+_(
'Kobo routinely updates the firmware and the '
'database version. With this option calibre will attempt '
'to perform full read-write functionality - Here be Dragons!! '
'Enable only if you are comfortable with restoring your kobo '
'to factory defaults and testing software'),
]
EXTRA_CUSTOMIZATION_DEFAULT = [
@ -353,8 +360,7 @@ class KOBO(USBMS):
cursor.execute(query)
except Exception as e:
err = str(e)
if not ('___ExpirationStatus' in err or 'FavouritesIndex' in err or
'Accessibility' in err or 'IsDownloaded' in err):
if not (any_in(err, '___ExpirationStatus', 'FavouritesIndex', 'Accessibility', 'IsDownloaded')):
raise
query= ('select Title, Attribution, DateCreated, ContentID, MimeType, ContentType, '
'ImageID, ReadStatus, "-1" as ___ExpirationStatus, "-1" as '
@ -1316,7 +1322,7 @@ class KOBOTOUCH(KOBO):
' Based on the existing Kobo driver by %s.') % KOBO.author
# icon = I('devices/kobotouch.jpg')
supported_dbversion = 143
supported_dbversion = 146
min_supported_dbversion = 53
min_dbversion_series = 65
min_dbversion_externalid = 65
@ -1328,7 +1334,7 @@ class KOBOTOUCH(KOBO):
# 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
# when testing the firmware version.
max_supported_fwversion = (4, 7, 10413)
max_supported_fwversion = (4, 8, 10956)
# 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.
min_fwversion_shelves = (2, 0, 0)
@ -1337,8 +1343,9 @@ class KOBOTOUCH(KOBO):
min_aurah2o_fwversion = (3, 7, 0)
min_reviews_fwversion = (3, 12, 0)
min_glohd_fwversion = (3, 14, 0)
min_auraone_fwversion = (3, 20, 7280)
min_fwversion_overdrive = (4, 0, 7523)
min_auraone_fwversion = (3, 20, 7280)
# min_clarahd_fwversion = (4, 8, 10956) # It is coming, this is probably the firmware, but I don't have any ids for it.
min_fwversion_overdrive = (4, 0, 7523)
has_kepubs = True
@ -1839,13 +1846,7 @@ class KOBOTOUCH(KOBO):
cursor.execute(query)
except Exception as e:
err = str(e)
if not ('___ExpirationStatus' in err or
'FavouritesIndex' in err or
'Accessibility' in err or
'IsDownloaded' in err or
'Series' in err or
'ExternalId' in err
):
if not (any_in(err, '___ExpirationStatus', 'FavouritesIndex', 'Accessibility', 'IsDownloaded', 'Series', 'ExternalId')):
raise
query= ('SELECT Title, Attribution, DateCreated, ContentID, MimeType, ContentType, '
'ImageID, ReadStatus, -1 AS ___ExpirationStatus, "-1" AS '
@ -2039,7 +2040,8 @@ class KOBOTOUCH(KOBO):
# debug_print('KoboTouch:upload_books: Delete record left if deleted on Touch')
cursor.execute(cleanup_query, cleanup_values)
self.set_filesize_in_device_database(connection, contentID, fname)
if self.override_kobo_replace_existing:
self.set_filesize_in_device_database(connection, contentID, fname)
if not self.upload_covers:
imageID = self.imageid_from_contentid(contentID)
@ -2963,6 +2965,7 @@ class KOBOTOUCH(KOBO):
c.add_opt('update_device_metadata', default=True)
c.add_opt('modify_css', default=False)
c.add_opt('override_kobo_replace_existing', default=True) # Overriding the replace behaviour is how the driver has always worked.
c.add_opt('support_newer_firmware', default=False)
c.add_opt('debugging_title', default='')
@ -3124,6 +3127,10 @@ class KOBOTOUCH(KOBO):
def modifying_css(self):
return self.get_pref('modify_css')
@property
def override_kobo_replace_existing(self):
return self.get_pref('override_kobo_replace_existing')
@property
def update_device_metadata(self):
return self.get_pref('update_device_metadata')

View File

@ -114,6 +114,7 @@ class KOBOTOUCHConfig(TabbedDeviceConfig):
p['update_series'] = self.update_series
p['modify_css'] = self.modify_css
p['override_kobo_replace_existing'] = self.override_kobo_replace_existing
p['support_newer_firmware'] = self.support_newer_firmware
p['debugging_title'] = self.debugging_title
@ -185,14 +186,29 @@ class BookUploadsGroupBox(DeviceOptionsGroupBox):
'these are removed for all styles in the original stylesheet.').format(device.KOBO_EXTRA_CSSFILE),
device.get_pref('modify_css')
)
self.override_kobo_replace_existing_checkbox = create_checkbox(
_("Do not treat replacements as new books"),
_('When a new book is side-loaded, the Kobo firmware imports details of the book into the internal database. '
'Even if the book is a replacement for an existing book, the Kobo will remove the book from the database and then treat it as a new book. '
'This means that the reading status, bookmarks and collections for the book will be lost. '
'This option overrides firmware behavior and attempts to prevent a book that has been resent from being treated as a new book. '
'If you prefer to have replacements treated as new books, turn this option off.'
),
device.get_pref('override_kobo_replace_existing')
)
self.options_layout.addWidget(self.modify_css_checkbox, 0, 0, 1, 2)
self.options_layout.setRowStretch(1, 1)
self.options_layout.addWidget(self.override_kobo_replace_existing_checkbox, 1, 0, 1, 2)
self.options_layout.setRowStretch(2, 1)
@property
def modify_css(self):
return self.modify_css_checkbox.isChecked()
@property
def override_kobo_replace_existing(self):
return self.override_kobo_replace_existing_checkbox.isChecked()
class CollectionsGroupBox(DeviceOptionsGroupBox):
@ -211,7 +227,7 @@ class CollectionsGroupBox(DeviceOptionsGroupBox):
self.collections_columns_label = QLabel(_('Collections columns:'))
self.collections_columns_edit = QLineEdit(self)
self.collections_columns_edit.setToolTip(_('The Kobo from firmware V2.0.0 supports bookshelves.'
' These are created on the Kobo. ' +
' These are created on the Kobo. '
'Specify a tags type column for automatic management.'))
self.collections_columns_edit.setText(device.get_pref('collections_columns'))
@ -228,8 +244,8 @@ class CollectionsGroupBox(DeviceOptionsGroupBox):
self.ignore_collections_names_label = QLabel(_('Ignore collections:'))
self.ignore_collections_names_edit = QLineEdit(self)
self.ignore_collections_names_edit.setToolTip(_('List the names of collections to be ignored by ' +
'the collection management. The collections listed ' +
self.ignore_collections_names_edit.setToolTip(_('List the names of collections to be ignored by '
'the collection management. The collections listed '
'will not be changed. Names are separated by commas.'))
self.ignore_collections_names_edit.setText(device.get_pref('ignore_collections_names'))