No description
  • Rust 96.3%
  • HTML 1.4%
  • CSS 1%
  • Nix 0.8%
  • Dockerfile 0.5%
Find a file
2026-06-23 20:59:23 +02:00
little-hesinde use i16 instead of u16 becaus epostrges can not cope otherwise 2026-06-23 20:59:23 +02:00
little-hesinde-macros basic derive macro for error response in axum 2026-06-04 14:53:30 +02:00
.containerignore add containerfile and update readme 2026-06-19 09:24:34 +02:00
.envrc initial commit of basic calibre-db handling 2026-06-03 12:17:41 +02:00
.gitignore initial commit of basic calibre-db handling 2026-06-03 12:17:41 +02:00
.rustfmt.toml wip oidc auth 2026-06-04 12:10:27 +02:00
Cargo.lock add source code download 2026-06-19 10:03:51 +02:00
Cargo.toml implement search 2026-06-18 12:20:35 +02:00
Containerfile use i16 instead of u16 becaus epostrges can not cope otherwise 2026-06-23 20:59:23 +02:00
flake.lock initial commit of basic calibre-db handling 2026-06-03 12:17:41 +02:00
flake.nix remove diesel cli from flake 2026-06-19 12:51:57 +02:00
README.md add reference to old version 2026-06-19 13:00:46 +02:00

Little Hesinde

Simple OPDS server for a calibre library, with KOReader progress sync built in.

I wrote it very specifically for my own needs, your mileage may vary.

It lets you browse and download ebooks from any OPDS-compatible reader and syncs reading progress across KOReader devices. A web UI behind OIDC login lets you manage API keys for both.

The last version with the integrated HTML interface is found at tag 0.3.5.

Building

Use nix develop to get a shell with all dependencies. Otherwise, check flake.nix for the required toolchain.

Setup

You need a calibre library, an OIDC provider (with PKCE enabled), and a database (SQLite by default; PostgreSQL and MySQL via feature flags). All secrets are read from files.

Generate a cookie encryption key and prepare the secret files:

openssl rand -hex 64 > cookie_key
echo "sqlite:///var/lib/little-hesinde/data.db?mode=rwc" > db_url
echo "your-oidc-client-secret" > oidc_secret

Start the server:

Usage: little-hesinde [OPTIONS] --oidc-issuer-url <URL> --oidc-redirect-url <URL>
        --oidc-client-secret-file <PATH> --database-url-file <PATH>
        --cookie-key-file <PATH> -- <LIBRARY_PATH>

Arguments:
  <LIBRARY_PATH>                Calibre library path [env: LIBRARY_PATH=]

Options:
  -l, --listen-address <ADDR>   Address to listen on [env: LISTEN_ADDRESS=] [default: [::1]:3000]
  -c, --cache-path <PATH>       Thumbnail cache path [env: CACHE_PATH=] [default: $TMP/little-hesinde]
  -u, --oidc-issuer-url <URL>   OIDC issuer URL [env: OIDC_ISSUER_URL=]
  -r, --oidc-redirect-url <URL> Redirect URL after login [env: OIDC_REDIRECT_URL=]
  -i, --oidc-client-id <ID>     OIDC client ID [env: OIDC_CLIENT_ID=]
  -s, --oidc-client-secret-file <PATH>  File containing the OIDC client secret
  -d, --database-url-file <PATH>        File containing the database URL
  -o, --cookie-key-file <PATH>          File with 64-byte cookie encryption key
  -m, --max-session-duration <SECS>     Session lifetime [default: 31622400]
  -h, --help                    Print help
  -V, --version                 Print version

Container

All options can be set via environment variables (see --help for the env var names). Secrets are read from files. so they have to be mounted into the container.

podman run \
  -v /data/library:/library \
  -v little_hesinde_cache:/tmp/cache \
  -v ./oidc_secret:/run/secrets/oidc_secret:ro \
  -v ./db_url:/run/secrets/db_url:ro \
  -v ./cookie_key:/run/secrets/cookie_key:ro \
  -e OIDC_ISSUER_URL=https://auth.example.com \
  -e OIDC_REDIRECT_URL=https://hesinde.example.com/login/callback \
  -e OIDC_CLIENT_ID=myapp \
  -e OIDC_CLIENT_SECRET_FILE=/run/secrets/oidc_secret \
  -e DATABASE_URL_FILE=/run/secrets/db_url \
  -e COOKIE_KEY_FILE=/run/secrets/cookie_key \
  -p 3000:3000 \
  little-hesinde

Connecting clients

After starting the server, open http://localhost:3000 and log in via OIDC. Create an API key on the key management page (/keys).

For both OPDS and sync, the API key acts as your credential.

OPDS

Point your reader to http://localhost:3000/opds/v1. Use the API key as the username in HTTP Basic auth. The password field is required by most clients but ignored by the server.

Sync

Point KOReader's progress sync to http://localhost:3000/sync. Set user to your API key. Password has to be provided but can be anything (it is ignored by the server).