コード例 #1
0
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