fix(player): show live track metadata, not the stale queue snapshot
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:
@@ -15,8 +15,9 @@ import {
|
||||
} from '../../store/slices/player';
|
||||
import { useAudioPlayer } from '../../hooks/useAudioPlayer';
|
||||
import { useStreamCached } from '../../hooks/useStreamCached';
|
||||
import { useResolvedQueueEntry } from '../../hooks/useResolvedQueueEntry';
|
||||
import { formatDuration } from '../../lib/format';
|
||||
import { getCoverUrl } from '../../api/endpoints/streaming';
|
||||
import { getCoverUrl, getTrackCoverUrl } from '../../api/endpoints/streaming';
|
||||
|
||||
export function PersistentPlayer() {
|
||||
const { t } = useTranslation();
|
||||
@@ -24,7 +25,11 @@ export function PersistentPlayer() {
|
||||
const { seek, playNext, playPrev } = useAudioPlayer();
|
||||
const player = useAppSelector((s) => s.player);
|
||||
const queue = useAppSelector((s) => s.queue);
|
||||
const token = useAppSelector((s) => s.auth.accessToken);
|
||||
const currentEntry = queue.entries[queue.currentIndex];
|
||||
// Read through to the live Track cache so enrichment updates reach the player,
|
||||
// not just the play-time snapshot frozen in the queue slice.
|
||||
const current = useResolvedQueueEntry(currentEntry);
|
||||
// Source indicator: cached → playing locally, otherwise streaming.
|
||||
const cached = useStreamCached(currentEntry?.trackId);
|
||||
|
||||
@@ -32,8 +37,12 @@ export function PersistentPlayer() {
|
||||
return <div className="player empty">{t('player.nothingPlaying')}</div>;
|
||||
}
|
||||
|
||||
const artUrl = getCoverUrl(currentEntry?.albumArtUrl);
|
||||
const seedLabel = currentEntry?.albumTitle ?? currentEntry?.title ?? '';
|
||||
const artUrl =
|
||||
getCoverUrl(currentEntry?.albumArtUrl) ??
|
||||
(token && current?.hasCover
|
||||
? getTrackCoverUrl(current.trackId, token, true)
|
||||
: undefined);
|
||||
const seedLabel = current?.albumTitle ?? current?.title ?? '';
|
||||
const onStream = !cached;
|
||||
|
||||
return (
|
||||
@@ -45,8 +54,8 @@ export function PersistentPlayer() {
|
||||
>
|
||||
<ArtTile seed={seedLabel} size={54} label={seedLabel} src={artUrl} />
|
||||
<div className="pl-now-tt">
|
||||
<div className="t">{currentEntry?.title ?? '—'}</div>
|
||||
<div className="a">{currentEntry?.artistName ?? ''}</div>
|
||||
<div className="t">{current?.title ?? '—'}</div>
|
||||
<div className="a">{current?.artistName ?? ''}</div>
|
||||
<div
|
||||
className="pl-srcbadge"
|
||||
style={{ color: onStream ? 'var(--fg-3)' : 'var(--lime)' }}
|
||||
|
||||
Reference in New Issue
Block a user