def update_booklist(self, bl, bl_index): if bl_index not in self.record_roots: return debug_print('Updating JSON cache:', bl_index) playlist_map = self.build_id_playlist_map(bl_index) root = self.record_roots[bl_index] lpath_map = self.build_lpath_map(root) for book in bl: record = lpath_map.get(book.lpath, None) if record is not None: for thumbnail in record.xpath( 'descendant::*[local-name()="thumbnail"]'): for img in thumbnail.xpath( 'descendant::*[local-name()="jpeg"]|' 'descendant::*[local-name()="png"]'): if img.text: try: raw = b64decode(img.text.strip()) except: continue book.thumbnail = raw break break book.device_collections = playlist_map.get(book.lpath, []) debug_print('Finished updating JSON cache:', bl_index)
def books(self, oncard=None, end_session=True): debug_print('PRS505: starting fetching books for card', oncard) bl = USBMS.books(self, oncard=oncard, end_session=end_session) c = self.initialize_XML_cache() c.update_booklist(bl, {'carda': 1, 'cardb': 2}.get(oncard, 0)) debug_print('PRS505: finished fetching books for card', oncard) return bl
def commit(self): debug_print("KOBOTOUCHConfig::commit: start") p = super(KOBOTOUCHConfig, self).commit() p['manage_collections'] = self.manage_collections p['create_collections'] = self.create_collections p['collections_columns'] = self.collections_columns p['ignore_collections_names'] = self.ignore_collections_names p['delete_empty_collections'] = self.delete_empty_collections p['upload_covers'] = self.upload_covers p['keep_cover_aspect'] = self.keep_cover_aspect p['upload_grayscale'] = self.upload_grayscale p['show_recommendations'] = self.show_recommendations p['show_previews'] = self.show_previews p['show_archived_books'] = self.show_archived_books p['update_series'] = self.update_series p['modify_css'] = self.modify_css p['support_newer_firmware'] = self.support_newer_firmware p['debugging_title'] = self.debugging_title p['driver_version'] = '.'.join( [unicode(i) for i in self.device.version]) return p
def remove_orphaned_records(self, connection, dbpath): try: cursor = connection.cursor() debug_print("Removing Orphaned Collection Records") # Purge any collections references that point into the abyss query = 'DELETE FROM booktags WHERE book_id NOT IN (SELECT _id FROM books)' cursor.execute(query) query = 'DELETE FROM booktags WHERE tag_id NOT IN (SELECT _id FROM tags)' cursor.execute(query) debug_print("Removing Orphaned Book Records") cursor.close() except Exception: import traceback tb = traceback.format_exc() raise DeviceError(( ('The Paladin database is corrupted. ' ' Delete the file %s on your reader and then disconnect ' ' reconnect it. If you are using an SD card, you ' ' should delete the file on the card as well. Note that ' ' deleting this file will cause your reader to forget ' ' any notes/highlights, etc.') % dbpath) + ' Underlying error:' '\n' + tb)
def _log_location(self, *args): ''' Upon first call, switch to appropriate method ''' from calibre_plugins.syncman.config import prefs if not prefs.get('debug_plugin', False): # Neuter the method self._log = self.__null self._log_location = self.__null else: # Log the message from here so stack trace is valid arg1 = arg2 = '' if len(args) > 0: arg1 = str(args[0]) if len(args) > 1: arg2 = str(args[1]) debug_print(self.LOCATION_TEMPLATE.format(cls=self.__class__.__name__, func=sys._getframe(1).f_code.co_name, arg1=arg1, arg2=arg2)) # Switch to real method self._log = self.__log self._log_location = self.__log_location
def get_or_create_playlist(self, bl_idx, title): # maintain a private map of playlists to their ids. Don't check if it # exists, because reset_existing_playlist_map must be called before it # is used to ensure that deleted playlists are taken into account root = self.record_roots[bl_idx] if bl_idx not in self._playlist_to_playlist_id_map: self._playlist_to_playlist_id_map[bl_idx] = {} for playlist in root.xpath('//*[local-name()="playlist"]'): pl_title = playlist.get('title', None) if pl_title is not None: self._playlist_to_playlist_id_map[bl_idx][ pl_title] = playlist if title in self._playlist_to_playlist_id_map[bl_idx]: return self._playlist_to_playlist_id_map[bl_idx][title] debug_print('Creating playlist:', title) ans = root.makeelement('{%s}playlist' % self.namespaces[bl_idx], nsmap=root.nsmap, attrib={ 'uuid': uuid(), 'title': title, 'id': unicode_type(self.max_id(root) + 1), 'sourceid': '1' }) root.append(ans) self._playlist_to_playlist_id_map[bl_idx][title] = ans return ans
def books(self, oncard=None, end_session=True): debug_print('PRS505: starting fetching books for card', oncard) bl = USBMS.books(self, oncard=oncard, end_session=end_session) c = self.initialize_XML_cache() c.update_booklist(bl, {'carda':1, 'cardb':2}.get(oncard, 0)) debug_print('PRS505: finished fetching books for card', oncard) return bl
def update_booklist(self, bl, bl_index): if bl_index not in self.record_roots: return debug_print('Updating JSON cache:', bl_index) playlist_map = self.build_id_playlist_map(bl_index) root = self.record_roots[bl_index] lpath_map = self.build_lpath_map(root) for book in bl: record = lpath_map.get(book.lpath, None) if record is not None: for thumbnail in record.xpath( 'descendant::*[local-name()="thumbnail"]'): for img in thumbnail.xpath( 'descendant::*[local-name()="jpeg"]|' 'descendant::*[local-name()="png"]'): if img.text: try: raw = from_base64_bytes(img.text.strip()) except Exception: continue book.thumbnail = raw break break book.device_collections = playlist_map.get(book.lpath, []) debug_print('Finished updating JSON cache:', bl_index)
def remove_orphaned_records(self, connection, dbpath): try: cursor = connection.cursor() debug_print("Removing Orphaned Collection Records") # Purge any collections references that point into the abyss query = 'DELETE FROM booktags WHERE book_id NOT IN (SELECT _id FROM books)' cursor.execute(query) query = 'DELETE FROM booktags WHERE tag_id NOT IN (SELECT _id FROM tags)' cursor.execute(query) debug_print("Removing Orphaned Book Records") cursor.close() except Exception: import traceback tb = traceback.format_exc() raise DeviceError((('The Paladin database is corrupted. ' ' Delete the file %s on your reader and then disconnect ' ' reconnect it. If you are using an SD card, you ' ' should delete the file on the card as well. Note that ' ' deleting this file will cause your reader to forget ' ' any notes/highlights, etc.')%dbpath)+' Underlying error:' '\n'+tb)
def _upload_cover(self, path, filename, metadata, filepath): if metadata.thumbnail and metadata.thumbnail[-1]: path = path.replace('/', os.sep) is_main = path.startswith(self._main_prefix) thumbnail_dir = MEDIA_THUMBNAIL if is_main else CACHE_THUMBNAIL prefix = None if is_main: prefix = self._main_prefix else: if self._card_a_prefix and \ path.startswith(self._card_a_prefix): prefix = self._card_a_prefix elif self._card_b_prefix and \ path.startswith(self._card_b_prefix): prefix = self._card_b_prefix if prefix is None: prints('WARNING: Failed to find prefix for:', filepath) return thumbnail_dir = os.path.join(prefix, *thumbnail_dir.split('/')) relpath = os.path.relpath(filepath, prefix) if relpath.startswith('..\\'): relpath = relpath[3:] thumbnail_dir = os.path.join(thumbnail_dir, relpath) if not os.path.exists(thumbnail_dir): os.makedirs(thumbnail_dir) cpath = os.path.join(thumbnail_dir, 'main_thumbnail.jpg') with lopen(cpath, 'wb') as f: f.write(metadata.thumbnail[-1]) debug_print('Cover uploaded to: %r'%cpath)
def commit(self): debug_print("KOBOTOUCHConfig::commit: start") p = super(KOBOTOUCHConfig, self).commit() p['manage_collections'] = self.manage_collections p['create_collections'] = self.create_collections p['collections_columns'] = self.collections_columns p['ignore_collections_names'] = self.ignore_collections_names p['delete_empty_collections'] = self.delete_empty_collections p['upload_covers'] = self.upload_covers p['keep_cover_aspect'] = self.keep_cover_aspect p['upload_grayscale'] = self.upload_grayscale p['dithered_covers'] = self.dithered_covers p['letterbox_fs_covers'] = self.letterbox_fs_covers p['png_covers'] = self.png_covers p['show_recommendations'] = self.show_recommendations p['show_previews'] = self.show_previews p['show_archived_books'] = self.show_archived_books p['update_series'] = self.update_series p['update_core_metadata'] = self.update_core_metadata p['update_purchased_kepubs'] = self.update_purchased_kepubs p['subtitle_template'] = self.subtitle_template p['update_subtitle'] = self.update_subtitle 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 p['driver_version'] = '.'.join([unicode(i) for i in self.device.version]) return p
def open(self, parent=None, detail_item=None, external=False): ''' Open the specified item in the external, or Calibre's browser ''' debug_print('Libgen Fiction::__init__.py:LibgenStore:open:locals() =', locals()) detail_url = ( self.libgen.get_detail_url(detail_item) if detail_item else self.libgen.base_url ) debug_print('Libgen Fiction::__init__.py:LibgenStore:open:detail_url =', detail_url) if external or self.config.get('open_external', False): open_url(QUrl(detail_url)) else: d = WebStoreDialog( self.gui, self.libgen.base_url, parent, detail_url) d.setWindowTitle(self.name) d.set_tags(self.config.get('tags', '')) d.exec_()
def genesis(self): ''' Initialize the Libgen Client ''' debug_print('Libgen Fiction::__init__.py:LibgenStore:genesis') self.libgen = LibgenFictionClient()
def _upload_cover(self, path, filename, metadata, filepath): if metadata.thumbnail and metadata.thumbnail[-1]: path = path.replace('/', os.sep) is_main = path.startswith(self._main_prefix) thumbnail_dir = MEDIA_THUMBNAIL if is_main else CACHE_THUMBNAIL prefix = None if is_main: prefix = self._main_prefix else: if self._card_a_prefix and \ path.startswith(self._card_a_prefix): prefix = self._card_a_prefix elif self._card_b_prefix and \ path.startswith(self._card_b_prefix): prefix = self._card_b_prefix if prefix is None: prints('WARNING: Failed to find prefix for:', filepath) return thumbnail_dir = os.path.join(prefix, *thumbnail_dir.split('/')) relpath = os.path.relpath(filepath, prefix) if relpath.startswith('..\\'): relpath = relpath[3:] thumbnail_dir = os.path.join(thumbnail_dir, relpath) if not os.path.exists(thumbnail_dir): os.makedirs(thumbnail_dir) cpath = os.path.join(thumbnail_dir, 'main_thumbnail.jpg') with lopen(cpath, 'wb') as f: f.write(metadata.thumbnail[-1]) debug_print('Cover uploaded to: %r' % cpath)
def __init__(self, parent, object_name): self.parent = parent self.prefs = parent.prefs self.elements = self.prefs.get('appearance_css', None) debug_print("AnnotationElementsTable::__init__ - self.elements", self.elements) if not self.elements: self.elements = default_elements debug_print("AnnotationElementsTable::__init__ - self.elements", self.elements) QTableWidget.__init__(self) self.setObjectName(object_name) self.layout = parent.elements_hl.layout() # Add ourselves to the layout sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) sizePolicy.setHorizontalStretch(0) #sizePolicy.setVerticalStretch(0) #sizePolicy.setHeightForWidth(self.sizePolicy().hasHeightForWidth()) self.setSizePolicy(sizePolicy) #self.setMaximumSize(QSize(16777215, self.MAXIMUM_TABLE_HEIGHT)) self.setColumnCount(0) self.setRowCount(0) self.layout.addWidget(self)
def commit(self): debug_print("KOBOTOUCHConfig::commit: start") p = super(KOBOTOUCHConfig, self).commit() p['manage_collections'] = self.manage_collections p['create_collections'] = self.create_collections p['collections_columns'] = self.collections_columns p['ignore_collections_names'] = self.ignore_collections_names p['delete_empty_collections'] = self.delete_empty_collections p['upload_covers'] = self.upload_covers p['keep_cover_aspect'] = self.keep_cover_aspect p['upload_grayscale'] = self.upload_grayscale p['show_recommendations'] = self.show_recommendations p['show_previews'] = self.show_previews p['show_archived_books'] = self.show_archived_books p['update_series'] = self.update_series p['modify_css'] = self.modify_css p['support_newer_firmware'] = self.support_newer_firmware p['debugging_title'] = self.debugging_title p['driver_version'] = '.'.join([unicode(i) for i in self.device.version]) return p
def upload_book_cover(self, connection, book, source_id): debug_print('PRST1: Uploading/Refreshing Cover for ' + book.title) if (not book.thumbnail or isinstance(book.thumbnail, ImageWrapper) or not book.thumbnail[-1]): # If the thumbnail is an ImageWrapper instance, it refers to a book # not in the calibre library return cursor = connection.cursor() thumbnail_path = THUMBPATH%book.bookId prefix = self._main_prefix if source_id == 0 else self._card_a_prefix thumbnail_file_path = os.path.join(prefix, *thumbnail_path.split('/')) thumbnail_dir_path = os.path.dirname(thumbnail_file_path) if not os.path.exists(thumbnail_dir_path): os.makedirs(thumbnail_dir_path) with lopen(thumbnail_file_path, 'wb') as f: f.write(book.thumbnail[-1]) fsync(f) query = 'UPDATE books SET thumbnail = ? WHERE _id = ?' t = (thumbnail_path, book.bookId,) cursor.execute(query, t) connection.commit() cursor.close()
def upload_book_cover(self, connection, book, source_id): debug_print('PRST1: Uploading/Refreshing Cover for ' + book.title) if (not book.thumbnail or isinstance(book.thumbnail, ImageWrapper) or not book.thumbnail[-1]): # If the thumbnail is an ImageWrapper instance, it refers to a book # not in the calibre library return cursor = connection.cursor() thumbnail_path = THUMBPATH%book.bookId prefix = self._main_prefix if source_id is 0 else self._card_a_prefix thumbnail_file_path = os.path.join(prefix, *thumbnail_path.split('/')) thumbnail_dir_path = os.path.dirname(thumbnail_file_path) if not os.path.exists(thumbnail_dir_path): os.makedirs(thumbnail_dir_path) with open(thumbnail_file_path, 'wb') as f: f.write(book.thumbnail[-1]) query = 'UPDATE books SET thumbnail = ? WHERE _id = ?' t = (thumbnail_path, book.bookId,) cursor.execute(query, t) connection.commit() cursor.close()
def __log(self, msg=None): ''' The real method ''' if msg: debug_print(" {0}".format(str(msg))) else: debug_print()
def prune_empty_playlists(self): for i, root in self.record_roots.items(): self.purge_broken_playlist_items(root) for playlist in root.xpath('//*[local-name()="playlist"]'): if len(playlist) == 0 or not playlist.get("title", None): if DEBUG: debug_print("Removing playlist id:", playlist.get("id", None), playlist.get("title", None)) playlist.getparent().remove(playlist)
def remap_playlist_references(root, idmap): for playlist in root.xpath('//*[local-name()="playlist"]'): for item in playlist.xpath('descendant::*[@id and local-name()="item"]'): id_ = item.get("id") if id_ in idmap: item.set("id", idmap[id_]) if DEBUG: debug_print("Remapping id %s to %s" % (id_, idmap[id_]))
def update(self, booklists, collections_attributes, plugboard): debug_print('Starting update', collections_attributes) use_tz_var = False for i, booklist in booklists.items(): playlist_map = self.build_id_playlist_map(i) debug_print('Updating XML Cache:', i) root = self.record_roots[i] lpath_map = self.build_lpath_map(root) ext_root = self.ext_roots[i] if i in self.ext_roots else None ext_lpath_map = None if ext_root is not None: ext_lpath_map = self.build_lpath_map(ext_root) gtz_count = ltz_count = 0 use_tz_var = False for book in booklist: path = os.path.join(self.prefixes[i], *(book.lpath.split('/'))) record = lpath_map.get(book.lpath, None) created = False if record is None: created = True record = self.create_text_record(root, i, book.lpath) if plugboard is not None: newmi = book.deepcopy_metadata() newmi.template_to_attribute(book, plugboard) newmi.set('_new_book', getattr(book, '_new_book', False)) book.set('_pb_title_sort', newmi.get('title_sort', newmi.get('title', None))) book.set('_pb_author_sort', newmi.get('author_sort', '')) else: newmi = book (gtz_count, ltz_count, use_tz_var) = \ self.update_text_record(record, newmi, path, i, gtz_count, ltz_count, use_tz_var) # Ensure the collections in the XML database are recorded for # this book if book.device_collections is None: book.device_collections = [] book.device_collections = playlist_map.get(book.lpath, []) if created and ext_root is not None and \ ext_lpath_map.get(book.lpath, None) is None: ext_record = self.create_ext_text_record(ext_root, i, book.lpath, book.thumbnail) self.periodicalize_book(book, ext_record) debug_print('Timezone votes: %d GMT, %d LTZ, use_tz_var=%s'% (gtz_count, ltz_count, use_tz_var)) self.update_playlists(i, root, booklist, collections_attributes) # Update the device collections because update playlist could have added # some new ones. debug_print('In update/ Starting refresh of device_collections') for i, booklist in booklists.items(): playlist_map = self.build_id_playlist_map(i) for book in booklist: book.device_collections = playlist_map.get(book.lpath, []) self.fix_ids() debug_print('Finished update')
def remap_playlist_references(root, idmap): for playlist in root.xpath('//*[local-name()="playlist"]'): for item in playlist.xpath( 'descendant::*[@id and local-name()="item"]'): id_ = item.get('id') if id_ in idmap: item.set('id', idmap[id_]) if DEBUG: debug_print('Remapping id %s to %s'%(id_, idmap[id_]))
def prune_empty_playlists(self): for i, root in self.record_roots.items(): self.purge_broken_playlist_items(root) for playlist in root.xpath('//*[local-name()="playlist"]'): if len(playlist) == 0 or not playlist.get('title', None): if DEBUG: debug_print('Removing playlist id:', playlist.get('id', None), playlist.get('title', None)) playlist.getparent().remove(playlist)
def rebuild_collections(self, booklist, oncard): debug_print('PRS505: started rebuild_collections on card', oncard) c = self.initialize_XML_cache() c.rebuild_collections(booklist, { 'carda': 1, 'cardb': 2 }.get(oncard, 0)) c.write() debug_print('PRS505: finished rebuild_collections')
def remove_orphaned_records(self, connection, dbpath): from sqlite3 import DatabaseError try: cursor = connection.cursor() debug_print("Removing Orphaned Collection Records") # Purge any collections references that point into the abyss query = "DELETE FROM collections WHERE content_id NOT IN (SELECT _id FROM books)" cursor.execute(query) query = "DELETE FROM collections WHERE collection_id NOT IN (SELECT _id FROM collection)" cursor.execute(query) debug_print("Removing Orphaned Book Records") # Purge any references to books not in this database # Idea is to prevent any spill-over where these wind up applying to some other book query = "DELETE FROM %s WHERE content_id NOT IN (SELECT _id FROM books)" cursor.execute(query % "annotation") cursor.execute(query % "bookmark") cursor.execute(query % "current_position") cursor.execute(query % "freehand") cursor.execute(query % "history") cursor.execute(query % "layout_cache") cursor.execute(query % "preference") cursor.close() except DatabaseError: import traceback tb = traceback.format_exc() raise DeviceError( ( ( "The SONY database is corrupted. " " Delete the file %s on your reader and then disconnect " " reconnect it. If you are using an SD card, you " " should delete the file on the card as well. Note that " " deleting this file will cause your reader to forget " " any notes/highlights, etc." ) % dbpath ) + " Underlying error:" "\n" + tb ) def get_lastrowid(self, cursor): # SQLite3 + Python has a fun issue on 32-bit systems with integer overflows. # Issue a SQL query instead, getting the value as a string, and then converting to a long python int manually. query = "SELECT last_insert_rowid()" cursor.execute(query) row = cursor.fetchone() return long(row[0])
def save_settings(cls, config_widget): try: config_widget = config_widget.widget() debug_print( "KoboTouchExtended:save_settings: Have old style configuration.") except: debug_print( "KoboTouchExtended:save_settings: Have new style configuration.") super(KOBOTOUCHEXTENDED, cls).save_settings(config_widget)
def settings(cls): opts = super(KOBOTOUCHEXTENDED, cls).settings() debug_print("KoboTouchExtended:settings: settings=", opts) # Make sure that each option is actually the right type for idx in range(0, len(cls.EXTRA_CUSTOMIZATION_DEFAULT)): if not isinstance(opts.extra_customization[idx], type(cls.EXTRA_CUSTOMIZATION_DEFAULT[idx])): opts.extra_customization[ idx] = cls.EXTRA_CUSTOMIZATION_DEFAULT[idx] return opts
def commit(self): debug_print("TabbedDeviceConfig::commit: start") p = self.device._configProxy() p['format_map'] = self.formats.format_map p['use_subdirs'] = self.use_subdirs() p['read_metadata'] = self.read_metadata() p['save_template'] = self.template.template p['extra_customization'] = self.extra_tab.extra_customization() return p
def _log(self, msg=None): ''' Print msg to console ''' if not self.verbose: return if msg: debug_print(" %s" % msg) else: debug_print()
def filename_callback(self, path, mi): opts = self.settings() if opts.extra_customization[self.OPT_EXTRA_FEATURES]: debug_print("KoboTouchExtended:filename_callback:Path - {0}".format(path)) if path.endswith(KEPUB_EXT): path += EPUB_EXT elif path.endswith(EPUB_EXT) and mi.uuid not in self.skip_renaming_files: path = path[:-len(EPUB_EXT)] + KEPUB_EXT + EPUB_EXT debug_print("KoboTouchExtended:filename_callback:New path - {0}".format(path)) return path
def _log(self, msg=None): ''' Print msg to console ''' if not plugin_prefs.get('cfg_plugin_debug_log_checkbox', False): return if msg: debug_print(" %s" % str(msg)) else: debug_print()
def _log(self, msg=None): ''' Print msg to console ''' from calibre_plugins.annotations.config import plugin_prefs if not plugin_prefs.get('cfg_plugin_debug_log_checkbox', False): return if msg: debug_print(" %s" % str(msg)) else: debug_print()
def _log(self, msg=None): ''' Print msg to console ''' from calibre_plugins.marvin_manager.config import plugin_prefs if not plugin_prefs.get('debug_plugin', False): return if msg: debug_print(" %s" % str(msg)) else: debug_print()
def save_settings(cls, config_widget): try: config_widget = config_widget.widget() debug_print( "KoboTouchExtended:save_settings: Have old style configuration." ) except: debug_print( "KoboTouchExtended:save_settings: Have new style configuration." ) super(KOBOTOUCHEXTENDED, cls).save_settings(config_widget)
def filename_callback(self, path, mi): opts = self.settings() if opts.extra_customization[self.OPT_EXTRA_FEATURES]: debug_print("KoboTouchExtended:filename_callback:Path - {0}".format(path)) idx = path.rfind('.') ext = path[idx:] if ext == KEPUB_EXT or (ext == EPUB_EXT and mi.uuid not in self.skip_renaming_files): path = "{0}.kepub{1}".format(path[:idx], EPUB_EXT) debug_print("KoboTouchExtended:filename_callback:New path - {0}".format(path)) return path
def _log(msg=None): ''' Print msg to console ''' from calibre_plugins.annotations.config import plugin_prefs if not plugin_prefs.get('cfg_plugin_debug_log_checkbox', False): return if msg: debug_print(" %s" % str(msg)) else: debug_print()
def upload_books(self, files, names, on_card = None, end_session = True, metadata = None): opts = self.settings() if opts.extra_customization[self.OPT_EXTRA_FEATURES]: debug_print("KoboTouchExtended:upload_books:Enabling extra ePub features for Kobo devices") for file in files: ext = file[file.rfind('.'):] if ext == EPUB_EXT: self._modify_epub(file) result = super(KOBOTOUCHEXTENDED, self).upload_books(files, names, on_card, end_session, metadata) return result
def filename_callback(self, path, mi): opts = self.settings() if opts.extra_customization[self.OPT_EXTRA_FEATURES]: debug_print("KoboTouchExtended:filename_callback:Path - {0}".format(path)) idx = path.rfind('.') ext = path[idx:] if ext == EPUB_EXT: path = "{0}.kepub{1}".format(path[:idx], EPUB_EXT) debug_print("KoboTouchExtended:filename_callback:New path - {0}".format(path)) return path
def _log(self, msg=None): """ Print msg to console """ from calibre_plugins.marvin_manager.config import plugin_prefs if not plugin_prefs.get("debug_plugin", False): return if msg: debug_print(" %s" % str(msg)) else: debug_print()
def __log_location(self, *args): ''' The real method ''' arg1 = arg2 = '' if len(args) > 0: arg1 = str(args[0]) if len(args) > 1: arg2 = str(args[1]) debug_print(self.LOCATION_TEMPLATE.format(cls=self.__class__.__name__, func=sys._getframe(1).f_code.co_name, arg1=arg1, arg2=arg2))
def ensure_numeric_ids(root): idmap = {} for x in root.xpath('child::*[@id]'): id_ = x.get('id') try: id_ = int(id_) except: x.set('id', '-1') idmap[id_] = '-1' if DEBUG and idmap: debug_print('Found non numeric ids:') debug_print(list(idmap.keys())) return idmap
def upload_cover(self, path, filename, metadata, filepath): import sqlite3 as sqlite debug_print('PRS-T1: uploading cover') if filepath.startswith(self._main_prefix): prefix = self._main_prefix source_id = 0 else: prefix = self._card_a_prefix source_id = 1 metadata.lpath = filepath.partition(prefix)[2] metadata.lpath = metadata.lpath.replace('\\', '/') dbpath = self.normalize_path(prefix + DBPATH) debug_print("SQLite DB Path: " + dbpath) with closing(sqlite.connect(dbpath)) as connection: cursor = connection.cursor() query = 'SELECT _id FROM books WHERE file_path = ?' t = (metadata.lpath,) cursor.execute(query, t) for i, row in enumerate(cursor): metadata.bookId = row[0] cursor.close() if getattr(metadata, 'bookId', None) is not None: debug_print('PRS-T1: refreshing cover for book being sent') self.upload_book_cover(connection, metadata, source_id) debug_print('PRS-T1: done uploading cover')
def update_device_database(self, booklist, collections_attributes, oncard): import sqlite3 as sqlite debug_print('PRST1: starting update_device_database') plugboard = None if self.plugboard_func: plugboard = self.plugboard_func(self.__class__.__name__, 'device_db', self.plugboards) debug_print("PRST1: Using Plugboard", plugboard) prefix = self._card_a_prefix if oncard == 'carda' else self._main_prefix if prefix is None: # Reader has no sd card inserted return source_id = 1 if oncard == 'carda' else 0 dbpath = self.normalize_path(prefix + DBPATH) debug_print("SQLite DB Path: " + dbpath) collections = booklist.get_collections(collections_attributes) with closing(sqlite.connect(dbpath)) as connection: self.remove_orphaned_records(connection, dbpath) self.update_device_books(connection, booklist, source_id, plugboard, dbpath) self.update_device_collections(connection, booklist, collections, source_id, dbpath) debug_print('PRST1: finished update_device_database')
def ensure_numeric_ids(root): idmap = {} for x in root.xpath("child::*[@id]"): id_ = x.get("id") try: id_ = int(id_) except: x.set("id", "-1") idmap[id_] = "-1" if DEBUG and idmap: debug_print("Found non numeric ids:") debug_print(list(idmap.keys())) return idmap
def convert_kobo_date(kobo_date): """ KoBo stores dates as a timestamp string. The exact format has changed with firmware and what part of the firmware writes it. The following is overkill, but it handles all the formats I have seen. """ from calibre.utils.date import utc_tz, local_tz from calibre.devices.usbms.driver import debug_print # debug_print("convert_kobo_date - start - kobo_date={0}'".format(kobo_date)) try: converted_date = datetime.datetime.strptime(kobo_date, "%Y-%m-%dT%H:%M:%S+00:00") # debug_print("convert_kobo_date - '%Y-%m-%dT%H:%M:%S+00:00' - kobo_date=%s' - kobo_date={0}'".format(kobo_date)) except Exception as e: # debug_print("convert_kobo_date - exception={0}'".format(e)) try: converted_date = datetime.datetime.strptime( kobo_date, "%Y-%m-%dT%H:%M:%SZ") # debug_print("convert_kobo_date - '%Y-%m-%dT%H:%M:%SZ' - kobo_date={0}'".format(kobo_date)) except: try: converted_date = datetime.datetime.strptime( kobo_date[0:19], "%Y-%m-%dT%H:%M:%S") # debug_print("convert_kobo_date - '%Y-%m-%dT%H:%M:%S' - kobo_date={0}'".format(kobo_date)) except: try: converted_date = datetime.datetime.strptime( kobo_date.split('+')[0], "%Y-%m-%dT%H:%M:%S") # debug_print("convert_kobo_date - '%Y-%m-%dT%H:%M:%S' - kobo_date={0}'".format(kobo_date)) except: try: converted_date = datetime.datetime.strptime( kobo_date.split('+')[0], "%Y-%m-%d") # converted_date = converted_date.replace(tzinfo=utc_tz) # debug_print("convert_kobo_date - '%Y-%m-%d' - kobo_date={0}'".format(kobo_date)) except: try: from calibre.utils.date import parse_date converted_date = parse_date( kobo_date) #, assume_utc=True) # debug_print("convert_kobo_date - parse_date - kobo_date={0}'".format(kobo_date)) except: converted_date = time.gmtime() debug_print( "convert_kobo_date - could not convert, using current time - kobo_date={0}'" .format(kobo_date)) converted_date = converted_date.replace(tzinfo=utc_tz).astimezone(local_tz) return converted_date
def upload_books(self, files, names, on_card = None, end_session = True, metadata = None): opts = self.settings() skip_failed = opts.extra_customization[self.OPT_SKIP_FAILED] new_files = [] new_names = [] new_metadata = [] errors = [] if opts.extra_customization[self.OPT_EXTRA_FEATURES]: debug_print("KoboTouchExtended:upload_books:Enabling extra ePub features for Kobo devices") i = 0 for file, n, mi in zip(files, names, metadata): self.report_progress(i / float(len(files)), "Processing book: {0} by {1}".format(mi.title, " and ".join(mi.authors))) ext = file[file.rfind('.'):] if ext == EPUB_EXT: try: self._modify_epub(file, mi) except Exception as e: (exc_type, exc_obj, exc_tb) = sys.exc_info() while exc_tb.tb_next and 'kobotouch_extended' in exc_tb.tb_next.tb_frame.f_code.co_filename: exc_tb = exc_tb.tb_next fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] if not skip_failed: raise InvalidEPub(mi.title, " and ".join(mi.authors), e.message, fname = fname, lineno = exc_tb.tb_lineno) else: errors.append("Failed to upload {0} with error: {1}".format("'{0}' by '{1}'".format(mi.title, " and ".join(mi.authors)), e.message)) if mi.uuid not in self.skip_renaming_files: self.skip_renaming_files.append(mi.uuid) debug_print("Failed to process {0} by {1} with error: {2} (file: {3}, lineno: {4})".format(mi.title, " and ".join(mi.authors), e.message, fname, exc_tb.tb_lineno)) else: new_files.append(file) new_names.append(n) new_metadata.append(mi) else: new_files.append(file) new_names.append(n) new_metadata.append(mi) i += 1 else: new_files = files new_names = names new_metadata = metadata if metadata and new_metadata and len(metadata) != len(new_metadata) and len(new_metadata) > 0: print("The following books could not be processed and will not be uploaded to your device:") print("\n".join(errors)) self.report_progress(0, 'Working...') result = super(KOBOTOUCHEXTENDED, self).upload_books(new_files, new_names, on_card, end_session, new_metadata) return result
def filename_callback(self, path, mi): if self.extra_features: debug_print( "KoboTouchExtended:filename_callback:Path - {0}".format(path)) if path.endswith(KEPUB_EXT): path += EPUB_EXT elif path.endswith( EPUB_EXT) and mi.uuid not in self.skip_renaming_files: path = path[:-len(EPUB_EXT)] + KEPUB_EXT + EPUB_EXT debug_print( "KoboTouchExtended:filename_callback:New path - {0}".format( path)) return path
def __init__(self, prefix, lpath, title=None, authors=None, mime=None, date=None, ContentType=None, thumbnail_name=None, size=None, other=None): from calibre.utils.date import parse_date # debug_print('Book::__init__ - title=', title) show_debug = title is not None and title.lower().find("xxxxx") >= 0 if other is not None: other.title = title other.published_date = date if show_debug: debug_print("Book::__init__ - title=", title, 'authors=', authors) debug_print("Book::__init__ - other=", other) super(Book, self).__init__(prefix, lpath, size, other) if title is not None and len(title) > 0: self.title = title if authors is not None and len(authors) > 0: self.authors_from_string(authors) if self.author_sort is None or self.author_sort == "Unknown": self.author_sort = author_to_author_sort(authors) self.mime = mime self.size = size # will be set later if None if ContentType == '6' and date is not None: try: self.datetime = time.strptime(date, "%Y-%m-%dT%H:%M:%S.%f") except: try: self.datetime = time.strptime(date.split('+')[0], "%Y-%m-%dT%H:%M:%S") except: try: self.datetime = time.strptime(date.split('+')[0], "%Y-%m-%d") except: try: self.datetime = parse_date(date, assume_utc=True).timetuple() except: try: self.datetime = time.gmtime(os.path.getctime(self.path)) except: self.datetime = time.gmtime() self.kobo_metadata = Metadata(title, self.authors) self.contentID = None self.current_shelves = [] self.kobo_collections = [] self.can_put_on_shelves = True 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_id = None self.kobo_subtitle = None if thumbnail_name is not None: self.thumbnail = ImageWrapper(thumbnail_name) if show_debug: debug_print("Book::__init__ end - self=", self) debug_print("Book::__init__ end - title=", title, 'authors=', authors)
def remove_orphaned_records(self, connection, dbpath): from sqlite3 import DatabaseError try: cursor = connection.cursor() debug_print("Removing Orphaned Collection Records") # Purge any collections references that point into the abyss query = 'DELETE FROM collections WHERE content_id NOT IN (SELECT _id FROM books)' cursor.execute(query) query = 'DELETE FROM collections WHERE collection_id NOT IN (SELECT _id FROM collection)' cursor.execute(query) debug_print("Removing Orphaned Book Records") # Purge any references to books not in this database # Idea is to prevent any spill-over where these wind up applying to some other book query = 'DELETE FROM %s WHERE content_id NOT IN (SELECT _id FROM books)' cursor.execute(query % 'annotation') cursor.execute(query % 'bookmark') cursor.execute(query % 'current_position') cursor.execute(query % 'freehand') cursor.execute(query % 'history') cursor.execute(query % 'layout_cache') cursor.execute(query % 'preference') cursor.close() except DatabaseError: import traceback tb = traceback.format_exc() raise DeviceError(( ('The SONY database is corrupted. ' ' Delete the file %s on your reader and then disconnect ' ' reconnect it. If you are using an SD card, you ' ' should delete the file on the card as well. Note that ' ' deleting this file will cause your reader to forget ' ' any notes/highlights, etc.') % dbpath) + ' Underlying error:' '\n' + tb) def get_lastrowid(self, cursor): # SQLite3 + Python has a fun issue on 32-bit systems with integer overflows. # Issue a SQL query instead, getting the value as a string, and then converting to a long python int manually. query = 'SELECT last_insert_rowid()' cursor.execute(query) row = cursor.fetchone() return long(row[0])
def upload_books(self, files, names, on_card=None, end_session=True, metadata=None): opts = self.settings() if opts.extra_customization[self.OPT_MODIFY_CSS]: debug_print( "KoboTouchExtended:upload_books:Searching for device-specific CSS file" ) device_css_file_name = self.KOBO_EXTRA_CSSFILE if self.isAuraHD(): device_css_file_name = 'kobo_extra_AURAHD.css' elif self.isAura(): device_css_file_name = 'kobo_extra_AURA.css' elif self.isGlo(): device_css_file_name = 'kobo_extra_GLO.css' elif self.isMini(): device_css_file_name = 'kobo_extra_MINI.css' elif self.isTouch(): device_css_file_name = 'kobo_extra_TOUCH.css' device_css_file_name = os.path.join(self.configdir, device_css_file_name) if os.path.isfile(device_css_file_name): debug_print( "KoboTouchExtended:upload_books:Found device-specific file {0}" .format(device_css_file_name)) shutil.copy( device_css_file_name, os.path.join(self._main_prefix, self.KOBO_EXTRA_CSSFILE)) else: debug_print( "KoboTouchExtended:upload_books:No device-specific CSS file found (expecting {0})" .format(device_css_file_name)) kobo_config_file = os.path.join(self._main_prefix, '.kobo', 'Kobo', 'Kobo eReader.conf') if os.path.isfile(kobo_config_file): cfg = SafeConfigParser(allow_no_value=True) cfg.optionxform = str cfg.read(kobo_config_file) if not cfg.has_section("FeatureSettings"): cfg.add_section("FeatureSettings") debug_print( "KoboTouchExtended:upload_books:Setting FeatureSettings.FullBookPageNumbers to {0}" .format("true" if opts.extra_customization[ self.OPT_FULL_PAGE_NUMBERS] else "false")) cfg.set( "FeatureSettings", "FullBookPageNumbers", "true" if opts.extra_customization[self.OPT_FULL_PAGE_NUMBERS] else "false") with open(kobo_config_file, 'wb') as cfgfile: cfg.write(cfgfile) return super(KOBOTOUCHEXTENDED, self).upload_books(files, names, on_card, end_session, metadata)