OpenReader v5 is a ground-up rebuild of how playback, document processing, storage and self-hosting work. Audio is now generated ahead of you by a background compute worker and streamed as one continuous, seekable timeline. The worker owns every heavy workload, one policy engine rate-limits all of them, and a new admin, account and email layer makes OpenReader practical to run for other people.
This is a major release with breaking changes. Read the ⚠️ Upgrading from v4.4.0 section below before you deploy.
✨ What's New
🚀 New
Progressive background playback (PR #133, PR #135, PR #137, PR #138, PR #139, PR #140)
- Press play and audio starts as soon as the first segment is ready. The compute worker keeps generating ahead in the background, outside the browser request, so playback no longer depends on the tab driving each request.
- The whole document is one continuous, seekable timeline, and audio streams directly from the worker as a signed MP3.
- Generated audio is cached and reused when you seek, reload, or move between pages and chapters. Nothing is regenerated that already exists.
- Pausing, seeking or resetting the cache cancels stale generation right away, so provider calls stop for audio you'll never hear.
- A duration-based play-ahead buffer keeps a ready window in front of you. Forward generation grew from 8 to 48 segments, to stay ahead even with production provider latency.
- Admins can choose how far generation continues after the reader stops listening: the current PDF page or EPUB chapter (default), or the rest of the document (Settings → Admin → Instance).
- Stalled streams recover automatically with bounded retries and keep the audio already cached. Safari and iOS autoplay now unlock correctly.
Brand-new player (PR #133, PR #140)
- A scrub bar along the top edge covers the whole document. Already-generated audio is shown in your accent color, and dragging shows a time preview.
current / totaltime readout for the document.- Live buffer badge ("12s ahead", "Loading ahead · 4s ready") shows how much audio is ready.
- The play button doubles as a cancel button while audio loads.
- Dedicated phone layout: two rows, larger touch targets and a compact PDF page-navigation row.
Unified compute rate limiting (PR #141, PR #142, PR #146), docs
- One versioned policy covers every expensive workload: PDF layout parsing, playback sessions, playback planning, audiobook export, document previews, DOCX conversion, account export and TTS synthesis. Each action has its own enable switch.
- Four layers of control:
- admission windows (burst and sustained limits per user or IP)
- active leases and queues
- worker resource pools (CPU, speech-alignment model, FFmpeg, LibreOffice, archive)
- per-provider concurrency plus rolling request and character limits
- Limits are coordinated across worker replicas, and a provider
429 Retry-Aftertriggers a shared cooldown instead of a retry storm. - TTS characters are charged only for segments that are actually synthesized, not for cached audio. Audio you've already generated stays playable after you reach a limit.
- New visual policy editor in Settings → Admin → Compute. Users can see their own TTS usage in Settings → Account.
- Self-host defaults stay out of the way: admission limits and generated-character limits are off, and provider concurrency is 3.
User administration (PR #145), docs
- New Admin → Users directory with search, account-kind and status filters, and document count, stored bytes and compute activity for each user.
- Change a user's role or status, or delete them. Select many users to approve, suspend, restore or delete in bulk.
- The last administrator is protected: every demote, suspend and delete path, including self-deletion, is checked atomically.
- User deletion is durable. If the server restarts mid-delete, cleanup resumes automatically on the next startup.
Signup policy with approval queue (PR #145)
- The on/off signup toggle is now a three-way policy: Open, Approve (new accounts wait in a pending state until an admin approves them) or Closed.
First-boot bootstrap admin (PR #145), docs
- Set
BOOTSTRAP_ADMIN_EMAILandBOOTSTRAP_ADMIN_PASSWORD(orBOOTSTRAP_ADMIN_PASSWORD_FILE; minimum 16 characters) to create the first administrator of a new instance. - Admin rights activate after that account changes its initial password in Settings → Account.
Account self-service (PR #145)
- New Account Security panel: edit your display name, email and password inline.
- Email changes are verified, with resend support. Changing your password signs out your other sessions.
Account email with Resend (PR #143), docs
- Opt-in email verification, forgot-password and reset-password flows, with new
/verify-email,/forgot-passwordand/reset-passwordpages. - New Admin → Email panel stores the Resend API key encrypted and can send a test email.
- The worker delivers email durably using responsive, theme-aware templates. You can pre-configure it through the
accountEmailruntime seed key.
⚡ Improved
Compute worker owns all heavy work (PR #133), docs
- PDF layout parsing, PDF and EPUB preview rendering, DOCX conversion (headless LibreOffice), audiobook and account exports, retention, and cleanup all run on the worker now. The web app stays responsive while it works.
- The worker is locked down: it has no database access and never receives
POSTGRES_URLorAUTH_SECRET.- TTS provider API keys are handed out per job by an authenticated app credential broker. They never pass through NATS, SSE, stored artifacts or logs.
- Each trust boundary uses its own secret.
- Worker HTTP requests that are aborted now release their in-flight slots (PR #136).
Audiobook export rebuilt (PR #133, PR #144)
- M4B and MP3 audiobooks are now assembled by the worker from the same cache playback uses, so audio you've already listened to isn't generated again.
- A segment that fails to generate becomes a short pause instead of failing the whole export. The export reports how many segments were skipped, generated and planned, and an export that would be entirely silent is rejected.
- Export progress survives page reloads and reconnects.
- This replaces v4's per-chapter generate, regenerate and delete workflow with a single progress-tracked export.
Account export rebuilt (PR #133, PR #144)
- Account data export is now a worker job with live progress and a dedicated download. It covers the v5 schema and still reads legacy archives.
One reader startup for every format (PR #133)
- PDF, EPUB and HTML documents now share one startup pipeline, with live server-sent progress and a consistent loading screen. This replaces the PDF-only layout-scan animation.
More accurate word highlighting (PR #133, PR #135, PR #140)
- Highlighting uses only exact Whisper word timings. The proportional estimates that drifted out of sync are gone.
- English documents use the faster Whisper Tiny English model, and other languages use multilingual Whisper Base.
- Model download progress is bounded and clearly labeled.
Settings is now a full page (PR #143)
- The settings modal is now a Finder-style page at
/app/settings, with General and Admin sections that have their own URLs. - General: Appearance and Account, including account security, your TTS provider and the changelog.
- Admin: Users, Providers, Email, Instance, Compute, Maintenance.
- Maintenance tasks for expiring export artifacts and pruning compute-limit records can be run on demand.
Uploads (PR #143)
- The file picker, drag-and-drop, created documents, URL import and server-library import all share one upload pipeline.
- Real transfer and DOCX-conversion progress, per-file cancel, and retry for failed files only.
- Files upload into the folder you're viewing, and browser memory use is bounded for large batches.
- New Add Documents entry point and upload status in the sidebar.
Finder
- Simpler header and status areas. Previews and scroll position are kept when you switch folders (PR #143).
- In presigned deployments, document previews load straight from object storage with long-lived cached URLs, making large libraries faster and cheaper to browse (PR #146).
Storage transport (PR #133), docs
- New explicit
S3_INTERNAL_ENDPOINTandS3_PUBLIC_ENDPOINT, plusS3_BROWSER_TRANSPORT(auto,proxyorpresigned). They replace loopback-address guessing and the old fallback routes. - The embedded SeaweedFS default now serves browser traffic through a same-origin proxy, so port
8333no longer has to be exposed. - New
S3_AUTO_CREATE_BUCKET, andWEED_MINI_BIND_HOST/WEED_MINI_ADVERTISE_HOST/WEED_MINI_PORTfor the embedded store.
- Docker Compose is now the recommended setup, with slim, full and local-build stacks in
examples/docker/. - A complete runtime seed example ships at
examples/openreader-seed.json. API_MODEL_NAMEsets the default model for the seeded TTS provider.
Lower hosting cost and more resilient config (PR #146)
- The worker refreshes its limit policy every 5 minutes instead of every 60 seconds.
- Runtime config is cached briefly (
RUNTIME_CONFIG_CACHE_TTL_MS, default 15s) and falls back to the last known-good values if the database has a transient error. A database blip can no longer, for example, reopen signups.
Privacy and security
- Refreshed privacy page and data disclosures. You're asked to accept the privacy terms again when the policy changes.
- Analytics require explicit consent, and ONNX and Next.js telemetry are disabled (PR #133).
Packages and testing (PR #133)
- TTS provider code now lives in a reusable
@openreader/ttspackage, and runtime configuration in@openreader/runtime-config. - The end-to-end suite was rebuilt as real browser walkthroughs on Chromium and WebKit, alongside a much larger unit test suite.
🐛 Fixed
- Fixed document downloads in presigned-storage deployments (PR #134)
- Fixed live playback state being overwritten by stale sessions, and provider work now stops promptly when you pause or seek (PR #137)
- Fixed playback progress updates that could be missed right after a session started. Cached audio is found per segment instead of by probing the whole book (PR #138)
- Fixed seek and playback lifecycle races that could leave the player stuck (PR #139)
- Fixed playback readiness leaking between sessions (PR #140)
- Fixed a WebKit flake when saving PDF view preferences, and reduced redundant timeline refreshes (PR #142)
- Fixed audiobook export progress after reconnects, queued exports carried over from v4, and account export on the v5 schema (PR #144)
- Fixed glitchy transitions between the changelog and onboarding modals (PR #144)
- Fixed signup-policy migration for instances that had signups disabled, so they stay closed after upgrading (PR #145)
- Fixed clearer email verification messaging, the email settings loading state, the anonymous device limit label, and email settings saves
- Fixed compute-limit callbacks from the credential broker being rejected
⚠️ Upgrading from v4.4.0
v5 is a hard cut. Back up your database and object-storage volumes before upgrading. Never run docker compose down -v: it deletes the data you are upgrading.
What happens automatically
On startup, the Docker entrypoint applies schema migrations 0013 through 0020 and then permanently deletes the retired v4 object prefixes tts_segments_v1/, tts_segments_v2/ and audiobooks_v1/. Check the logs for the migration and decommission completion messages.
v4 generated audio and audiobooks are not carried over.
- The migrations drop the old TTS segment cache and audiobook tables, and reset TTS usage counters.
- Audio regenerates on demand into the new v5 playback cache.
- Export anything you want to keep before upgrading.
Documents, folders, users, settings, preferences and reading progress are preserved. Existing administrators remain administrators.
Docker Compose
Pull the new image and recreate your stack with the same project name, volumes, AUTH_SECRET and storage settings. See Upgrade from v4.4 to v5.
The Compose examples moved from docker/examples/ to examples/docker/. Update your -f paths if you use the repository files.
Required new configuration
TTS_PLAYBACK_TOKEN_SECRETis required for playback in every deployment, including the embedded worker. Set a stable random value.COMPUTE_CREDENTIAL_BROKER_TOKENis generated automatically when the worker is embedded. With an external worker, set it on both the app and the worker, and setCOMPUTE_CREDENTIAL_BROKER_URLon the worker.- Browsers must be able to reach the compute worker (port
8081). Audio streams directly from the worker.- The Compose examples already publish it. With plain
docker run, add-p 8081:8081,COMPUTE_WORKER_HOST=0.0.0.0andCOMPUTE_WORKER_PUBLIC_URL=http://<host>:8081for LAN or remote access. - Port
8333no longer needs to be exposed.
- The Compose examples already publish it. With plain
- External worker: deploy the v5 app and v5 worker together. Do not give the worker
POSTGRES_URLorAUTH_SECRET. See Compute worker.
External S3 storage
- With external (non-embedded) S3,
S3_BROWSER_TRANSPORT=autorefuses to start unless you set either:S3_PUBLIC_ENDPOINT(a dedicated HTTPS hostname, not a path mount), orS3_BROWSER_TRANSPORT=proxy.
- Proxy mode is not supported on Vercel.
S3_ENDPOINTstill works but is deprecated and logs a warning. Switch toS3_INTERNAL_ENDPOINTandS3_PUBLIC_ENDPOINT.
Vercel and other app-only deployments
These deployments have no entrypoint to run migrations.
- Take the v4 deployment offline and back up.
- Run
pnpm migrateagainst production. - Run
pnpm migrate-decommissionwith the production S3 configuration. - Deploy v5 together with its compute worker.
See Migrations.
Removed and renamed settings
| v4 | v5 |
|---|---|
ADMIN_EMAILS
| No longer grants admin. Existing admins are kept; new instances use BOOTSTRAP_ADMIN_EMAIL and BOOTSTRAP_ADMIN_PASSWORD
|
RUN_FS_MIGRATIONS
| RUN_V4_DECOMMISSION (the filesystem-to-S3 migration was removed)
|
IMPORT_LIBRARY_DIR
| IMPORT_LIBRARY_DIRS
|
COMPUTE_JOB_CONCURRENCY
| Removed. Concurrency is set in the compute limit policy |
ENABLE_TEST_NAMESPACE
| Removed |
enableUserSignups (setting and seed)
| signupPolicy: open, approval or closed (migrated automatically)
|
disableTtsRateLimit, ttsDailyLimit*, computeParse* (seed)
| computeLimitPolicies
|
The full list is in Environment variables.
Removed API routes
If you call OpenReader's API directly:
/api/audiobook*: use the worker-backed audiobook export./api/tts/segments/ensure,/api/tts/segments/manifestand/api/tts/segments/audio/fallback: use the playback session API./api/documents/blob/*/fallbackand/api/documents/blob/get/presign: removed./api/rate-limit/status: removed./api/documents/library*: moved to/api/local-library*.
Full Changelog: v4.4.0...v5.0.0