def _get_metadata(self, book, pdf_stats): ''' Return a populated Book object with available metadata ''' from calibre.ebooks.metadata import author_to_author_sort, authors_to_string, title_sort from calibre.ebooks.metadata.pdf import get_metadata self._log_location(repr(book)) pdf_path = os.path.join(self.temp_dir, pdf_stats['path']) with open(pdf_path, 'rb') as f: stream = cStringIO.StringIO(f.read()) mi = get_metadata(stream, cover=False) this_book = Book(mi.title, authors=mi.authors) this_book.author_sort = author_to_author_sort(mi.authors[0]) this_book.datetime = datetime.fromtimestamp( int(pdf_stats['stats']['st_birthtime'])).timetuple() this_book.dateadded = int(pdf_stats['stats']['st_birthtime']) this_book.path = book this_book.size = int(pdf_stats['stats']['st_size']) this_book.thumbnail = self._get_goodreader_thumb(book) if this_book.thumbnail: this_book.thumb_data = base64.b64encode(this_book.thumbnail) else: this_book.thumb_data = None this_book.title_sort = title_sort(mi.title) this_book.uuid = None return this_book
def _create_new_book(self, fpath, metadata, thumb): ''' ''' from calibre.ebooks.metadata import authors_to_string self._log_location(metadata.title) format = fpath.rpartition('.')[2].lower() this_book = Book(metadata.title, '; '.join(metadata.authors)) this_book.author_sort = metadata.author_sort this_book.dateadded = time.mktime(time.gmtime()) this_book.datetime = datetime.fromtimestamp( this_book.dateadded).timetuple() this_book.path = self.path_template.format(metadata.title, metadata.authors[0], format) this_book.size = os.path.getsize(fpath) this_book.thumbnail = self._cover_to_thumb(metadata) this_book.thumb_data = base64.b64encode(this_book.thumbnail) this_book.title_sort = metadata.title_sort this_book.uuid = metadata.uuid if False: self._log("%s by %s" % (this_book.title, '; '.join(this_book.authors))) self._log("path: %s" % this_book.path) self._log("author_sort: %s" % this_book.author_sort) self._log("title_sort: %s" % this_book.title_sort) return this_book
def _get_metadata(self, book, pdf_stats): """ Return a populated Book object with available metadata """ from calibre.ebooks.metadata import author_to_author_sort, authors_to_string, title_sort from calibre.ebooks.metadata.pdf import get_metadata self._log_location(repr(book)) pdf_path = os.path.join(self.temp_dir, pdf_stats["path"]) with open(pdf_path, "rb") as f: stream = cStringIO.StringIO(f.read()) mi = get_metadata(stream, cover=False) this_book = Book(mi.title, " & ".join(mi.authors)) this_book.author_sort = author_to_author_sort(mi.authors[0]) this_book.datetime = datetime.fromtimestamp(int(pdf_stats["stats"]["st_birthtime"])).timetuple() this_book.dateadded = int(pdf_stats["stats"]["st_birthtime"]) this_book.path = book this_book.size = int(pdf_stats["stats"]["st_size"]) this_book.thumbnail = self._get_goodreader_thumb(book) if this_book.thumbnail: this_book.thumb_data = base64.b64encode(this_book.thumbnail) else: this_book.thumb_data = None this_book.title_sort = title_sort(mi.title) this_book.uuid = None return this_book
def _get_metadata(self, book, book_stats): ''' Return a populated Book object with available metadata ''' from calibre.ebooks.metadata import author_to_author_sort, authors_to_string, title_sort self._log_location(repr(book)) format = book.rsplit('.')[1].lower() if format == 'mobi': from calibre.ebooks.metadata.mobi import get_metadata as get_mobi_metadata path = os.path.join(self.temp_dir, book_stats['path']) with open(path, 'rb') as f: stream = cStringIO.StringIO(f.read()) mi = get_mobi_metadata(stream) elif format == 'pdf': from calibre.ebooks.metadata.pdf import get_metadata as get_pdf_metadata path = os.path.join(self.temp_dir, book_stats['path']) with open(path, 'rb') as f: stream = cStringIO.StringIO(f.read()) mi = get_pdf_metadata(stream) else: self._log("unsupported format: '{}'".format(format)) return Book() if False: ''' Perform a bit of voodoo to match Kindle multiple author style ''' ks_authors = [] for a in mi.authors: if "," in a: # Already ln, fn ks_authors.append(a) else: ks_authors.append(author_to_author_sort(a)) this_book = Book(mi.title, '; '.join(mi.authors)) this_book.author_sort = '; '.join(mi.authors) this_book.datetime = datetime.fromtimestamp( int(book_stats['stats']['st_birthtime'])).timetuple() this_book.dateadded = int(book_stats['stats']['st_birthtime']) this_book.path = book this_book.size = int(book_stats['stats']['st_size']) this_book.thumbnail = self._get_kindle_thumb(mi.cover_data[1]) if this_book.thumbnail: this_book.thumb_data = base64.b64encode(this_book.thumbnail) else: this_book.thumb_data = None this_book.title_sort = title_sort(mi.title) this_book.uuid = None return this_book
def _get_metadata(self, book, book_stats): ''' Return a populated Book object with available metadata ''' from calibre.ebooks.metadata import author_to_author_sort, authors_to_string, title_sort self._log_location(repr(book)) format = book.rsplit('.')[1].lower() if format == 'mobi': from calibre.ebooks.metadata.mobi import get_metadata as get_mobi_metadata path = os.path.join(self.temp_dir, book_stats['path']) with open(path, 'rb') as f: stream = cStringIO.StringIO(f.read()) mi = get_mobi_metadata(stream) elif format == 'pdf': from calibre.ebooks.metadata.pdf import get_metadata as get_pdf_metadata path = os.path.join(self.temp_dir, book_stats['path']) with open(path, 'rb') as f: stream = cStringIO.StringIO(f.read()) mi = get_pdf_metadata(stream) else: self._log("unsupported format: '{}'".format(format)) return Book() if False: ''' Perform a bit of voodoo to match Kindle multiple author style ''' ks_authors = [] for a in mi.authors: if "," in a: # Already ln, fn ks_authors.append(a) else: ks_authors.append(author_to_author_sort(a)) this_book = Book(mi.title, '; '.join(mi.authors)) this_book.author_sort = '; '.join(mi.authors) this_book.datetime = datetime.fromtimestamp(int(book_stats['stats']['st_birthtime'])).timetuple() this_book.dateadded = int(book_stats['stats']['st_birthtime']) this_book.path = book this_book.size = int(book_stats['stats']['st_size']) this_book.thumbnail = self._get_kindle_thumb(mi.cover_data[1]) if this_book.thumbnail: this_book.thumb_data = base64.b64encode(this_book.thumbnail) else: this_book.thumb_data = None this_book.title_sort = title_sort(mi.title) this_book.uuid = None return this_book
def _get_cached_metadata(self, cur, book): ''' Return a populated Book object from a cached book's metadata ''' self._log_location(book) cur.execute(''' SELECT authors, author_sort, dateadded, filename, size, thumb_data, title, title_sort, uuid FROM metadata WHERE filename={0} '''.format(self._quote_sqlite_identifier(book))) cached_book = cur.fetchone() if cached_book: #self._log(cached_book.keys()) #self._log(repr(cached_book[b'authors'])) #self._log(authors_to_string(cached_book[b'authors'].split(' & '))) this_book = Book(cached_book[b'title'], authors=cached_book[b'authors'].split(' & ')) this_book.author_sort = cached_book[b'author_sort'] this_book.datetime = datetime.fromtimestamp( cached_book[b'dateadded']).timetuple() this_book.path = cached_book[b'filename'] this_book.size = cached_book[b'size'] if cached_book[b'thumb_data']: this_book.thumbnail = base64.b64decode( cached_book[b'thumb_data']) else: this_book.thumbnail = None this_book.title_sort = cached_book[b'title_sort'] this_book.uuid = cached_book[b'uuid'] return this_book else: self._log("***Error: unable to find '%s' in db" % book) return None
def _get_cached_metadata(self, cur, book): """ Return a populated Book object from a cached book's metadata format(json.dumps(book))) """ self._log_location(book) cur.execute( """ SELECT authors, author_sort, dateadded, filename, size, thumb_data, title, title_sort, uuid FROM metadata WHERE filename=? """, (book,), ) cached_book = cur.fetchone() if cached_book: # self._log(cached_book.keys()) this_book = Book(cached_book[b"title"], cached_book[b"authors"]) this_book.author_sort = cached_book[b"author_sort"] this_book.datetime = datetime.fromtimestamp(cached_book[b"dateadded"]).timetuple() this_book.path = cached_book[b"filename"] this_book.size = cached_book[b"size"] if cached_book[b"thumb_data"]: this_book.thumbnail = base64.b64decode(cached_book[b"thumb_data"]) else: this_book.thumbnail = None this_book.title_sort = cached_book[b"title_sort"] this_book.uuid = cached_book[b"uuid"] return this_book else: self._log("***Error: unable to find '%s' in db" % book) return None
def _get_cached_metadata(self, cur, book): ''' Return a populated Book object from a cached book's metadata ''' self._log_location(book) cur.execute(''' SELECT authors, author_sort, dateadded, filename, size, thumb_data, title, title_sort, uuid FROM metadata WHERE filename={0} '''.format(self._quote_sqlite_identifier(book)) ) cached_book = cur.fetchone() if cached_book: #self._log(cached_book.keys()) #self._log(repr(cached_book[b'authors'])) #self._log(authors_to_string(cached_book[b'authors'].split(' & '))) this_book = Book(cached_book[b'title'], authors=cached_book[b'authors'].split(' & ')) this_book.author_sort = cached_book[b'author_sort'] this_book.datetime = datetime.fromtimestamp(cached_book[b'dateadded']).timetuple() this_book.path = cached_book[b'filename'] this_book.size = cached_book[b'size'] if cached_book[b'thumb_data']: this_book.thumbnail = base64.b64decode(cached_book[b'thumb_data']) else: this_book.thumbnail = None this_book.title_sort = cached_book[b'title_sort'] this_book.uuid = cached_book[b'uuid'] return this_book else: self._log("***Error: unable to find '%s' in db" % book) return None
def _create_new_book(self, fpath, metadata, thumb): """ """ from calibre.ebooks.metadata import authors_to_string self._log_location(metadata.title) this_book = Book(metadata.title, " & ".join(metadata.authors)) this_book.author_sort = metadata.author_sort this_book.dateadded = time.mktime(time.gmtime()) this_book.datetime = datetime.fromtimestamp(this_book.dateadded).timetuple() this_book.path = self.path_template.format(metadata.title) this_book.size = os.path.getsize(fpath) this_book.thumbnail = self._cover_to_thumb(metadata) this_book.thumb_data = base64.b64encode(this_book.thumbnail) this_book.title_sort = metadata.title_sort this_book.uuid = metadata.uuid if False: self._log("%s by %s" % (this_book.title, " & ".join(this_book.authors))) self._log("path: %s" % this_book.path) self._log("author_sort: %s" % this_book.author_sort) self._log("title_sort: %s" % this_book.title_sort) return this_book
def books(self, oncard=None, end_session=True): ''' Return a list of ebooks on the device. @param oncard: If 'carda' or 'cardb' return a list of ebooks on the specific storage card, otherwise return list of ebooks in main memory of device. If a card is specified and no books are on the card return empty list. @return: A BookList. ''' if oncard: return BookList() self._log_location() booklist = BookList() cached_books = {} # Fetch current assets from Media folder assets_profile = self._localize_database_path(self.assets_subpath) #Fetch current metadata from iBooks's DB db_profile = self._localize_database_path(self.books_subpath) con = sqlite3.connect(db_profile['path']) # Mount the Media folder self.ios.mount_ios_media_folder() # Get Books.plist so we can find the covers books_plist = {} if True: raw_plist = XmlPropertyListParser().parse(self.ios.read('/Books/Sync/Books.plist'))['Books'] for book in raw_plist: if not 'Path' in book: print(" No 'Path' element found for '%s' by '%s'" % (book['Name'], book['Artist'])) #print(book) #print continue if 'Cover Path' in book: books_plist['/'.join(['/Books', book['Path']])] = unicode('/'.join(['/Books', book['Path'], book['Cover Path']])) else: books_plist['/'.join(['/Books', book['Path']])] = unicode('/'.join(['/Books', 'Sync', 'Artwork', book['Persistent ID']])) # Process any outliers raw_plist = XmlPropertyListParser().parse(self.ios.read('/Books/Books.plist'))['Books'] for book in raw_plist: if not 'Path' in book: print(" No 'Path' element found for '%s' by '%s'" % (book['Name'], book['Artist'])) #print(book) #print continue # Don't overwrite existing cover_paths if not '/'.join(['/Books', book['Path']]) in books_plist: if 'Cover Path' in book and not ['/'.join(['/Books', book['Path']])] in book_plist: books_plist['/'.join(['/Books', book['Path']])] = unicode('/'.join(['/Books', book['Path'], book['Cover Path']])) else: books_plist['/'.join(['/Books', book['Path']])] = unicode('/'.join(['/Books', 'Sync', 'Artwork', book['Persistent ID']])) raw_plist = XmlPropertyListParser().parse(self.ios.read('/Books/Purchases/Purchases.plist'))['Books'] for book in raw_plist: if not 'Path' in book: print(" No 'Path' element found for '%s' by '%s'" % (book['Name'], book['Artist'])) print(book) print continue # Don't overwrite existing cover_paths if not '/'.join(['/Books', book['Path']]) in books_plist: if 'Cover Path' in book: books_plist['/'.join(['/Books/Purchases', book['Path']])] = unicode('/'.join(['/Books/Purchases', book['Path'], book['Cover Path']])) else: books_plist['/'.join(['/Books/Purchases', book['Path']])] = unicode('/'.join(['/Books', 'Sync', 'Artwork', book['Persistent ID']])) else: raw_plist = XmlPropertyListParser().parse(self.ios.read('/Books/Books.plist'))['Books'] for book in raw_plist: if not 'Path' in book: print(" No 'Path' element found for '%s' by '%s'" % (book['Name'], book['Artist'])) print(book) print continue if 'Cover Path' in book: books_plist['/'.join(['/Books', book['Path']])] = unicode('/'.join(['/Books', book['Path'], book['Cover Path']])) else: books_plist['/'.join(['/Books', book['Path']])] = unicode('/'.join(['/Books', 'Sync', 'Artwork', book['Persistent ID']])) raw_plist = XmlPropertyListParser().parse(self.ios.read('/Books/Purchases/Purchases.plist'))['Books'] for book in raw_plist: if not 'Path' in book: print(" No 'Path' element found for '%s' by '%s'" % (book['Name'], book['Artist'])) print(book) print continue if 'Cover Path' in book: books_plist['/'.join(['/Books/Purchases', book['Path']])] = unicode('/'.join(['/Books/Purchases', book['Path'], book['Cover Path']])) else: books_plist['/'.join(['/Books/Purchases', book['Path']])] = unicode('/'.join(['/Books', 'Sync', 'Artwork', book['Persistent ID']])) print(books_plist) with con: con.row_factory = sqlite3.Row # Build a collection map collections_map = {} # Get the books cur = con.cursor() #cur.execute("ATTACH DATABASE '{0}' as 'ASSETS'".format(assets_profile['path']) cur.execute('''SELECT ZASSETURL, ZBOOKAUTHOR, ZSORTAUTHOR, ZBOOKTITLE, ZSORTTITLE, ZDATABASEKEY, ZDATEADDED FROM ZBKBOOKINFO WHERE ZASSETURL LIKE 'file://localhost%' AND ZASSETURL LIKE '%.epub/' ''') rows = cur.fetchall() book_count = len(rows) for i, row in enumerate(rows): book_id = row[b'ZDATABASEKEY'] # Get the collection assignments collections = [] # Get the primary metadata this_book = Book(row[b'ZBOOKTITLE'], row[b'ZBOOKAUTHOR']) original_path = row[b'ZASSETURL'] path = original_path[original_path.find('Media/') + len('Media'):-1] this_book.path = path.replace('%20', ' ') timestamp = int(row[b'ZDATEADDED']) + NSTimeIntervalSince1970 this_book.datetime = datetime.fromtimestamp(timestamp).timetuple() this_book.device_collections = collections this_book.uuid = None this_book.thumbnail = self._generate_thumbnail(this_book, books_plist[this_book.path]) # Retrieve folder size from cache or compute and cache try: zfr = ZipFile(self.folder_archive_path) file_size = zfr.read(this_book.path) this_book.size = int(file_size) self._log_diagnostic("returning folder size from cache") except: self._log_diagnostic("opening folder cache for appending") zfw = ZipFile(self.folder_archive_path, mode='a') stats = self.ios.stat(this_book.path) this_book.size = self.ios.get_folder_size(this_book.path) zfw.writestr(this_book.path, str(this_book.size)) zfw.close() finally: zfr.close() booklist.add_book(this_book, False) if self.report_progress is not None: self.report_progress(float((i + 1)*100 / book_count)/100, '%(num)d of %(tot)d' % dict(num=i + 1, tot=book_count)) cached_books[this_book.path] = { 'title': this_book.title, 'author': this_book.author, 'authors': this_book.author.split(' & '), 'uuid': this_book.uuid } cur.close() # Close the connection self.ios.dismount_ios_media_folder() if self.report_progress is not None: self.report_progress(1.0, _('finished')) self.cached_books = cached_books return booklist