Skip to content
ZnOw01Public

About

No description, website, or topics provided.

Resources

Code of conduct

Contributing

Stars

4 stars

Watchers

0 watching

Forks

Repository files navigation

Ryliox

Your O'Reilly Learning library, yours to keep.
Export any book to EPUB 3 or PDF from a single, beautiful local web app.

CI Version Python FastAPI Astro + React Bun Code style: Ruff License: MIT

Features · Quick Start · Architecture · Configuration · Contributing · Changelog


Caution

Disclaimer — read before use. Ryliox is for personal and educational use only. By using it, you agree to the O'Reilly Terms of Service. The authors are not affiliated with O'Reilly Media and assume no liability for how the tool is used. Only export content you have legal access to.

Features

Feature What you get
EPUB 3 export Clean, reflowable e-books built with EbookLib
PDF export Print-quality rendering via WeasyPrint
Persistent download queue Jobs survive restarts — persisted in SQLite
Live progress Real-time status streamed with Server-Sent Events
Session vault Cookie-based auth, SQLite-first storage with Fernet encryption
Microkernel architecture Auth, book, chapters, assets, EPUB and PDF as hot-pluggable plugins
OWASP-aware defaults Same-origin checks, security headers, CSP, rate limiting, audit logging with HMAC
Observability Prometheus metrics, health probes, typed Pydantic configuration
Internationalized UI i18next-powered Astro 7 + React 19 + Tailwind CSS 4 frontend
One-command Docker docker compose up -d and you're done
Full test matrix Unit, integration, contract, security, e2e, a11y and performance suites

Quick Start

Docker (recommended)

git clone https://github.com/ZnOw01/Ryliox.git
cd Ryliox
docker compose up -d

Then open http://localhost:8000.

Warning

The Compose port is bound to 127.0.0.1 intentionally. Ryliox does not authenticate clients of its own API, and the cookie endpoint can return stored O'Reilly cookie values to the local UI. Never expose port 8000 to a LAN or the public internet without an authenticating reverse proxy — see Secure Deployment.

Local

Requirements

Tool Version Notes
Python 3.11 · 3.12 · 3.13 Managed with uv
Bun 1.3+ Frontend toolchain
Node.js 22.13+ or 24+ Required by Bun/Astro tooling
GTK3 runtime Windows only Needed by WeasyPrint for PDF export — GTK for Windows
git clone https://github.com/ZnOw01/Ryliox.git
cd Ryliox
uv sync --extra dev
python -m launcher --no-browser

Then open http://localhost:8000.

The launcher creates an isolated Python environment in .run/venv, installs frontend dependencies with Bun, builds the frontend when needed, and starts the FastAPI app. Use python -m launcher --docker to run through Docker Compose instead.

Cookie Setup

Ryliox needs your O'Reilly session cookies to access purchased or subscribed content.

  1. Open the web UI.
  2. Click Set cookies.
  3. Paste a full JSON cookie export from a browser extension such as EditThisCookie.

Important

Use a full browser export, not a console snippet. Only the export can include the HttpOnly orm-rt refresh cookie — document.cookie cannot read HttpOnly cookies, so sessions created that way expire quickly.

Cookie storage is SQLite-first:

  • The UI writes cookies to data/session.sqlite3 through POST /api/cookies.
  • GET /api/cookies reads from the same SQLite store.
  • data/cookies.json is only a legacy import path — once SQLite has cookies, editing it has no effect.

Warning

Protect the local account, filesystem, backups and Docker volume that contain data/session.sqlite3. Deleting cookies from the UI or the database does not revoke an O'Reilly session already copied elsewhere.

Architecture

flowchart TB
    subgraph Client["Browser"]
        UI["Astro 7 + React 19<br/><code>frontend/</code>"]
    end

    subgraph Server["FastAPI application — <code>web/</code>"]
        direction TB
        MW["Security middleware"]
        API["REST routes"]
        SSE["SSE progress stream"]
    end

    subgraph Core["Core — <code>core/</code>"]
        direction TB
        SVC["Services"]
        REPO["Repository · DTOs · Mappers"]
        KRN["Microkernel"]
    end

    subgraph Plugins["Plugins — <code>plugins/</code>"]
        direction LR
        P1["auth"]
        P2["book"]
        P3["chapters"]
        P4["assets"]
        P5["epub"]
        P6["pdf"]
    end

    DB[("SQLite<br/><code>data/*.sqlite3</code>")]
    OR["O'Reilly V2 API"]

    UI --> MW
    MW --> API & SSE
    API --> SVC
    SVC --> REPO --> DB
    SVC --> KRN --> Plugins
    P2 & P3 & P4 --> OR

    classDef external fill:#f3f4f6,stroke:#6b7280,color:#111827,stroke-dasharray:4 3
    class DB,OR external
Loading

A download, step by step:

sequenceDiagram
    autonumber
    actor U as User
    participant F as Frontend
    participant A as FastAPI
    participant Q as Queue (SQLite)
    participant W as Worker
    participant O as O'Reilly API

    U->>F: Save cookies · pick a book
    F->>A: POST /api/download
    A->>Q: Enqueue job (persisted)
    A-->>F: job_id
    Q->>W: Dequeue
    loop Each chapter
        W->>O: Fetch chapter + assets
        O-->>W: HTML · images · CSS
        W->>Q: Persist progress
        Q-->>F: SSE update (live %)
    end
    W->>W: Build EPUB 3 / PDF
    W-->>U: Saved to output/
Loading

Runtime flow, in words:

  1. The user saves cookies through the UI or API.
  2. The frontend searches books and requests metadata through /api/*.
  3. POST /api/download validates the request and enqueues a job.
  4. DownloadQueueService persists the job in SQLite.
  5. A worker runs DownloaderPlugin, which fetches chapters, assets and output formats.
  6. Progress is persisted and streamed through /api/progress/stream.

API Surface

Method Path Purpose
GET /api/status Auth and cookie status
GET /api/search?q= Search books
GET /api/book/{id} Book metadata
GET /api/book/{id}/chapters Chapter list
POST /api/download Queue a download
GET /api/progress?job_id= Job progress snapshot
GET /api/progress/stream Live progress stream
POST /api/cancel Cancel a job
POST /api/cookies Save session cookies
GET /api/health Liveness probe
GET /api/health/detailed Disk, memory, SQLite, external APIs
GET /metrics Prometheus metrics
GET /api/docs Swagger UI (development)

Configuration

Configuration is loaded from .env into a typed Pydantic settings model. Start from the fully commented .env.example.

Area Examples Notes
Server HOST, PORT, APP_VERSION Bind address and app metadata
HTTP REQUEST_*, USER_AGENT, ACCEPT_* Outbound client behavior
Security ENVIRONMENT, CSP_POLICY, ALLOWED_HOSTS Headers, host checks, CSP
Rate limit RATE_LIMIT_*, API_RATE_LIMIT_* Endpoint throttling
Secrets SECRET_MASTER_PASSWORD Encryption and rotation
Audit AUDIT_* Audit log retention and integrity
Cache CACHE_* Resource cache sizes and TTLs

Runtime paths default to local, git-ignored directories:

Path Contents
data/ SQLite databases, cookies, audit logs, secrets
output/ Generated EPUB / PDF files
.run/ Launcher-managed local runtime files

Secure Deployment

Localhost keeps the zero-configuration workflow. A non-loopback bind — and every production deployment — requires:

Variable Requirement
RYLIOX_SECURITY__ADMIN_TOKEN At least 32 characters. Remote clients send it as Authorization: Bearer <token>; it is never compiled into the frontend bundle
RYLIOX_SESSION__ENCRYPTION_KEY Fernet key (or RYLIOX_SESSION__ENCRYPTION_KEY_FILE)
RYLIOX_AUDIT__HMAC_KEY Audit-log integrity key (or its _FILE variant)
RYLIOX_SESSION__OLD_ENCRYPTION_KEYS Optional JSON list of old cookie keys while rotating

Migrations & filesystem safety

  • On first startup, plaintext cookie rows and legacy cookie files are imported, encrypted transactionally, and the plaintext source is removed. Back up before upgrading.
  • Development keys are stored with mode 0600 in the platform user configuration directory, separate from SQLite and audit ciphertext.
  • Output paths — including values selected by the local native picker — must remain below RYLIOX_PATHS__OUTPUT_ROOT (default ./output). The native picker is disabled for remote binds.

Development

uv sync --extra dev   # install Python dependencies

Backend checks

uv run ruff format --check .
uv run ruff check .
uv run mypy
uv run pytest

Frontend checks

cd frontend
bun run typecheck
bun run test
bun run format:check
bun run build

Security checks

uv sync --extra security
uv run pytest tests/security -q --run-security

Tip

If uv run tries to reuse a broken .venv on Windows, point uv at a clean ignored environment:

$env:UV_PROJECT_ENVIRONMENT=".run\dev-venv"
uv sync --extra dev

Troubleshooting

bun test --run fails with Vitest errors

Use bun run test. The test script runs vitest run with the configured JSDOM environment.

uv run fails on .venv/lib64 with access denied

The local .venv is likely incomplete or has a Windows symlink permission problem. Use an ignored project environment:

$env:UV_PROJECT_ENVIRONMENT=".run\dev-venv"
uv sync --extra dev
PDF export fails on Windows

Install the GTK3 runtime linked in Quick Start. WeasyPrint needs native libraries to render PDFs.

Cookies save but auth expires quickly

Use a full browser cookie JSON export. Console-based cookie snippets cannot read the HttpOnly orm-rt refresh cookie — see Cookie Setup.

Project Structure

Ryliox/
├── config.py            Typed settings and legacy module-level constants
├── main.py              Thin server entry point
├── launcher/            Local workflow launcher (venv, frontend, Docker)
├── web/                 FastAPI app, middleware, schemas, routes
├── core/                Services, repository, DTOs, kernel, security, storage
├── plugins/             Auth, book, chapter, asset, EPUB, PDF, downloader
├── utils/               File and filename helpers
├── frontend/            Astro 7 + React 19 + Tailwind CSS 4
├── tests/               Unit · integration · contract · security · e2e · a11y · performance
├── Dockerfile           Multi-stage production image
├── docker-compose.yml   Local orchestration (loopback-only)
└── epubcheck/           EPUB validation assets

Roadmap

  • Unified FastAPI backend with persistent SQLite queue
  • Astro 7 + React 19 frontend with i18n
  • Encrypted session storage and audit logging
  • Standalone CLI mode
  • Prebuilt Docker image published to GHCR
  • EPUB validation in CI (epubcheck)
  • More UI languages

Contributing

Contributions of all kinds are welcome — bug reports, features, docs and translations. Read the Contributing Guide and follow the Code of Conduct.

# The short version
git checkout -b feat/my-change
uv run ruff check . && uv run mypy && uv run pytest
# open a PR

Credits

Ryliox is a from-scratch refactor inspired by:

License

Distributed under the MIT License — see LICENSE.


If Ryliox helps you, consider giving it a ⭐ — it helps others find it!

Back to top

About

No description, website, or topics provided.

Resources

Code of conduct

Contributing

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages