Commit Graph

28 Commits

Author SHA1 Message Date
neon de0954e77f feat(settings): polish the libraries page and add in-place controls
Cut long paths from the start, name layouts and schedules the way the editor
does, and switch to cards when the ledger would scroll sideways. Rows now
toggle automation in place with undo, open recent scan history, show live
scan counts, flag failed or never-scanned libraries, and can seed a new
library from another's settings.
2026-09-30 06:53:37 +00:00
neon 1dd389563c style(client): unify modal backdrops with dedicated scrim tokens
Replace tinted modal veils with dedicated scrim tokens so dialogs, sheets, and image lightboxes dim consistently in both light and dark themes. Enforce scrim token usage in style validation to prevent backdrops that wash out in dark mode.
2026-09-29 03:42:01 +00:00
neon e92cc36146 feat(library): rebuild the library editor as a settings sheet
Replace the seven-step wizard with a sheet whose section rail summarizes each
setting. Format priority shows only the formats a library holds, folders are
checked as they are added, and people can be granted access while creating.
2026-09-29 02:11:31 +00:00
neon e0d3d42150 feat: add read-aloud and media playback support
Add EPUB narration, shared media controls, and native device session integration.

Apply the generated migrations and update all first-party clients alongside the server.

BREAKING CHANGE: introduce incompatible database and API contracts for media playback
2026-09-19 02:27:05 +00:00
bobberb 17aa7425f8 feat(library): per-library added_at source (imported/file_modified/file_created) (#1239)
* 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>
2026-09-10 10:43:47 -06:00
neon 515f7b89e9 feat(client): redesign sidebar navigation, settings, and user management
Rework the app shell around a customizable sidebar: reorderable sections, sidebar zones, entity
popovers, and per-user preference persistence, backed by a dedicated browse counts endpoint so
entity totals stay cheap on large libraries.

Redesign the file naming settings with pattern fields, a token helper sheet, and a debounced live
preview. Rebuild the admin users table with server-side pagination, search, and filter DTOs, status
pills, confirmation dialogs, and magic link actions. Group notification preferences by category and
refine the account and privacy settings layouts.

Update theme tokens, icon references, and template event handler bindings across client features for
consistency, extend all locale catalogs, and add unit coverage for the new composables, components,
and server modules.
2026-07-28 16:12:36 +00:00
neon d0047bbf18 feat(library): add FB2 file metadata writing and library settings
Add server support for writing metadata, embedded covers, and FictionBook XML structures directly into FB2 format files. Introduce migration 0058 to persist FB2 file write preferences per library, and update library creator UI and locale catalogs.
2026-07-28 06:50:37 +00:00
neon f7716bdbdb feat(library): add MOBI file metadata writing and Kindle library settings
Add server support for writing metadata, covers, and EXTH records directly into MOBI/AZW format files. Introduce migration 0057 to persist Kindle file write preferences per library, and update the library creation UI and locale catalogs.
2026-07-28 05:48:15 +00:00
Dennis van der Stelt 31bda18c9a feat(i18n): add multi-language support with Dutch translation (#500)
* 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>
2026-07-12 15:07:29 -06:00
neon fd05156186 feat(library): refactor creator modal and virtualize folder browser
Scale personal library management to handle tens of thousands of directories by virtualizing
the server directory list in the folder picker. Standardize Vue event handlers to satisfy
linting rules and restructure the creator workflow with modular composables to simplify
state management and ensure accessible dialog semantics.
2026-07-11 16:55:34 +00:00
neon a7805f7c14 fix(library): lock organization mode after creation
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.
2026-06-26 16:00:56 +00:00
neon 920aa3b477 build(deps): refresh client and server dependencies
Keep the dependency baseline current after the release window, and adapt the icon and zip integrations to current package APIs.
2026-06-21 06:00:55 +00:00
Chris Mansell d06e65a42b feat(audio): embed cover image in audiobook files (#197)
* feat(audio): embed cover image in audiobook files

- Add audio cover embedder
- Implement format writers for M4B, M4A, MP3, and FLAC using ffmpeg
- Add library settings for audio file writes

Closes #145

* fix(library): disable audio file write by default and add ffmpeg timeout

Change the default value of file_write_audio_enabled from true to false in the database schema and migrations. Automatically disable audio writing in the UI if cover writing is toggled off. Add a 60-second timeout to the ffmpeg child process to prevent hanging when embedding covers.

---------

Co-authored-by: neon <18559658+neonsolstice@users.noreply.github.com>
2026-06-02 12:40:27 -06:00
neon 75d9161962 feat(library): rename files on metadata update (#76)
Add file rename feature that renames physical book files on disk when
naming-relevant metadata fields are updated (title, authors, series,
seriesIndex, publishedYear).

Closes #69
2026-05-21 11:15:22 -06:00
neon f0787914b7 style(client): standardize card and dialog corner radius
apply rounded-lg consistently across client cards, dialogs, and surface containers to keep UI shape language uniform
2026-04-21 20:20:46 -06:00
neon deb2b6d92c fix: epub identifier round-trip, metadata extraction, and misc UI bugs
- Switch EPUB provider identifiers to opf:scheme style (Calibre-compatible)
  and teach the OPF parser to read both opf:scheme and legacy urn: formats
- Extract all provider IDs, rating, pageCount, and tags from EPUB on scan
- Validate publication years (1000-2200) across all metadata providers
- Guard SmartScope service against null filter to prevent runtime crash
- Replace window.confirm() in EditCollectionDialog with inline confirm state
- Fix useLiveScanBooks to apply book updates, not just prepend new arrivals
- Add toast feedback and fix route name on SmartScope/Collection delete
- Streamline onboarding tour order (left-to-right, no page jumps)
2026-04-21 17:04:07 -06:00
neon cfc3672a6c refactor: rename book-bucket to book-dock and lens to smart-scope 2026-04-20 22:57:27 -06:00
neon 1f43ea2cb5 feat: enforce non-empty icons for collections, lenses, and libraries 2026-04-12 10:32:31 -06:00
neon 6de8e8bc60 feat(scanner): add live book grid during active scan 2026-04-08 05:02:57 -06:00
neon cfc424ea37 feat: move file write settings from global to per-library 2026-04-06 14:54:50 -06:00
neon 77a1a3fecb feat: add reading progress thresholds to library settings 2026-03-28 13:34:40 -06:00
neon f628d6dfc4 feat: add book-per-file organization mode and refine library creator UI 2026-03-28 12:04:42 -06:00
neon 10a4a2045a feat(cover): add per-library aspect ratio and per-view cover size 2026-03-26 21:14:22 -06:00
neon 416952a3a0 feat: refine theme tokens and apply consistent styling 2026-03-18 06:57:19 -06:00
neon 51dd3d30f3 chore: backend infrastructure improvements
- add URI versioning: global prefix changed to api/v1, all frontend call sites updated
- add AbortSignal.timeout to all outbound fetch calls (10s API, 15s scrapers)
- add X-Request-Id response header and requestId field in error payloads
- add response compression via @fastify/compress (gzip + brotli)
- add security headers via @fastify/helmet with CSP for the Vite SPA
- tune pg pool: max 20, idle/connection/statement timeouts on app and migration pools
- add GET /api/v1/health endpoint via @nestjs/terminus with DB connectivity check
2026-02-28 16:02:15 -06:00
neon 55c104f173 fix: resolve all ESLint errors across server and client 2026-02-10 23:06:44 -06:00
neon 588c1b8972 feat(client): add native image loading via cookie and sonner toasts 2026-01-15 00:10:29 -06:00
neon 760cc6476f feat(library): add creator wizard, folder picker, and full CRUD 2026-01-14 13:13:07 -06:00