Skip to main content

Python library for Apple Books

Project description

PyAppleBooks

PyAppleBooks is a Python API library to access your Apple Books data.

PyPI License: MIT Buy Me A Coffee

Installation

pip install py_apple_books

Available Functions

Collections

Function Description Parameters Return Type
list_collections() List all collections limit?, order_by? ModelIterable
get_collection_by_id(collection_id) Get a collection by its ID collection_id: str Collection
get_collection_by_title(title) Search collections by title substring title: str ModelIterable

Books

Function Description Parameters Return Type
list_books() List all books limit?, order_by? ModelIterable
get_book_by_id(book_id) Get a book by its ID book_id: str Book
get_book_by_title(title) Search books by title substring title: str ModelIterable
get_books_by_genre(genre) Search books by genre substring genre: str, limit?, order_by? ModelIterable

Reading Progress

Function Description Parameters Return Type
get_books_in_progress() Books currently being read (0% < progress < 100%) limit?, order_by? ModelIterable
get_finished_books() Books marked as finished limit?, order_by? ModelIterable
get_unstarted_books() Books not yet started limit?, order_by? ModelIterable
get_recently_read_books() Books ordered by last-opened date, most recent first limit? (default 10) ModelIterable

Annotations

Function Description Parameters Return Type
list_annotations() List all annotations limit?, order_by? ModelIterable
get_annotation_by_id(annotation_id) Get an annotation by its ID annotation_id: str Annotation
get_annotations_by_color(color) Filter annotations by highlight color color: str, limit?, order_by? ModelIterable
search_annotation_by_highlighted_text(text) Substring search in highlighted text text: str, limit?, order_by? ModelIterable
search_annotation_by_note(note) Substring search in user notes note: str, limit?, order_by? ModelIterable
search_annotation_by_text(text) Substring search across highlighted text, representative text, and notes text: str, limit?, order_by? ModelIterable
get_annotations_by_date_range(after?, before?) Filter annotations by creation date after?: datetime, before?: datetime, limit?, order_by? ModelIterable

Book Content (v1.7.0+)

Read the full text of your non-DRM EPUBs. Powered by ebooklib and beautifulsoup4.

Function Description Parameters Return Type
get_book_content(book_id) Return a BookContent handle after verifying the book is downloaded and not DRM-protected book_id: int BookContent
get_current_reading_location(book_id) Apple Books' auto-tracked "current reading position" bookmark (a zero-width annotation with a CFI) book_id: int Optional[Annotation]
get_current_reading_chapter(book_id) Convenience: resolve the bookmark's CFI to a Chapter book_id: int Optional[Chapter]

BookContent methods:

Method Description Return Type
list_chapters() Flattened table of contents with title, href, fragment, order, depth list[Chapter]
get_chapter_content(chapter_id) Plain text of a chapter, scoped to its fragment anchor str
chapter_at_cfi(cfi) Resolve an EPUB CFI to the containing Chapter Optional[Chapter]

BookContent properties:

Property Description
is_epub True if the path is an EPUB bundle directory
is_pdf True if the path is a single PDF file
is_downloaded True if locally materialized (not an iCloud placeholder) — does not trigger hydration
is_drm_protected True if the EPUB has META-INF/encryption.xml (Apple Books Store FairPlay-protected book)

Exceptions

Content-access methods may raise:

Exception When
BookNotDownloadedError The book has no local file (never downloaded) or the file is an iCloud placeholder
DRMProtectedError The book is FairPlay-protected (Apple Books Store purchase)
AppleBooksError Base class for all exceptions above, plus EPUB-parsing errors

Examples

Creating a client

from py_apple_books import PyAppleBooks

api = PyAppleBooks()

List books

for book in api.list_books():
    print(f"{book.title}{book.author}")

Get annotations

for a in api.list_annotations(limit=5):
    print(f"[{a.color}] {a.selected_text}")

Search highlights

for a in api.search_annotation_by_highlighted_text('genome'):
    print(a.selected_text)

Filter by color

for a in api.get_annotations_by_color('yellow'):
    print(a.selected_text)

Reading progress

for book in api.get_books_in_progress(limit=5):
    print(f"{book.title}: {book.reading_progress:.1f}%")

Read chapter content

from py_apple_books.exceptions import BookNotDownloadedError, DRMProtectedError

book = api.get_book_by_id(42)
try:
    content = api.get_book_content(book.id)
except BookNotDownloadedError:
    print("Open the book in Apple Books first to download it.")
except DRMProtectedError:
    print("DRM-protected Store purchase — text content isn't readable.")
else:
    for ch in content.list_chapters():
        print(f"{'  ' * ch.depth}[{ch.order}] {ch.title}")

    # Read the first substantive chapter
    text = content.get_chapter_content(content.list_chapters()[0].id)
    print(text[:500])

See what the user is currently reading

# The book they most recently opened
for book in api.get_recently_read_books(limit=1):
    ch = api.get_current_reading_chapter(book.id)
    if ch is None:
        continue
    content = api.get_book_content(book.id)
    text = content.get_chapter_content(ch.id)
    print(f"Currently reading: {book.title}")
    print(f"Progress: {book.reading_progress:.1f}%")
    print(f"Chapter {ch.order}: {ch.title}")
    print(text[:500])

Get all collections and books

for collection in api.list_collections():
    print(f"{collection.title}: {len(collection.books)} books")
    for book in collection.books:
        print(f"  - {book.title}")

How content access handles Apple Books' quirks

  • iCloud placeholders — books you've imported but haven't opened lately can live only in iCloud. is_downloaded detects this via os.stat (for files) or du -sk (for bundle directories) without triggering a download. get_book_content raises BookNotDownloadedError so you can prompt the user to open the book in Apple Books.
  • DRM'd Store purchases — FairPlay-encrypted EPUBs have META-INF/encryption.xml and their chapter bodies are opaque ciphertext. Detected up-front; callers get a clear DRMProtectedError.
  • Non-standard EPUB layouts — OPFs at unusual paths, NCX files not declared in <spine toc=…> (e.g. The 4-Hour Workweek), EPUB3 books with nav docs only (e.g. On Numbers and Games), URL-encoded href characters (%21!), duplicate navPoint ids — all handled, with a stdlib NCX override for the ebooklib blind spots.
  • Fragment-scoped chapters — Project Gutenberg EPUBs often put multiple sections in one XHTML file, separated by anchors. get_chapter_content returns only the requested section, not the whole file.

Running the tests

pip install -e '.[dev]'
pytest

The test suite covers placeholder/DRM detection, NCX parsing, XHTML text extraction, fragment scoping, and end-to-end BookContent behavior against generated EPUB fixtures. No real Apple Books library required.

Upcoming Features

  • Adding a book to collection
  • Removing a book from collection
  • Updating annotations

Contribution

Thank you for considering contributing to this project! Your help is greatly appreciated.

Opening Issues

If you encounter a bug, have a feature request, or want to discuss something related to the project, please open an issue on the GitHub repository. When opening an issue, please provide:

Bug Reports: Describe the issue in detail. Include steps to reproduce the bug if possible, along with any error messages or screenshots.

Feature Requests: Clearly explain the new feature you'd like to see added to the project. Provide context on why this feature would be beneficial.

General Discussions: Feel free to start discussions on broader topics related to the project.

Contributing

1️⃣ Fork the GitHub repository https://github.com/vgnshiyer/py-apple-books
2️⃣ Create a new branch for your changes (git checkout -b feature/my-new-feature).
3️⃣ Make your changes and test them thoroughly.
4️⃣ Push your changes and open a Pull Request to main.

Please provide a clear title and description of your changes.

License

PyAppleBooks is licensed under the MIT license. See the LICENSE file for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

py_apple_books-1.8.0.tar.gz (39.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

py_apple_books-1.8.0-py3-none-any.whl (35.1 kB view details)

Uploaded Python 3

File details

Details for the file py_apple_books-1.8.0.tar.gz.

File metadata

  • Download URL: py_apple_books-1.8.0.tar.gz
  • Upload date:
  • Size: 39.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.4

File hashes

Hashes for py_apple_books-1.8.0.tar.gz
Algorithm Hash digest
SHA256 dc402f61fd351e9d33f9fc16e21c0c33e92fb6f6f21cca28b75dc7a8cf972c1f
MD5 0ac031ac7b4d33c0a6c4bef852b7027c
BLAKE2b-256 6e3c6e942d514790bf8f570cfa9e248ef6e0c233af30dd4adb8f539d74abed9f

See more details on using hashes here.

File details

Details for the file py_apple_books-1.8.0-py3-none-any.whl.

File metadata

  • Download URL: py_apple_books-1.8.0-py3-none-any.whl
  • Upload date:
  • Size: 35.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.4

File hashes

Hashes for py_apple_books-1.8.0-py3-none-any.whl
Algorithm Hash digest
SHA256 16c1621df87e77d5ea415a8545a3016bebc9b5bc64a77f1b710c8f8ea89e068e
MD5 4ed490e1033bb2d4ae87288b882423c6
BLAKE2b-256 ed299d26710b217340afef0e9f88b4a7dcbbdc2488fe9f05f36b3e1d0683f755

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page