Kobo driver: Update for new firmware from Kobo

Also fix incorrect cover size being uploaded to the Glo HD

Merge branch 'master' of https://github.com/davidfor/calibre
This commit is contained in:
Kovid Goyal 2017-01-21 17:57:49 +05:30
commit 1d0d413f8f

View File

@ -65,7 +65,7 @@ class KOBO(USBMS):
gui_name = 'Kobo Reader'
description = _('Communicate with the Kobo Reader')
author = 'Timothy Legge and David Forrester'
version = (2, 3, 2)
version = (2, 3, 3)
dbversion = 0
fwversion = (0,0,0)
@ -1325,7 +1325,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, 2, 8094)
max_supported_fwversion = (4, 2, 8283)
# 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)
@ -1397,19 +1397,29 @@ class KOBOTOUCH(KOBO):
# Used for Details screen from FW2.8.1
' - AndroidBookLoadTablet_Aspect.parsed':[(355,479), 88, 100,False,],
}
GLO_HD_COVER_FILE_ENDINGS = {
# Used for screensaver, home screen
' - N3_FULL.parsed': [(1072,1448), 0, 200,True,],
# Used for Details screen before FW2.8.1, then for current book tile on home screen
' - N3_LIBRARY_FULL.parsed':[(355, 479), 0, 200,False,],
# Used for library lists
' - N3_LIBRARY_GRID.parsed':[(149, 201), 0, 200,False,],
# Used for Details screen from FW2.8.1
' - AndroidBookLoadTablet_Aspect.parsed':[(355, 471), 88, 100,False,],
}
AURA_HD_COVER_FILE_ENDINGS = {
# Used for screensaver, home screen
' - N3_FULL.parsed': [(1080,1440), 0, 200,True,], # Used for screensaver, home screen
' - N3_FULL.parsed': [(1080,1440), 0, 200,True,],
# Used for Details screen before FW2.8.1, then for current book tile on home screen
' - N3_LIBRARY_FULL.parsed':[(355, 471), 0, 200,False,],
# Used for library lists
' - N3_LIBRARY_GRID.parsed':[(149, 198), 0, 200,False,], # Used for library lists
' - N3_LIBRARY_GRID.parsed':[(149, 198), 0, 200,False,],
# Used for Details screen from FW2.8.1
' - AndroidBookLoadTablet_Aspect.parsed':[(355, 471), 88, 100,False,],
}
AURA_ONE_COVER_FILE_ENDINGS = {
# Used for screensaver, home screen
' - N3_FULL.parsed': [(1404,1872), 0, 200,True,], # Used for screensaver, home screen
' - N3_FULL.parsed': [(1404,1872), 0, 200,True,],
# Used for Details screen before FW2.8.1, then for current book tile on home screen
' - N3_LIBRARY_FULL.parsed':[(355, 473), 0, 200,False,],
# Used for library lists
@ -2428,19 +2438,55 @@ class KOBOTOUCH(KOBO):
path = os.path.join(path, imageId)
return path
def _upload_cover(self, path, filename, metadata, filepath, uploadgrayscale, keep_cover_aspect=False):
from calibre.utils.img import save_cover_data_to
from calibre.utils.imghdr import identify
debug_print("KoboTouch:_upload_cover - filename='%s' uploadgrayscale='%s' "%(filename, uploadgrayscale))
def _calculate_kobo_cover_size(self, library_size, kobo_size, keep_cover_aspect, is_full_size):
if keep_cover_aspect:
library_aspect = library_size[0] / library_size[1]
kobo_aspect = kobo_size[0] / kobo_size[1]
if library_aspect > kobo_aspect:
kobo_size = (kobo_size[0], int(kobo_size[0] / library_aspect))
else:
kobo_size = (int(library_aspect * kobo_size[1]), kobo_size[1])
return kobo_size
def _create_cover_data(self, cover_data, resize_to, kobo_size, upload_grayscale=False, keep_cover_aspect=False, is_full_size=False):
'''
This will generate the new cover image from the cover in the library. It is a wrapper
for save_cover_data_to to allow it to be overriden in a subclass. For this reason,
options are passed in that are not used by this implementation.
:param cover_data: original cover data
:param resize_to: Size to resize the cover to (width, height). None means do not resize.
:param kobo_size: Size of the cover image on the device.
:param upload_grayscale: boolean True if driver configured to send grayscale thumbnails
Passed to allow ability to decide to quantize to 16-col grayscale
at calibre end
:param keep_cover_aspect: bookean - True if the aspect ratio of the cover in the library is to be kept.
:param is_full_size: True if this is the kobo_size is for the full size cover image
Passed to allow ability to process screensaver differently
to smaller thumbnails
'''
from calibre.utils.img import save_cover_data_to
data = save_cover_data_to(cover_data, grayscale=upload_grayscale, resize_to=resize_to)
return data
def _upload_cover(self, path, filename, metadata, filepath, upload_grayscale, keep_cover_aspect=False):
from calibre.utils.imghdr import identify
debug_print("KoboTouch:_upload_cover - filename='%s' upload_grayscale='%s' "%(filename, upload_grayscale))
if not metadata.cover:
return
if metadata.cover:
show_debug = self.is_debugging_title(filename)
if show_debug:
debug_print("KoboTouch:_upload_cover - path='%s'"%path, "filename='%s'"%filename)
debug_print(" filepath='%s'"%filepath)
cover = self.normalize_path(metadata.cover.replace('/', os.sep))
if os.path.exists(cover):
if not os.path.exists(cover):
debug_print("KoboTouch:_upload_cover - Cover file does not exist in library")
return
# Get ContentID for Selected Book
extension = os.path.splitext(filepath)[1]
ContentType = self.get_content_type_from_extension(extension) if extension != '' else self.get_content_type_from_path(filepath)
@ -2472,33 +2518,27 @@ class KOBOTOUCH(KOBO):
debug_print("KoboTouch:_upload_cover - Image directory does not exust. Creating path='%s'" % (image_dir))
os.makedirs(image_dir)
with lopen(cover, 'rb') as f:
cover_data = f.read()
fmt, width, height = identify(cover_data)
library_cover_size = (width, height)
for ending, cover_options in self.cover_file_endings().items():
resize, min_dbversion, max_dbversion, isFullsize = cover_options
kobo_size, min_dbversion, max_dbversion, is_full_size = cover_options
if show_debug:
debug_print("KoboTouch:_upload_cover - resize=%s min_dbversion=%d max_dbversion=%d" % (resize, min_dbversion, max_dbversion))
debug_print("KoboTouch:_upload_cover - library_cover_size=%s min_dbversion=%d max_dbversion=%d" % (
library_cover_size, min_dbversion, max_dbversion))
if self.dbversion >= min_dbversion and self.dbversion <= max_dbversion:
if show_debug:
debug_print("KoboTouch:_upload_cover - creating cover for ending='%s'"%ending) # , "resize'%s'"%resize)
debug_print("KoboTouch:_upload_cover - creating cover for ending='%s'"%ending) # , "library_cover_size'%s'"%library_cover_size)
fpath = path + ending
fpath = self.normalize_path(fpath.replace('/', os.sep))
with lopen(cover, 'rb') as f:
data = f.read()
resize_to = self._calculate_kobo_cover_size(library_cover_size, kobo_size, keep_cover_aspect, is_full_size)
if keep_cover_aspect:
if isFullsize:
resize = None
else:
fmt, width, height = identify(data)
cover_aspect = width / height
if cover_aspect > 1:
resize = (resize[0], int(resize[0] / cover_aspect))
elif cover_aspect < 1:
resize = (int(cover_aspect * resize[1]), resize[1])
# Return the data resized and in Grayscale if
# required
data = save_cover_data_to(data, grayscale=uploadgrayscale, resize_to=resize)
# Return the data resized and in Grayscale if required
data = self._create_cover_data(cover_data, resize_to, kobo_size, upload_grayscale, keep_cover_aspect, is_full_size)
with lopen(fpath, 'wb') as f:
f.write(data)
@ -2507,8 +2547,6 @@ class KOBOTOUCH(KOBO):
err = str(e)
debug_print("KoboTouch:_upload_cover - Exception string: %s"%err)
raise
else:
debug_print("KoboTouch:_upload_cover - ImageID could not be retrieved from the database")
def remove_book_from_device_bookshelves(self, connection, book):
show_debug = self.is_debugging_title(book.title) # or True
@ -2914,10 +2952,30 @@ class KOBOTOUCH(KOBO):
return self.detected_device.idProduct in self.TOUCH2_PRODUCT_ID
def cover_file_endings(self):
return self.GLO_COVER_FILE_ENDINGS if self.isGlo() or self.isAura() or self.isAuraEdition2() \
else self.AURA_HD_COVER_FILE_ENDINGS if self.isAuraHD() or self.isAuraH2O() or self.isGloHD() \
else self.AURA_ONE_COVER_FILE_ENDINGS if self.isAuraOne() \
else self.COVER_FILE_ENDINGS
if self.isAura():
_cover_file_endings = self.GLO_COVER_FILE_ENDINGS
elif self.isAuraEdition2():
_cover_file_endings = self.GLO_COVER_FILE_ENDINGS
elif self.isAuraHD():
_cover_file_endings = self.AURA_HD_COVER_FILE_ENDINGS
elif self.isAuraH2O():
_cover_file_endings = self.AURA_HD_COVER_FILE_ENDINGS
elif self.isAuraOne():
_cover_file_endings = self.AURA_ONE_COVER_FILE_ENDINGS
elif self.isGlo():
_cover_file_endings = self.GLO_COVER_FILE_ENDINGS
elif self.isGloHD():
_cover_file_endings = self.GLO_HD_COVER_FILE_ENDINGS
elif self.isMini():
_cover_file_endings = self.COVER_FILE_ENDINGS
elif self.isTouch():
_cover_file_endings = self.COVER_FILE_ENDINGS
elif self.isTouch2():
_cover_file_endings = self.COVER_FILE_ENDINGS
else:
_cover_file_endings = self.COVER_FILE_ENDINGS
return _cover_file_endings
def set_device_name(self):
device_name = self.gui_name