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.
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
Reduce large author listings to one card per series while preserving book counts, scoped visibility, and row-based pagination. Compute both totals in the collapsed query so deep pages remain consistent without a second author-wide scan.
Closes#301
Co-authored-by: neon <18559658+neonsolstice@users.noreply.github.com>
Derive catalog typeahead values only from books in libraries the requester can access, and enforce their content filters. Preserve superuser visibility, exact-match ranking, and user-scoped collection lookup.
* feat(scanner): set book added_at from earliest on-disk file mtime
A book's "date added" now reflects when its content files first landed on
disk (the earliest mtime across its content-role files) instead of the
moment BookOrbit imported it. Cover/metadata/supplement sidecars are
excluded. When no content file has a usable mtime, addedAt is left unset so
the DB defaultNow() fallback (import time) still applies. Only set at
initial book creation; re-scan/restore paths do not touch it.
* feat(library): add per-library added_at source with recompute
Add an addedAtSource setting to libraries so "date added" can follow the
book's files on disk rather than the moment the scanner happened to see
them. The setting takes imported (unchanged default), file_modified, or
file_created, guarded by a check constraint on the column.
Expose a recompute action so the chosen source can be applied to books
that are already imported. file_modified runs as a single set-based
update over the stored mtimes; file_created has to stat the files, since
birthtime is not persisted, so it batches those reads.
Leave every existing library on imported so behavior is unchanged unless
a user opts in.
* feat(library): add added_at source control to the library editor
Surface the new addedAtSource setting in the library editor as a radio
group, alongside a button that triggers the recompute for the library
being edited.
Keep the recompute out of the save path so changing the setting stays
cheap: the setting alone only affects books imported from then on, and
applying it to existing books is an explicit choice.
* i18n(library): translate added_at source strings (de/nl/pt/sl)
* fix(library): correct create payload, recompute floor and failure logging
The library creator posts its whole form, so omitting addedAtSource from
CreateLibraryDto made the global whitelist reject every create request
with a 400. Declare the field, validate it against the same source list
as the update DTO, and persist it so the initial scan uses the requested
source rather than silently falling back to imported.
Apply the scanner's usable-time floor to the mtime recompute query too.
It previously excluded only NULL, so a filesystem reporting epoch 0 would
rewrite added_at to 1970 instead of leaving the import time in place. The
floor now lives in library.constants rather than being spelled out twice.
Wrap the recompute in try/catch so a database or stat failure emits the
[fail] log the logging conventions require instead of propagating with
only a [start] line recorded.
* fix(library): gate recompute on the saved source and label the radios
The recompute button stayed enabled while the selected source differed
from the stored one. Because the request carries no source, clicking it
recomputed against the old stored value while the UI showed the new
selection. A hint already said to save first; disable the control as well
so the mismatch is not actionable.
Give the source list radiogroup semantics with aria-checked so screen
readers can tell which option is active, since selection was conveyed by
styling alone.
* test(library): assert the create DTO under the real validation options
The previous comment claimed the case exercised whitelist and
forbidNonWhitelisted, but the shared helper calls validate without them,
so it only proved @IsIn rejects an unknown value.
Drop the misleading comment and add a case that validates with the same
options main.ts gives ValidationPipe, so an undeclared addedAtSource
fails the way it would in a real request.
* docs(library): remove redundant date-added documentation
---------
Co-authored-by: Bob Bobber <user@example.com>
Co-authored-by: neon <18559658+neonsolstice@users.noreply.github.com>
Stream cross-device moves into exclusive destination-side temporary files to avoid copying permissions onto ACL-controlled shares. Publish completed files with rename and clean up failed copies while preserving the source.
Cover storage failures, staging collisions, concurrent moves, and source preservation with real-file unit tests.
Fixes#1342
Classify private trust-chain failures with a stable error code and direct administrators to a mounted CA bundle without weakening TLS verification.
Fixes#1346
Recurse into nested subfolders during book dock watcher scans and discovery so that books organized under category or author subdirectories are processed. Keep shared folders from claiming exclusive directory ownership so siblings and multi-track units can finalize and discard cleanly without collisions.
Closes#1311
Preserve the stored v1 identity while resolving primary hashes through bounded,
cached lookups for polling, retries, tracker checks, removal, and reconciliation.
Cover alias handling and lookup failures with unit tests and verify completion,
import scheduling, duplicate adoption, and removal against qBittorrent 5.2.3.
Closes#1318
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
Guard against the display preference mismatch reported in #1290 by checking author fields in cover-mode saves and verifying server acceptance of the complete payload.
Ref #1290
Use KOReader highlight times for annotation history while retaining ingestion times for diagnostics. Export all stored location representations and backfill existing rows during sync.
Fixes#1300
Prioritize exact genre and tag results within bounded catalog searches. Resolve Enter presses against existing IDs and ignore stale lookup responses.
Fixes#1295
Keep relative file paths synchronized during manual renames and repair
stale rows during watcher and full-scan reconciliation. Derive email
attachment names from the file being streamed.
Fixes#1286
Validate iTunes lookup identities against the book medium so stale ebook IDs fall back to audiobook search instead of preserving portrait covers.
Closes#1285
Use the supported Alpine 3.23 Node image to avoid vulnerable util-linux packages in Alpine 3.24. Force fast-uri 3.1.6 to resolve the SSRF advisories reported by the image scan.
Retry central-directory discovery at the ZIP comment limit when the default scan reaches the end of the file. Preserve the archive comment while rewriting ComicInfo.xml.
Fixes#1272
Restore the resolved entity title whenever a kept-alive view becomes active.
Prevent inactive cached views from replacing the current page title.
Fixes#1261
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
Use Amazon's readable mobile search route because the desktop route now returns an Akamai interstitial. Detect bot challenges and ignore sponsored cards before detail lookups.
Require the complete metadata value to be a valid GraphQL integer before using an ID lookup. Keep slug matching and sync change detection consistent through one parser.
Fixes#1243
Preserve Prowlarr's REST feed route and accept diagnostic responses so a server URL reports a useful Torznab mismatch instead of an opaque 406.
Fixes#1244
Prevent automatic metadata refreshes from searching alternate identities when a book already has trusted provider IDs. Preserve discovery and manual search behavior, and avoid dirtying descriptions on empty refreshes.
Closes#1222