fix(player): show live track metadata, not the stale queue snapshot
Docker Build & Publish / build (push) Has been cancelled
Docker Build & Publish / push (push) Has been cancelled
Docker Build & Publish / Prune old image versions (push) Has been cancelled

The queue slice stores denormalized display fields captured at play-time, so the
player and queue panel kept showing pre-enrichment title/artist after a track's
metadata was updated — the library (RTKQ cache) and the player disagreed.

Add useResolvedQueueEntry: read through to the RTKQ Track cache and prefer its
fresh values, keeping the snapshot only as instant/offline fallback. Wire it into
PersistentPlayer (now-playing + cover) and QueuePanel (now-playing + up-next
rows), so enrichment updates reach the player through the same Track tags that
refresh the library.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Senko-san
2026-06-13 13:37:34 +03:00
parent 42080b37ea
commit 9c344b98c4
3 changed files with 97 additions and 32 deletions
+37
View File
@@ -0,0 +1,37 @@
import { skipToken } from '@reduxjs/toolkit/query';
import { useGetTrackQuery } from '../api/endpoints/library';
import type { QueueEntry } from '../store/slices/queue';
export interface ResolvedQueueEntry {
trackId: string;
title: string;
artistName: string;
albumTitle: string;
durationMs: number;
hasCover: boolean;
}
/**
* Merge a queue entry's play-time snapshot with the live `Track` cache.
*
* The queue slice stores denormalized display fields (title/artist/…) captured
* when a track was queued, so they go stale after metadata enrichment updates
* the track. This reads through to the RTKQ `Track` cache — invalidated by the
* same tags that refresh the library — and prefers its fresh values, falling
* back to the snapshot for instant render and offline. Returns undefined when
* there is no current entry.
*/
export function useResolvedQueueEntry(
entry: QueueEntry | undefined,
): ResolvedQueueEntry | undefined {
const { data } = useGetTrackQuery(entry?.trackId ?? skipToken);
if (!entry) return undefined;
return {
trackId: entry.trackId,
title: data?.title ?? entry.title,
artistName: data?.artistName ?? entry.artistName,
albumTitle: data?.albumTitle ?? entry.albumTitle,
durationMs: data?.durationMs ?? entry.durationMs,
hasCover: data?.hasCover ?? false,
};
}