Kobo: Add support for uploading new covers to the device without converting the ePub. Default to grayscale images, supports colour

This commit is contained in:
Timothy Legge 2011-10-02 20:40:44 -03:00
parent 5219a61557
commit 49783d44b7
2 changed files with 128 additions and 12 deletions

View File

@ -5,10 +5,10 @@ __license__ = 'GPL v3'
__copyright__ = '2010, Timothy Legge <timlegge at gmail.com> and Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import os
import os, shutil
import sqlite3 as sqlite
from contextlib import closing
from tempfile import NamedTemporaryFile
from calibre.devices.usbms.books import BookList
from calibre.devices.kobo.books import Book
from calibre.devices.kobo.books import ImageWrapper
@ -16,6 +16,7 @@ from calibre.devices.mime import mime_type_ext
from calibre.devices.usbms.driver import USBMS, debug_print
from calibre import prints
from calibre.devices.usbms.books import CollectionsBookList
from calibre.utils.magick.draw import Image, save_cover_data_to, thumbnail
class KOBO(USBMS):
@ -53,11 +54,23 @@ class KOBO(USBMS):
_('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'
' ebook 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')
]
EXTRA_CUSTOMIZATION_DEFAULT = [', '.join(['tags'])]
EXTRA_CUSTOMIZATION_DEFAULT = [
', '.join(['tags']),
True,
True
]
OPT_COLLECTIONS = 0
OPT_COLLECTIONS = 0
OPT_UPLOAD_COVERS = 1
OPT_UPLOAD_GRAYSCALE_COVERS = 2
def initialize(self):
USBMS.initialize(self)
@ -593,7 +606,7 @@ class KOBO(USBMS):
raise
else:
connection.commit()
debug_print(' Commit: Reset ReadStatus list')
# debug_print(' Commit: Reset ReadStatus list')
cursor.close()
@ -616,7 +629,7 @@ class KOBO(USBMS):
raise
else:
connection.commit()
debug_print(' Commit: Setting ReadStatus List')
# debug_print(' Commit: Setting ReadStatus List')
cursor.close()
def reset_favouritesindex(self, connection, oncard):
@ -635,7 +648,7 @@ class KOBO(USBMS):
raise
else:
connection.commit()
debug_print(' Commit: Reset FavouritesIndex list')
# debug_print(' Commit: Reset FavouritesIndex list')
def set_favouritesindex(self, connection, ContentID):
cursor = connection.cursor()
@ -650,7 +663,7 @@ class KOBO(USBMS):
raise
else:
connection.commit()
debug_print(' Commit: Set FavouritesIndex')
# debug_print(' Commit: Set FavouritesIndex')
def update_device_database_collections(self, booklists, collections_attributes, oncard):
# Only process categories in this list
@ -702,9 +715,9 @@ class KOBO(USBMS):
# Process any collections that exist
for category, books in collections.items():
if category in supportedcategories:
debug_print("Category: ", category, " id = ", readstatuslist.get(category))
# debug_print("Category: ", category, " id = ", readstatuslist.get(category))
for book in books:
debug_print(' Title:', book.title, 'category: ', category)
# debug_print(' Title:', book.title, 'category: ', category)
if category not in book.device_collections:
book.device_collections.append(category)
@ -763,3 +776,103 @@ class KOBO(USBMS):
collections_attributes = []
self.update_device_database_collections(booklist, collections_attributes, oncard)
def upload_cover(self, path, filename, metadata, filepath):
'''
Upload book cover to the device. Default implementation does nothing.
:param path: The full path to the directory where the associated book is located.
:param filename: The name of the book file without the extension.
:param metadata: metadata belonging to the book. Use metadata.thumbnail
for cover
:param filepath: The full path to the ebook file
'''
opts = self.settings()
if not opts.extra_customization[self.OPT_UPLOAD_COVERS]:
# Building thumbnails disabled
debug_print('KOBO: not uploading cover')
return
if not opts.extra_customization[self.OPT_UPLOAD_GRAYSCALE_COVERS]:
uploadgrayscale = False
else:
uploadgrayscale = True
debug_print('KOBO: uploading cover')
try:
self._upload_cover(path, filename, metadata, filepath, uploadgrayscale)
except:
debug_print('FAILED to upload cover', filepath)
def _upload_cover(self, path, filename, metadata, filepath, uploadgrayscale):
if metadata.cover:
cover = self.normalize_path(metadata.cover.replace('/', os.sep))
if os.path.exists(cover):
# 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)
ContentID = self.contentid_from_path(filepath, ContentType)
with closing(sqlite.connect(self.normalize_path(self._main_prefix +
'.kobo/KoboReader.sqlite'))) as connection:
# return bytestrings if the content cannot the decoded as unicode
connection.text_factory = lambda x: unicode(x, "utf-8", "ignore")
cursor = connection.cursor()
t = (ContentID,)
cursor.execute('select ImageId from Content where BookID is Null and ContentID = ?', t)
result = cursor.fetchone()
if result is None:
debug_print("No rows exist in the database - cannot upload")
return
else:
ImageID = result[0]
# debug_print("ImageId: ", result[0])
cursor.close()
if ImageID != None:
path_prefix = '.kobo/images/'
path = self._main_prefix + path_prefix + ImageID
file_endings = {' - iPhoneThumbnail.parsed':(103,150),
' - bbMediumGridList.parsed':(93,135),
' - NickelBookCover.parsed':(500,725),
' - N3_LIBRARY_FULL.parsed':(355,530),
' - N3_LIBRARY_GRID.parsed':(149,233),
' - N3_LIBRARY_LIST.parsed':(60,90),
' - N3_SOCIAL_CURRENTREAD.parsed':(120,186)}
for ending, resize in file_endings.items():
fpath = path + ending
fpath = self.normalize_path(fpath.replace('/', os.sep))
if os.path.exists(fpath):
try:
with open(cover, 'rb') as f:
data = f.read()
f.close()
tmppath = 'tempdata.jpg'
# Return the data resized and in Grayscale if required
data = save_cover_data_to(data, tmppath, grayscale=uploadgrayscale, resize_to=resize, return_data=True)
# Save the image data to a file
with NamedTemporaryFile(mode='w+b', suffix='kobo.jpg', prefix='tmp', dir=None, delete=False) as f1:
f1.write(data)
tmppath = f1.name
f1.close()
# Copy the resized temporary file over the existing image file
shutil.copy(tmppath, fpath)
if os.path.exists(tmppath):
os.unlink(tmppath)
except:
raise
else:
debug_print("ImageID could not be retreived from the database")

View File

@ -47,7 +47,7 @@ def normalize_format_name(fmt):
return fmt
def save_cover_data_to(data, path, bgcolor='#ffffff', resize_to=None,
return_data=False, compression_quality=90, minify_to=None):
return_data=False, compression_quality=90, minify_to=None, grayscale=False):
'''
Saves image in data to path, in the format specified by the path
extension. Removes any transparency. If there is no transparency and no
@ -71,6 +71,9 @@ def save_cover_data_to(data, path, bgcolor='#ffffff', resize_to=None,
fmt = os.path.splitext(path)[1]
fmt = normalize_format_name(fmt[1:])
if grayscale == True:
img.type = "GrayscaleType"
if resize_to is not None:
img.size = (resize_to[0], resize_to[1])
changed = True