'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.
Implementation notes:
iTunes does not sync purchased books, they are only on the device.  They are visible, but
they are not backed up to iTunes.  Since calibre can\'t manage them, don\'t show them in the
list of device books.'

def books(self, oncard=None, end_session=True):

    from calibre.utils.date import parse_date
    if (not oncard):
        if self.verbose:
            logger().info(('%s.books()' % self.__class__.__name__))
            if self.settings().extra_customization[self.CACHE_COVERS]:
                logger().info('    Cover    fetching/caching    enabled')
            else:
                logger().info('    Cover    fetching/caching    disabled')
        booklist = BookList(logger())
        cached_books = {}
        if isosx:
            library_books = self._get_library_books()
            book_count = float(len(library_books))
            for (i, book) in enumerate(library_books):
                format = ('pdf' if library_books[book].kind().startswith('PDF') else 'epub')
                this_book = Book(library_books[book].name(), library_books[book].artist())
                this_book.path = (self.path_template % (library_books[book].name(), library_books[book].artist(), format))
                try:
                    this_book.datetime = parse_date(str(library_books[book].date_added())).timetuple()
                except:
                    this_book.datetime = time.gmtime()
                this_book.device_collections = []
                this_book.library_id = library_books[book]
                this_book.size = library_books[book].size()
                this_book.uuid = library_books[book].composer()
                this_book.cid = None
                if (self.report_progress is not None):
                    this_book.thumbnail = self._generate_thumbnail(this_book.path, library_books[book])
                else:
                    this_book.thumbnail = None
                booklist.add_book(this_book, False)
                cached_books[this_book.path] = {'title': library_books[book].name(), 'author': library_books[book].artist().split('    &    '), 'lib_book': library_books[book], 'dev_book': None, 'uuid': library_books[book].composer(), 'format': format}
                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)))
        elif iswindows:
            import pythoncom, win32com.client
            try:
                pythoncom.CoInitialize()
                self.iTunes = win32com.client.Dispatch('iTunes.Application')
                library_books = self._get_library_books()
                book_count = float(len(library_books))
                for (i, book) in enumerate(library_books):
                    this_book = Book(library_books[book].Name, library_books[book].Artist)
                    format = ('pdf' if library_books[book].KindAsString.startswith('PDF') else 'epub')
                    this_book.path = (self.path_template % (library_books[book].Name, library_books[book].Artist, format))
                    try:
                        this_book.datetime = parse_date(str(library_books[book].DateAdded)).timetuple()
                    except:
                        this_book.datetime = time.gmtime()
                    this_book.device_collections = []
                    this_book.library_id = library_books[book]
                    this_book.size = library_books[book].Size
                    this_book.uuid = library_books[book].Composer
                    this_book.cid = None
                    if (self.report_progress is not None):
                        this_book.thumbnail = self._generate_thumbnail(this_book.path, library_books[book])
                    else:
                        this_book.thumbnail = None
                    booklist.add_book(this_book, False)
                    cached_books[this_book.path] = {'title': library_books[book].Name, 'author': library_books[book].Artist.split('    &    '), 'lib_book': library_books[book], 'uuid': library_books[book].Composer, 'format': format}
                    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)))
            finally:
                pythoncom.CoUninitialize()
        if (self.report_progress is not None):
            self.report_progress(1.0, _('finished'))
        self.cached_books = cached_books
        if self.verbose:
            self._dump_booklist(booklist, 'returning    from    books()', indent=2)
            self._dump_cached_books('returning    from    books()', indent=2)
        return booklist
    else:
        return BookList(logger())
