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
* feat(reader): add PDF highlights and annotations
Persist and render PDF highlights through the same annotation system as
EPUB. The annotation_positions table already supported a 'pdf' format, so
this wires the web create path, response, and reader UI to it.
Backend:
- create-annotation DTO accepts a pdf position (page + segment rects) as an
alternative to a cfi; exactly one is required
- repository createPdf() persists a format='pdf' position (geometry in pos0,
pageno in extras); selectWithCfi exposes the pdf geometry and status
- response DTO parses the pdf position and derives positionStatus
Frontend (pdf-v4 reader):
- usePdfAnnotations REST store and usePdfHighlights orchestration render
persisted highlights via the EmbedPDF annotation plugin (autoCommit off,
DB stays source of truth)
- selection popup (colour/style/note/copy/delete), note dialog, and a
Highlights sidebar tab with search/colour/notes filters, navigate, delete
- NoteDialog relocated to reader/shared for reuse by both readers
Shared types gain AnnotationRect/AnnotationPdfPosition and an optional pdf
field on AnnotationItem.
* fix(reader): preserve input on failed PDF annotation save; convert mixed PDF+CFI for KOReader
- usePdfHighlights: createFromSelection/restyleExisting now return success;
applyHighlight and saveNote only clear the selection, dismiss the popup, and
close the note dialog on success. On failure the mark, popup, and typed note
are preserved so the user can retry without losing input.
- koreader annotation exchange: the PDF push-down guard now skips only PDF-only
annotations (no EPUB anchor). A mixed PDF+CFI annotation still converts its CFI
to xpointer instead of being dropped.
- Tests for both paths.
* fix(reader): label PDF selection buttons and dedupe multi-page highlight retries
- PdfSelectionPopup: add aria-labels to the copy, highlight, note, and delete
icon-only buttons so screen readers can identify them.
- usePdfHighlights: createFromSelection keeps only the pages that failed, so a
retry after a partial multi-page failure never duplicates already-saved pages.
- Test for the multi-page partial-failure retry path.
* fix(reader): harden PDF annotation store, validation, and create logging
- usePdfAnnotations: catch rejected api() calls (session expiry / network) so
load() sets loadError and mutations return null/false instead of rejecting.
- create-annotation DTO: require positive rect width/height so degenerate PDF
geometry is rejected; tests for zero/negative dimensions.
- annotation.service: add [annotation.create] start/end/fail lifecycle logs with
IDs, durationMs, and sanitized error for the multi-step create.
* test(reader): cover PDF annotations in the hub and add missing docstrings
Adds a real-DB e2e proving a PDF highlight persists as a pdf position and surfaces in the library-wide Annotations hub with the exact fields the page deep link needs (jumpFileFormat=pdf, cfi=null, pageno). Adds a hub-service unit test for the pdf row mapping. Documents the PDF render helpers, the annotation deep-link builder, and the createPdf repository method.
* fix(annotations): make PDF highlights reliable across reloads
Reconcile persisted highlights after EmbedPDF finishes loading its annotation state. Keep file-scoped pagination bounded and prevent PDF-only positions from starving device sync.
Ref #1195
* fix(annotations): keep pdf annotations stable during reload
Use authenticated native pagination fetches and discard responses that overlap successful mutations. Align shared dialog styling and annotation tests with project conventions.
Ref #1195
---------
Co-authored-by: neon <18559658+neonsolstice@users.noreply.github.com>
Keep KOSync limited to position synchronization and rely on measured page timings from the BookOrbit plugin for KOReader reading sessions. Remove legacy estimates at startup and rebuild affected daily totals.
Fixes#1233
* fix(scanner): invalidate dir scan state on book deletion
Deleting a book row left its library_dir_scan_state entries intact, so the incremental scanner kept skipping the unchanged directory and never re-created the book on rescan. Invalidate the deleted books' folder paths and ancestors after deleteByIds so the next scan re-reads them and re-discovers the records.
* fix(scanner): make scan-state invalidation atomic
Prevent deleted books and concurrent scans from restoring stale directory state by versioning each library folder and coordinating writes under a database transaction.
* test(server): repair full-suite failures
Update the Book Dock expectation to the unit-record processor contract and bound the watchdog cutoff against timestamps captured around the sweep.
---------
Co-authored-by: neon <18559658+neonsolstice@users.noreply.github.com>
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
Preserve target-only statuses and update conflicts only when the source carries newer evidence. Treat timestamp-free source rows as insert-only so they cannot overwrite curated target state.
Fixes#1104
Keep expanded synopsis content in the existing page or column flow so touch users do not encounter an undiscoverable nested scroll area. Expose the toggle state to assistive technology.
Fixes#1202
Normalize integer-like Calibre OPF positions while preserving exact fractional labels. Make the static reply decoration explicit so Nest accepts production container builds.
Fixes#1212
Reject numeric trust-proxy values that Fastify no longer honors and retain explicit boolean or address-based configuration. Bridge Nest and cookie type augmentation differences so the pre-push typecheck succeeds under TypeScript 6.
Accept the author display fields already emitted by the client and include them in automatic account sync. Keep older payloads compatible with defaults and cover the client-server contract with regression tests.
Fixes#1209
Expose promotion and demotion to existing superusers while keeping shared and self targets blocked. Serialize role lifecycle changes, preserve one active superuser, and invalidate stale credentials.
Closes#1208
Treat partial-hash matches across distinct books as unresolved so progress cannot be written to an unrelated file. Preserve same-book duplicates and user-scoped manual links as valid disambiguation paths.
Fixes#1135
Size book detail layouts from usable pane width so sidebar width and browser zoom do not force inappropriate compact layouts. Keep metadata save actions reachable while secondary controls overflow safely.
Fixes#1192
Use KOReader's destination filesystem rules for each server-provided path segment so Kindle downloads reject invalid names without changing Linux-compatible names. Preserve bulk collision handling after sanitization.
Fixes#1203
Normalize legacy float values before migration 0076 so 2.7 databases can upgrade without constraint failures or precision loss. Serialize the compatibility conversion across concurrent startup processes.
Fixes#1189
Add an isPublic flag to collections allowing users to share collections across the instance. Public collections are readable by all authenticated users while write, edit, reorder, and delete operations remain restricted to the owner.
Add fileSize as a filterable rule field resolved against the book's primary file size in bytes. In the filter builder UI, allow operators to input sizes in megabytes with automatic serialization to bytes for queries.