def GetAllBooks(user: User, outputPath: str) -> None:
    kobo = Kobo(user)
    kobo.LoadInitializationSettings()
    bookList = kobo.GetMyBookList()
    for entitlement in bookList:
        newEntitlement = entitlement.get("NewEntitlement")
        if newEntitlement is None:
            continue
        try:
            bookMetadata = newEntitlement["BookMetadata"]
        except Exception:
            # skip audiobooks
            continue
        fileName = __MakeFileNameForBook(bookMetadata)
        outputFilePath = os.path.join(outputPath, fileName)

        # Skip archived books.
        if __IsBookArchived(newEntitlement):
            title = bookMetadata["Title"]
            author = __GetBookAuthor(bookMetadata)
            if len(author) > 0:
                title += " by " + author

            click.echo(f"Skipping archived book {title}")
            continue
        try:
            output = kobo.Download(bookMetadata["RevisionId"], outputFilePath)
            click.echo(f"Downloaded to {output}", err=True)
        except Exception as e:
            click.echo("could not download".format(bookMetadata["Title"]))
            click.echo(e)
def GetBook(user: User, revisionId: str, outputPath: str) -> None:
    kobo = Kobo(user)
    kobo.LoadInitializationSettings()
    book = kobo.GetBookInfo(revisionId)
    fileName = __MakeFileNameForBook(book)
    outputFilePath = os.path.join(outputPath, fileName)
    return kobo.Download(revisionId, outputFilePath)
def ListBooks(users: List[User], listAll: bool) -> List[Book]:
    for user in users:
        kobo = Kobo(user)
        kobo.LoadInitializationSettings()
        rows = __GetBookList(kobo, listAll)
        for columns in rows:
            yield Book(
                RevisionId=columns[0],
                Title=columns[1],
                Author=columns[2],
                Archived=columns[3],
                Owner=user,
            )
Пример #4
0
def ListBooks(users: List[User], listAll: bool, exportFile: Union[TextIO, None]) -> List[Book]:
    '''list all books currently in the account'''
    for user in users:
        kobo = Kobo(user)
        kobo.LoadInitializationSettings()
        rows = __GetBookList(kobo, listAll, exportFile)
        for columns in rows:
            yield Book(
                RevisionId=columns[0],
                Title=columns[1],
                Author=columns[2],
                Archived=columns[3],
                Audiobook=columns[4],
                Owner=user,
            )
Пример #5
0
def GetBookOrBooks(user: User, outputPath: str, productId: str = '') -> Union[None, str]:
    '''
    download 1 or all books to file
    returns output filepath if identifier is passed, otherwise returns None
    '''
    outputPath = os.path.abspath(outputPath)
    kobo = Kobo(user)
    kobo.LoadInitializationSettings()

    # Must call GetBookList every time, even if you're only getting 1 book,
    # because it invokes a library sync endpoint.
    # This is the only known endpoint that returns
    # download URLs along with book metadata.
    bookList = kobo.GetMyBookList()

    for entitlement in bookList:
        newEntitlement = entitlement.get('NewEntitlement')
        if newEntitlement is None:
            continue

        bookMetadata, book_type = __GetBookMetadata(newEntitlement)
        if book_type is None:
            click.echo('Skipping book of unknown type')
            continue

        elif book_type == BookType.SUBSCRIPTION:
            click.echo('Skipping subscribtion entity')
            continue

        fileName = __MakeFileNameForBook(bookMetadata)
        if book_type == BookType.EBOOK:
            # Audiobooks go in sub-directories
            # but epub files go directly in outputPath
            fileName += '.epub'
        outputFilePath = os.path.join(outputPath, fileName)

        if not productId and os.path.exists(outputFilePath):
            # when downloading ALL books, skip books we've downloaded before
            click.echo(f'Skipping already downloaded book {outputFilePath}')
            continue

        if productId and productId != Kobo.GetProductId(bookMetadata):
            # user only asked for a single title,
            # and this is not the book they want
            continue

        # Skip archived books.
        if __IsBookArchived(newEntitlement):
            click.echo(f'Skipping archived book {fileName}')
            continue

        kobo.Download(bookMetadata, book_type == BookType.AUDIOBOOK, outputFilePath)
        click.echo(f'Downloaded {productId} to {outputFilePath}', err=True)

        if productId:
            # TODO: support audiobook downloads from web
            return outputFilePath

    return None
Пример #6
0
def __GetBookList(kobo: Kobo, listAll: bool, exportFile: Union[TextIO,
                                                               None]) -> list:
    bookList = kobo.GetMyBookList()
    rows = []

    if exportFile:
        exportFile.write(json.dumps(bookList, indent=2))

    for entitlement in bookList:
        newEntitlement = entitlement.get('NewEntitlement')
        if newEntitlement is None:
            continue

        bookEntitlement = newEntitlement.get('BookEntitlement')
        if bookEntitlement is not None:
            # Skip saved previews.
            if bookEntitlement.get('Accessibility') == 'Preview':
                continue

            # Skip refunded books.
            if bookEntitlement.get('IsLocked'):
                continue

        if (not listAll) and __IsBookRead(newEntitlement):
            continue

        bookMetadata, book_type = __GetBookMetadata(newEntitlement)

        if book_type is None:
            click.echo('Skipping book of unknown type')
            continue

        elif book_type in SUPPORTED_BOOK_TYPES:
            book = [
                bookMetadata['RevisionId'],
                bookMetadata['Title'],
                __GetBookAuthor(bookMetadata),
                __IsBookArchived(newEntitlement),
                book_type == BookType.AUDIOBOOK,
            ]
            rows.append(book)

    rows = sorted(rows, key=lambda columns: columns[1].lower())
    return rows
def __GetBookList(kobo: Kobo, listAll: bool) -> list:
    bookList = kobo.GetMyBookList()
    rows = []

    for entitlement in bookList:
        newEntitlement = entitlement.get("NewEntitlement")
        if newEntitlement is None:
            continue

        bookEntitlement = newEntitlement.get("BookEntitlement")
        if bookEntitlement is not None:
            # Skip saved previews.
            if bookEntitlement.get("Accessibility") == "Preview":
                continue

            # Skip refunded books.
            if bookEntitlement.get("IsLocked"):
                continue

        if (not listAll) and __IsBookRead(newEntitlement):
            continue
        try:
            bookMetadata = newEntitlement["BookMetadata"]
        except Exception as e:
            # skip audiobook
            continue
        book = [
            bookMetadata["RevisionId"],
            bookMetadata["Title"],
            __GetBookAuthor(bookMetadata),
            __IsBookArchived(newEntitlement),
        ]
        rows.append(book)

    rows = sorted(rows, key=lambda columns: columns[1].lower())
    return rows
Пример #8
0
def Login(user: User, password: str, captcha: str) -> None:
    '''perform device initialization and get token'''
    kobo = Kobo(user)
    kobo.AuthenticateDevice()
    kobo.LoadInitializationSettings()
    kobo.Login(user.Email, password, captcha)
def Login(user: User, password: str, captcha: str) -> None:
    kobo = Kobo(user)
    kobo.AuthenticateDevice()
    kobo.LoadInitializationSettings()
    kobo.Login(user.Email, password, captcha)
Пример #10
0
def GetBookOrBooks(user: User,
                   outputPath: str,
                   productId: str = '') -> Union[None, str]:
    """
    download 1 or all books to file
    returns output filepath if identifier is passed, otherwise returns None
    """
    outputPath = os.path.abspath(outputPath)
    kobo = Kobo(user)
    kobo.LoadInitializationSettings()

    # Must call GetBookList every time, even if you're only getting 1 book,
    # because it invokes a library sync endpoint.
    # This is the only known endpoint that returns
    # download URLs along with book metadata.
    bookList = kobo.GetMyBookList()

    for entitlement in bookList:
        newEntitlement = entitlement.get('NewEntitlement')
        if newEntitlement is None:
            continue

        bookMetadata, book_type = __GetBookMetadata(newEntitlement)
        if book_type is None:
            click.echo('Skipping book of unknown type')
            continue

        elif book_type == BookType.SUBSCRIPTION:
            click.echo('Skipping subscribtion entity')
            continue

        fileName = __MakeFileNameForBook(bookMetadata)
        if book_type == BookType.EBOOK:
            # Audiobooks go in sub-directories
            # but epub files go directly in outputPath
            fileName += '.epub'
        outputFilePath = os.path.join(outputPath, fileName)

        if not productId and os.path.exists(outputFilePath):
            # when downloading ALL books, skip books we've downloaded before
            click.echo(f'Skipping already downloaded book {outputFilePath}')
            continue

        currentProductId = Kobo.GetProductId(bookMetadata)
        if productId and productId != currentProductId:
            # user only asked for a single title,
            # and this is not the book they want
            continue

        # Skip archived books.
        if __IsBookArchived(newEntitlement):
            click.echo(f'Skipping archived book {fileName}')
            continue

        try:
            click.echo(f'Downloading {currentProductId} to {outputFilePath}',
                       err=True)
            kobo.Download(bookMetadata, book_type == BookType.AUDIOBOOK,
                          outputFilePath)
        except KoboException as e:
            if productId:
                raise e
            else:
                click.echo(
                    (f'Skipping failed download for {currentProductId}: {str(e)}'
                     '\n  -- Try downloading it as a single book to get the complete exception details'
                     ' and open an issue on the project GitHub page: https://github.com/subdavis/kobo-book-downloader/issues'
                     ),
                    err=True,
                )

        if productId:
            # TODO: support audiobook downloads from web
            return outputFilePath

    return None