diff --git a/docs-site/versioned_docs/version-v2.1.2/about/acknowledgements.md b/docs-site/versioned_docs/version-v2.1.2/about/acknowledgements.md new file mode 100644 index 0000000..0a6c5ec --- /dev/null +++ b/docs-site/versioned_docs/version-v2.1.2/about/acknowledgements.md @@ -0,0 +1,16 @@ +--- +title: Acknowledgements +--- + +This project is built with support from the following open-source projects and tools: + +- [Kokoro-82M](https://huggingface.co/hexgrad/Kokoro-82M) +- [Kokoro-FastAPI](https://github.com/remsky/Kokoro-FastAPI) +- [Better Auth](https://www.better-auth.com/) +- [SQLite](https://www.sqlite.org/) +- [PostgreSQL](https://www.postgresql.org/) +- [SeaweedFS](https://github.com/seaweedfs/seaweedfs) +- [whisper.cpp](https://github.com/ggerganov/whisper.cpp) +- [ffmpeg](https://ffmpeg.org) +- [react-pdf](https://github.com/wojtekmaj/react-pdf) +- [react-reader](https://github.com/happyr/react-reader) diff --git a/docs-site/versioned_docs/version-v2.1.2/about/license.md b/docs-site/versioned_docs/version-v2.1.2/about/license.md new file mode 100644 index 0000000..24af383 --- /dev/null +++ b/docs-site/versioned_docs/version-v2.1.2/about/license.md @@ -0,0 +1,7 @@ +--- +title: License +--- + +OpenReader is licensed under the MIT License. + +- Repository license file: [LICENSE](https://github.com/richardr1126/openreader/blob/main/LICENSE) diff --git a/docs-site/versioned_docs/version-v2.1.2/about/support-and-contributing.md b/docs-site/versioned_docs/version-v2.1.2/about/support-and-contributing.md new file mode 100644 index 0000000..cef6224 --- /dev/null +++ b/docs-site/versioned_docs/version-v2.1.2/about/support-and-contributing.md @@ -0,0 +1,19 @@ +--- +title: Support and Contributing +--- + +## Feature requests + +Use [GitHub Discussions](https://github.com/richardr1126/openreader/discussions) for feature requests and ideas. + +## Issues and support + +If you encounter a bug, open an issue in [GitHub Issues](https://github.com/richardr1126/openreader/issues). + +## Contributing + +Contributions are welcome. + +- Fork the repository +- Create your branch +- Open a pull request with your changes diff --git a/docs-site/versioned_docs/version-v2.1.2/configure/auth.md b/docs-site/versioned_docs/version-v2.1.2/configure/auth.md new file mode 100644 index 0000000..c89400c --- /dev/null +++ b/docs-site/versioned_docs/version-v2.1.2/configure/auth.md @@ -0,0 +1,46 @@ +--- +title: Auth +--- + +This page covers application-level configuration for provider access and authentication. + +## Auth behavior + +- Auth is enabled only when both `BASE_URL` and `AUTH_SECRET` are set. +- Remove either value to disable auth. +- Keep `AUTH_TRUSTED_ORIGINS` empty to trust only `BASE_URL`. +- Anonymous auth sessions are disabled by default. +- Set `USE_ANONYMOUS_AUTH_SESSIONS=true` to enable anonymous session flows. + +## Route behavior + +- `/` is a public landing/onboarding page and remains indexable. +- `/app` is the protected app home (document list and uploader UI). +- If auth is enabled and a valid session exists (including anonymous), visiting `/` redirects to `/app`. +- Protected app routes continue to require auth; when anonymous sessions are disabled and no session exists, users are redirected to `/signin`. + +## Related docs + +- For auth environment variables: [Environment Variables](../reference/environment-variables#auth-and-identity) +- For TTS character limits and quota behavior: [TTS Rate Limiting](./tts-rate-limiting) +- For provider-specific guidance: [TTS Providers](./tts-providers) +- For storage/S3/SeaweedFS behavior: [Object / Blob Storage](./object-blob-storage) +- For database mode: [Database](./database) +- For migration behavior and commands: [Migrations](./migrations) + +## Sync notes + +### Auth enabled + +- Settings and reading progress are saved to the server. +- Updates are not instant push-based sync; they use normal client polling/refresh behavior. +- If two devices change the same item around the same time, the newest update wins. + +### Auth disabled + +- Settings and reading progress stay local in the browser (Dexie/IndexedDB). +- This avoids no-auth cross-browser conflicts, but there is no cross-device sync. + +## Claim modal note + +- You may still see old anonymous settings/progress available to claim from older deployments. diff --git a/docs-site/versioned_docs/version-v2.1.2/configure/database.md b/docs-site/versioned_docs/version-v2.1.2/configure/database.md new file mode 100644 index 0000000..45586af --- /dev/null +++ b/docs-site/versioned_docs/version-v2.1.2/configure/database.md @@ -0,0 +1,39 @@ +--- +title: Database +--- + +This page covers database mode selection for OpenReader. + +## Database mode + +- SQLite (default): embedded DB at `docstore/sqlite3.db`; good for local/self-host single-instance setups. +- Postgres: enabled when `POSTGRES_URL` is set; recommended for production/distributed deployments. + +## What the database stores + +- Document and audiobook metadata/state used by server routes. +- Auth/session tables (`user`, `session`, `account`, `verification`) when auth is enabled — schema is auto-generated by Better Auth. +- TTS character usage counters (`user_tts_chars`) for daily rate limiting (when enabled). +- User settings preferences (`user_preferences`) when auth is enabled. +- User reading progress (`user_document_progress`) when auth is enabled. +- Document preview job/asset metadata (`document_previews`) for server-side PDF/EPUB thumbnails. + +App-specific tables are manually maintained in Drizzle schema files, while auth tables are generated by the Better Auth CLI. Both are migrated together via Drizzle. See [Migrations](./migrations) for details. + +## Related variables + +- `POSTGRES_URL` + +For database variable behavior, see [Environment Variables](../reference/environment-variables#database-and-object-blob-storage). + +## Related docs + +- [Migrations](./migrations) +- [Object / Blob Storage](./object-blob-storage) +- [Auth](./auth) + +## State sync summary + +- With auth enabled, settings and reading progress are stored in SQL and synced from the app. +- With auth disabled, settings and reading progress remain local in the browser. +- Sync is currently request-based (not realtime push invalidation). diff --git a/docs-site/versioned_docs/version-v2.1.2/configure/migrations.md b/docs-site/versioned_docs/version-v2.1.2/configure/migrations.md new file mode 100644 index 0000000..66c8f4b --- /dev/null +++ b/docs-site/versioned_docs/version-v2.1.2/configure/migrations.md @@ -0,0 +1,132 @@ +--- +title: Migrations +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +This page covers migration behavior for both database schema and storage data in OpenReader. + +## Startup migration behavior + +By default, the shared entrypoint runs migrations automatically before app startup in: + +- Docker container startup +- `pnpm dev` +- `pnpm start` + +Startup migration phases: + +- DB schema migrations (`pnpm migrate`) +- Storage/data migration (`pnpm migrate-fs`) for legacy filesystem content into S3 + DB rows + +:::info +In most setups, you do not need to run migration commands manually because startup handles this automatically. +::: + +To skip automatic startup migrations: + +- Set `RUN_DRIZZLE_MIGRATIONS=false` +- Set `RUN_FS_MIGRATIONS=false` + +:::warning +If you disable startup migrations, ensure your deployment process runs migrations before serving traffic. +::: + +## Apply migrations + +In most cases, you do not need manual migration commands because startup runs migrations automatically. + +`pnpm migrate` applies migrations for one database target: + +- Postgres when `POSTGRES_URL` is set +- SQLite when `POSTGRES_URL` is unset + +You can always override the target explicitly with `--config`. + + + + +```bash +# Run pending migrations for one target: +# - Postgres if POSTGRES_URL is set +# - SQLite if POSTGRES_URL is unset +pnpm migrate + +# Run storage migration (filesystem -> S3 + DB) +pnpm migrate-fs + +# Dry-run storage migration without uploading/deleting +pnpm migrate-fs:dry-run +``` + + + + +```bash +# Migrate SQLite +pnpm exec drizzle-kit migrate --config drizzle.config.sqlite.ts + +# Migrate Postgres +pnpm exec drizzle-kit migrate --config drizzle.config.pg.ts +``` + + + + +## Generate migrations + +`pnpm generate` is a two-phase script for contributors and schema changes: + +1. **Better Auth schema generation** — runs the Better Auth CLI twice (once for SQLite, once for Postgres) to produce auto-generated Drizzle schema files for auth tables (`user`, `session`, `account`, `verification`). +2. **Drizzle migration generation** — runs `drizzle-kit generate` for both `drizzle.config.sqlite.ts` and `drizzle.config.pg.ts`, producing SQL migration files from all schema files (app + auth). + +:::note +Most users do not need to run `pnpm generate`. Use it when contributing or when you have changed Drizzle schema files and need new migration files. +::: + +### Schema ownership + +Auth tables are owned by Better Auth. Their Drizzle schema definitions are auto-generated and should **not** be hand-edited: + +- `src/db/schema_auth_sqlite.ts` +- `src/db/schema_auth_postgres.ts` + +App-specific tables are manually maintained in the standard Drizzle schema files: + +- `src/db/schema_sqlite.ts` +- `src/db/schema_postgres.ts` + +Both sets of schema files are included in the Drizzle configs, so `drizzle-kit generate` and `drizzle-kit migrate` handle all tables together. + + + + +```bash +# Full pipeline: Better Auth CLI + Drizzle generate (both dialects) +pnpm generate +``` + + + + +```bash +# Generate SQLite migrations only (skips Better Auth CLI) +pnpm exec drizzle-kit generate --config drizzle.config.sqlite.ts + +# Generate Postgres migrations only (skips Better Auth CLI) +pnpm exec drizzle-kit generate --config drizzle.config.pg.ts +``` + +:::warning +Running `drizzle-kit generate` directly skips the Better Auth CLI step. If auth schema has changed upstream (e.g. after a Better Auth version bump), run `pnpm generate` instead to regenerate the auth schema files first. +::: + + + + +## Related docs + +- [Database](./database) +- [Object / Blob Storage](./object-blob-storage) +- [Migration Environment Variables](../reference/environment-variables#migration-controls) diff --git a/docs-site/versioned_docs/version-v2.1.2/configure/object-blob-storage.md b/docs-site/versioned_docs/version-v2.1.2/configure/object-blob-storage.md new file mode 100644 index 0000000..ff46fd1 --- /dev/null +++ b/docs-site/versioned_docs/version-v2.1.2/configure/object-blob-storage.md @@ -0,0 +1,103 @@ +--- +title: Object / Blob Storage +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +This page documents storage backends, blob upload routing, and core Docker mount behavior. + +## Storage backends + +- Embedded (default): SQLite metadata + embedded SeaweedFS (`weed mini`) blobs. +- External: Postgres + external S3-compatible object storage. + +Storage variables are documented in [Environment Variables](../reference/environment-variables#database-and-object-blob-storage). + +## Ports + +- `3003`: OpenReader app and API routes +- `8333`: Embedded SeaweedFS S3 endpoint for direct browser blob access + +:::info +`8333` is only needed for direct browser presigned access to embedded SeaweedFS. +::: + +## Upload behavior + +- Primary path: browser uploads to presigned URL from `/api/documents/blob/upload/presign`. +- Fallback path: `/api/documents/blob/upload/fallback` when direct upload fails/unreachable. +- Read/download path: blob/content serving route `/api/documents/blob` (not the upload fallback route). +- Preview path: `/api/documents/blob/preview` (returns `202` while a preview is generating; serves/redirects when ready). + +## Document previews + +- PDF/EPUB previews are generated server-side and stored in object storage under `document_previews_v1`. +- Preview generation is triggered on upload registration and also backfills on first preview request for older docs. +- Preview artifacts are temporary-cache friendly and can be regenerated from the source document blob. + +## FS / Volume Mounts + +### App data mount + +- Target: `/app/docstore` +- Recommended: yes, for persistence +- Purpose: persists SeaweedFS blob data, SQLite metadata DB, migrations, and local runtime temp state +- Mount string: `-v openreader_docstore:/app/docstore` + +### Library source mount (optional) + +- Target: `/app/docstore/library` +- Recommended: optional, use read-only (`:ro`) +- Purpose: exposes host files as a source for server library import +- Mount string: `-v /path/to/your/library:/app/docstore/library:ro` +- Details: [Server Library Import](./server-library-import) + +## Private blob endpoint mode + +If `8333` is not published externally: + +- Document uploads still work through upload fallback proxy +- Reads/snippets continue through app API routes +- Direct presigned browser upload/download to embedded endpoint is unavailable + +:::warning +Without `8333`, expect higher app-server traffic because uploads/downloads go through API routes instead of direct object endpoint access. +::: + +## Audiobook Storage Debug Commands + +Audiobook assets are stored in object storage under the `audiobooks_v1` keyspace. Use these commands to inspect and download objects for debugging. + + + + +```bash +# List all audiobook objects +aws s3 ls "s3://$S3_BUCKET/$S3_PREFIX/audiobooks_v1/" --recursive + +# Filter to one book id (replace ) +aws s3 ls "s3://$S3_BUCKET/$S3_PREFIX/audiobooks_v1/" --recursive | grep "-audiobook/" + +# Download one object by full key +aws s3 cp "s3://$S3_BUCKET/$S3_PREFIX/audiobooks_v1//.m4b" "./audiobook.m4b" +``` + + + + +```bash +# List all audiobook objects +aws s3 ls "s3://$S3_BUCKET/$S3_PREFIX/audiobooks_v1/" --recursive --endpoint-url "$S3_ENDPOINT" + +# Filter to one book id (replace ) +aws s3 ls "s3://$S3_BUCKET/$S3_PREFIX/audiobooks_v1/" --recursive --endpoint-url "$S3_ENDPOINT" | grep "-audiobook/" + +# Download one object by full key +aws s3 cp "s3://$S3_BUCKET/$S3_PREFIX/audiobooks_v1//.m4b" "./audiobook.m4b" --endpoint-url "$S3_ENDPOINT" +``` + +Embedded default example: `S3_ENDPOINT=http://127.0.0.1:8333` (or your mapped host/port). + + + diff --git a/docs-site/versioned_docs/version-v2.1.2/configure/server-library-import.md b/docs-site/versioned_docs/version-v2.1.2/configure/server-library-import.md new file mode 100644 index 0000000..acdecd2 --- /dev/null +++ b/docs-site/versioned_docs/version-v2.1.2/configure/server-library-import.md @@ -0,0 +1,68 @@ +--- +title: Server Library Import +--- + +This page documents how server library import works and how to configure it. + +## What it does + +Server library import lets you browse files from one or more server directories and import selected files into OpenReader. + +- Import is user-driven via a selection modal +- Only selected files are imported +- Imported files become normal OpenReader documents + +## FS / Volume Mounts + +### App data mount + +- Target: `/app/docstore` +- Recommended: yes, for persistence +- Purpose: stores app runtime data, metadata DB, and embedded storage state +- Mount string: `-v openreader_docstore:/app/docstore` + +### Library source mount + +- Target: `/app/docstore/library` +- Recommended: yes for this feature, use read-only (`:ro`) +- Purpose: exposes host files as import candidates in Server Library Import +- Mount string: `-v /path/to/your/library:/app/docstore/library:ro` + +## Import flow + +1. Open **Settings -> Documents -> Server Library Import**. +2. Select files in the modal. +3. Click **Import**. + +Selected files are fetched from the server library endpoint and imported into OpenReader storage. + +:::warning Shared Library Roots +Library roots are configured at the server level (not per-user). Any user who can access Server Library Import can browse/import from the same configured roots. + +Imported documents are still saved to the importing user's document scope. +::: + +## Supported file types + +- `.pdf` +- `.epub` +- `.html`, `.htm` +- `.txt` +- `.md`, `.mdown`, `.markdown` + +## Optional: Configure Library Roots + +You only need this when the default mounted path is not what you want. + +By default, OpenReader uses `docstore/library` as the import root. You can override that with environment variables: + +- `IMPORT_LIBRARY_DIRS` (takes precedence): multiple roots separated by comma, colon, or semicolon +- `IMPORT_LIBRARY_DIR`: single root + +See [Environment Variables](../reference/environment-variables#library-import) for variable details. + +## Notes + +- Library listing is capped per request (up to 10,000 files). +- When auth is enabled, library import endpoints require a valid session. +- The mounted library is a source; removing it does not delete already imported documents. diff --git a/docs-site/versioned_docs/version-v2.1.2/configure/tts-provider-guides/deepinfra.md b/docs-site/versioned_docs/version-v2.1.2/configure/tts-provider-guides/deepinfra.md new file mode 100644 index 0000000..d1d6426 --- /dev/null +++ b/docs-site/versioned_docs/version-v2.1.2/configure/tts-provider-guides/deepinfra.md @@ -0,0 +1,36 @@ +--- +title: DeepInfra +--- + +Use DeepInfra's hosted TTS models as your provider. + +## Setup + +**Environment variables (recommended for deployment):** + +```env +API_BASE=https://api.deepinfra.com/v1/openai +API_KEY=your-deepinfra-key +NEXT_PUBLIC_DEFAULT_TTS_PROVIDER=deepinfra +``` + +**Or in-app via Settings → TTS Provider:** + +1. Set provider to `Deepinfra`. +2. The base URL is pre-filled, no changes needed. +3. Enter your `API_KEY`. +4. Choose a model and voice. + +Settings modal values override env vars. See [TTS Providers](../tts-providers) for how the two layers interact. + +## Notes + +- Available models include `hexgrad/Kokoro-82M` and `canopylabs/orpheus-3b-0.1-ft`. +- Without an API key, only the free-tier model (`hexgrad/Kokoro-82M`) is shown in the dropdown. +- TTS requests are sent from the server, not the browser. The API key is never exposed to clients. + +## References + +- [DeepInfra TTS models](https://deepinfra.com/models/text-to-speech) +- [TTS Providers](../tts-providers) +- [TTS Environment Variables](../../reference/environment-variables#tts-provider-and-request-behavior) diff --git a/docs-site/versioned_docs/version-v2.1.2/configure/tts-provider-guides/kitten-tts-fastapi.md b/docs-site/versioned_docs/version-v2.1.2/configure/tts-provider-guides/kitten-tts-fastapi.md new file mode 100644 index 0000000..427a41c --- /dev/null +++ b/docs-site/versioned_docs/version-v2.1.2/configure/tts-provider-guides/kitten-tts-fastapi.md @@ -0,0 +1,40 @@ +--- +title: KittenTTS-FastAPI +--- + +Run [KittenTTS-FastAPI](https://github.com/richardr1126/KittenTTS-FastAPI) locally and connect it to OpenReader using the `Custom OpenAI-Like` provider. Lightweight and CPU-friendly. + +## Run KittenTTS + +```bash +docker run -it --rm \ + --name kittentts-fastapi \ + -e KITTEN_MODEL_REPO_ID="KittenML/kitten-tts-nano-0.8-fp32" \ + -p 8005:8005 \ + ghcr.io/richardr1126/kittentts-fastapi-cpu +``` + +## Connect to OpenReader + +**Environment variables (recommended for deployment):** + +```env +API_BASE=http://kittentts-fastapi:8005/v1 +``` + +> Use `kittentts-fastapi` if that's the container name, or `host.docker.internal` if not. + +**Or in-app via Settings → TTS Provider:** + +1. Set provider to `Custom OpenAI-Like`. +2. Set `API_BASE` to your KittenTTS endpoint (e.g. `http://kittentts-fastapi:8005/v1`). +3. Leave `API_KEY` blank unless your deployment requires one. +4. Choose model `kitten-tts` (or the model your deployment exposes). + +Settings modal values override env vars. See [TTS Providers](../tts-providers) for how the two layers interact. + +## References + +- [richardr1126/KittenTTS-FastAPI](https://github.com/richardr1126/KittenTTS-FastAPI) +- [TTS Providers](../tts-providers) +- [TTS Environment Variables](../../reference/environment-variables#tts-provider-and-request-behavior) diff --git a/docs-site/versioned_docs/version-v2.1.2/configure/tts-provider-guides/kokoro-fastapi.md b/docs-site/versioned_docs/version-v2.1.2/configure/tts-provider-guides/kokoro-fastapi.md new file mode 100644 index 0000000..10271ff --- /dev/null +++ b/docs-site/versioned_docs/version-v2.1.2/configure/tts-provider-guides/kokoro-fastapi.md @@ -0,0 +1,68 @@ +--- +title: Kokoro-FastAPI +--- + +Run [Kokoro-FastAPI](https://github.com/remsky/Kokoro-FastAPI) locally and connect it to OpenReader using the `Custom OpenAI-Like` provider. + +:::warning +For Kokoro issues and support, use the upstream repository: [remsky/Kokoro-FastAPI](https://github.com/remsky/Kokoro-FastAPI). +::: + +## Run Kokoro + +**CPU:** + +```bash +docker run --name kokoro-tts \ + --restart unless-stopped \ + -d \ + -p 8880:8880 \ + -e ONNX_NUM_THREADS=8 \ + -e ONNX_INTER_OP_THREADS=4 \ + -e ONNX_EXECUTION_MODE=parallel \ + -e ONNX_OPTIMIZATION_LEVEL=all \ + -e ONNX_MEMORY_PATTERN=true \ + -e ONNX_ARENA_EXTEND_STRATEGY=kNextPowerOfTwo \ + -e API_LOG_LEVEL=DEBUG \ + ghcr.io/remsky/kokoro-fastapi-cpu:v0.2.4 +``` + +**GPU (NVIDIA):** + +```bash +docker run --name kokoro-tts \ + --restart unless-stopped \ + -d \ + --gpus all \ + --user 1001:1001 \ + -p 8880:8880 \ + -e USE_GPU=true \ + -e PYTHONUNBUFFERED=1 \ + -e API_LOG_LEVEL=DEBUG \ + ghcr.io/remsky/kokoro-fastapi-gpu:v0.2.4 +``` + +## Connect to OpenReader + +**Environment variables (recommended for deployment):** + +```env +API_BASE=http://kokoro-tts:8880/v1 +``` + +> Use `kokoro-tts` if that's the container name, or `host.docker.internal` if not. + +**Or in-app via Settings → TTS Provider:** + +1. Set provider to `Custom OpenAI-Like`. +2. Set `API_BASE` to your Kokoro endpoint (e.g. `http://kokoro-tts:8880/v1`). +3. Leave `API_KEY` blank unless your deployment requires one. +4. Choose model `Kokoro`. + +Settings modal values override env vars. See [TTS Providers](../tts-providers) for how the two layers interact. + +## References + +- [remsky/Kokoro-FastAPI](https://github.com/remsky/Kokoro-FastAPI) +- [TTS Providers](../tts-providers) +- [TTS Environment Variables](../../reference/environment-variables#tts-provider-and-request-behavior) diff --git a/docs-site/versioned_docs/version-v2.1.2/configure/tts-provider-guides/openai.md b/docs-site/versioned_docs/version-v2.1.2/configure/tts-provider-guides/openai.md new file mode 100644 index 0000000..b5cf6fe --- /dev/null +++ b/docs-site/versioned_docs/version-v2.1.2/configure/tts-provider-guides/openai.md @@ -0,0 +1,35 @@ +--- +title: OpenAI +--- + +Use the OpenAI TTS API as your provider. + +## Setup + +**Environment variables (recommended for deployment):** + +```env +API_BASE=https://api.openai.com/v1 +API_KEY=sk-... +NEXT_PUBLIC_DEFAULT_TTS_PROVIDER=openai +``` + +**Or in-app via Settings → TTS Provider:** + +1. Set provider to `OpenAI`. +2. The base URL is pre-filled, no changes needed. +3. Enter your `API_KEY`. +4. Choose a model and voice. + +Settings modal values override env vars. See [TTS Providers](../tts-providers) for how the two layers interact. + +## Notes + +- Models: `tts-1`, `tts-1-hd`, `gpt-4o-mini-tts` +- TTS requests are sent from the server, not the browser. The API key is never exposed to clients. + +## References + +- [OpenAI TTS pricing](https://platform.openai.com/docs/pricing#transcription-and-speech) +- [TTS Providers](../tts-providers) +- [TTS Environment Variables](../../reference/environment-variables#tts-provider-and-request-behavior) diff --git a/docs-site/versioned_docs/version-v2.1.2/configure/tts-provider-guides/orpheus-fastapi.md b/docs-site/versioned_docs/version-v2.1.2/configure/tts-provider-guides/orpheus-fastapi.md new file mode 100644 index 0000000..fef9a7c --- /dev/null +++ b/docs-site/versioned_docs/version-v2.1.2/configure/tts-provider-guides/orpheus-fastapi.md @@ -0,0 +1,34 @@ +--- +title: Orpheus-FastAPI +--- + +Run [Orpheus-FastAPI](https://github.com/Lex-au/Orpheus-FastAPI) locally and connect it to OpenReader using the `Custom OpenAI-Like` provider. + +## Run Orpheus + +Refer to the upstream repository for Docker instructions: [Lex-au/Orpheus-FastAPI](https://github.com/Lex-au/Orpheus-FastAPI). + +## Connect to OpenReader + +**Environment variables (recommended for deployment):** + +```env +API_BASE=http://orpheus:8000/v1 +``` + +> Use the container name if that's how it's named, or `host.docker.internal` if not. + +**Or in-app via Settings → TTS Provider:** + +1. Set provider to `Custom OpenAI-Like`. +2. Set `API_BASE` to your Orpheus endpoint (e.g. `http://orpheus:8000/v1`). +3. Leave `API_KEY` blank unless your deployment requires one. +4. Choose model `Orpheus` (or the model your deployment exposes). + +Settings modal values override env vars. See [TTS Providers](../tts-providers) for how the two layers interact. + +## References + +- [Lex-au/Orpheus-FastAPI](https://github.com/Lex-au/Orpheus-FastAPI) +- [TTS Providers](../tts-providers) +- [TTS Environment Variables](../../reference/environment-variables#tts-provider-and-request-behavior) diff --git a/docs-site/versioned_docs/version-v2.1.2/configure/tts-provider-guides/other.md b/docs-site/versioned_docs/version-v2.1.2/configure/tts-provider-guides/other.md new file mode 100644 index 0000000..c509872 --- /dev/null +++ b/docs-site/versioned_docs/version-v2.1.2/configure/tts-provider-guides/other.md @@ -0,0 +1,45 @@ +--- +title: Other +--- + +Use any OpenAI-compatible TTS service with OpenReader, including self-hosted servers not covered by a dedicated guide. + +## Requirements + +Your service must expose these endpoints: + +- `GET /v1/audio/voices` +- `POST /v1/audio/speech` + +Known compatible implementations: [Kokoro-FastAPI](./kokoro-fastapi), [KittenTTS-FastAPI](./kitten-tts-fastapi), [Orpheus-FastAPI](./orpheus-fastapi). + +## Setup + +**Environment variables (recommended for deployment):** + +```env +API_BASE=http://your-tts-server/v1 +API_KEY=optional-key-if-required +``` + +**Or in-app via Settings → TTS Provider:** + +1. Set provider to `Custom OpenAI-Like`. +2. Set `API_BASE` to your service's base URL (typically ending in `/v1`). +3. Set `API_KEY` if your service requires authentication. +4. Choose a model and voice supported by your backend. + +Settings modal values override env vars. See [TTS Providers](../tts-providers) for how the two layers interact. + +:::warning TTS requests are server-side +`API_BASE` must be reachable from the **Next.js server**, not just the browser. In Docker, use container names or `host.docker.internal`. +::: + +## Troubleshooting + +If voices don't load, check that `/v1/audio/voices` is reachable from the server and returns a valid response shape. + +## References + +- [TTS Providers](../tts-providers) +- [TTS Environment Variables](../../reference/environment-variables#tts-provider-and-request-behavior) diff --git a/docs-site/versioned_docs/version-v2.1.2/configure/tts-providers.md b/docs-site/versioned_docs/version-v2.1.2/configure/tts-providers.md new file mode 100644 index 0000000..01783e6 --- /dev/null +++ b/docs-site/versioned_docs/version-v2.1.2/configure/tts-providers.md @@ -0,0 +1,46 @@ +--- +title: TTS Providers +--- + +OpenReader routes all TTS requests through the Next.js server to an OpenAI-compatible API. You choose your provider and credentials in one of two places: + +**Environment variables**: set in your `.env` or `docker-compose.yml` as server-level defaults. Applied when the user has no saved Settings. + +**Settings modal** (Settings > TTS Provider): stored in the browser and sent with every TTS request. **Overrides env vars.** + +:::note +Set env vars as deployment-level defaults. Users (or you, in a single-user setup) can then change the provider, base URL, and API key from the Settings modal without redeploying. Clearing the Settings fields falls back to the env var defaults. +::: + +## Providers + +- **OpenAI**: Cloud. Base URL pre-filled (`https://api.openai.com/v1`). API key required. +- **Deepinfra**: Cloud. Base URL pre-filled (`https://api.deepinfra.com/v1/openai`). API key required. +- **Custom OpenAI-Like**: Self-hosted or any custom endpoint. `API_BASE` must be set manually (typically ending in `/v1`). API key optional. + +For `OpenAI` and `Deepinfra` you only need to supply an API key. For `Custom OpenAI-Like` you must also set `API_BASE`. + +## Custom provider requirements + +Self-hosted or custom providers must expose OpenAI-compatible audio endpoints: + +- `GET /v1/audio/voices` +- `POST /v1/audio/speech` + +:::warning TTS requests are server-side +TTS requests originate from the **Next.js server**, not the browser. `API_BASE` must be reachable from the server runtime. In Docker, use container names or `host.docker.internal` rather than `localhost`. +::: + +## Provider guides + +- [Kokoro-FastAPI](./tts-provider-guides/kokoro-fastapi) +- [KittenTTS-FastAPI](./tts-provider-guides/kitten-tts-fastapi) +- [Orpheus-FastAPI](./tts-provider-guides/orpheus-fastapi) +- [DeepInfra](./tts-provider-guides/deepinfra) +- [OpenAI](./tts-provider-guides/openai) +- [Other](./tts-provider-guides/other) + +## Related + +- [TTS Environment Variables](../reference/environment-variables#tts-provider-and-request-behavior) +- [TTS Rate Limiting](./tts-rate-limiting) diff --git a/docs-site/versioned_docs/version-v2.1.2/configure/tts-rate-limiting.md b/docs-site/versioned_docs/version-v2.1.2/configure/tts-rate-limiting.md new file mode 100644 index 0000000..ed507d1 --- /dev/null +++ b/docs-site/versioned_docs/version-v2.1.2/configure/tts-rate-limiting.md @@ -0,0 +1,51 @@ +--- +title: TTS Rate Limiting +--- + +This page explains OpenReader's TTS character rate limiting controls. + +## Overview + +- TTS rate limiting is disabled by default. +- To enable it, set `TTS_ENABLE_RATE_LIMIT=true`. +- Limits are enforced per day in UTC. +- Enforcement applies only when auth is enabled. + +## How enforcement works + +When enabled, OpenReader enforces: + +- Per-user daily character limits. +- IP backstop daily character limits. +- Anonymous device backstop tracking (cookie-based) to reduce limit resets. + +If a request exceeds the active limit, the TTS API returns `429` with reset metadata for the next UTC day. + +## Required auth behavior + +- Auth must be enabled (`BASE_URL` + `AUTH_SECRET`) for TTS char limits to apply. +- If auth is disabled, TTS character limits are effectively unlimited. +- `DISABLE_AUTH_RATE_LIMIT` only affects Better Auth's own request throttling. +- `DISABLE_AUTH_RATE_LIMIT` does not disable TTS character limits. + +## Environment variables + +Enable/disable: + +- `TTS_ENABLE_RATE_LIMIT` (default: `false`) + +Per-user daily limits: + +- `TTS_DAILY_LIMIT_ANONYMOUS` (default: `50000`) +- `TTS_DAILY_LIMIT_AUTHENTICATED` (default: `500000`) + +IP backstop daily limits: + +- `TTS_IP_DAILY_LIMIT_ANONYMOUS` (default: `100000`) +- `TTS_IP_DAILY_LIMIT_AUTHENTICATED` (default: `1000000`) + +## Related docs + +- TTS/rate-limit environment variables: [Environment Variables](../reference/environment-variables#tts-provider-and-request-behavior) +- Auth configuration: [Auth](./auth) +- Provider setup: [TTS Providers](./tts-providers) diff --git a/docs-site/versioned_docs/version-v2.1.2/deploy/local-development.md b/docs-site/versioned_docs/version-v2.1.2/deploy/local-development.md new file mode 100644 index 0000000..dedc337 --- /dev/null +++ b/docs-site/versioned_docs/version-v2.1.2/deploy/local-development.md @@ -0,0 +1,138 @@ +--- +title: Local Development +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +## Prerequisites + +- Node.js (recommended with [nvm](https://github.com/nvm-sh/nvm)) +- `pnpm` (recommended) or `npm` + +```bash +npm install -g pnpm +``` + +- A reachable TTS API server +- [SeaweedFS](https://github.com/seaweedfs/seaweedfs) `weed` binary (required unless using external S3 storage) + + + + +```bash +brew install seaweedfs +``` + + + + +Install the `weed` binary from the [SeaweedFS releases](https://github.com/seaweedfs/seaweedfs/releases) and ensure it is available on `PATH`. + + + + +Optional, depending on features: + +- [libreoffice](https://www.libreoffice.org) (required for DOCX conversion) + +```bash +brew install libreoffice +``` + +- [whisper.cpp](https://github.com/ggml-org/whisper.cpp) (optional, for word-by-word highlighting) + +```bash +# clone and build whisper.cpp (no model download needed – OpenReader handles that) +git clone https://github.com/ggml-org/whisper.cpp.git +cd whisper.cpp +cmake -B build +cmake --build build -j --config Release + +# point OpenReader to the compiled whisper-cli binary +echo WHISPER_CPP_BIN="$(pwd)/build/bin/whisper-cli" +``` + +:::tip +Set `WHISPER_CPP_BIN` in your `.env` to enable word-by-word highlighting. +::: + +## Steps + +1. Clone the repository. + +```bash +git clone https://github.com/richardr1126/openreader.git +cd openreader +``` + +2. Install dependencies. + +```bash +pnpm i +``` + +3. Configure the environment. + +```bash +cp .env.example .env +``` + +Then edit `.env`. + +- No auth mode: leave `BASE_URL` or `AUTH_SECRET` unset. +- Auth enabled mode: set both `BASE_URL` (typically `http://localhost:3003`) and `AUTH_SECRET` (generate with `openssl rand -hex 32`). + +Optional: + +- `AUTH_TRUSTED_ORIGINS=http://localhost:3003,http://192.168.0.116:3003` +- Stable S3 credentials via `S3_ACCESS_KEY_ID` and `S3_SECRET_ACCESS_KEY` +- External S3 storage by setting `USE_EMBEDDED_WEED_MINI=false` and related S3 vars + +:::info +For all environment variables, see [Environment Variables](../reference/environment-variables). +::: + +See [Auth](../configure/auth) for app/auth behavior. +Storage configuration details are in [Object / Blob Storage](../configure/object-blob-storage). +Refer to [Database](../configure/database) for database modes. +Learn about migration behavior and commands in [Migrations](../configure/migrations). + +4. Run DB migrations. + +- Migrations run automatically on startup through the shared entrypoint for both `pnpm dev` and `pnpm start`. +- You only need manual migration commands for one-off troubleshooting or explicit migration workflows: + +```bash +pnpm migrate +``` + +:::info +If `POSTGRES_URL` is set, migrations target Postgres; otherwise local SQLite is used. To disable automatic startup migrations, set `RUN_DRIZZLE_MIGRATIONS=false` and/or `RUN_FS_MIGRATIONS=false`. You can run storage migration manually with `pnpm migrate-fs`. +::: + +5. Start the app. + + + + +```bash +pnpm dev +``` + + + + +```bash +pnpm build +pnpm start +``` + + + + +:::warning API Base Reachability +`API_BASE` must be reachable from the Next.js server process, not just your browser. +::: + +Visit [http://localhost:3003](http://localhost:3003). diff --git a/docs-site/versioned_docs/version-v2.1.2/deploy/vercel-deployment.md b/docs-site/versioned_docs/version-v2.1.2/deploy/vercel-deployment.md new file mode 100644 index 0000000..1bede11 --- /dev/null +++ b/docs-site/versioned_docs/version-v2.1.2/deploy/vercel-deployment.md @@ -0,0 +1,110 @@ +--- +title: Vercel Deployment +--- + +This guide covers deploying OpenReader to Vercel with external Postgres and S3-compatible object storage. + +## What works on Vercel + +- Documents (PDF/EPUB/TXT/MD) work with `POSTGRES_URL` + external S3 storage. +- Audiobook routes work on Node.js serverless functions using `ffmpeg-static`. + +:::warning DOCX Conversion Limitation +`docx` conversion requires `soffice` (LibreOffice), which is not available in a standard Vercel runtime. +::: + +## 1. Environment Variables + +Recommended production setup (auth enabled): + +```bash +API_BASE=https://api.deepinfra.com/v1/openai +API_KEY=your_deepinfra_key +POSTGRES_URL=postgres://... +USE_EMBEDDED_WEED_MINI=false +S3_ACCESS_KEY_ID=... +S3_SECRET_ACCESS_KEY=... +S3_BUCKET=... +S3_REGION=us-east-1 +S3_PREFIX=openreader +BASE_URL=https://your-app.vercel.app +AUTH_SECRET=... +# Optional client/runtime feature defaults: +NEXT_PUBLIC_ENABLE_DOCX_CONVERSION=false +NEXT_PUBLIC_ENABLE_DESTRUCTIVE_DELETE_ACTIONS=false +NEXT_PUBLIC_ENABLE_TTS_PROVIDERS_TAB=false +NEXT_PUBLIC_DEFAULT_TTS_PROVIDER=deepinfra +NEXT_PUBLIC_DEFAULT_TTS_MODEL=hexgrad/Kokoro-82M +NEXT_PUBLIC_SHOW_ALL_DEEPINFRA_MODELS=false +NEXT_PUBLIC_ENABLE_AUDIOBOOK_EXPORT=true +NEXT_PUBLIC_ENABLE_WORD_HIGHLIGHT=false +# Optional (non-AWS S3-compatible providers): +# S3_ENDPOINT=https://... +# S3_FORCE_PATH_STYLE=true +``` + +:::info Production Configuration & Feature Flags +We recommend setting these defaults for a production-like environment: + +- `NEXT_PUBLIC_ENABLE_DOCX_CONVERSION=false`: Disables DOCX upload (requires external tools anyway) +- `NEXT_PUBLIC_ENABLE_DESTRUCTIVE_DELETE_ACTIONS=false`: Hides destructive "Delete All" actions +- `NEXT_PUBLIC_ENABLE_TTS_PROVIDERS_TAB=false`: Hides the Settings -> TTS Provider section +- `NEXT_PUBLIC_DEFAULT_TTS_PROVIDER=deepinfra`: Points default TTS to a scalable provider +- `NEXT_PUBLIC_DEFAULT_TTS_MODEL=hexgrad/Kokoro-82M`: Uses a high-quality default model +- `NEXT_PUBLIC_SHOW_ALL_DEEPINFRA_MODELS=false`: Restricts usage to free models if no key is provided +- `NEXT_PUBLIC_ENABLE_AUDIOBOOK_EXPORT=true`: (Optional) Controls audiobook export UI +- `NEXT_PUBLIC_ENABLE_WORD_HIGHLIGHT=false`: (Optional) Controls word highlighting UI (requires timestamp backend) +::: + +:::warning Auth recommendation +For internet-exposed Vercel deployments, set both `BASE_URL` and `AUTH_SECRET`. Running without auth is possible, but not recommended for public environments. +::: + +:::tip +For all variables and defaults, see [Environment Variables](../reference/environment-variables). +::: + +## 2. FFmpeg packaging in Vercel functions + +`ffmpeg-static` binaries must be included in function traces. This repo already does that in `next.config.ts` via `outputFileTracingIncludes` for: + +- `/api/audiobook` +- `/api/audiobook/chapter` +- `/api/audiobook/status` +- `/api/whisper` + +:::info +`serverExternalPackages` should include `ffmpeg-static` so package paths resolve at runtime instead of being bundled into route output. +::: + +If you change route paths or split handlers, update `outputFileTracingIncludes` accordingly. + +## 3. Function memory sizing + +FFmpeg workloads benefit from more memory/CPU. This repo includes: + +```json +{ + "$schema": "https://openapi.vercel.sh/vercel.json", + "functions": { + "app/api/audiobook/route.ts": { "memory": 3009 }, + "app/api/whisper/route.ts": { "memory": 3009 } + } +} +``` + +Adjust memory per route if your files are larger or your plan differs. + +## 4. Runtime expectations and caveats + +- Audiobook APIs require S3 configuration; otherwise they return `503`. +- For production Vercel deploys, use `POSTGRES_URL` instead of SQLite. +- Filesystem-to-object-store migrations run via server scripts/entrypoint (`scripts/migrate-fs-v2.mjs`), not API routes. +- Vercel deployments do not run `scripts/openreader-entrypoint.mjs`, so run `pnpm migrate-fs` in a controlled environment when migrating legacy filesystem data. + +## 5. Smoke test after deploy + +1. Upload and read a PDF/EPUB document. +2. Confirm sync/blob fetch works across refreshes/devices. +3. Generate at least one audiobook chapter and play/download it. +4. If using word highlighting, verify timestamps are produced and rendered. diff --git a/docs-site/versioned_docs/version-v2.1.2/docker-quick-start.md b/docs-site/versioned_docs/version-v2.1.2/docker-quick-start.md new file mode 100644 index 0000000..b700e35 --- /dev/null +++ b/docs-site/versioned_docs/version-v2.1.2/docker-quick-start.md @@ -0,0 +1,121 @@ +--- +title: Docker Quick Start +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +## Prerequisites + +- A recent Docker version installed +- A TTS API server that OpenReader can reach (Kokoro-FastAPI, KittenTTS-FastAPI, Orpheus-FastAPI, DeepInfra, OpenAI, or equivalent) + +:::note +If you have suitable hardware, you can run Kokoro locally with Docker. See [Kokoro-FastAPI](./configure/tts-provider-guides/kokoro-fastapi). +::: + +## 1. Start the Docker container + + + + +Auth disabled, embedded storage ephemeral, no library import: + +```bash +docker run --name openreader \ + --restart unless-stopped \ + -p 3003:3003 \ + -p 8333:8333 \ + ghcr.io/richardr1126/openreader:latest +``` + + + + +Persistent storage, embedded SeaweedFS `weed mini`, optional auth, optional library mount: + +```bash +docker run --name openreader \ + --restart unless-stopped \ + -p 3003:3003 \ + -p 8333:8333 \ + -v openreader_docstore:/app/docstore \ + -v /path/to/your/library:/app/docstore/library:ro \ + -e API_BASE=http://host.docker.internal:8880/v1 \ + -e API_KEY=none \ + -e BASE_URL=http://localhost:3003 \ + -e AUTH_SECRET=$(openssl rand -hex 32) \ + ghcr.io/richardr1126/openreader:latest +``` + + + + +Use this when the app should be reachable from other devices on your LAN: + +```bash +docker run --name openreader \ + --restart unless-stopped \ + -p 3003:3003 \ + -p 8333:8333 \ + -v openreader_docstore:/app/docstore \ + -e API_BASE=http://host.docker.internal:8880/v1 \ + -e BASE_URL=http://:3003 \ + -e AUTH_SECRET=$(openssl rand -hex 32) \ + -e AUTH_TRUSTED_ORIGINS=http://localhost:3003,http://127.0.0.1:3003 \ + -e USE_ANONYMOUS_AUTH_SESSIONS=true \ + ghcr.io/richardr1126/openreader:latest +``` + +Replace `` with the Docker host IP address on your local network to allow access from other devices. + + + + +:::tip Quick Tips +- Remove `/app/docstore/library` if you do not need server library import. +- Remove either `BASE_URL` or `AUTH_SECRET` to keep auth disabled. +- Set `API_BASE` to your reachable TTS server base URL. +::: + +:::warning Port `8333` Exposure +Expose `8333` for direct browser presigned upload/download with embedded SeaweedFS. + +If `8333` is not reachable from the browser, direct presigned access is unavailable. Uploads can still fall back to `/api/documents/blob/upload/fallback`, and document reads/downloads continue through `/api/documents/blob`. +::: + +:::info Auth and Migrations +- Auth is enabled only when both `BASE_URL` and `AUTH_SECRET` are set. +- DB/storage migrations run automatically at container startup via the shared entrypoint. +::: + +:::info Related Docs +- [Environment Variables](./reference/environment-variables) +- [Auth](./configure/auth) +- [Database](./configure/database) +- [Object / Blob Storage](./configure/object-blob-storage) +- [Migrations](./configure/migrations) +::: + +## 2. Configure settings in the app UI + +- Set TTS provider and model in Settings +- Set TTS API base URL and API key if needed +- Select the model voice from the voice dropdown + +## 3. Update Docker image + +Legacy image compatibility: `ghcr.io/richardr1126/openreader-webui:latest` remains available as an alias. + +```bash +docker stop openreader || true && \ +docker rm openreader || true && \ +docker image rm ghcr.io/richardr1126/openreader:latest || true && \ +docker pull ghcr.io/richardr1126/openreader:latest +``` + +:::tip +If you use a mounted volume for `/app/docstore`, your persisted data remains after image updates. +::: + +Visit [http://localhost:3003](http://localhost:3003) after startup. diff --git a/docs-site/versioned_docs/version-v2.1.2/introduction.md b/docs-site/versioned_docs/version-v2.1.2/introduction.md new file mode 100644 index 0000000..4187ebf --- /dev/null +++ b/docs-site/versioned_docs/version-v2.1.2/introduction.md @@ -0,0 +1,52 @@ +--- +id: intro +title: Introduction +slug: / +--- + +OpenReader is an open source text-to-speech document reader built with Next.js. It provides a read-along experience with narration for **EPUB, PDF, TXT, MD, and DOCX documents**. + +> Previously named **OpenReader-WebUI**. + +It supports multiple TTS providers including OpenAI, DeepInfra, and custom OpenAI-compatible endpoints such as [Kokoro-FastAPI](https://github.com/remsky/Kokoro-FastAPI), [KittenTTS-FastAPI](https://github.com/richardr1126/KittenTTS-FastAPI), and [Orpheus-FastAPI](https://github.com/Lex-au/Orpheus-FastAPI). + +## ✨ Highlights + +- 🎯 **Multi-Provider TTS Support** + - [**Kokoro-FastAPI**](https://github.com/remsky/Kokoro-FastAPI): supports multi-voice combinations (for example `af_heart+af_bella`) + - [**KittenTTS-FastAPI**](https://github.com/richardr1126/KittenTTS-FastAPI): lightweight, CPU-friendly self-hosted TTS + - [**Orpheus-FastAPI**](https://github.com/Lex-au/Orpheus-FastAPI) + - **Custom OpenAI-compatible**: any TTS API with `/v1/audio/voices` and `/v1/audio/speech` endpoints + - **Cloud TTS providers**: + - [**DeepInfra**](https://deepinfra.com/models/text-to-speech): Kokoro-82M and other hosted models + - [**OpenAI API**](https://platform.openai.com/docs/pricing#transcription-and-speech): `tts-1`, `tts-1-hd`, and `gpt-4o-mini-tts` +- 🛜 **Server-side Document Storage** + - Documents are persisted in server blob/object storage for consistent access +- 📚 **External Library Import** + - Import documents from server-mounted folders +- 🎧 **Server-side Audiobook Export** in `m4b`/`mp3` with resumable chapter generation +- 📖 **Read Along Experience** + - Real-time highlighting for PDF/EPUB, with optional word-level [whisper.cpp](https://github.com/ggml-org/whisper.cpp) timestamps +- 🔐 **Auth Optional by Design** + - Run no-auth for local use, or enable auth with user isolation and claim flow +- 🗂️ **Flexible Storage and Database Modes** with embedded defaults or external S3/Postgres +- 🚀 **Production-ready Server Behavior** with TTS caching/retries/rate limits and startup migrations +- 🎨 **Customizable Experience** + - 13 built-in themes (light and dark palettes), TTS, and document handling controls + +## 🧭 Key Docs + +- [Docker Quick Start](./docker-quick-start) +- [Local Development](./deploy/local-development) +- [Vercel Deployment](./deploy/vercel-deployment) +- [Environment Variables](./reference/environment-variables) +- [Auth](./configure/auth) +- [Database](./configure/database) +- [Object / Blob Storage](./configure/object-blob-storage) +- [Migrations](./configure/migrations) +- [Server Library Import](./configure/server-library-import) +- [TTS Providers](./configure/tts-providers) + +## Source Repository + +- GitHub: [richardr1126/openreader](https://github.com/richardr1126/openreader) diff --git a/docs-site/versioned_docs/version-v2.1.2/reference/environment-variables.md b/docs-site/versioned_docs/version-v2.1.2/reference/environment-variables.md new file mode 100644 index 0000000..0c525c8 --- /dev/null +++ b/docs-site/versioned_docs/version-v2.1.2/reference/environment-variables.md @@ -0,0 +1,415 @@ +--- +title: Environment Variables +toc_max_heading_level: 3 +--- + +This is the single reference page for OpenReader environment variables. + +## Quick Reference Table + +| Variable | Area | Default | When to set | +| --- | --- | --- | --- | +| `NEXT_PUBLIC_ENABLE_DOCX_CONVERSION` | Client feature flags | `true` unless set to `false` | Set `false` to hide DOCX support | +| `NEXT_PUBLIC_ENABLE_DESTRUCTIVE_DELETE_ACTIONS` | Client feature flags | `true` unless set to `false` | Set `false` to hide destructive actions | +| `NEXT_PUBLIC_ENABLE_TTS_PROVIDERS_TAB` | Client feature flags | `true` unless set to `false` | Set `false` to hide the TTS Provider settings tab | +| `NEXT_PUBLIC_DEFAULT_TTS_PROVIDER` | Client feature flags | `custom-openai` | Override default TTS provider | +| `NEXT_PUBLIC_DEFAULT_TTS_MODEL` | Client feature flags | `kokoro` | Override default TTS model | +| `NEXT_PUBLIC_SHOW_ALL_DEEPINFRA_MODELS` | Client feature flags | `true` unless set to `false` | Set `false` to restrict DeepInfra models | +| `NEXT_PUBLIC_ENABLE_AUDIOBOOK_EXPORT` | Client feature flags | `true` unless set to `false` | Set `false` to hide audiobook export UI | +| `NEXT_PUBLIC_ENABLE_WORD_HIGHLIGHT` | Client feature flags | `true` unless set to `false` | Set `false` to disable word highlight + alignment | +| `API_BASE` | TTS provider | none | Point to your OpenAI-compatible TTS base URL | +| `API_KEY` | TTS provider | `none` fallback in TTS route | Set when provider requires auth | +| `TTS_CACHE_MAX_SIZE_BYTES` | TTS caching | `268435456` (256 MB) | Tune in-memory TTS cache size | +| `TTS_CACHE_TTL_MS` | TTS caching | `1800000` (30 min) | Tune in-memory TTS cache TTL | +| `TTS_MAX_RETRIES` | TTS retry | `2` | Tune retry attempts for upstream 429/5xx | +| `TTS_RETRY_INITIAL_MS` | TTS retry | `250` | Tune initial retry delay | +| `TTS_RETRY_MAX_MS` | TTS retry | `2000` | Tune max retry delay | +| `TTS_RETRY_BACKOFF` | TTS retry | `2` | Tune exponential backoff factor | +| `TTS_UPSTREAM_TIMEOUT_MS` | TTS request timeout | `285000` | Set max upstream TTS request duration before fail-fast | +| `TTS_ENABLE_RATE_LIMIT` | Rate limiting | `false` | Set `true` to enable TTS per-user/IP daily character limits | +| `TTS_DAILY_LIMIT_ANONYMOUS` | Rate limiting | `50000` | Override anonymous per-user daily character limit | +| `TTS_DAILY_LIMIT_AUTHENTICATED` | Rate limiting | `500000` | Override authenticated per-user daily character limit | +| `TTS_IP_DAILY_LIMIT_ANONYMOUS` | Rate limiting | `100000` | Override anonymous IP backstop daily limit | +| `TTS_IP_DAILY_LIMIT_AUTHENTICATED` | Rate limiting | `1000000` | Override authenticated IP backstop daily limit | +| `BASE_URL` | Auth | unset | Required (with `AUTH_SECRET`) to enable auth | +| `AUTH_SECRET` | Auth | unset | Required (with `BASE_URL`) to enable auth | +| `AUTH_TRUSTED_ORIGINS` | Auth | empty | Add extra allowed origins | +| `USE_ANONYMOUS_AUTH_SESSIONS` | Auth | `false` | Set `true` to enable anonymous auth sessions | +| `GITHUB_CLIENT_ID` | Auth/OAuth | unset | Set with `GITHUB_CLIENT_SECRET` to enable GitHub sign-in | +| `GITHUB_CLIENT_SECRET` | Auth/OAuth | unset | Set with `GITHUB_CLIENT_ID` to enable GitHub sign-in | +| `DISABLE_AUTH_RATE_LIMIT` | Rate limiting | `false` | Set `true` to disable auth-layer rate limiting | +| `POSTGRES_URL` | Database | unset (SQLite mode) | Set to switch metadata/auth DB to Postgres | +| `USE_EMBEDDED_WEED_MINI` | Storage | `true` when unset | Set `false` to use external S3-compatible storage only | +| `WEED_MINI_DIR` | Storage | `docstore/seaweedfs` | Override embedded SeaweedFS data directory | +| `WEED_MINI_WAIT_SEC` | Storage | `20` | Tune SeaweedFS startup wait timeout | +| `S3_ACCESS_KEY_ID` | Storage | auto-generated in embedded mode | Set explicitly for stable/external credentials | +| `S3_SECRET_ACCESS_KEY` | Storage | auto-generated in embedded mode | Set explicitly for stable/external credentials | +| `S3_BUCKET` | Storage | `openreader-documents` in embedded mode | Required for external S3-compatible storage | +| `S3_REGION` | Storage | `us-east-1` in embedded mode | Required for external S3-compatible storage | +| `S3_ENDPOINT` | Storage | derived in embedded mode | Set for S3-compatible providers (MinIO/SeaweedFS/R2/etc.) | +| `S3_FORCE_PATH_STYLE` | Storage | `true` in embedded mode | Set per provider requirement | +| `S3_PREFIX` | Storage | `openreader` | Customize object key prefix | +| `RUN_DRIZZLE_MIGRATIONS` | Database migrations | `true` | Set `false` to skip startup Drizzle schema migrations | +| `RUN_FS_MIGRATIONS` | Storage migrations | `true` | Set `false` to skip startup filesystem -> S3/DB migration pass | +| `IMPORT_LIBRARY_DIR` | Library import | `docstore/library` fallback | Set a single server library root | +| `IMPORT_LIBRARY_DIRS` | Library import | unset | Set multiple roots (comma/colon/semicolon separated) | +| `WHISPER_CPP_BIN` | Word timing | unset | Set to enable `whisper.cpp` timestamps | +| `FFMPEG_BIN` | Audio runtime | auto-detected (`ffmpeg-static`) | Override ffmpeg binary path | + + + +## TTS Provider and Request Behavior + +### API_BASE + +Server-level default base URL for OpenAI-compatible TTS API requests. + +- Example: `http://host.docker.internal:8880/v1` +- Used when no `API_BASE` is set in the user's Settings modal +- If the user sets `API_BASE` in **Settings → TTS Provider**, that value takes precedence +- Related docs: [TTS Providers](../configure/tts-providers) + +### API_KEY + +Server-level default API key for TTS provider requests. + +- Example: your provider token, or omit if the provider doesn't require auth +- Used when no `API_KEY` is set in the user's Settings modal +- If the user sets `API_KEY` in **Settings → TTS Provider**, that value takes precedence +- Related docs: [TTS Providers](../configure/tts-providers) + +### TTS_CACHE_MAX_SIZE_BYTES + +Maximum in-memory TTS audio cache size in bytes. + +- Default: `268435456` (256 MB) + +### TTS_CACHE_TTL_MS + +In-memory TTS audio cache TTL in milliseconds. + +- Default: `1800000` (30 minutes) + +### TTS_MAX_RETRIES + +Maximum retries for upstream TTS failures (429/5xx). + +- Default: `2` + +### TTS_RETRY_INITIAL_MS + +Initial retry delay in milliseconds for TTS upstream requests. + +- Default: `250` + +### TTS_RETRY_MAX_MS + +Maximum retry delay in milliseconds. + +- Default: `2000` + +### TTS_RETRY_BACKOFF + +Exponential backoff multiplier between retries. + +- Default: `2` + +### TTS_UPSTREAM_TIMEOUT_MS + +Maximum upstream TTS request timeout in milliseconds. + +- Default: `285000` (285 seconds) +- Applies to outbound provider calls from server routes using shared TTS generation +- Increase for slower providers/models; decrease to fail fast and surface retryable errors sooner + +### TTS_ENABLE_RATE_LIMIT + +Controls TTS character rate limiting in the TTS API. + +- Default: `false` (TTS char limits disabled) +- Set to `true` to enforce `TTS_DAILY_LIMIT_*` and `TTS_IP_DAILY_LIMIT_*` +- For behavior details and examples, see [TTS Rate Limiting](../configure/tts-rate-limiting) + +### TTS_DAILY_LIMIT_ANONYMOUS + +Anonymous per-user daily character limit. + +- Default: `50000` + +### TTS_DAILY_LIMIT_AUTHENTICATED + +Authenticated per-user daily character limit. + +- Default: `500000` + +### TTS_IP_DAILY_LIMIT_ANONYMOUS + +Anonymous IP backstop daily character limit. + +- Default: `100000` + +### TTS_IP_DAILY_LIMIT_AUTHENTICATED + +Authenticated IP backstop daily character limit. + +- Default: `1000000` + +## Auth and Identity + +### BASE_URL + +External base URL for this OpenReader instance. + +- Required with `AUTH_SECRET` to enable auth +- Example: `http://localhost:3003` or `https://reader.example.com` +- Related docs: [Auth](../configure/auth) + +### AUTH_SECRET + +Secret key used by auth/session handling. + +- Required with `BASE_URL` to enable auth +- Generate with `openssl rand -hex 32` +- Related docs: [Auth](../configure/auth) + +### AUTH_TRUSTED_ORIGINS + +Additional allowed origins for auth requests. + +- Comma-separated list +- `BASE_URL` origin is always trusted automatically +- Related docs: [Auth](../configure/auth) + +### USE_ANONYMOUS_AUTH_SESSIONS + +Controls whether auth-enabled deployments can create/use anonymous sessions. + +- Default: `false` (anonymous sessions disabled) +- Set `true` to allow anonymous sessions and guest-style flows +- When `false`, users must sign in or sign up with an account +- Related docs: [Auth](../configure/auth) + +### GITHUB_CLIENT_ID + +GitHub OAuth client ID. + +- Enable only with `GITHUB_CLIENT_SECRET` + +### GITHUB_CLIENT_SECRET + +GitHub OAuth client secret. + +- Enable only with `GITHUB_CLIENT_ID` + +### DISABLE_AUTH_RATE_LIMIT + +Controls Better Auth rate limiting. + +- Default behavior: auth-layer rate limiting enabled +- Set to `true` to disable auth-layer rate limiting +- This does not affect TTS character rate limiting +- Related docs: [Auth](../configure/auth) + +## Database and Object Blob Storage + +### POSTGRES_URL + +Switches metadata/auth storage from SQLite to Postgres. + +- Unset: SQLite at `docstore/sqlite3.db` +- Set: Postgres mode +- Related docs: [Database](../configure/database) + +### USE_EMBEDDED_WEED_MINI + +Controls embedded SeaweedFS startup. + +- Default behavior: treated as enabled when unset +- Set `false` to rely on external S3-compatible storage +- Related docs: [Object / Blob Storage](../configure/object-blob-storage) + +### WEED_MINI_DIR + +Data directory for embedded SeaweedFS (`weed mini`). + +- Default: `docstore/seaweedfs` +- Related docs: [Object / Blob Storage](../configure/object-blob-storage) + +### WEED_MINI_WAIT_SEC + +Maximum seconds to wait for embedded SeaweedFS startup. + +- Default: `20` +- Related docs: [Object / Blob Storage](../configure/object-blob-storage) + +### S3_ACCESS_KEY_ID + +Access key for S3-compatible storage. + +- Auto-generated in embedded mode if unset +- Set explicitly for stable credentials or external providers +- Related docs: [Object / Blob Storage](../configure/object-blob-storage) + +### S3_SECRET_ACCESS_KEY + +Secret key for S3-compatible storage. + +- Auto-generated in embedded mode if unset +- Set explicitly for stable credentials or external providers +- Related docs: [Object / Blob Storage](../configure/object-blob-storage) + +### S3_BUCKET + +Bucket name used for document blobs. + +- Default in embedded mode: `openreader-documents` +- Required for external S3-compatible storage +- Related docs: [Object / Blob Storage](../configure/object-blob-storage) + +### S3_REGION + +Region used by the S3 client. + +- Default in embedded mode: `us-east-1` +- Related docs: [Object / Blob Storage](../configure/object-blob-storage) + +### S3_ENDPOINT + +Endpoint URL for S3-compatible storage. + +- In embedded mode, defaults to `http://:8333` (or detected host) +- For AWS S3, usually leave unset +- For MinIO/SeaweedFS/R2/B2-style APIs, typically set explicitly +- Related docs: [Object / Blob Storage](../configure/object-blob-storage) + +### S3_FORCE_PATH_STYLE + +Path-style S3 addressing toggle. + +- Default in embedded mode: `true` +- Set according to provider requirements +- Related docs: [Object / Blob Storage](../configure/object-blob-storage) + +### S3_PREFIX + +Prefix prepended to stored object keys. + +- Default: `openreader` +- Related docs: [Object / Blob Storage](../configure/object-blob-storage) + +## Migration Controls + +### RUN_DRIZZLE_MIGRATIONS + +Controls startup migration execution in shared entrypoint. + +- Default: `true` +- Set `false` to skip automatic startup Drizzle schema migrations +- Related docs: [Migrations](../configure/migrations), [Database](../configure/database) + +### RUN_FS_MIGRATIONS + +Controls startup filesystem-to-object-store migration execution in shared entrypoint. + +- Default: `true` +- Runs `scripts/migrate-fs-v2.mjs` at startup after DB migrations +- Set `false` to skip automatic storage migration pass +- Related docs: [Migrations](../configure/migrations), [Database](../configure/database), [Object / Blob Storage](../configure/object-blob-storage) + +## Library Import + +### IMPORT_LIBRARY_DIR + +Single directory root for server library import. + +- Used when `IMPORT_LIBRARY_DIRS` is unset +- Default fallback root: `docstore/library` +- Related docs: [Server Library Import](../configure/server-library-import) + +### IMPORT_LIBRARY_DIRS + +Multiple library roots for server library import. + +- Separator: comma, colon, or semicolon +- Takes precedence over `IMPORT_LIBRARY_DIR` +- Related docs: [Server Library Import](../configure/server-library-import) + +## Audio Tooling and Alignment + +### WHISPER_CPP_BIN + +Absolute path to compiled `whisper.cpp` binary for word-level timestamps. + +- Example: `/whisper.cpp/build/bin/whisper-cli` +- Required only for optional word-by-word highlighting + +### FFMPEG_BIN + +Absolute path or executable name for the ffmpeg binary used by audiobook/processing routes. + +- Resolution order: `FFMPEG_BIN` -> `ffmpeg-static` +- Example: `/var/task/node_modules/ffmpeg-static/ffmpeg` + +## Client Runtime and Feature Flags + +### NEXT_PUBLIC_ENABLE_DOCX_CONVERSION + + Controls whether the experimental DOCX-to-PDF conversion and upload feature is enabled. + + - Default: `true` (enabled) + - Set `false` to hide DOCX support in the upload UI + + ### NEXT_PUBLIC_ENABLE_DESTRUCTIVE_DELETE_ACTIONS + + Controls whether the "Delete all user docs" and other bulk-delete buttons are shown in Settings. + + - Default: `true` (enabled) + - Set `false` to hide destructive actions (recommended for production) + +### NEXT_PUBLIC_ENABLE_TTS_PROVIDERS_TAB + +Controls whether the **TTS Provider** section appears in the Settings modal. + +- Default: `true` (enabled) +- Set `false` to hide provider/model/API controls in Settings +- Useful when you want provider config locked to environment defaults + + ### NEXT_PUBLIC_DEFAULT_TTS_PROVIDER + + Sets the default TTS provider for new users. + + - Default: `custom-openai` + - Example values: `deepinfra`, `openai`, `custom-openai` + + ### NEXT_PUBLIC_DEFAULT_TTS_MODEL + + Sets the default TTS model for new users. + + - Default: `kokoro` + - Example values: `hexgrad/Kokoro-82M`, `tts-1` + + ### NEXT_PUBLIC_SHOW_ALL_DEEPINFRA_MODELS + + Controls whether the DeepInfra model list shows all models or just the free tier when no API key is set. + + - Default: `true` (show all) + - Set `false` to restrict to free tier models when no API key is provided + +### NEXT_PUBLIC_ENABLE_AUDIOBOOK_EXPORT + +Controls whether audiobook export UI/actions are shown in the client. + +- Default behavior: enabled unless explicitly set to `false` +- Applies in both development and production +- Affects export entry points in PDF/EPUB pages and document settings UI + +### NEXT_PUBLIC_ENABLE_WORD_HIGHLIGHT + +Controls word-by-word highlighting UI and timestamp-alignment behavior. + +- Default behavior: enabled unless explicitly set to `false` +- Applies in both development and production +- Requires working timestamp generation (for example `WHISPER_CPP_BIN`) +- Affects: + - Word-highlight toggles in document settings + - Alignment requests during TTS playback diff --git a/docs-site/versioned_docs/version-v2.1.2/reference/stack.md b/docs-site/versioned_docs/version-v2.1.2/reference/stack.md new file mode 100644 index 0000000..cc45fa2 --- /dev/null +++ b/docs-site/versioned_docs/version-v2.1.2/reference/stack.md @@ -0,0 +1,44 @@ +--- +title: Stack +--- + +## Framework + +- [Next.js](https://nextjs.org/) 15 (App Router) +- [React](https://react.dev/) 19 +- [TypeScript](https://www.typescriptlang.org/) + +## Containerization and runtime + +- [Docker](https://www.docker.com/) (linux/amd64 and linux/arm64) +- Shared entrypoint that runs DB migrations by default and can bootstrap embedded SeaweedFS before app startup + +## Next.js client + +- UI: [Tailwind CSS](https://tailwindcss.com), [Headless UI](https://headlessui.com), [@tailwindcss/typography](https://tailwindcss.com/docs/typography-plugin) +- Interactions: `react-dnd`, `react-dropzone` +- Authentication: [Better Auth](https://www.better-auth.com/) client SDK +- Local storage/cache: [Dexie.js](https://dexie.org/) (IndexedDB) +- Document rendering: + - PDF: [react-pdf](https://github.com/wojtekmaj/react-pdf), [pdf.js](https://mozilla.github.io/pdf.js/) + - EPUB: [react-reader](https://github.com/gerhardsletten/react-reader), [epubjs](https://github.com/futurepress/epub.js/) + - Markdown/Text: [react-markdown](https://github.com/remarkjs/react-markdown), [remark-gfm](https://github.com/remarkjs/remark-gfm) +- Text preprocessing/matching: [compromise](https://github.com/spencermountain/compromise), [cmpstr](https://github.com/remsky/cmpstr) + +## Next.js server + +- APIs: Route Handlers for sync, blob/content access, migrations, audiobook export, TTS/Whisper proxying +- State sync: request-based today (not realtime push updates) +- Authentication: [Better Auth](https://www.better-auth.com/) server handlers/adapters +- Metadata DB: [Drizzle ORM](https://orm.drizzle.team/) with SQLite (`better-sqlite3`) by default and optional Postgres (`pg`) + - App tables are manually maintained in Drizzle schema files + - Auth tables are auto-generated by the [Better Auth](https://www.better-auth.com/) CLI and migrated alongside app tables via Drizzle +- Blob storage: embedded [SeaweedFS](https://github.com/seaweedfs/seaweedfs) (`weed mini`) by default, or external S3-compatible storage via AWS SDK v3 +- Audio/processing pipeline: OpenAI-compatible TTS providers, [ffmpeg](https://ffmpeg.org/) for audiobook assembly, optional [whisper.cpp](https://github.com/ggerganov/whisper.cpp) for word timestamps + +## Tooling and testing + +- ESLint +- TypeScript +- [Playwright](https://playwright.dev/) end-to-end tests +- Drizzle migration/generation scripts diff --git a/docs-site/versioned_sidebars/version-v2.1.2-sidebars.json b/docs-site/versioned_sidebars/version-v2.1.2-sidebars.json new file mode 100644 index 0000000..057df29 --- /dev/null +++ b/docs-site/versioned_sidebars/version-v2.1.2-sidebars.json @@ -0,0 +1,71 @@ +{ + "tutorialSidebar": [ + "intro", + { + "type": "doc", + "id": "docker-quick-start", + "label": "🐳 Docker Quick Start" + }, + { + "type": "category", + "label": "⚙️ Configure", + "items": [ + { + "type": "category", + "label": "🔊 TTS Providers", + "link": { + "type": "doc", + "id": "configure/tts-providers" + }, + "items": [ + "configure/tts-provider-guides/kokoro-fastapi", + "configure/tts-provider-guides/kitten-tts-fastapi", + "configure/tts-provider-guides/orpheus-fastapi", + "configure/tts-provider-guides/deepinfra", + "configure/tts-provider-guides/openai", + "configure/tts-provider-guides/other" + ] + }, + { + "type": "doc", + "id": "configure/auth", + "label": "🔐 Auth" + }, + { + "type": "doc", + "id": "configure/server-library-import", + "label": "📥 Server Library Import" + }, + "configure/tts-rate-limiting", + "configure/database", + "configure/object-blob-storage", + "configure/migrations" + ] + }, + { + "type": "category", + "label": "🚀 Deploy", + "items": [ + "deploy/local-development", + "deploy/vercel-deployment" + ] + }, + { + "type": "category", + "label": "Reference", + "items": [ + "reference/environment-variables", + "reference/stack" + ] + }, + { + "type": "category", + "label": "About", + "items": [ + "about/support-and-contributing", + "about/acknowledgements", + "about/license" + ] + } + ] +} diff --git a/docs-site/versions.json b/docs-site/versions.json index 6b40ee8..1ad2cce 100644 --- a/docs-site/versions.json +++ b/docs-site/versions.json @@ -1,4 +1,5 @@ [ + "v2.1.2", "v2.1.1", "v2.1.0", "v2.0.1",