From fc5024be90a58e476248d0adc65cfbab4954081f Mon Sep 17 00:00:00 2001 From: jeffvli Date: Fri, 16 Jan 2026 04:18:02 -0800 Subject: [PATCH] revalidate current song in queue during playback --- .../player/components/audio-players.tsx | 2 + .../player/hooks/use-update-current-song.ts | 76 +++++++++++++++++++ src/renderer/store/player.store.ts | 14 ++++ 3 files changed, 92 insertions(+) create mode 100644 src/renderer/features/player/hooks/use-update-current-song.ts diff --git a/src/renderer/features/player/components/audio-players.tsx b/src/renderer/features/player/components/audio-players.tsx index 3b0f4eb41..f94efee5b 100644 --- a/src/renderer/features/player/components/audio-players.tsx +++ b/src/renderer/features/player/components/audio-players.tsx @@ -14,6 +14,7 @@ import { usePlaybackHotkeys } from '/@/renderer/features/player/hooks/use-playba import { usePowerSaveBlocker } from '/@/renderer/features/player/hooks/use-power-save-blocker'; import { useQueueRestoreTimestamp } from '/@/renderer/features/player/hooks/use-queue-restore'; import { useScrobble } from '/@/renderer/features/player/hooks/use-scrobble'; +import { useUpdateCurrentSong } from '/@/renderer/features/player/hooks/use-update-current-song'; import { useWebAudio } from '/@/renderer/features/player/hooks/use-webaudio'; import { RadioWebPlayer } from '/@/renderer/features/radio/components/radio-web-player'; import { @@ -54,6 +55,7 @@ export const AudioPlayers = () => { usePlaybackHotkeys(); useAutoDJ(); useQueueRestoreTimestamp(); + useUpdateCurrentSong(); useRadioAudioInstance(); useRadioMetadata(); diff --git a/src/renderer/features/player/hooks/use-update-current-song.ts b/src/renderer/features/player/hooks/use-update-current-song.ts new file mode 100644 index 000000000..67d38ddfb --- /dev/null +++ b/src/renderer/features/player/hooks/use-update-current-song.ts @@ -0,0 +1,76 @@ +import { useQueryClient } from '@tanstack/react-query'; +import { useCallback } from 'react'; + +import { api } from '/@/renderer/api'; +import { queryKeys } from '/@/renderer/api/query-keys'; +import { usePlayerEvents } from '/@/renderer/features/player/audio-player/hooks/use-player-events'; +import { updateQueueSong } from '/@/renderer/store/player.store'; +import { LogCategory, logFn } from '/@/renderer/utils/logger'; +import { QueueSong, SongDetailQuery } from '/@/shared/types/domain-types'; + +export const useUpdateCurrentSong = () => { + const queryClient = useQueryClient(); + + const handleSongChange = useCallback( + async (properties: { index: number; song: QueueSong | undefined }) => { + const currentSong = properties.song; + + if (!currentSong?.id || !currentSong?._serverId) { + return; + } + + try { + const queryFilter: SongDetailQuery = { id: currentSong.id }; + const queryKey = queryKeys.songs.detail(currentSong._serverId, queryFilter); + + const updatedSong = await queryClient.fetchQuery({ + queryFn: async ({ signal }) => + api.controller.getSongDetail({ + apiClientProps: { + serverId: currentSong._serverId, + signal, + }, + query: queryFilter, + }), + queryKey, + }); + + if (updatedSong) { + updateQueueSong(currentSong.id, updatedSong); + + logFn.debug('Song updated in queue', { + category: LogCategory.PLAYER, + meta: { + id: currentSong.id, + name: updatedSong.name, + }, + }); + } + } catch (error) { + logFn.error('Failed to update song in queue', { + category: LogCategory.PLAYER, + meta: { + error: error instanceof Error ? error.message : String(error), + id: currentSong.id, + }, + }); + } + }, + [queryClient], + ); + + usePlayerEvents( + { + onCurrentSongChange: (properties, prev) => { + // Only update if the song actually changed + if ( + properties.song?.id !== prev.song?.id || + properties.song?._uniqueId !== prev.song?._uniqueId + ) { + handleSongChange(properties); + } + }, + }, + [handleSongChange], + ); +}; diff --git a/src/renderer/store/player.store.ts b/src/renderer/store/player.store.ts index 92d8b0e0d..ed6dc904d 100644 --- a/src/renderer/store/player.store.ts +++ b/src/renderer/store/player.store.ts @@ -2641,6 +2641,20 @@ export const incrementQueuePlayCount = (ids: string[]) => { }); }; +export const updateQueueSong = (songId: string, updatedSong: Song) => { + usePlayerStoreBase.setState((state) => { + Object.values(state.queue.songs).forEach((song) => { + if (song.id === songId) { + const uniqueId = song._uniqueId; + state.queue.songs[song._uniqueId] = { + ...updatedSong, + _uniqueId: uniqueId, + }; + } + }); + }); +}; + export const usePlayerMuted = () => { return usePlayerStoreBase((state) => state.player.muted); };