Commit Graph

13 Commits

Author SHA1 Message Date
Garret Patti
0842769125 add tag imports 2026-04-19 21:41:34 -04:00
Garret Patti
b0e9c9790c add manga library 2026-04-19 20:25:06 -04:00
Garret Patti
0238dbda7a Add AI-powered image tagging via local LLM
Adds automatic image tagging that runs as a post-scan phase, sending
thumbnails to an OpenAI-compatible vision API and applying matching
tags from the user-defined tag vocabulary.

- New ai-tagger module with batch processing, failure tolerance, and
  tag validation against existing vocabulary
- Admin settings page (Manage > AI Tagging) for endpoint, model, and
  enable toggle with connection testing
- DB migration for ai_tagged_at tracking column and AI config seeds
- Re-tag All support to queue items for reprocessing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-12 15:18:03 -04:00
Garret Patti
aae41e9803 add individual library scanning 2026-04-12 13:51:51 -04:00
Garret Patti
53205d4a19 Add multi-platform game support with per-OS download detection
- Detect Windows (.zip), Linux (.tar.gz), and macOS (.dmg / .app bundle) game archives during scan
- Store GameFile[] with platform metadata in DB instead of plain zipFiles[]
- Stream .app bundles as on-the-fly zip archives via archiver
- Show WIN/LIN/MAC platform badge pills on GameCard and SeriesCard
- Auto-select the download matching the user's OS in GameDetailModal
- Persist cover URL to DB immediately on upload (no re-scan needed)
- Backward-compatible: legacy zipFiles entries map to platform 'windows'

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 09:47:09 -04:00
Garret Patti
768c49ef00 add more management capabilities 2026-04-11 18:33:03 -04:00
Garret Patti
6f86750a99 Unify media_key and item_key — use item_key everywhere
media_key was a lossy shortening of item_key (libraryId:lastSegment) that
introduced a real collision bug: two TV episodes from different series with
the same filename would share the same media_key and each other's tags.

- DB migration converts existing media_tags rows from short format to full
  item_key by joining against media_items; ambiguous/orphaned rows are dropped
- media_tags column renamed media_key → item_key
- Removed itemKeyToMediaKey() from scanner; reconcileAndPrune now passes
  item_key directly to reKeyMediaItem
- DB reader functions (tv, movies, games) now expose item_key on returned
  entities; frontend components use entity.item_key instead of constructing
  the short libraryId:id form
- MixedView now constructs the full mixed_file: item_key format
- Tag API renamed mediaKey param → itemKey throughout

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 18:04:29 -04:00
Garret Patti
4d75e74cab Fix post-scan CPU spike and improve scan performance at scale
- Remove fire-and-forget thumbnail pre-warming from scanMixed(): firing
  48k+ simultaneous unresolved getThumbnailPath() promises was saturating
  sharp and ffmpeg after scan completion, keeping CPU pegged. Mixed-library
  thumbnails are now generated on-demand by /api/thumbnail as before.
- Add incremental fingerprinting: load existing (item_key → fingerprint)
  map from DB before each walk; reuse stored fingerprint for unchanged paths
  instead of re-reading 64 KB per file. Stable re-scans now do ~0 bytes of
  fingerprint I/O.
- Wrap all bulk DB upsert and delete loops in db.transaction() in
  scanMovies(), scanTv(), scanMixed(), and reconcileAndPrune(). Reduces
  N auto-committed WAL writes to a single batch commit per scan phase.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 19:58:05 -04:00
Garret Patti
58c5e424d9 Fix media_tags not updating when fingerprint move is detected
reKeyMediaItem was called with item_key values (e.g. "lib1:movie:Inception")
but media_tags stores keys in the shorter UI format (e.g. "lib1:Inception"),
so the UPDATE never matched any rows.

Add itemKeyToMediaKey() to extract the terminal segment of an item_key and
reconstruct the media_key format the UI uses:
  lib1:movie:Inception%20(2010)          → lib1:Inception%20(2010)
  lib1:tv_episode:Show:Season1:ep.mkv   → lib1:ep.mkv
  lib1:mixed_file:dir%2Ffile.mp4        → lib1:dir%2Ffile.mp4

Also skip the UPDATE when old and new media_keys are identical (e.g. a TV
episode moved between seasons keeps the same filename-based media_key).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 18:59:51 -04:00
Garret Patti
38a6886863 Add file fingerprinting for move-resilient media item identity
Computes a SHA-256 partial-content fingerprint (file size + first 64 KB) for
movies, TV episodes, and mixed files during scans. When a file is moved or
renamed within a library, the scan detects the fingerprint match, renames the
media_items row in-place, and updates media_tags.media_key to match — so tags
and NFO metadata survive the move transparently.

- src/lib/fingerprint.ts: new computeFingerprint() using sync FS reads
- src/lib/db.ts: fingerprint TEXT column + index migration
- src/lib/tags.ts: reKeyMediaItem() to update media_tags on rename
- src/lib/scanner.ts: replace clear+upsert with detectMoves/reconcileAndPrune
  for movies, TV episodes, and mixed files; games retain clear+upsert (v1)
- TV scan restructured to a single filesystem pass (no double-scanning)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 18:35:02 -04:00
Garret Patti
819748d1ff DB-first library reads, mixed library indexing, and manual NFO refresh
- API reads now serve from media_items cache instead of scanning the filesystem
  on every request; scans (manual or scheduled) remain the write path
- NFO metadata is no longer parsed automatically during scans; title falls back
  to folder/filename — metadata can be refreshed per-item via the kabob menu
- Mixed libraries are now indexed in media_items (new mixed_file item type)
  with file_path stored; scanMixed walks recursively and upserts all files
- Added file_path column to media_items and migrated item_type CHECK constraint
  to include mixed_file via safe table-recreation migration
- New POST /api/nfo-refresh endpoint reads the .nfo for a single item and
  patches its DB row (supports movie, tv_series, tv_episode)
- Added "Refresh metadata" button to movie and TV series kabob menus

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 18:20:21 -04:00
Garret Patti
6b5ff81654 Reduce code duplication and update README
- Extract shared utilities (HIDDEN_FILES, VIDEO_EXTENSIONS, fileApiUrl,
  thumbnailApiUrl, findFile) into new src/lib/media-utils.ts, removing
  identical copies from games.ts, movies.ts, tv.ts, files.ts, and scanner.ts
- Add comment in files.ts clarifying why its VIDEO_EXTENSIONS set intentionally
  differs from the media library set (web-playable formats for the mixed browser)
- Rewrite README to reflect the current feature set: Movies/TV libraries, auth
  system, tag system, background scanner, updated project structure, folder
  conventions for all four library types, and a complete API reference

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 12:49:24 -04:00
Garret Patti
8829188c58 add scanning 2026-04-05 18:55:53 -04:00