Self-hosted book and audiobook automation — a working replacement for Readarr.
Readarr is officially retired: the Servarr team shut it down after its metadata source, Goodreads, locked down its public API, and nobody stepped up to migrate it to a workable alternative. If you were running Readarr, you're currently stuck on an unmaintained tool with a broken metadata backend.
Pageturnarr is a from-scratch replacement built around two decisions that avoid Readarr's failure mode:
- Metadata from OpenLibrary and Google Books, not Goodreads — no dependency on an API that can be revoked by a third party.
- Ebooks and audiobooks in one instance, not two separate Readarr/ Readarr-audio setups.
It also adds Send-to-Kindle (convert + email a successful ebook import straight to a registered Kindle address), which Readarr never had.
Pageturnarr is pre-release software (v0.1.0). It has a tested backend and a working frontend, and the maintainer runs it against real indexers and a real SABnzbd instance — but it hasn't had a broad multi-user shakeout yet. Expect rough edges. See what it doesn't do yet before you commit your library to it.
Pageturnarr automates the same acquisition loop as Sonarr/Radarr, applied to books and audiobooks:
metadata search → indexer search → score → grab → download → post-process → organize → notify
- Metadata search & monitoring against OpenLibrary and Google Books, for both books and audiobooks.
- Indexer search via direct Newznab (NZBgeek, NZBPlanet, or any Newznab-compatible indexer) or through Prowlarr as an aggregator.
- Release scoring — ranks results by preferred/blocked formats, an acceptable size window, and preferred/blocked keywords in the release title.
- SABnzbd (Usenet) and qBittorrent (torrent) downloads. Use either
client or both in the same instance;
PROTOCOL_PREFERENCEdecides how results from the two protocols compete. SABnzbd gets offline resilience (a download is queued even if it's briefly unreachable, and retried automatically), and both clients get automatic category routing (books vs. audiobooks). Torrent imports are copied or hardlinked into your library so seeding continues. - Download lifecycle tracking — real status transitions (wanted → downloading → imported), progress/speed/ETA, retry of failed grabs, and title-based blocklisting.
- Post-processing — organizes ebooks by author/title, and tags audiobooks (ID3v2 for MP3, MP4 atoms for M4B/M4A: title, author, series, narrator, cover art) and organizes them by author/series/title. See docs/post-processing.md.
- Send-to-Kindle — converts and emails successful ebook imports to a Kindle address via SMTP.
- Quality profiles with per-profile cutoffs and automatic upgrades (re-grab when a better release shows up).
- Database-backed indexer configuration — indexers are managed through the UI/API and are the single source of truth for search (no more env-only indexer config).
- Import lists with exclusions, for auto-adding titles from external sources.
- Calendar view and iCal feed for upcoming releases.
- Notifications via Discord webhook and/or Obsidian vault notes (one markdown note per import).
- Unified web UI — Library, Wanted, Add, Activity, Calendar, and Settings, covering both media types from one interface.
As of this release, the backend test suite passes (225 tests) and the frontend production build succeeds. See CHANGELOG.md for the full v0.1.0 feature list.
Honestly, and in rough order of how often they matter:
- API-key auth only. All
/api/*routes require theX-Api-Keyheader (Sonarr/Radarr-style; the key is generated on first startup and shown in Settings). There is no multi-user login or 2FA — still treat a public-internet exposure with care (reverse proxy + your own auth layer). - No Transmission support. SABnzbd (Usenet), qBittorrent, and Deluge are the supported downloaders; other torrent clients remain on the roadmap (see ROADMAP.md).
- No tags or per-item configuration. Quality profile, monitored state, and root folder are global/profile-level, not overridable per book or author.
- No configurable naming/folder templates. Output layout is hardcoded in the post-processing service.
- Young migration history. Schema changes ship as Alembic migrations and run automatically on startup (with a pre-upgrade SQLite backup — see docs/MIGRATIONS-AND-BACKUP.md). A database that doesn't match any known revision fails startup rather than guessing.
- No Readarr import. There's no migration tool to pull an existing Readarr library/history into Pageturnarr yet.
Full list with complexity estimates: ROADMAP.md.
| Library | Activity | Add |
|---|---|---|
![]() |
![]() |
![]() |
Requires Docker and Docker Compose, an existing SABnzbd instance (Usenet) and/or qBittorrent instance (torrents), plus at least one Newznab-compatible indexer (or a Prowlarr instance aggregating indexers for you).
-
Clone the repo and copy the example environment file:
git clone <this-repo-url> cd pageturnarr cp .env.example .env
-
Edit
.env— configure at least one downloader (SABNZBD_URLandSABNZBD_API_KEYfor Usenet, and/orQBITTORRENT_URLwithQBITTORRENT_USERNAME/QBITTORRENT_PASSWORDfor torrents), plus at least one indexer (NZBGEEK_URL/NZBGEEK_API_KEY, orPROWLARR_URL/PROWLARR_API_KEY). See Usenet, torrents, or both below to tune which protocol wins. -
Start it with the checked-in Compose file (single container — the backend serves the built web UI):
docker compose up -d
Or with plain Docker:
docker build -t pageturnarr . docker run -d --name pageturnarr \ -p 8000:8000 \ -e PUID=1000 -e PGID=1000 \ -v pageturnarr_config:/config \ -v /path/to/library:/books \ -v /path/to/downloads:/downloads \ --env-file .env \ pageturnarrSee DOCKER.md for the full deployment reference (volumes, PUID/PGID, healthcheck, upgrades).
-
Open
http://<host>:8000in a browser. On first startup the app generates an API key (shown in the container log and in Settings) — the UI will prompt you for it once.
Auth is API-key only (no multi-user login) — for anything internet-facing, keep a reverse proxy with your own access controls in front.
Pageturnarr supports SABnzbd (Usenet) plus qBittorrent or Deluge
(torrents) independently — run any combination in the same instance. When both
are configured, PROTOCOL_PREFERENCE decides how results compete:
prefer-usenet(default) — Usenet wins ties; torrents fill gaps.prefer-torrent— torrents win ties; Usenet fills gaps.usenet-only— ignore torrent results entirely.torrent-only— ignore Usenet results entirely.
Torrent results come from your Prowlarr/torznab indexers; among otherwise equal releases, more seeders win. Imports from qBittorrent are copied or hardlinked into your library (never moved or deleted), so seeding continues uninterrupted.
All configuration is via environment variables (see
.env.example and backend/app/config.py). Secrets have no
defaults and must be set explicitly.
| Variable | Default | Description |
|---|---|---|
APP_NAME |
Pageturnarr |
Display name used in the API title. |
DEBUG |
false |
Enables debug mode. |
LOG_LEVEL |
INFO |
Python logging level. |
DATABASE_URL |
sqlite+aiosqlite:///./pageturnarr.db |
SQLAlchemy async database URL. |
BOOKS_ROOT |
/data/media/ebooks |
Library root for organized ebooks. |
AUDIOBOOKS_ROOT |
/data/media/audiobooks |
Library root for organized audiobooks. |
ENABLE_POSTPROCESS |
true |
Toggles the post-processing pipeline. |
CALIBRE_PATH |
calibredb |
Path to Calibre's CLI tools, if installed. |
SABNZBD_URL |
http://sabnzbd:8080 |
SABnzbd base URL. |
SABNZBD_API_KEY |
(none — required) | SABnzbd API key. |
QBITTORRENT_URL |
http://qbittorrent:8080 |
qBittorrent base URL. |
QBITTORRENT_USERNAME |
(none) | qBittorrent WebUI username. |
QBITTORRENT_PASSWORD |
(none) | qBittorrent WebUI password. |
QBITTORRENT_CATEGORY |
pageturnarr |
qBittorrent category Pageturnarr assigns to its downloads. |
PROTOCOL_PREFERENCE |
prefer-usenet |
How Usenet and torrent results compete: prefer-usenet, prefer-torrent, usenet-only, or torrent-only. |
DELUGE_URL |
http://deluge:8112 |
Deluge WebUI base URL. Setting DELUGE_PASSWORD enables Deluge; when qBittorrent is also configured, qBittorrent takes new grabs. |
DELUGE_PASSWORD |
(none) | Deluge WebUI password. |
PUID / PGID |
1000 / 1000 |
User/group the app runs as (it refuses to run as root). The entrypoint owns /config and the configured library roots at startup; make sure these match the owner of your media mounts, *arr-style. |
PLEX_URL |
(none) | Plex server URL (optional). |
PLEX_TOKEN |
(none) | Plex auth token (optional). |
AUDIOBOOKSHELF_URL |
(none) | Audiobookshelf URL — when set (with token), triggers a library scan after each audiobook import. |
AUDIOBOOKSHELF_TOKEN |
(none) | Audiobookshelf admin API token. |
AUTO_DOWNLOAD_WANTED |
false |
Auto-grab the top indexer result for wanted+monitored items. Opt-in. |
DISCORD_WEBHOOK_URL |
(none) | Discord webhook for import success/failure notifications. |
OBSIDIAN_VAULT_PATH |
(none) | Path to an Obsidian vault (must be writable by the container) — Pageturnarr writes one note per import under Pageturnarr/Books or Pageturnarr/Audiobooks. |
KINDLE_EMAIL |
(none) | Destination @kindle.com address for Send-to-Kindle. |
KINDLE_SEND_ENABLED |
false |
Enables Send-to-Kindle on successful ebook import. |
KINDLE_FORMAT |
epub |
Format emailed to Kindle (epub needs no conversion; azw3 requires calibredb). |
SMTP_HOST |
(none) | SMTP server for Send-to-Kindle. |
SMTP_PORT |
587 |
SMTP port. |
SMTP_USERNAME |
(none) | SMTP username. |
SMTP_PASSWORD |
(none) | SMTP password (use an app password for Gmail, etc.). |
SMTP_FROM |
(none) | From address — must be on Amazon's approved sender list for the target Kindle. |
SMTP_USE_TLS |
true |
Use TLS for SMTP. |
PREFERRED_BOOK_FORMATS |
epub,azw3,mobi,pdf |
Format preference order used by release scoring. |
MIN_BOOK_SIZE_KB |
100 |
Minimum acceptable ebook size. |
MAX_BOOK_SIZE_KB |
100000 |
Maximum acceptable ebook size. |
BLOCKED_RELEASE_WORDS |
comic,magazine,manga,audiobook,m4b,mp3 |
Release title tokens that reject a result outright. |
PREFERRED_RELEASE_WORDS |
retail,proper,repack |
Release title tokens that add a small scoring bonus. |
GOOGLE_BOOKS_API_KEY |
(none) | Optional — raises Google Books rate limits. |
OPENLIBRARY_BASE_URL |
https://openlibrary.org |
OpenLibrary API base URL. |
GOOGLE_BOOKS_BASE_URL |
https://www.googleapis.com/books/v1 |
Google Books API base URL. |
PROWLARR_URL |
(none) | Prowlarr base URL. When set with an API key, search routes through Prowlarr instead of direct Newznab. |
PROWLARR_API_KEY |
(none) | Prowlarr API key. |
PROWLARR_INCLUDE_TORRENTS |
false |
Include torrent results from Prowlarr; grabbed via qBittorrent when configured. |
NZBGEEK_URL |
https://api.nzbgeek.info |
NZBgeek Newznab endpoint (direct-indexer fallback). |
NZBGEEK_API_KEY |
(none) | NZBgeek API key. |
NZBPLANET_URL |
https://api.nzbplanet.net |
NZBPlanet Newznab endpoint. |
NZBPLANET_API_KEY |
(none) | NZBPlanet API key. |
SEARCH_INTERVAL_HOURS |
6 |
How often the scheduler searches for wanted/missing items. |
IMPORT_INTERVAL_MINUTES |
15 |
How often the scheduler checks for completed downloads to import. |
CORS_ORIGINS |
http://localhost:5173,http://localhost:3000,http://localhost:8000 |
Allowed CORS origins for the API. |
- ROADMAP.md — known gaps and where help is wanted.
- docs/post-processing.md — how downloads get organized and tagged.
- docs/design-system.md — frontend design system, for anyone touching the UI.
- CONTRIBUTING.md — dev setup, tests, and PR conventions.
- SECURITY.md — how to report a vulnerability.
- CHANGELOG.md — release history.
Pageturnarr is licensed under the GNU General Public License v3.0.
© 2026 Joe McLaughlin


