Skip to content

ranobelib-python-sdk

Async Python SDK for ranobelib.me: fetch title metadata, download chapters and volumes, and export to epub, fb2, txt, or pdf.

The SDK talks to the undocumented but open JSON API behind the site (api.cdnlibs.org, part of the lib.social network) instead of scraping HTML — see API notes for what's been learned about it along the way.

Installation

uv add ranobelib-python-sdk

or

pip install ranobelib-python-sdk

Requires Python 3.11+. fmt="pdf" on RanobeLib.export() additionally needs WeasyPrint's native dependencies (Pango/cairo, via a GTK3 runtime) installed on the system — pip install/uv add alone doesn't guarantee that on every platform. Without them, export(fmt="pdf") raises the same "unknown format" error the other three formats don't.

Quickstart

from ranobelib import RanobeLib

async with RanobeLib("https://ranobelib.me/ru/book/6712--high-school-dxd-novel") as lib:
    info = await lib.get_info()
    toc = await lib.get_table_of_contents()

    chapter = await lib.get_chapter(volume=6, number="51.6")
    volume = await lib.get_volume(volume=6)

    chapters = await lib.get_chapters([(6, "51.6"), (6, "52")])
    volumes = await lib.get_volumes([1, 2, 3])

    translations = await lib.get_translations(volume=6, number="51.6")
    chapter = await lib.get_chapter(volume=6, number="51.6", branch_id=...)

    await lib.export(chapters, fmt="epub", path="output.epub")

number is a string exactly as the API returns it, and may contain a decimal for sub-chapters ("51.6") — there's no separate parameter for the fractional part.

Selecting a translation

When a chapter has more than one team's translation, get_chapter() (and anything built on it — get_chapters(), get_volume(), get_volumes()) raises MultipleTranslationsError instead of guessing which one you want:

from ranobelib import MultipleTranslationsError

try:
    chapter = await lib.get_chapter(volume=6, number="51.6")
except MultipleTranslationsError as exc:
    for branch in exc.branches:
        print(branch.branch_id, [team.name for team in branch.teams])
    chapter = await lib.get_chapter(volume=6, number="51.6", branch_id=exc.branches[0].branch_id)

Caching

Raw API responses (title metadata, chapter list, chapter content) are cached to disk by default, so re-exporting to a different format or downloading newly added chapters doesn't re-fetch data already on hand:

async with RanobeLib(url, cache_dir=".cache", cache_ttl=3600) as lib:
    toc = await lib.get_table_of_contents()  # First call: hits the API.
    toc = await lib.get_table_of_contents()  # Second call: served from disk.
    toc = await lib.get_table_of_contents(refresh=True)  # Bypasses the cache.

Documentation

  • API reference — generated from the source's own docstrings.
  • API notes — a running log of what's been learned about ranobelib's undocumented API and the design decisions that followed from it (translation selection, rate limiting, why each exporter is built the way it is, and more).
  • The project's CLAUDE.md documents the full architecture, public API contract, and roadmap.

License

MIT — see LICENSE.