Update the `updatedAt` field on the `books` table whenever book metadata is
automatically fetched or bulk updated. Additionally, filter codecov reports
to only include server coverage and ignore test/config files, and update
the README codecov badge to reflect this.
Closes#186
* feat(metadata): add RanobeDB metadata provider
Introduces a new metadata provider to fetch book metadata from RanobeDB.
- Adds `ranobedb.client` to interact with the RanobeDB API.
- Implements `ranobedb.mapper` to map RanobeDB data to the internal metadata schema.
- Maps native Japanese titles to subtitles.
- Uses the original language as a fallback for the language field.
- Parses specific release dates to determine the original publication year.
- Registers RanobeDB as an available provider in the preferences UI.
- Adds `ranobedb_id` to the metadata database schema.
- Removes the `bookId` override when manually performing a metadata search in the UI.
Closes#114
* ci: upload server and client coverage reports to codecov
Generate client lcov output and publish per-package coverage from CI so Codecov checks and README coverage artifacts stay up to date.
* ci: configure codecov project status and pr comments
* ci: isolate codecov coverage status by flags
* ci: add patch coverage status, per-flag badges, and client coverage scope
- Add patch coverage status in codecov.yml (server and client flags) so
Codecov checks coverage on changed lines in PRs, not just overall trend
- Add include/exclude patterns to client vitest coverage config so test
files and entry points are excluded from coverage stats
- Add per-flag server/client coverage badges to the README coverage section
* docs: restructure coverage map in README
Move the coverage map down to the documentation and contributing section, giving it its own heading. Remove the redundant server and client badges from the top.
Add a user preference to configure the label displayed underneath book
and series cards in grid view. The option allows users to select
between hiding labels completely, showing book titles, or showing series
titles.
Closes#159
Virtualization can incorrectly hide books in the series detail view, showing only a small subset until the page is interacted with. This adds a static rendering mode to the book grid component and uses it for the series detail view to ensure all books remain visible.
Closes#171
When a newly filled metadata field is locked before saving, the subsequent
save causes a 409 conflict because the field was locked but not yet saved.
This introduces a new endpoint and DTO to update both metadata and locks
simultaneously, resolving the conflict.
Closes#172
Allow readers to choose which representative series cover appears in collapsed grid view so browsing can prioritize first, latest, or first unread volumes.
Closes#160
Unify accent metadata in one client module to prevent hue and tone drift across theme picker, chart palettes, and cover placeholders.
Guard placeholder theme-store access when Pinia is unavailable so non-store mounts remain stable while preserving reactive updates when a store is active.
The database check constraint for the library reading threshold was previously enforcing a maximum value of 1, causing an internal server error when configuring a threshold greater than 1% via the UI. The constraint max has been increased to 100 to support percentage-based values and align with the mark_as_finished constraint.
Closes#142
Allow users to choose how cover artwork is fitted so mixed aspect ratios render cleanly in cards, lists, carousels, and widgets.
Persist display preferences through shared types and user-preferences endpoints so these settings stay consistent across sessions and devices.
Closes#152
When DATABASE_URL is not provided, entrypoint.sh assembled it by
interpolating POSTGRES_USER, POSTGRES_PASSWORD and POSTGRES_DB directly
into a postgres:// URL. Any reserved URL character in those values (for
example a '#', '/' or '?' in the password) produced an invalid URL, and
pg-connection-string's new URL() call then threw ERR_INVALID_URL,
preventing the container from starting.
Percent-encode the user, password and database components via
encodeURIComponent before building the URL so passwords containing
special characters work without manual escaping.
Co-authored-by: MohammadYusif <MohammadYusif@users.noreply.github.com>
The Content Security Policy was previously blocking external images,
preventing admin-configured OIDC provider icons from loading.
This allows https: images to be loaded while continuing to block
plain http: to maintain mixed-content protection.
Closes#131
Introduce a user-preferences module and database schema to sync theme
settings (theme, accent, radius, background, brightness) across devices.
Users can now enable theme sync to persist their customization choices.
Closes#146
Add a dialog to batch-edit metadata for multiple selected books.
Support add/remove/replace/clear modes for list fields, with clear as an explicit
frontend-only mode.
Fix scalar input border rendering, year field validation/coercion, tags replace
optimistic updates, and submit error handling.
Closes#150
allow users to trigger file write-back and rename from the edit metadata tab as a single explicit action.
return write and rename outcomes with library setting flags so the UI can show clear result and warning states.
Closes#143
Align recommendation data and rendering with per-book media format semantics.
Expose audiobook state from recommendation queries and render audiobook cards as square while preserving portrait and spine treatment for non-audiobooks.
Closes#149
Align Book Dock metadata validation with the database year constraint to prevent intermittent finalize failures from malformed extracted years.
Return a user-safe validation message when metadata constraints are hit.
Closes#144
Allow users to select a range of files in the book dock by holding the shift key while clicking checkboxes, matching standard multi-select behavior.
Closes#136
Enable cross-platform path sanitization by default to prevent file and folder renaming failures
caused by invalid special characters or reserved names on various filesystems. Update the frontend
settings UI description to clarify the behavior of this setting, and update tests to reflect the
new default and verify correct sanitization behavior.
Closes#134
Remove the \.stop modifier from the inherit toggle update handler so value changes emit correctly and per-library overrides can switch modes again.
Closes#130
Add UI and backend support for testing metadata provider credentials
before saving. Include parsing and validation for Bearer tokens,
display test results in the settings panel, and execute a test
connection specifically against the Hardcover provider.
Closes#127
* feat(library): add bulk rename based on file naming settings
Provides a way to rename all books in a library according to the user's
configured file naming template without requiring manual metadata edits.
Includes a streaming endpoint to report progress back to the frontend.
Closes#121
* test(library): add e2e tests for bulk file rename
Introduce a comprehensive E2E test suite for the bulk rename functionality to verify behavior across different library modes (book per file, book per folder) and handle edge cases like naming collisions or special characters.
Additionally fix a TypeScript compilation error in BulkRenameView.vue by replacing `replaceAll` with a regex-based `replace` for broader target compatibility.
---------
Co-authored-by: neon <18559658+neonsolstice@users.noreply.github.com>
Expose magic links as its own admin tab and route it directly in Admin settings.
Keep it superuser-only and cover tab visibility and routing behavior in tests.
The icon picker panel was overflowing the viewport bottom boundary when there wasn't enough space, cutting off the search bar. Add dynamic max height calculation and visual viewport resize listeners. Also includes a style fix for the sidebar section header kebab buttons.
Closes#125
Parallel refresh requests from a single client (multi-tab SPA, mobile tab restore)
tripped reuse-detection and logged users out every few hours. Track rotation
provenance via new rotated_at + replaced_by_token_hash columns and accept revoked-
token reuse only inside a configurable grace window with a chain that reaches a
live, non-logout link. Scope the rotate UPDATE with revoked_at IS NULL so a
concurrent logout or admin revoke fails the racing refresh instead of handing the
user a fresh access token.
Closes#120
Provide the ability to sort and display annotations by their physical location in the book. Previously, annotations and bookmarks could only be sorted chronologically, making it difficult to track reading progress or locate notes.
By parsing EpubCFI strings into numeric sort keys, the sidebar can now reliably order items by their position. This also introduces human-readable location labels and fallback states for missing or invalid CFIs. Foliate integration is enhanced to resolve chapter titles and reading fractions for better context.
Closes#119
On old hardware (e.g. AMD Turion/Phenom, Intel Core 2), sharp's musl binary
crashes with SIGILL during NestJS module init. Combined with bufferLogs: true
and restart: unless-stopped, this produces a silent infinite restart loop -
only the migration success message is ever visible.
Add check_cpu_sse42 to entrypoint.sh: greps /proc/cpuinfo for sse4_2, exits
with a clear error if absent, no-op when /proc/cpuinfo is unavailable. Also
add a System Requirements section to README documenting the SSE4.2 minimum.
Closes#116
Prevent unauthorized users from seeing integrations they cannot use and keep settings routing consistent with API authorization behavior. Add hardcover_sync and enforce it server-side so tab visibility and endpoint access stay aligned.
Validate DATABASE_URL with pg's connection-string parser so unix-socket DSNs with empty authority hosts pass while malformed/non-postgres values are rejected.
Closes#106
* fix(scanner): clamp precision-unsafe inodes to avoid lossy matching
Clamp inode values above Number.MAX_SAFE_INTEGER to 0 before scanner, upload,
and file-event matching paths consume them.
Add regression tests for Unraid-style inodes so precision-unsafe values
cannot collapse file detection during scans.
Lower server coverage thresholds from 85 to 80 as requested for this branch.
Closes#84
* fix(scanner): reuse existing book for same-library folder renames
Keep the original book id when a folder path changes so scan does not create a duplicate entry with no files. Use inode first and hash fallback for precision-unsafe inode values while keeping book_per_file behavior unchanged.
Book titles and author names can contain characters that are invalid on Windows,
SMB/NFS shares, or cloud sync platforms (e.g., `:`, `?`, `*`, `"`). Without
sanitization these characters appear verbatim in generated file and folder names,
which causes failures on Windows filesystems, broken NFS/SMB mounts, and sync issues.
Add a toggleable app setting that, when enabled, sanitizes illegal filesystem
characters in all pattern-resolved paths (upload, rename, book-dock finalize, and
download). Each token value is sanitized before substitution: invalid chars are
replaced with `_`, trailing dots and spaces are stripped, and Windows reserved names
(CON, AUX, NUL, COM1-COM9, LPT1-LPT9) get a suffix to avoid conflicts. The setting
defaults to off to preserve existing behavior.
Closes#103
document cross-reader sync limitations in the KOReader settings panel.
set clear expectations for direction-specific accuracy so users understand why resume location can differ between KOReader and the web reader.
treat the series-position badge as a non-open interactive target and
exclude those clicks from card-open handling.
add regression tests for hover hit-testing and badge-click behavior.
type vitest mock functions in the series detail spec to satisfy
the repository pre-push lint checks.
Closes#99
Handle add-to-collection actions in the series detail view so the collection sheet opens with the selected book id. Add regression tests for grid and table actions plus sheet close state reset.
Closes#102
Extracts the in-memory caching logic previously duplicated across
UserStatisticsService and StatisticsService into a new shared
StatsCache class. This standardizes cache keys, improves invalidation
by scope (such as userId), and makes the dashboard widget and
statistics caching more robust.
The previous SQL query used a LATERAL join and complex aggregations that caused series collapsing to fail. This refactors the query to use a unified base_rows CTE and explicit window functions for fetching series covers, ensuring that series are correctly grouped and displayed.
Closes#87
The backend previously only checked for new releases from GitHub
during application bootstrap. If the server stayed up for a long time,
the UI would never be notified of new releases.
The AppInfoService now re-checks GitHub when the frontend requests
app info, using a 10-minute cache TTL to balance freshness with
API rate limits.
The previous hardcoded AUTHOR_MAP was incomplete and caused missing authors
in the generated release notes. The config now attempts to fetch actual
GitHub usernames associated with commit SHAs using the GitHub API,
falling back to local git log author names if the API request fails.
Use a single semantic-release config to avoid diverging behavior, and update the release notes context logic to map authors with full commit hashes and stable issue URLs.
Add books.id ASC tiebreaker to all 7 OPDS_SORT_MAP sort orders so
pagination is deterministic even when books share identical addedAt
timestamps (e.g. after a bulk library scan). Without a tiebreaker,
PostgreSQL returns equal-valued rows in an undefined order, causing
books to appear on multiple pages or not at all.
Make catalog feed IDs context-specific: filtered views (by library,
collection, smartScope, author, series, or search query) now produce
distinct URNs instead of all sharing urn:bookorbit:catalog. This
aligns with the OPDS spec requirement that <id> uniquely identify
the logical feed.
Remove the dead idQuery.$dynamic() block from paginatedBookQuery
that was built and conditionally mutated but never awaited.
Closes#93
support toggling membership in the collection sheet so users can remove books without leaving the details and quick-view flow.
cover add/remove paths plus access edge cases with frontend and backend tests.
Closes#85
Run recipient fetch on initial open state so dialogs mounted with open=true load data immediately. Add dialog and recipient composable unit tests to lock in the regression behavior and error paths.
Closes#89