- 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>
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>
- Game series: filter now checks child games for both search and tag matches instead of always passing series through
- TV episodes: tag selector no longer closes after picking a tag
- TV episodes: filter panel now filters episodes within a season view
- TV series list: series now appear when any of their episodes match the active tag filter (via new /api/tv/series-episode-tags endpoint backed by media_items)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a toggle button to show/hide the filter panel in Movies, Games,
Mixed, and TV views. On mobile the layout stacks vertically (filter
above content); on md+ it returns to the side-by-side layout. The
toggle button highlights when filters are active so hidden filters
remain discoverable. Also fixes a layout bug where items-start on the
flex-col container caused MixedView thumbnails to collapse on narrow
screens.
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>
- Add left sidebar filter panel to MixedView and GamesView with name
search and tag toggles; only shows tags/categories used in the current
library; AND logic when multiple tags are selected
- Add GET /api/tags/library-assignments endpoint returning all tag
assignments for a library keyed by mediaKey
- Add getTagAssignmentsForLibrary() and getTagsSortedByUsage() to tags lib
- Support ?sort=usage on GET /api/tags/items to order by assignment count
- Tag selector: per-category search, top-25-by-usage display, inline add
tag (auto-assigned to current item) and add category flows
- Tag selector: group assigned tags by category into nested pills
- Fix nested <button> hydration error in EntryTile (outer element is now
a div with role="button")
- Keep filter panel assignments in sync when tags are toggled or created
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>