Prefer the server account reading streak when provided by the dashboard endpoint, falling back to local KOReader statistics database data when offline or absent. This aligns the KOReader plugin day streak display with the web app.
Closes#711
Update dependency versions across root, server, and client package files and refresh the lockfile.
Upgrade @fastify/static to the patched major release and verify production static-serving compatibility.
Validate smart scope filter rules before constructing query clauses during count computation. Catch validation errors for broken rules so invalid filters return null for bookCount rather than triggering an internal server error when fetching all smart scopes.
Closes#787
Add translate.googleapis.com to the connect-src Content-Security-Policy directive so the built-in eBook reader's translation feature can perform fetch requests without being blocked by CSP.
Closes#786
Add an explicit return type to findBookFilesByBookIds so TypeScript
resolves the bookFiles row shape instead of collapsing it to an index
signature, which broke structural typing against fileStateMatches.
Re-encode uploaded progressive JPEG custom cover images to baseline JPEG format so they render correctly across OPDS clients that lack progressive JPEG support.
Closes#782
Separate transient query filter rules from saved smart scope rules when evaluating series collapsing eligibility so series collapse as expected when requested in smart scopes.
Closes#780
When creating Postgres connection clients or pools, pg-connection-string
parsed SSL configurations did not explicitly set the SSL host matching
the database host, causing hostname verification failures against
localhost when DATABASE_URL specified an external host.
Use a helper to construct postgres client configurations that set the
SSL host from the parsed DATABASE_URL host across the server database
module and CLI scripts.
Closes#778
Raw file hash and exact metadata signatures can exceed PostgreSQL's btree tuple size limit (2704 bytes) for books with large file counts or long author lists, causing duplicate scans to fail. Hashing signature values with md5 ensures indexed duplicate scan keys maintain a fixed length within PostgreSQL index limits.
Closes#762Closes#768
Disable default HSTS header in fastifyHelmet and register an onSend hook that includes Strict-Transport-Security only when request protocol is HTTPS. This prevents unencrypted HTTP setups and other services on the host from being forced onto HTTPS by browser HSTS caching.
Closes#760
Register internally written and renamed library files with a self-write registry to prevent the file watcher from triggering redundant rescan events during application file operations.
Update metadata and cover editing components to align UI state handling with self-write updates.
Replace metadata-based duplicate checks (ISBN, title/author) during BookDock finalization with destination path lookup. This allows books with shared or incorrect metadata to be imported whenever their resolved library target paths differ, matching the standard upload workflow.
Closes#736
Kobo devices send GET requests to /v1/analytics/gettests during sync checks. Previously only POST was handled, causing 404 errors during subsequent syncs.
Closes#697
Re-evaluate the library format priority when uploading additional files to an existing book so higher-priority file formats properly take over as the primary file.
Closes#755
Query-based book selections failed with a 500 error when filtering by metadata fields because findIdsByWhere queried the bare books table without joining book_metadata. Left join book_metadata so WHERE clause predicates referencing metadata fields resolve correctly.
Closes#732
Normalize legacy and invalid fields in BookDock metadata objects before returning them to the client or processing DTO updates. This prevents unexpected properties such as legacy duration keys or extra rating attributes from failing DTO validation during file updates and finalize operations.
Closes#729
Ensure EPUB cover image updates produce standards-compliant EPUB2 and
EPUB3 metadata, manifest items, guide entries, and landmarks so e-readers
such as Readest and KOReader can render updated covers correctly.
Closes#730
Books containing both ebook and audiobook formats were incorrectly rendered with square covers in dashboard widgets, series views, and cards because aspect ratio logic checked for any audio format file instead of relying on the configured cover aspect ratio or primary media profile.
Closes#712
* fix(storygraph): preserve reading attempt start date
Skip redundant active-reading status updates before syncing progress so StoryGraph keeps the existing reading attempt and start date.
Fixes#667
* test(storygraph): cover active status equivalence
Exercise exact and cross-mapped active reading statuses so patch coverage verifies every start-date preservation path.
* test(storygraph): complete active status matrix
Cover the exact rereading status pair and retain literal tuple types for every active-reading equivalence case.
---------
Co-authored-by: chooh2 <chooh2@users.noreply.github.com>
Co-authored-by: neon <18559658+neonsolstice@users.noreply.github.com>
Pass external provider IDs (including Hardcover and Open Library IDs) from book dock metadata selection through ingest and finalization so they are saved to book metadata on import.
Closes#704
Extend jump rails across alphabetical, temporal, and categorical sorts.
Keep large libraries responsive with bounded database buckets and exact offsets.
Refine active-state tracking, Unicode initials, localized labels, accessibility, adaptive sizing, and flat or collapsed-series navigation.
Add bounded, user-scoped temporal buckets for supported date sorts and adapt resolution to populated dates. Keep rail navigation responsive with viewport sizing, sparse-gap compression, and virtual-grid synchronization.
Add system preference option for appearance theme with auto-switching based on OS color scheme settings. Update default theme preference to system and listen for OS dark mode changes dynamically.
Closes#695
Parse the sum aggregation for book file sizes as a JavaScript number to match the statistics API contract, preventing missing values in the library stats overview.
Closes#696
Introduce backend duplicate scanning services, persistence schemas, and frontend view components to allow users to scan their library for duplicate books by title/author similarity, group potential matches, and bulk delete redundant duplicates safely.
Add isNull(annotations.deletedAt) condition to both count and offset queries in DashboardWidgetRepository to prevent soft-deleted annotations from being selected for the Highlight of the Day widget.
Closes#685
Write and extract MP4-native series tags ('show', 'episode_id', 'episode_sort') for M4B and M4A audio files alongside existing custom tags to ensure series metadata is preserved during tag extraction and library scans.
Closes#680
Ensure author enrichment progress notifications can be dismissed and resolve stuck status indicators that persist on screen after completion or matching failures.
Closes#678
Ensure entity manager strategies and duplicate computation restrict book references and candidate entities to libraries accessible by the current user.
Closes#664
Add indexes on foreign key columns referencing books, book files, and libraries across user activity and integration tables to prevent table scans during cascade deletes.
Closes#663
Use the cleaned file stem as the search title when searching for book dock metadata if no title is present in embedded or selected metadata.
Closes#655
* build(deps): synchronize i18n lockfile
Record the locale dependencies so frozen installs can resolve the client workspace.
* feat(stats): expose privacy-aware reading insights
- Give administrators permission-gated access to bounded account activity.
- Let readers opt into auditable shared reading insights.
Ref #501
Exclude the originating device from reading-state fan-out and ignore stale or identical state echoes so paginated syncs can advance. Preserve pending new entitlements while propagating genuine changes to other devices.
Closes#654
* feat(i18n): add vue-i18n foundation with language switcher and Dutch locale
Introduce multi-language support for the client using vue-i18n and
@intlify/unplugin-vue-i18n. Locale is detected from a stored preference
or the browser language and persisted client-first, with optional server
sync riding the existing theme-sync mechanism (new locale category on the
generic user_preferences store, no migration needed).
Adds a language selector in Appearance > Behavior settings and seeds
en/nl message catalogs. Extraction of existing hardcoded strings follows
in subsequent commits.
* feat(i18n): add full en/nl message catalogs and test/build wiring
Populate the English and Dutch message catalogs (~4300 keys) covering the
whole UI, register a vitest setup that installs vue-i18n globally so
component tests resolve real messages, and allow inline HTML in messages
(strictMessage/escapeHtml off) for notes rendered via v-html / <i18n-t>.
* feat(i18n): localize settings and book UI strings
Replace hardcoded strings with t() calls across the settings and book
feature areas (including book detail, table, metadata edit, reading log,
highlights). Label collections captured at setup are wrapped in computed()
so they react to locale changes.
* feat(i18n): localize remaining feature UI strings
Replace hardcoded strings with t() across reader, email, library, tools,
migration, dashboard, auth, hardcover, author, series, book-dock,
book-metadata-fetch, annotations, admin, statistics, collection,
smart-scope, audit, whats-new, achievements, notifications, custom-icons,
scanner and metadata-score. Reactive label maps use computed().
* feat(i18n): localize shared components and view wrappers
Replace hardcoded strings with t() across shared components (app header,
sidebar, view header, pickers, selection bar) and top-level views.
* feat(i18n): localize settings tab bars and browser page titles
Make settings tab labels reactive via t() in the consuming components and
slim the *-tabs.ts helpers to ids/order/permission only. Route the browser
page titles in the router through the app i18n instance so document.title
follows the active locale. Adds settings.<area>.tabs.* and titles.* keys.
* feat(i18n): localize KOReader hash-linking and reader sidebar pin
Localize the strings from the KOReader manual hash-linking feature and the
reader sidebar pin/close controls that were merged from main during the
rebase, adding the corresponding en/nl keys.
* feat(i18n): localize upstream features merged during rebase onto main
Add en/nl catalog keys for the new upstream functionality pulled in by the
rebase (Kobo activity log, KOReader dismiss/remove-device and hash-link
modal, default library access, upload-size settings) and update a few
existing keys whose wording changed upstream (dynamic upload-size hints,
write-and-rename phrasing).
* feat(i18n): switch language picker to a dropdown
Replace the segmented language buttons with a native select, which scales
better as more locales are added.
* feat(i18n): add German and Slovenian translations
Register de and sl in the supported locales and ship full de.json and
sl.json catalogs (4616 keys each, structural parity with en.json).
* fix(client): harden locale switching and translation coverage
Keep locale catalogs structurally aligned, localize rebased UI changes, and use locale-aware formatting. Move language selection into the header, persist authenticated preferences, and prevent stale locale loads from winning.
---------
Co-authored-by: neon <18559658+neonsolstice@users.noreply.github.com>
Retrieve the book file format when querying the annotation hub, and dynamically determine the router parameters for navigation. This prevents hardcoding the epub format and correctly routes fb2 and other non-epub format annotations to their respective readers.
Closes#634
Introduce a metadata provider for Libro.fm to fetch audiobook details, offering an alternative to Audible and iTunes. Add server-side mapping, fetch controller endpoints, validation DTOs, and client-side UI configurations for user metadata preferences.
Closes#636
Store file inodes as numeric rather than bigint on PostgreSQL, and read/process them as BigInt in Node.js. This preserves exact 64-bit inodes from filesystems like MergerFS (hybrid-hash) and avoids folder mis-merging or disabled rename detection.
Closes#618
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
Updating status to read on StoryGraph automatically logs the remaining page count. Sending a
subsequent progress update for the full book page count would create a duplicate journal entry,
inflating the logged page count. Skip the progress update when transitioning to the read status.
Closes#643
The KOReader plugin's update check response provides the server version,
which already contains a leading "v". The update and plugin popups in
the KOReader plugin format the version with an explicit "v" prefix,
resulting in a "vv" typo (e.g. "vv1.2.0").
Strip the leading "v" from the server version in the updater script
if present to ensure it is displayed with a single "v" prefix.
Closes#644
Make long PDF reading sessions easier to navigate across desktop and mobile. Keep document loading recoverable when EmbedPDF initializes or tears down out of order, without enabling document-editing capabilities.