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>
This commit is contained in:
Garret Patti
2026-04-10 18:04:29 -04:00
parent 390ce8fcc6
commit 6f86750a99
20 changed files with 161 additions and 124 deletions

View File

@@ -10,6 +10,7 @@ export interface Library {
export interface Game {
id: string
item_key?: string
title: string
coverUrl: string | null
wideCoverUrl: string | null
@@ -18,6 +19,7 @@ export interface Game {
export interface GameSeries {
id: string
item_key?: string
title: string
coverUrl: string | null
wideCoverUrl: string | null
@@ -36,6 +38,7 @@ export interface FileEntry {
export interface Movie {
id: string
item_key?: string
title: string
year: number | null
plot: string | null
@@ -49,6 +52,7 @@ export interface Movie {
export interface TvSeries {
id: string
item_key?: string
title: string
year: number | null
plot: string | null
@@ -61,6 +65,7 @@ export interface TvSeries {
export interface TvSeason {
id: string
item_key?: string
seriesId: string
title: string
seasonNumber: number | null
@@ -70,6 +75,7 @@ export interface TvSeason {
export interface TvEpisode {
id: string
item_key?: string
title: string
episodeNumber: number | null
seasonNumber: number | null