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>
- 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>
- 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>
- Series grouping: a top-level folder with no .zip but game subfolders is
now treated as a GameSeries. Clicking a series drills into it with a
breadcrumb; a game-count badge distinguishes series cards from game cards.
Series fall back to the first game's cover when no series-level cover exists.
- Cover upload: new POST /api/game-cover endpoint writes cover.jpg or
widecover.jpg directly into the game/series folder (re-encoded via sharp).
A kebab menu on GameDetailModal opens an Edit Images panel showing previews
and upload/replace buttons for both cover and wide cover.
- Multi-zip download: Game.zipFiles replaces zipPath and includes all .zip
files in the folder. A single zip shows the existing download button; multiple
zips render a split button — primary action downloads the first file, a
dropdown arrow lists all files by name.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>