Upgrades all references of pgvector/pgvector from pg16 to pg18,
including docker-compose files and e2e testing environments.
Updates the development docker-compose to mount the postgres volume
at /var/lib/postgresql to align with pg18+ directory requirements.
Also adds `shrink-0` to WhatsNewDialog header and footer to resolve
a layout overflow glitch.
Add a next steps checklist to the pairing success card and a permanent help card to the sync settings tab. Explain that books will only sync to the Kobo device if they are placed in a collection with Kobo sync enabled.
Closes#522
Ensure that fixed-layout EPUB content structures expose their frame index and overlayer attributes during retrieval. This prevents the navigation subsystem from falling back to the final page of the document due to unverified page position indexes.
Closes#541
Prevent duplicate annotations from being created when a user modifies the style or color of an existing highlight. Route the popover actions through a PATCH request on the existing annotation ID instead of invoking the creation flow.
Closes#543
When transitioning from the series detail view to another view (like edit
metadata), route params update before the component unmounts. This causes
the seriesId computed property to change to null, triggering the seriesId
watcher to reload/reset the books state, which in turn calls setBookContext
with empty values.
Prevent this reset by ignoring null series IDs in both the seriesId watcher
and the books/total watcher, keeping the navigation context intact for the
next view.
Closes#540
Previously, attempting to rename a book into a folder that already existed on disk was blocked. This change allows users to move books into existing folders, enabling scenarios where different formats (like ebooks and audiobooks) can coexist in the same directory. If a book is already tracked at the target path, the files are merged.
Closes#523
Add configuration settings and backend support to define default library access permissions for newly created users. Newly registered users automatically receive these default library access permissions upon creation. Also align current users page controls and magic link options in the admin tab settings UI, adding styled callout cards for empty states.
Closes#486
Records success and failure events for Kobo device syncs in the database, including operation duration, event types, and error details. Surfaces the recent sync history in the Kobo Settings UI for users to monitor their device activity.
Use request generation counters in composables to ignore in-flight fetches that resolve after a state reset. This ensures that user-scoped data like smart scopes, libraries, and collections do not persist across user switches.
Closes#510
Introduces the koreader_unmatched_book_devices schema to track unmatched
books per device. Adds API endpoints and UI in settings for dismissing
unmatched books and completely removing a KOReader device.
Closes#504
Keep reader sidebar navigation open for repeated jumps when users pin the panel. Use session-scoped state so each book file can remember the preference.
Closes#497
When KOReader syncs progress or annotations, it identifies books by a document
hash. BookOrbit normally resolves this automatically, but some books cannot be
matched. This adds a tracking table for unmatched hashes and a UI to manually
link them to existing library books.
Closes#458
During an automatic metadata refresh, the fetched Hardcover edition ID was not being copied to the update payload. This ensures the value is persisted to the database alongside the other metadata fields.
Closes#440
Adds a fixedLayoutSpread preference to EPUB reader settings to allow forcing single-page display. This is particularly useful for image-based EPUBs like comics and manga.
Closes#487
Replace the plain textarea for book descriptions with a Tiptap-based rich text editor in the metadata edit tab. Include HTML sanitization utilities to ensure safe rendering of user-provided descriptions.
Closes#460
Reading source is often less relevant for day-to-day analytics than
book format or reading pace. Shift the source distribution chart to the
end of the user dashboard and change the default breakdown dimension
from source to format to prioritize more useful metrics. Include a
migration to update existing users who have not customized their chart
order.
Progress values computed during reader events could occasionally result in NaN, Infinity, or out-of-bounds numbers, which caused API validation failures or corrupted state. Progress values are now clamped to valid ranges and sanitized to omit non-finite numbers before tracking.
Closes#479
Import Booklore and Grimmory reading sessions, personal ratings, and progress state through the migration pipeline.
Preserve book-level progress as primary-file progress when source file progress rows are absent.
Closes#482Closes#483
The search dropdown previously limited results to a fixed number. This change implements virtual scrolling and lazy loading in the AppHeader search bar to allow users to scroll through an unlimited number of matching books efficiently.
Closes#480
The group rule validator now accepts an optional `provider` field for
`communityRating` rules. This enables smart scopes to filter books based
on community ratings from specific providers (e.g., Goodreads, Amazon)
rather than just the aggregate rating.
The validator ensures that the provider field is only applied to community
rating rules and rejects unsupported providers.
Closes#477
Adds support for displaying custom metadata as columns in the book
table view. The frontend now fetches active fields and dynamically
renders the corresponding cells, backed by book card API updates.
Closes#465
Previously, the explicit metadata search modal for a book was restricted
to only the providers configured in the library's field rules. This
prevented users from manually searching a specific provider if it
was not part of their default automated fetch pipeline.
This change allows all globally enabled providers to be used during
a manual metadata search, while still defaulting the selected UI
checkboxes to the providers specified in the field rules.
Routes multiple book selection to the edit tab instead of details.
Fixes a bug where deactivated kept-alive sources would passively
clobber the active navigation context by tracking component
activation state. Converts route param computed refs to shallow
refs to prevent reactivity issues during navigation.
Closes#455
Introduce BookDockWorkQueue to serialize metadata extraction and auto-finalize
jobs. Files process newest-first with a 250 ms drain window and 500-1000 ms
inter-job spacing to avoid hammering metadata providers. Watched-folder rescans
now requeue files stuck in extracting or fetching status after a server restart
rather than silently dropping them.
Replace the global ThrottlerGuard with SensitiveEndpointThrottlerGuard, which
only activates on endpoints that carry explicit @Throttle() metadata. This
eliminates all @SkipThrottle() decorators from non-auth controllers and adds
missing throttle coverage for oidcGenerateLinkState and oidcGeneratePreviewState.
Update the login page to match the simplified 429 error message.
Fix countsByStatus to aggregate extracting and fetching rows into the pending
bucket so the UI counter stays accurate mid-pipeline. Add a secondary id sort
to findAll for deterministic pagination ordering.
Auto-detect the container memory limit via cgroup v1/v2 in entrypoint.sh and
compute --max-old-space-size proportionally (50-75 % of limit) instead of
defaulting to a fixed 2048 MB that OOMs small containers.
Closes#441
Pass the authenticated API fetcher to the streaming book loader instead of a static token. This ensures the token is automatically refreshed if it expires while reading, preventing 401 Unauthorized errors when navigating between chapters.
Closes#446
The reader previously hardcoded left/right interactions (arrows, clicks,
swipes) to prev/next actions. This change uses physical left/right
navigation methods to respect the EPUB's resolved text direction (RTL).
Closes#444
Add full-stack support for uploading, managing, and using custom SVG icons for libraries and smart scopes. Includes database schema, server module for storage and sanitization, and client UI under Appearance settings.
Add the KOReader catalog surfaces, plugin package metadata, and device progress handling needed for the plugin workflow. Keep progress status updates non-blocking so secondary status failures do not reject successful sync writes.
The organization mode determines how the scanner maps files to books. Changing it after creation leaves the library in an inconsistent state. This change disables the mode selector in the library edit modal and enforces the restriction in the backend service.
Additionally:
- Fixed TooltipContent z-index so it renders above modals.
- Bypassed rate limiting on the cover proxy endpoint to prevent 429 errors when loading large lists.
Users rely on community feedback when evaluating books in their library. This change
introduces aggregated community ratings and rating counts from external metadata
providers, allowing users to see popular opinion directly within the book details
without needing to leave the application.
Closes#414
Adds hardcoverEditionId to the database schema and shared types, enabling it to be stored as first-class metadata. Updates the file metadata parsers and writers (EPUB, PDF, CBZ) to read and embed this ID, and exposes it in the frontend metadata editor.
Closes#420
Allow users to define new custom fields for books beyond the standard
metadata properties. This provides flexibility for cataloging arbitrary
data like reading formats, editions, or personal ratings.
Closes#419
- Cache view state (DOM, scroll, virtual lists) using KeepAlive during navigation.
- Restore scroll position on view activation using requestAnimationFrame for grids and TanStack scrollToIndex for tables.
- Wrap multi-root views in single elements to support Transition animations.
- Blur focused descendants when aria-hidden is applied to fix Reka UI Chrome 124+ warnings.
Closes#417
Both AddToCollection and SendBook previously only operated on the explicitly provided list of book IDs. This prevented them from working correctly when a user selected all items across multiple pages in the UI. They now inherit from BulkSelectionDto and resolve queries to apply to all matching books.
Closes#416
Introduce a per-book sync toggle in the book detail view that lets
users include or exclude individual books from Hardcover sync.
Add a book sync scope setting with two modes:
- all_eligible: sync all books unless explicitly excluded (default)
- selected_only: sync only books the user explicitly includes
Extract sync eligibility logic into hardcover-sync-policy.ts for
testability. The toggle handles unread books correctly: sync is skipped
while the book is unread, but the user's inclusion intent is stored so
sync activates automatically once reading starts.
Closes#412
Add two per-file override flags to the Book Dock finalize flow:
- skipDuplicateCheck: bypasses ISBN/title+author duplicate detection for
a specific file. In book_per_folder mode the file naturally lands in
the same folder as the existing book, so createBookRecord auto-attaches
it as a second format on the same record.
- targetFileName: lets the user rename the file at the destination to
resolve a same-path collision. The extension is always appended from
the file format; if the user includes the extension it is stripped
first to avoid doubling. Setting targetFileName also implicitly skips
the duplicate check. A directory-traversal guard rejects any name
whose resolved path escapes the intended destination folder.
Frontend: results panel shows an "Import anyway" button for isDuplicate
rows and an inline rename input for file-exists-at-target rows. Both
retry calls forward defaultLibraryId/defaultFolderId so files that rely
on dialog-level defaults get the right destination. Concurrent double-
click is guarded. reimportingIds uses reactive(Set) so spinner and
disabled states update correctly.
Closes#213
triggerGlobal and triggerForLibrary skipped unpauseIfNeeded when no new
books were eligible (queued = 0), leaving a previously paused queue
permanently stuck on re-trigger.
Also add a live statusLabel to the auto-fetch settings components that
shows remaining queue count when active, replacing the misleading
"~0 eligible" count that appeared immediately after triggering a run.
Closes#408
Ensure the settings UI saves inherit toggles immediately and guards eligible-count previews against stale async responses. Align library override DTO validation with the shared partial override contract, and record manual library runs even when nothing queues.
Update copyToClipboard to reliably handle the legacy execCommand fallback across browsers. The utility now selects text before copying, returns a success boolean, and ensures proper element cleanup. Added comprehensive tests for clipboard.ts and updated MagicLinksSettings tests.
Closes#204
Extract and map multiple series memberships from AudNexus (primary, secondary, and fallback series) to a new seriesMemberships array. Update Goodreads mapper tests to verify correct extraction of the first series.
Closes#383
The epub reader's "Define" feature relies on api.dictionaryapi.dev and
wiktionary.org. These domains were being blocked by the server's Content
Security Policy. Adding them to the connect-src directive allows the
client to successfully fetch word definitions.
Closes#403
Tooltips on the color and style pickers were rendering behind the
popup due to z-index conflicts. Removing them fixes the issue and
simplifies the UI.
Closes#402
Calculate CFI range overlaps to detect when a selection intersects with
an existing annotation. Pass the overlapping annotation ID to the popup
so the delete option correctly renders.
Closes#401
Add a preview-and-review workflow that matches Hardcover books by cached IDs, ISBNs, slugs, and title/author confidence before updating BookOrbit read status.
Import reading progress only when requested and safe, preserve existing local progress, and keep status imports resilient when progress writes fail.
Closes#394