From 9a4a8eb742ddd3de023ffc388242cd26248afc11 Mon Sep 17 00:00:00 2001 From: jeffvli Date: Wed, 21 Jan 2026 02:02:49 -0800 Subject: [PATCH] refactor some usePlayerSong consumers to only fetch needed properties --- .../player/components/center-controls.tsx | 7 +- .../player/components/player-config.tsx | 450 ++++++++++-------- src/renderer/store/player.store.ts | 20 + 3 files changed, 266 insertions(+), 211 deletions(-) diff --git a/src/renderer/features/player/components/center-controls.tsx b/src/renderer/features/player/components/center-controls.tsx index dbd847189..20bcfa2d9 100644 --- a/src/renderer/features/player/components/center-controls.tsx +++ b/src/renderer/features/player/components/center-controls.tsx @@ -16,7 +16,7 @@ import { useButtonSize, usePlayerRepeat, usePlayerShuffle, - usePlayerSong, + usePlayerSongProperties, usePlayerStatus, useSkipButtons, } from '/@/renderer/store'; @@ -197,13 +197,14 @@ const SkipBackwardButton = ({ disabled }: { disabled?: boolean }) => { }; const CenterPlayButton = ({ disabled }: { disabled?: boolean }) => { - const currentSong = usePlayerSong(); + const { id: currentSongId } = usePlayerSongProperties(['id']) ?? {}; + const status = usePlayerStatus(); const { mediaTogglePlayPause } = usePlayer(); return ( diff --git a/src/renderer/features/player/components/player-config.tsx b/src/renderer/features/player/components/player-config.tsx index 14246d877..99ab719eb 100644 --- a/src/renderer/features/player/components/player-config.tsx +++ b/src/renderer/features/player/components/player-config.tsx @@ -6,8 +6,8 @@ import { ListConfigTable } from '/@/renderer/features/shared/components/list-con import { usePlaybackType, usePlayerActions, - usePlayerData, usePlayerProperties, + usePlayerSongProperties, usePlayerSpeed, usePlayerStatus, } from '/@/renderer/store'; @@ -51,13 +51,6 @@ const getMpvAudioDevices = async () => { export const PlayerConfig = () => { const { t } = useTranslation(); - const { currentSong } = usePlayerData(); - const speed = usePlayerSpeed(); - const status = usePlayerStatus(); - const playbackType = usePlaybackType(); - const { crossfadeDuration, crossfadeStyle, transitionType } = usePlayerProperties(); - const { setCrossfadeDuration, setCrossfadeStyle, setSpeed, setTransitionType } = - usePlayerActions(); const preservePitch = useSettingsStore((state) => state.playback.preservePitch); const showLyricsInSidebar = useShowLyricsInSidebar(); const showVisualizerInSidebar = useShowVisualizerInSidebar(); @@ -75,101 +68,15 @@ export const PlayerConfig = () => { [playbackSettings, setSettings], ); - const [audioDevices, setAudioDevices] = useState<{ label: string; value: string }[]>([]); - - useEffect(() => { - const fetchAudioDevices = async () => { - if (!isElectron()) { - return; - } - - if (playbackType === PlayerType.WEB) { - getAudioDevice() - .then((dev) => - setAudioDevices(dev.map((d) => ({ label: d.label, value: d.deviceId }))), - ) - .catch(() => - toast.error({ - message: t('error.audioDeviceFetchError', { - postProcess: 'sentenceCase', - }), - }), - ); - } else if (playbackType === PlayerType.LOCAL && mpvPlayer) { - try { - const devices = await getMpvAudioDevices(); - setAudioDevices(devices); - } catch { - toast.error({ - message: t('error.audioDeviceFetchError', { - postProcess: 'sentenceCase', - }), - }); - } - } - }; - - fetchAudioDevices(); - }, [playbackType, t]); - const options = useMemo(() => { - const formatPlaybackSpeedSliderLabel = (value: number) => { - const bpm = Number(currentSong?.bpm); - if (bpm > 0) { - return `${value} x / ${(bpm * value).toFixed(1)} BPM`; - } - return `${value} x`; - }; - const allOptions = [ { - component: ( - { - setSettings({ - playback: { - ...playbackSettings, - audioDeviceId: e, - }, - }); - }} - width="100%" - /> - ), + component: , id: 'audioDevice', label: t('setting.audioDevice', { postProcess: 'titleCase' }), }, @@ -180,93 +87,21 @@ export const PlayerConfig = () => { label: '', }, { - component: ( - setTransitionType(value as PlayerStyle)} - size="sm" - value={transitionType} - w="100%" - /> - ), + component: , id: 'transitionType', label: t('setting.playbackStyle', { postProcess: 'titleCase', }), }, { - component: ( - { + setSettings({ + playback: { ...playbackSettings, type: e as PlayerType }, + }); + ipc?.send('settings-set', { + property: 'playbackType', + value: e, + }); + }} + width="100%" + /> + ); +}; + +const AudioDeviceConfig = () => { + const { t } = useTranslation(); + const status = usePlayerStatus(); + const playbackType = usePlaybackType(); + const playbackSettings = usePlaybackSettings(); + const { setSettings } = useSettingsStoreActions(); + const [audioDevices, setAudioDevices] = useState<{ label: string; value: string }[]>([]); + + useEffect(() => { + const fetchAudioDevices = async () => { + if (!isElectron()) { + return; + } + + if (playbackType === PlayerType.WEB) { + getAudioDevice() + .then((dev) => + setAudioDevices(dev.map((d) => ({ label: d.label, value: d.deviceId }))), + ) + .catch(() => + toast.error({ + message: t('error.audioDeviceFetchError', { + postProcess: 'sentenceCase', + }), + }), + ); + } else if (playbackType === PlayerType.LOCAL && mpvPlayer) { + try { + const devices = await getMpvAudioDevices(); + setAudioDevices(devices); + } catch { + toast.error({ + message: t('error.audioDeviceFetchError', { + postProcess: 'sentenceCase', + }), + }); + } + } + }; + + fetchAudioDevices(); + }, [playbackType, t]); + + return ( + { + if (e) { + setCrossfadeStyle(e as CrossfadeStyle); + } + }} + width="100%" + /> + ); +}; + +const CrossfadeDurationConfig = () => { + const status = usePlayerStatus(); + const playbackSettings = usePlaybackSettings(); + const { crossfadeDuration, transitionType } = usePlayerProperties(); + const { setCrossfadeDuration } = usePlayerActions(); + + return ( + + ); +}; + +export const PlaybackSpeedSlider = () => { + const speed = usePlayerSpeed(); + const { setSpeed } = usePlayerActions(); + const { bpm } = usePlayerSongProperties(['bpm']) ?? {}; + + const formatPlaybackSpeedSliderLabel = useMemo( + () => (value: number) => { + const bpmValue = Number(bpm); + if (bpmValue > 0) { + return `${value} x / ${(bpmValue * value).toFixed(1)} BPM`; + } + return `${value} x`; + }, + [bpm], + ); + + return ( + setSpeed(1)} + step={0.01} + styles={{ + markLabel: {}, + root: {}, + }} + w="100%" + /> + ); +}; diff --git a/src/renderer/store/player.store.ts b/src/renderer/store/player.store.ts index 8c16bb7b1..35091755e 100644 --- a/src/renderer/store/player.store.ts +++ b/src/renderer/store/player.store.ts @@ -1984,6 +1984,26 @@ export const usePlayerSong = () => { ); }; +export const usePlayerSongProperties = ( + properties: T[], +): Partial> => { + return usePlayerStoreBase( + useShallow((state) => { + const song = state.getCurrentSong(); + if (!song) { + return {}; + } + + const result = {} as Pick; + + for (const prop of properties) { + result[prop] = song[prop]; + } + return result; + }), + ); +}; + export const usePlayerNum = () => { return usePlayerStoreBase((state) => state.player.playerNum); };