def write_metadata_cache(self, storage, bl): from calibre.devices.mtp.books import JSONCodec if bl.storage_id != storage.storage_id: # Just a sanity check, should never happen return json_codec = JSONCodec() stream = SpooledTemporaryFile(10*(1024**2)) json_codec.encode_to_file(stream, bl) size = stream.tell() stream.seek(0) self.put_calibre_file(storage, 'metadata', stream, size)
def books(self, oncard=None, end_session=True): from calibre.devices.mtp.books import JSONCodec from calibre.devices.mtp.books import BookList, Book self.report_progress(0, _('Listing files, this can take a while')) self.get_driveinfo() # Ensure driveinfo is loaded sid = {'carda':self._carda_id, 'cardb':self._cardb_id}.get(oncard, self._main_id) if sid is None: return BookList(None) bl = BookList(sid) # If True then there is a mismatch between the ebooks on the device and # the metadata cache need_sync = False all_books = list(self.filesystem_cache.iterebooks(sid)) steps = len(all_books) + 2 count = 0 self.report_progress(0, _('Reading e-book metadata')) # Read the cache if it exists storage = self.filesystem_cache.storage(sid) cache = storage.find_path(self.calibre_file_paths['metadata'].split('/')) if cache is not None: json_codec = JSONCodec() try: stream = self.get_mtp_file(cache) json_codec.decode_from_file(stream, bl, Book, sid) except: need_sync = True relpath_cache = {b.mtp_relpath:i for i, b in enumerate(bl)} for mtp_file in all_books: count += 1 relpath = mtp_file.mtp_relpath idx = relpath_cache.get(relpath, None) if idx is not None: cached_metadata = bl[idx] del relpath_cache[relpath] if cached_metadata.size == mtp_file.size: cached_metadata.datetime = mtp_file.last_modified.timetuple() cached_metadata.path = mtp_file.mtp_id_path debug('Using cached metadata for', '/'.join(mtp_file.full_path)) continue # No need to update metadata book = cached_metadata else: book = Book(sid, '/'.join(relpath)) bl.append(book) need_sync = True self.report_progress(count/steps, _('Reading metadata from %s')% ('/'.join(relpath))) try: book.smart_update(self.read_file_metadata(mtp_file)) debug('Read metadata for', '/'.join(mtp_file.full_path)) except: prints('Failed to read metadata from', '/'.join(mtp_file.full_path)) traceback.print_exc() book.size = mtp_file.size book.datetime = mtp_file.last_modified.timetuple() book.path = mtp_file.mtp_id_path # Remove books in the cache that no longer exist for idx in sorted(relpath_cache.itervalues(), reverse=True): del bl[idx] need_sync = True if need_sync: self.report_progress(count/steps, _('Updating metadata cache on device')) self.write_metadata_cache(storage, bl) self.report_progress(1, _('Finished reading metadata from device')) return bl