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
Example #5
0
    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
Example #6
0
    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, 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 _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 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