Commit Graph

55 Commits

Author SHA1 Message Date
neon 992224f2e8 feat(books): add read-aloud generation
Generate a synced read-aloud EPUB from a book's EPUB and audiobook through an
optional STAlign worker (Docker on CPU, or native with MLX on Apple Silicon),
with review, re-sync, replace in place, restart recovery and live progress on
the Files tab. Book details also stack the ebook and audiobook covers when
both exist. See docs/READ_ALOUD.md.
2026-10-21 23:44:37 +00:00
neon 95fa2c77fb docs: refresh KOReader plugin preview 2026-10-20 18:39:25 -06:00
neon 80244ea4e2 feat(koreader): rebuild the plugin interface and fix four-way annotation sync
Squash of feat/koreader-widget-board. KOReader plugin 2.0.0 gets the widget-board dashboard, redesigned
book details, menus, lists and dialogs, Decor page and reading companions. Highlights, notes and bookmarks
now stay in step across web, Kobo, KOReader and the phones (defects D-00 to D-20, migration 0121), and
reading progress and narration hand off cleanly between devices.
2026-10-20 16:05:27 -06:00
neon 97cd03325f feat(reader): open DjVu documents in the web reader
Scanned books are commonly distributed as DjVu, which the scanner only stored as a supplement.
Decode pages on the server with DjVuLibre so DjVu imports with a cover and page count, opens in
the image reader with its embedded OCR text, and can be the preferred format of an ordinary email
recipient. Migration 0113 widens the recipient format check to allow it.

Decoding runs on validated private snapshots behind a bounded, reader-first queue, and
revalidation and cached pages are answered without a decoder. Released iOS builds cannot open
DjVu, so series continuation offers it only to callers sending includeDjvu=true, and the
dashboard and notebook read file never name it. The first full scan after upgrading promotes
stored .djvu supplements to content.
2026-10-14 21:37:41 +00:00
neon fbaf0b63df feat(server): publish a stable installation identity for client connections
The iOS app lets an account reach one server through several addresses, such as a home network
IP and a public name. Before it sends credentials to an alternative address it needs to know the
address leads to the same installation, so expose a public, credential-free GET /server-identity
returning a persisted UUID, and add the same optional instanceId to app-info with the
server-connection-identity feature flag.

The UUID lives in a singleton server_identity row shared by every replica, created on first use
and cached per process. An unreadable identity omits instanceId instead of failing app-info,
which clients rely on for feature detection. Existing routes and bodies are unchanged and the
web client does not call the new route; the iOS app does.

The migration uses IF NOT EXISTS because an unreleased build created the same table as 0109.
2026-10-13 19:37:52 -06:00
neon b83a181128 chore: add community and help issue forms
Keep questions and community conversations in GitHub Issues with clear forms and guidance. Remove disabled Discussions links and exempt community topics from stale closure.

Closes #1046
2026-10-11 05:58:02 +00:00
neon cc50b55eeb feat(books): add read-aloud delivery policies and preserve sync
Add original and text-only EPUB delivery choices across Kobo, KOReader,
OPDS, web downloads and email while keeping source files unchanged.
Persist server defaults, device overrides and captured artifact identities
so retries and guided replacement retain the selected rendition.

Preserve saved progress across first opens, replacement resets and stale
updates, and project annotations against the copy delivered to each device.
Handle XML resource references, large inodes, retry backoff and background
worker state correctly. Consolidate the schema changes into one migration
and retain released-client request and response compatibility.

Verify with the full server and client checks, delivery and sync HTTP suites,
independent code reviews, and live KOReader download/settings/reader proof.

Fixes #1496
Closes #1603
Closes #1714
Fixes #1723
Ref #1633
Ref #1508
Ref #1621
Ref #1136
2026-10-11 03:11:27 +00:00
neon 2476195016 docs: add android coming soon badges to readme 2026-10-07 21:00:59 +00:00
neon 58756565fc fix(kobo): preserve koreader matching for converted downloads
Register the identity of delivered bytes so Kobo conversions and audio
removal continue matching their source books in KOReader. Keep download
registration recoverable without allowing database lock waits to stall it.

Preserve manual corrections across cached device identities, make review
semantics explicit, and keep cache invalidation bounded for large libraries.
Add unit, database, lifecycle and scale regressions with one generated migration.

Closes #1697
2026-10-07 00:07:50 +00:00
neon 05a55d6b62 build(deps): upgrade non-TypeScript dependencies
Keep TypeScript at 6.0.3 while moving the remaining server and client packages onto their current supported releases.

Allow the PWA asset generator 2 peer range because vite-plugin-pwa still declares the compatible version 1 range.
2026-09-30 21:37:55 +00:00
neon 4b86ff73cf build: move local development off port 3000
Run the dev API on 6262 and Vite on 6263 with strictPort; production
defaults stay on 3000. Define the dev client origin once and read the
typed appConfig instead of repeating its fallback in every gateway.
2026-09-23 18:18:51 +00:00
neon 06dcb6df6c docs: showcase official iPhone and Apple Watch apps 2026-09-20 15:30:24 +00:00
neon 58d90b3ab9 docs: add BookOrbit icon to README 2026-09-20 14:13:34 +00:00
neon e0d3d42150 feat: add read-aloud and media playback support
Add EPUB narration, shared media controls, and native device session integration.

Apply the generated migrations and update all first-party clients alongside the server.

BREAKING CHANGE: introduce incompatible database and API contracts for media playback
2026-09-19 02:27:05 +00:00
neon 50063b7775 ci: make crowdin source synchronization deterministic
Upload and verify the checked-out English catalog before exporting translations so delayed webhooks cannot stall the scheduled workflow.
2026-09-15 13:11:24 +00:00
neon 3bb33b615c feat(book-requests): add per-indexer seed goals
Add configurable seed ratio and seed time goals to request indexers, supporting both static goals and tracker-advertised ratio/seed-time limits via torznab attributes. Enforce indexer-specific seed policy during request fulfillment and display active seed targets in the request seed panel.

Closes #1360
2026-09-13 17:42:12 +00:00
neon 8f1215d331 feat(book-requests): add indexer plugin updates and release profiles
Add an in-app update service and UI controls for installed indexer plugins, verifying releases and fetching updates securely. Introduce configurable release profiles for fine-tuning score weights, format preferences, and rejection criteria in book request automation.
2026-09-13 15:04:20 +00:00
neon fcdd72a384 feat(book-requests): add newznab and nzbget support
Support Usenet indexers via the built-in Newznab adapter and Usenet downloads via NZBGet. Generalize active download tracking from torrent client hashes to protocol-agnostic client keys, add NZB release scoring and file handling, and expose Newznab indexer and NZBGet client options in settings and grab flows.

Closes #1312
2026-09-13 06:47:06 +00:00
neon d9ea13ba45 feat: add BookOrbit attribution requirements
Define AGPLv3 additional terms and expose attribution, source, and license details through unobtrusive About surfaces.
2026-09-10 18:03:11 +00:00
neon c2f9eea839 chore: add AGPL attribution notice
Preserve project credit in conveyed source distributions and include the legal files in runtime images.
2026-09-10 13:32:29 +00:00
neon 04a0f21c8b feat(server): allow configuring the listen address
Allow native and host-network deployments to select an IPv4 or IPv6 bind
address through HOST while preserving the existing wildcard default.
Keep Docker health checks aligned with the configured listener and document
how to restrict host port publishing independently of the container address.
Cover validation, real bootstrap sockets, and health-check commands with tests.

Closes #1315
2026-09-09 10:26:12 +00:00
neon 9165dbed1d feat(auth): add SSO-only authentication mode
Require an enabled OIDC-linked superuser before disabling password flows. Track session authentication methods and fail closed across the API, web client, WebSockets, and administrative mutations.

Closes #1002
2026-09-02 05:04:18 +00:00
neon fc6e6f03d5 feat(book-requests): add automated request fulfillment
Let users request books, route approvals, search configured sources, and import fulfilled releases through the Book Dock. Include scoped permissions, automation, download-client integrations, plugin support, requester visibility, and one consolidated schema migration.

Closes #248
Ref #1115
2026-08-31 16:52:43 +00:00
neon 90bb087180 i18n(client): fill a plural branch Crowdin omitted instead of dropping the message
Complete a plural category the target locale needs from the message's own
`other` branch during sync, so one missing branch no longer costs the whole
translation. Romanian arrived with `one` and `other` for all 156 of its
plurals and rendered English for every one of them. See docs/LOCALIZATION.md.
2026-08-27 18:54:17 +00:00
neon 5ff6bdfecb ci(i18n): stop the crowdin sync failing on a single translator edit
Fail the nightly export only when a catalog loses far more than churn
explains, rewrite a Crowdin em dash to the hyphen the source uses instead
of discarding the translation, and report a rejected message as a
rejection rather than a lost one. See docs/LOCALIZATION.md.
2026-08-27 18:29:42 +00:00
neon 3b9bae7525 ci(i18n): fix the two guards that keep the crowdin sync failing
Two independent guards were failing the workflow on healthy input.

Retention read "exported value equals the English source" as a lost translation, but exports are
built with skipUntranslatedStrings, so Crowdin omits a key entirely once it stops carrying a
translation. Anything present in the export is by definition translated, and the equality check only
ever fired on correct work: Spanish "Error", "Feb" and "Cookie", French "Description", Portuguese
"Readwise". Retention now compares presence alone, which is what absence already meant. The same
inference lived in a legacyComplete branch that would have silently stopped protecting the 2,318
keys whose translation legitimately equals the source once any locale reached full translation.

Scheduled runs had no way out of that. The only escape hatch is allowed_translation_losses, a
workflow_dispatch input that is never persisted, so every schedule rediscovered the same losses and
failed until someone dispatched the run by hand.

The slot count rule then only runs for the keys it is given, and the sync passed none, so its
rejection filter was weaker than the locale validation running on its output one step later. An
invalid ja message survived the filter, reached the catalog, and failed the next step instead of
being dropped and reported. Move the source scan into locale-source-keys.mjs so the sync and
validate-locales.mjs derive the same keys.
2026-08-21 15:50:03 +00:00
neon ec4072e4be feat(server): add Audiobookshelf and Calibre-Web Automated migration sources
Extend the migration module beyond Booklore and Grimmory so an existing Audiobookshelf or
Calibre-Web Automated library can be moved into BookOrbit without rebuilding user state by
hand. Audiobookshelf supports both a live API connection and an offline backup file, while
Calibre-Web Automated reads a stopped snapshot of the app and metadata databases.

Match source books by ASIN in addition to ISBN, and batch the ISBN, ASIN, file hash, file
path, and title/author lookups so planning a large library issues a bounded number of
queries rather than one per book. Route the batched author comparison through the shared
accent-insensitive predicate, which now accepts a SQL fragment so a per-row pattern column
is matched the same way a bound literal is.

Extract the shared source connection form into MigrationSourceFields so the modal and the
settings page stay in sync as source types are added, and allow a mapping to skip a source
user instead of forcing every account to be imported.

Closes #986
2026-08-16 05:15:34 +00:00
neon 7dcc509a54 feat(client): add nine interface languages and a searchable language picker
Traditional Chinese cannot reuse the `%two_letters_code%` filename because it would collide with
Simplified under `zh.json`, so `crowdin.yml` maps `zh-TW` to a `zh-Hant` catalog and locale
matching resolves by script subtag before falling back to the base language. Every other new
locale keeps its bare two-letter ID.

Twenty-five entries outgrew the old menus. The mobile submenu inherited `overflow-hidden` with no
max-height, so the last nine languages were unreachable on a phone, and the list was ordered by
ISO code while displaying endonyms, which reads as unsorted. Both header menus now render one
LanguagePicker that searches the native name, the English name and the locale code, groups the
browser's own languages as suggestions, and orders the rest with a collator on the string it
actually shows. Mobile opens a sheet instead of a nested flyout, since a flyout is the wrong
shape for touch regardless of height. Settings gains the Appearance language section its copy
has anticipated since the keys were added.

Tighten the Crowdin progress chart, which the longer language list had stretched to 810px tall.
2026-08-11 07:43:38 +00:00
neon 23fa46fca7 docs: correct postgresql version references to 18
docker-compose.dev.yml and e2e-runner.yml have run pgvector/pgvector:pg18
since v2.2.0, but the development and testing guides still described the
container as PostgreSQL 16.
2026-08-09 05:29:54 +00:00
neon ddf285f568 docs: require approval and end-to-end evidence 2026-08-07 19:07:25 +00:00
neon b9e041d1b7 ci(i18n): enforce controlled crowdin localization workflow and pr validation
Add Crowdin pull request validation script, centralize locale configuration, and update GitHub workflows to enforce sparse target catalog validation.
2026-08-06 00:00:04 +00:00
neon 8790208858 fix(client): prevent Crowdin translation loss
Use sparse target catalogs and validate Crowdin exports before proposing updates. Reject translation loss unless a maintainer acknowledges each key.
2026-08-05 23:02:58 +00:00
neon 9262704f0a docs: update PR template and contributing guide review requirements 2026-08-01 18:22:56 +00:00
neon a0bc01ea50 fix(client): remove Hungarian and Korean locales
Both catalogs held nothing but English fallback values, so selecting either language produced a
fully English interface that reads as broken rather than untranslated. Crowdin Translate covers only
24 languages and includes neither, so neither locale had any machine translation route, and no human
translations existed yet.

Drop them from the shared locale list, the Crowdin export configuration, the pull request allowlist,
the catalogs, and the tests, leaving fifteen target languages. Remove both from the Crowdin project
as well, after confirming each export was byte-identical to the English source so no translation work
was discarded.

Re-adding either is cheap once a translation route exists, whether that is a machine translation
engine that supports them or a volunteer translator.

Give the locale tests the same fallback semantics the application runs with. Production always loads
the English catalog and points `fallbackLocale` at it, so a key a target catalog does not carry
renders English. The test instances omitted both, which resolves a missing key to its own name, and
several assertions compared a translated label against the English one without checking that the
language actually translates that key. Both patterns pass only while every catalog is complete, and
would fail confusingly the first time a language lags behind a new key.

Delete the Crowdin service branch automatically once its pull request closes or merges. Crowdin
appends every export to the same branch and never rebases it, so a branch that outlives its pull
request keeps its original merge base and each later export diverges further from main until every
catalog conflicts. Deleting it forces Crowdin to recreate the branch from the current main.

Ref #576
2026-07-31 22:49:41 +00:00
neon 1215a45f93 feat(client): add nine locales with English fallback catalogs
Register Czech, Danish, Finnish, Hungarian, Korean, Russian, Simplified Chinese, Swedish, and
Ukrainian so the language picker, browser detection, and server preference validation accept them.
Catalogs hold English fallback values; Crowdin supplies translations through the normal export flow.

Give each catalog exactly the CLDR plural categories its locale defines rather than copying the
English branches. Czech, Russian, and Ukrainian gain `few` and `many` seeded from `other` because
the source has no matching text. Korean and Chinese drop `one`, which they have no rule for and
Crowdin cannot store. Those synthesized branches all start from the same English string, so machine
translation returns identical forms where the grammar differs and a human has to resolve them.

Ship Chinese as Simplified only under the bare `zh` locale so every zh-* browser resolves to it.
Traditional Chinese, also requested in #86, would arrive later as a separate zh-Hant catalog.

Use `sv-SE` for Swedish in the Crowdin config, because Crowdin has no bare `sv` language and would
have skipped the export. Tolerate a wrapped SUPPORTED_LOCALES array in validate-locales, which
prettier now produces since the list outgrew the print width, and extend the exhaustive ICU test to
reach Polish `other`, a category its counts never selected.

Add the repository activity embed to the README alongside the existing translation progress chart.

Repair the KOReader plugin source assertions that 40e366a4 left stale after reshaping the
dashboard streak block and the downloaded badge icon lookup, and watch `koreader-plugin/**` in
the server CI path filter so plugin-only changes run the server suite that reads those files.

Closes #86
Closes #363
Closes #576
2026-07-31 19:33:33 +00:00
neon c2884bd664 chore(translations): add catalog verification script and update localization docs 2026-07-28 19:15:15 +00:00
Chris Mansell 12ca966a79 i18n(client): add Spanish, French, Italian, and Polish locales (#811)
* i18n(client): add Spanish, French, Italian, and Polish locales

Add locale catalogs for Spanish, French, Italian, and Polish. Update locale types, Crowdin configuration, documentation, and test suites to support the expanded language options.

* i18n(client): sync Spanish, French, Italian, and Polish locale keys

Update Spanish, French, Italian, and Polish translation catalogs to include key additions for notification preferences, user management, and file naming settings.

* fix(client): correct expanded locale translations
2026-07-28 11:37:43 -06:00
neon 3aff8f521b chore(i18n): automate Crowdin translation progress SVG chart and consolidate repo chart workflows
Add automated Crowdin translation progress SVG chart generator, test, and workflow. Consolidate star history and translation stats generation into unified repo-charts workflow, and update README links.
2026-07-27 18:25:59 +00:00
neon 5f47145a64 docs: refresh dashboard screenshot and add KOReader plugin preview 2026-07-27 17:32:12 +00:00
neon e8ca5fceb2 ci: add automated star history chart
Keep README growth data self-hosted and resilient when detailed GitHub stargazer history is unavailable.
2026-07-27 16:10:46 +00:00
neon 92ade7dbba i18n(client): migrate plural messages to ICU MessageFormat
Replace pipe-delimited Vue I18n plural messages with ICU MessageFormat syntax across all locale catalogs and Vue components. Configure custom message formatting and validation to enforce ICU syntax and argument parity.

Closes #792
2026-07-27 01:28:52 +00:00
neon 66056a6eb9 ci(client): add Crowdin translation workflow
Establish native GitHub synchronization, scoped translation PR checks, locale safeguards, semantic-release handling, and contributor guidance.
2026-07-14 18:31:49 +00:00
neon d182d913c6 fix(books): support accent-insensitive search
Install the PostgreSQL unaccent extension and use a custom immutable wrapper function to perform accent-insensitive ILIKE comparisons when searching for books, authors, series, and narrators. Add database indexes on the unaccented values to maintain query performance.

Closes #640
2026-07-11 17:47:29 +00:00
neon 39d9be30f9 feat(library): support LIBRARY_BROWSE_ROOT to restrict file path access
Introduce a LIBRARY_BROWSE_ROOT environment variable (defaulting to the
current directory) to restrict directories users can browse and select when
setting up library paths. Add a PathPolicyService on the backend to enforce
path containment checks securely, and update the frontend FolderPickerModal
to prevent navigating above the configured browse root.

Closes #567
2026-07-07 17:02:46 +00:00
neon 2065af41f9 feat(server): add swagger setup for public api documentation
Introduces Swagger and OpenAPI documentation generation for the
backend API. Configures bearer authentication globally while
allowing explicit bypasses for public endpoints. Exports nested
DTO classes across several modules so the NestJS Swagger plugin
can correctly reflect their schema definitions.

Closes #399
2026-06-29 01:52:30 +00:00
neon c4ab4a9153 feat: add in-app release notes viewer
Introduces a new feature to fetch, parse, and display app release notes
and update highlights directly within the UI.

- Backend: Adds the `release-notes` module to fetch GitHub releases
  and parse markdown highlight sections.
- Frontend: Adds the `WhatsNew` dialog and view, including custom
  markdown rendering and an image lightbox for update media.
- Tools: Adds validation scripts (`whats-new-lint`, `whats-new-preview`)
  to ensure release content parses correctly before publication.
2026-06-18 03:37:53 +00:00
neon 329d1b6643 feat(metadata): add Kobo metadata provider
Add Kobo as a first-class metadata source so books can keep Kobo IDs across fetch, edit, import, scoring, and file-write flows. Provide the Python cloudscraper setup needed for production fetches while keeping local setup explicit.

Closes #247
2026-06-06 18:16:47 +00:00
neon e89f4ce0e4 ci: enforce PR issue references and branch conventions
Validate BO-<issue>-<slug> branch names and lint PR titles and commit headers in CI and release workflows.

Require GitHub closing-keyword issue references and verify referenced issues exist. Align contributing, release, commit, testing, and policy docs with the enforced behavior and tone.
2026-05-17 13:10:32 -06:00
neon db2b3f9696 ci: run E2E only on nightly schedule, skip E2E on PR/push/manual CI, keep manual e2e workflow for on-demand runs, and align matrix/docs accordingly 2026-05-14 16:37:18 +00:00
neon 266b57c38a chore: reorganize docs, improve README, and add FOSS project hygiene 2026-05-13 15:05:04 +00:00