diff --git a/src/calibre/devices/kobo/driver.py b/src/calibre/devices/kobo/driver.py index f24e00143b..a2be629449 100644 --- a/src/calibre/devices/kobo/driver.py +++ b/src/calibre/devices/kobo/driver.py @@ -5,15 +5,16 @@ __license__ = 'GPL v3' __copyright__ = '2010, Timothy Legge and Kovid Goyal ' __docformat__ = 'restructuredtext en' -import os +import os, time import sqlite3 as sqlite from calibre.devices.usbms.books import BookList from calibre.devices.kobo.books import Book from calibre.devices.kobo.books import ImageWrapper from calibre.devices.mime import mime_type_ext -from calibre.devices.usbms.driver import USBMS +from calibre.devices.usbms.driver import USBMS, debug_print from calibre import prints +from calibre.devices.usbms.books import CollectionsBookList class KOBO(USBMS): @@ -21,12 +22,15 @@ class KOBO(USBMS): gui_name = 'Kobo Reader' description = _('Communicate with the Kobo Reader') author = 'Timothy Legge and Kovid Goyal' - version = (1, 0, 4) + version = (1, 0, 6) supported_platforms = ['windows', 'osx', 'linux'] + booklist_class = CollectionsBookList + # Ordered list of supported formats FORMATS = ['epub', 'pdf'] + CAN_SET_METADATA = True VENDOR_ID = [0x2237] PRODUCT_ID = [0x4161] @@ -40,6 +44,12 @@ class KOBO(USBMS): VIRTUAL_BOOK_EXTENSIONS = frozenset(['kobo']) + EXTRA_CUSTOMIZATION_MESSAGE = _('The Kobo supports only one collection ' + 'currently: the \"Im_Reading\" list. Create a tag called \"Im_Reading\" ')+\ + 'for automatic management' + + EXTRA_CUSTOMIZATION_DEFAULT = ', '.join(['tags']) + def initialize(self): USBMS.initialize(self) self.book_class = Book @@ -63,6 +73,8 @@ class KOBO(USBMS): self._card_b_prefix if oncard == 'cardb' \ else self._main_prefix + self.booklist_class.rebuild_collections = self.rebuild_collections + # get the metadata cache bl = self.booklist_class(oncard, prefix, self.settings) need_sync = self.parse_metadata_cache(bl, prefix, self.METADATA_CACHE) @@ -85,9 +97,7 @@ class KOBO(USBMS): playlist_map = {} if readstatus == 1: - if lpath not in playlist_map: - playlist_map[lpath] = [] - playlist_map[lpath].append("I\'m Reading") + playlist_map[lpath]= "Im_Reading" path = self.normalize_path(path) # print "Normalized FileName: " + path @@ -104,14 +114,17 @@ class KOBO(USBMS): if self.update_metadata_item(bl[idx]): # print 'update_metadata_item returned true' changed = True - bl[idx].device_collections = playlist_map.get(lpath, []) + if lpath in playlist_map and \ + playlist_map[lpath] not in bl[idx].device_collections: + bl[idx].device_collections.append(playlist_map[lpath]) else: if ContentType == '6': book = Book(prefix, lpath, title, authors, mime, date, ContentType, ImageID, size=1048576) else: book = self.book_from_path(prefix, lpath, title, authors, mime, date, ContentType, ImageID) # print 'Update booklist' - book.device_collections = playlist_map.get(book.lpath, []) + book.device_collections = [playlist_map[lpath]] if lpath in playlist_map else [] + if bl.add_book(book, replace_metadata=False): changed = True except: # Probably a path encoding error @@ -398,3 +411,95 @@ class KOBO(USBMS): size = os.stat(cls.normalize_path(os.path.join(prefix, lpath))).st_size book = Book(prefix, lpath, title, authors, mime, date, ContentType, ImageID, size=size, other=mi) return book + + def get_device_paths(self): + paths, prefixes = {}, {} + for prefix, path, source_id in [ + ('main', 'metadata.calibre', 0), + ('card_a', 'metadata.calibre', 1), + ('card_b', 'metadata.calibre', 2) + ]: + prefix = getattr(self, '_%s_prefix'%prefix) + if prefix is not None and os.path.exists(prefix): + paths[source_id] = os.path.join(prefix, *(path.split('/'))) + return paths + + def update_device_database_collections(self, booklists, collections_attributes): +# debug_print('Starting update_device_database_collections', collections_attributes) + + # Force collections_attributes to be 'tags' as no other is currently supported +# debug_print('KOBO: overriding the provided collections_attributes:', collections_attributes) + collections_attributes = ['tags'] + + collections = booklists.get_collections(collections_attributes) +# debug_print('Collections', collections) + for category, books in collections.items(): + if category == 'Im_Reading': + # Create a connection to the sqlite database + connection = sqlite.connect(self._main_prefix + '.kobo/KoboReader.sqlite') + cursor = connection.cursor() + + # Reset Im_Reading list in the database + query= 'update content set ReadStatus=0, FirstTimeReading = \'true\' where BookID is Null' + try: + cursor.execute (query) + except: + debug_print('Database Exception: Unable to reset Im_Reading list') + raise + else: +# debug_print('Commit: Reset Im_Reading list') + connection.commit() + + for book in books: +# debug_print('Title:', book.title, 'lpath:', book.path) + book.device_collections = ['Im_Reading'] + + extension = os.path.splitext(book.path)[1] + ContentType = self.get_content_type_from_extension(extension) + + ContentID = self.contentid_from_path(book.path, ContentType) + datelastread = time.strftime("%Y-%m-%dT%H:%M:%S", time.gmtime()) + + t = (datelastread,ContentID,) + + try: + cursor.execute('update content set ReadStatus=1,FirstTimeReading=\'false\',DateLastRead=? where BookID is Null and ContentID = ?', t) + except: + debug_print('Database Exception: Unable create Im_Reading list') + raise + else: + connection.commit() + # debug_print('Database: Commit create Im_Reading list') + + cursor.close() + connection.close() + +# debug_print('Finished update_device_database_collections', collections_attributes) + + def sync_booklists(self, booklists, end_session=True): +# debug_print('KOBO: started sync_booklists') + paths = self.get_device_paths() + + blists = {} + for i in paths: + if booklists[i] is not None: + #debug_print('Booklist: ', i) + blists[i] = booklists[i] + opts = self.settings() + if opts.extra_customization: + collections = [x.lower().strip() for x in + opts.extra_customization.split(',')] + else: + collections = [] + + #debug_print('KOBO: collection fields:', collections) + for i, blist in blists.items(): + self.update_device_database_collections(blist, collections) + + USBMS.sync_booklists(self, booklists, end_session=end_session) + #debug_print('KOBO: finished sync_booklists') + + def rebuild_collections(self, booklist, oncard): + collections_attributes = [] + self.update_device_database_collections(booklist, collections_attributes) +