Commit Graph

115 Commits

Author SHA1 Message Date
neon 57d91ebea1 feat(cover,metadata): ffprobe extraction, cover placeholders, grid refresh, and audiobook search
- Replace music-metadata and mediainfo with @ffprobe-installer for all audio metadata extraction; remove mediainfo dependency
- Show BookCoverPlaceholder in all missing-cover locations: Similar/Series/Author Books carousel, cover editor panel, metadata search result cards, and metadata diff panel
- Extend BookRecommendation and SeriesBookRecommendation shared types with hasCover and authors; update recommendation and book repositories to supply them via parallel queries
- Fix cover refresh not updating in grid: BookCoverCard now merges refreshed BookDetail into the local BookCard and emits update:book; VirtualBookGrid forwards the event; Home, Series, Author, and Collection views wire the handler so covers update without a page reload
- Add audiobook covers checkbox to the Online Search drawer so users can toggle between square and portrait cover searches; result thumbnails and loading skeletons adapt their aspect ratio to match the selection
2026-05-11 00:06:05 +00:00
neon ce72cfd988 feat(entity-manager): pre-computed duplicate detection for large datasets
Replace the live self-join scan (O(N^2), times out at 100K+ authors) with a
background-computed candidates table served instantly at read time.

Key changes:
- Add entity_duplicate_candidates and entity_duplicate_scan_status tables
- Background job batches 1K authors at a time (~58s total for 200K authors)
- Scan endpoint reads from the indexed table (<10ms regardless of scale)
- Candidates are invalidated after merge/delete, not recomputed from scratch
- Add GET /duplicates/status and POST /duplicates/refresh endpoints
- Frontend updates clusters locally after merge/dismiss (no re-scan)
- Status bar shows last computed time and recompute button with progress
- Author browse in entity manager now shows all authors, not just those with books
2026-05-10 08:12:26 +00:00
neon 4e93e20bbb feat(books): add table view, metadata export, and filter builder 2026-05-01 23:59:37 -06:00
neon a41ce07834 feat(stats): add Speed trait and 4 new archetypes to Reading DNA widget 2026-04-28 13:50:26 -06:00
neon e6a18c0b50 feat(settings): add custom font upload with family grouping 2026-04-28 12:21:54 -06:00
neon c85379e4ff feat(auth): enforce edit restrictions on demo-restricted accounts 2026-04-25 23:34:57 -06:00
neon 739d311e9e chore: sync dependency branch with main 2026-04-25 21:35:27 -06:00
neon 46208fc82d feat(stats): add dashboard with stats, challenges, and streak widgets 2026-04-22 15:55:14 -06:00
neon cbb814827e feat(books): add discover, author, and series recommendation rows 2026-04-21 23:42:35 -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 ce6a439062 feat(server): add unified entity manager with duplicate detection
- Remove author insights and duplicate suggestions panels, composables, DTOs, and all backend support
- Add genre and tag duplicate detection, merge, and dismiss with server-side paginated scan results
- Consolidate per-entity-type tools into a single entity-manager module backed by the Strategy pattern
- Support browse, merge, rename, delete, split, and dismiss across all entity types (author, genre, tag, narrator, publisher, language, series)
- Replace old tools module with unified entity-manager controller, service, and repository; add 85+ unit tests
2026-04-20 19:10:47 -06:00
neon f2ede06ea2 feat(scanner): add incremental dir-mtime scanning with concurrency fix
Core performance overhaul - new library_dir_scan_state schema table persists per-directory
mtimes so unchanged directories are skipped entirely on subsequent scans, reducing filesystem
stat() calls from O(all-files) to O(changed-dirs) for large libraries.

Incremental scan (walk.ts / scanner.service.ts):
- New library_dir_scan_state table (bigint mtime, FK to library_folders ON DELETE CASCADE)
- findBookCandidates / findLooseFileCandidates now accept knownDirMtimes and return WalkResult
  (candidates + skippedDirs + unchangedDirs + dirMtimes) instead of bare BookCandidate[]
- Per-dir mtime skip with 3 safety rules: never skip disc dirs, never skip dirs with disc
  subdirs, never skip non-root dirs whose parent mtime changed (guards stem-named merging)
- Root directory now also skippable - parent-mtime check conditionally skipped for root since
  root-level files are never stem-merged (explicitly excluded in buildBookCandidates)
- Settings hash invalidation: SHA-256 of {allowedFormats, formatPriority, excludePatterns,
  organizationMode} forces full scan when settings change or on first scan after server restart
- isInUnchangedDir guard prevents false book-missing marks for skipped dirs
- Math.round() on stat().mtimeMs before storing - fixes bigint rejection of macOS fractional
  milliseconds (e.g. 1776138191093.9556) in PostgreSQL

Walk improvements:
- Bounded concurrency: subdirs processed in chunks of 50 to avoid EMFILE on deep trees
- format + role cached on FileStat to avoid re-classifying the same file twice
- statFilesIntoAcc helper extracted to deduplicate parallel stat logic
- skippedDirs set propagated up from permission-denied dirs

ScanJobStore:
- acquireStartLock / releaseStartLock prevent concurrent scan starts for the same library
- markPendingRescan / consumePendingRescan queue a follow-up scan if one arrives while running

waitForStability:
- Accepts optional knownMtimeMs to skip a redundant stat() call when mtime is already known

File event processor (Issue 25, 11, 20):
- Own-book restore: check file's own book before searching all missing books, fixing false
  book-moved results when an editor saves with a new inode (atomic-save pattern)
- Settings cache per library avoids repeated DB lookups during reconcile of many missing books
- Partial move guard: verify old file is gone before reassigning inode (multi-file books)

Live notifications (scanner.service.ts / file-watcher.service.ts):
- scanBookFolder now emits scan:books:added via existing WebSocket infrastructure so the
  frontend grid updates live when the file watcher adds a book (all 3 code paths covered)
- bufferWatcherNotification() with 30s debounce fires one ScanCompleted notification per
  library summarising watcher-driven additions and removals ('Novels updated - 3 added')
- Removals wired in FileWatcherService.process() and reconcile() on book-missing events
- findLibraryName() added to ScannerRepository for notification title lookup
2026-04-17 17:18:14 -06:00
neon 97207cd66f feat: implement scoped and mobile search in ViewHeader 2026-04-15 22:20:40 -06:00
neon cbaa3b0f1b feat(series): add series collapse with per-library preferences 2026-04-15 18:25:34 -06:00
neon 485bea5e5b feat: implement series browser with card deck visual style
- Add series browser page featuring browse and detail views
- Implement card deck cover design with horizontal spread and square aspect ratio
- Fix series-related bugs in decoding, state management, and data types
- Optimize responsive grid layout for series items
2026-04-15 08:55:25 -06:00
neon 40d829a8a9 feat(notifications): add notification center with real-time updates
- add notifications DB schema, repository, service, gateway, and controller
- add shared notification types, categories, and preference models
- add NotificationAccess permission with authorization matrix probe
- add frontend composable with Socket.IO subscription and REST API
- add NotificationPopover, NotificationItem, and NotificationPreferences components
- integrate notification producers in scanner, metadata fetch, book bucket, author enrichment, email, migration, and file write-back services
- add 30-day auto-cleanup via existing CleanupService cron
- add 29 backend unit tests for notification service and controller
2026-04-15 03:15:05 -06:00
neon dd9fd205d6 feat: add bulk tag update and improve selection action bar 2026-04-15 00:58:50 -06:00
neon 5ddabcf693 feat: add book cover placeholders and cover presence filtering 2026-04-14 04:06:21 -06:00
neon 0bf0a5b9fa feat: add guided onboarding tour
- install driver.js and add 9-step tour covering libraries, lenses,
  collections, search, statistics, appearance, upload, and book bucket
- first step context-aware: points to welcome card on first run, falls
  back to settings nav when libraries already exist
- tour state persisted in user.settings JSONB, survives across devices
- skip on mobile; any dismissal (skip or done) marks tour complete
- theme the tour popover with app design tokens (card, primary, radius)
- add "Take the tour again" button in Settings > Account (desktop only)
2026-04-14 02:54:08 -06:00
neon 71ba6cb566 feat: add support for multiple OIDC providers
- implement OIDC provider and identity repositories
- allow linking/unlinking multiple OIDC identities to a single user
- update login UI to display and handle multiple providers
2026-04-13 20:06:27 -06:00
neon 35594e849e feat: enhance OIDC flow with audit logs and improved error handling
- add audit events for OIDC login and user provisioning
- improve callback error messages and state validation
- add OIDC provider schema and initial migration
2026-04-13 14:44:30 -06:00
neon 1f43ea2cb5 feat: enforce non-empty icons for collections, lenses, and libraries 2026-04-12 10:32:31 -06:00
neon 0aad8c0d7d feat: consolidate mobile UX and filtering updates
- improve responsive layouts and controls across dashboard, home, lens, collection, authors, and book detail surfaces

- modernize settings and metadata provider UIs, including the floating dashboard settings action and cleaner section composition

- add synced or per-view cover sizing and spacing behavior, plus expanded mobile filter and sort control patterns

- extend backend filtering with library rules and increase hardcover ID limits across schema, DTO validation, and migration metadata
2026-04-12 09:45:00 -06:00
neon b0d6bc1957 chore: setup git hooks, refactor e2e test setup and fix ts build errors 2026-04-10 18:46:41 -06:00
neon 3fb99714d7 fix(stats): remove hardcoded library IDs from statistics page 2026-04-09 05:18:00 -06:00
neon 6de8e8bc60 feat(scanner): add live book grid during active scan 2026-04-08 05:02:57 -06:00
neon 0e9ae2ae10 feat(scanner): add kepub and audio format support to uploads 2026-04-07 13:56:58 -06:00
neon cfc424ea37 feat: move file write settings from global to per-library 2026-04-06 14:54:50 -06:00
neon 9fd4e162aa feat(server): harden booklore migration with adapters and E2E tests 2026-04-05 16:01:04 -06:00
neon bab3813ff8 feat(metadata): add per-field locking to protect fields from overwrites 2026-04-03 21:31:02 -06:00
neon 9dcc513a0d feat(books): add extra sort fields including user-specific progress 2026-04-03 20:52:11 -06:00
neon 0a58a87239 refactor(scanner): rename staging module to book bucket 2026-04-03 20:50:11 -06:00
neon bdbe36f9e5 feat(reader): add CBZ spread layout engine and settings 2026-04-02 08:07:00 -06:00
neon fe1b70c1dc feat(reader): polish reader settings and fix PDF and CBZ issues 2026-04-02 08:06:00 -06:00
neon 1fbc499ffc feat(books): show collections and collapsible genres in quick view 2026-04-01 12:01:49 -06:00
neon acc5f833e8 fix(cover): harden cover fetching and validate dashboard scroller lenses 2026-04-01 03:38:20 -06:00
neon 86f0478bc0 refactor(audit): streamline audit module structure 2026-03-31 05:36:35 -06:00
neon 5161fdf203 refactor(server): harden health, library, and lens module architecture 2026-03-31 05:11:33 -06:00
neon 32bbba9aa9 fix(metadata): harden preference concurrency and score recalculation 2026-03-31 04:50:04 -06:00
neon db30a45782 test(scanner): bootstrap scanner E2E test infrastructure 2026-03-30 01:18:32 -06:00
neon 400e5fabc9 feat(books): add read status values across schema, types, and validation 2026-03-29 16:56:57 -06:00
neon 399fa179d2 perf: remove unused tags, metadataScore, durationSeconds from BookCard
- drop tags field and bookTags fan-out query from all BookCard paths
- drop metadataScore from BookCard select (only used in BookDetail)
- fix durationSeconds: was never selected in DB; derive audiobook badge from file format using FORMAT_TO_GROUP instead
2026-03-29 14:09:24 -06:00
neon d5ba57f483 feat: harden nested audio metadata contract and UI consistency 2026-03-29 10:04:26 -06:00
neon efbb63e764 fix(books): fix rating display bug and trim recommendation response body 2026-03-29 09:21:23 -06:00
neon 77a1a3fecb feat: add reading progress thresholds to library settings 2026-03-28 13:34:40 -06:00
neon 6daeca7ab2 feat(stats): add top series and library insight charts with backend 2026-03-27 13:16:51 -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 61746cb62c feat: add format breakdown to Reading Clock with improved tooltip 2026-03-26 10:41:07 -06:00
neon ba37f19b45 feat(stats): add user analytics charts and stabilize ECharts theme 2026-03-26 04:28:08 -06:00
neon 1418957b6f chore: cleanup project structure and resolve client type errors
- resolve all 69 client type-checking errors for stricter TS compliance
- remove obsolete type-check baseline scripts and files
- overhaul project root with updated README.md and new DEVELOPMENT.md
- migrate to unified baseline migration strategy and cleanup docker configs
- remove redundant production and dev-specific shell scripts
2026-03-25 07:14:51 -06:00