re-implement mpv with new player

This commit is contained in:
jeffvli
2025-11-05 19:01:15 -08:00
parent a452495c22
commit 9fd4abec25
17 changed files with 642 additions and 233 deletions
@@ -1,15 +1,9 @@
import type {
CellDoubleClickedEvent,
RowClassRules,
RowDragEvent,
RowNode,
} from '@ag-grid-community/core';
import type { RowClassRules, RowDragEvent, RowNode } from '@ag-grid-community/core';
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
import type { Ref } from 'react';
import { useMergedRef } from '@mantine/hooks';
import '@ag-grid-community/styles/ag-theme-alpine.css';
import isElectron from 'is-electron';
import { useMergedRef } from '@mantine/hooks';
import debounce from 'lodash/debounce';
import { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
import { ErrorBoundary } from 'react-error-boundary';
@@ -19,29 +13,22 @@ import { getColumnDefs, VirtualTable } from '/@/renderer/components/virtual-tabl
import { ErrorFallback } from '/@/renderer/features/action-required/components/error-fallback';
import { QUEUE_CONTEXT_MENU_ITEMS } from '/@/renderer/features/context-menu/context-menu-items';
import { useHandleTableContextMenu } from '/@/renderer/features/context-menu/hooks/use-handle-context-menu';
import { PlayersRef } from '/@/renderer/features/player/ref/players-ref';
import { updateSong } from '/@/renderer/features/player/update-remote-song';
import { useAppFocus } from '/@/renderer/hooks';
import {
useAppStoreActions,
usePlayerQueue,
usePlayerSong,
usePlayerStatus,
usePlayerVolume,
} from '/@/renderer/store';
import {
PersistedTableColumn,
usePlaybackType,
useSettingsStore,
useSettingsStoreActions,
useTableSettings,
} from '/@/renderer/store/settings.store';
import { searchSongs } from '/@/renderer/utils/search-songs';
import { setQueue, setQueueNext } from '/@/renderer/utils/set-transcoded-queue-data';
import { LibraryItem, QueueSong } from '/@/shared/types/domain-types';
import { PlayerType, TableType } from '/@/shared/types/types';
const mpvPlayer = isElectron() ? window.api.mpvPlayer : null;
import { TableType } from '/@/shared/types/types';
type QueueProps = {
searchTerm?: string;
@@ -52,17 +39,12 @@ export const PlayQueue = forwardRef(({ searchTerm, type }: QueueProps, ref: Ref<
const tableRef = useRef<AgGridReactType | null>(null);
const mergedRef = useMergedRef(ref, tableRef);
const queue = usePlayerQueue();
// const { reorderQueue, setCurrentTrack } = useQueueControls();
const currentSong = usePlayerSong();
// const previousSong = usePreviousSong();
const status = usePlayerStatus();
const { setSettings } = useSettingsStoreActions();
const { setAppStore } = useAppStoreActions();
const tableConfig = useTableSettings(type);
const [gridApi, setGridApi] = useState<AgGridReactType | undefined>();
const playbackType = usePlaybackType();
// const { play } = usePlayerControls();
const volume = usePlayerVolume();
const isFocused = useAppFocus();
const isFocusedRef = useRef<boolean>(isFocused);
@@ -0,0 +1,221 @@
import type { RefObject } from 'react';
import isElectron from 'is-electron';
import { useEffect, useImperativeHandle, useRef, useState } from 'react';
import { AudioPlayer, PlayerOnProgressProps } from '/@/renderer/features/player/audio-player/types';
import { PlayerStatus } from '/@/shared/types/types';
export interface MpvPlayerEngineHandle extends AudioPlayer {}
interface MpvPlayerEngineProps {
currentSrc: string | undefined;
isMuted: boolean;
isTransitioning: boolean;
nextSrc: string | undefined;
onEnded: () => void;
onProgress: (e: PlayerOnProgressProps) => void;
playerRef: RefObject<MpvPlayerEngineHandle>;
playerStatus: PlayerStatus;
speed?: number;
volume: number;
}
const mpvPlayer = isElectron() ? window.api.mpvPlayer : null;
const mpvPlayerListener = isElectron() ? window.api.mpvPlayerListener : null;
const ipc = isElectron() ? window.api.ipc : null;
const PROGRESS_UPDATE_INTERVAL = 250;
const TRANSITION_PROGRESS_INTERVAL = 10;
export const MpvPlayerEngine = (props: MpvPlayerEngineProps) => {
const {
currentSrc,
isMuted,
isTransitioning,
nextSrc,
onEnded,
onProgress,
playerRef,
playerStatus,
speed,
volume,
} = props;
const [internalVolume, setInternalVolume] = useState(volume / 100 || 0);
const [duration] = useState(0);
const [previousCurrentSrc, setPreviousCurrentSrc] = useState<string | undefined>(currentSrc);
const progressIntervalRef = useRef<NodeJS.Timeout | null>(null);
// Update volume
useEffect(() => {
if (!mpvPlayer) {
return;
}
const vol = volume / 100 || 0;
setInternalVolume(vol);
mpvPlayer.volume(volume);
}, [volume]);
// Update mute status
useEffect(() => {
if (!mpvPlayer) {
return;
}
mpvPlayer.mute(isMuted);
}, [isMuted]);
// Update speed/playback rate
useEffect(() => {
if (!mpvPlayer) {
return;
}
if (!speed) {
return;
}
mpvPlayer.setProperties({ speed });
}, [speed]);
// Handle current song changes - update queue position 0
// When currentSrc changes, we need to update the queue
useEffect(() => {
if (!mpvPlayer) {
return;
}
// If currentSrc changed, update the queue
if (currentSrc !== previousCurrentSrc) {
if (currentSrc) {
// Set current song at position 0 and next song at position 1
mpvPlayer.setQueue(currentSrc, nextSrc, playerStatus !== PlayerStatus.PLAYING);
setPreviousCurrentSrc(currentSrc);
} else {
// Clear queue if no current song
mpvPlayer.setQueue(undefined, undefined, true);
setPreviousCurrentSrc(undefined);
}
} else {
// If currentSrc hasn't changed but nextSrc has, update position 1
// This happens when the next song changes but current song stays the same
if (currentSrc) {
mpvPlayer.setQueueNext(nextSrc);
}
}
}, [currentSrc, previousCurrentSrc, nextSrc, playerStatus]);
// Handle play/pause status
useEffect(() => {
if (!mpvPlayer) {
return;
}
if (playerStatus === PlayerStatus.PLAYING) {
mpvPlayer.play();
} else if (playerStatus === PlayerStatus.PAUSED) {
mpvPlayer.pause();
}
}, [playerStatus]);
// Set up progress tracking
useEffect(() => {
if (progressIntervalRef.current) {
clearInterval(progressIntervalRef.current);
}
const updateProgress = async () => {
if (!mpvPlayer) {
return;
}
try {
const time = await mpvPlayer.getCurrentTime();
if (time !== undefined) {
onProgress({
played: time / (duration || time + 10),
playedSeconds: time,
});
}
} catch {
// Handle error silently
}
};
if (currentSrc) {
const interval = isTransitioning
? TRANSITION_PROGRESS_INTERVAL
: PROGRESS_UPDATE_INTERVAL;
progressIntervalRef.current = setInterval(updateProgress, interval);
updateProgress();
}
return () => {
if (progressIntervalRef.current) {
clearInterval(progressIntervalRef.current);
}
};
}, [currentSrc, isTransitioning, duration, onProgress]);
useEffect(() => {
if (!mpvPlayerListener) {
return;
}
const handleOnEnded = () => {
onEnded();
};
mpvPlayerListener.rendererAutoNext(handleOnEnded);
return () => {
ipc?.removeAllListeners('renderer-player-auto-next');
};
}, [nextSrc, onEnded]);
useImperativeHandle<MpvPlayerEngineHandle, MpvPlayerEngineHandle>(playerRef, () => ({
decreaseVolume(by: number) {
const newVol = Math.max(0, internalVolume - by / 100);
setInternalVolume(newVol);
if (mpvPlayer) {
mpvPlayer.volume(newVol * 100);
}
},
increaseVolume(by: number) {
const newVol = Math.min(1, internalVolume + by / 100);
setInternalVolume(newVol);
if (mpvPlayer) {
mpvPlayer.volume(newVol * 100);
}
},
pause() {
if (mpvPlayer) {
mpvPlayer.pause();
}
},
play() {
if (mpvPlayer) {
mpvPlayer.play();
}
},
seekTo(seekTo: number) {
if (mpvPlayer) {
mpvPlayer.seekTo(seekTo);
}
},
setVolume(vol: number) {
const volDecimal = vol / 100 || 0;
setInternalVolume(volDecimal);
if (mpvPlayer) {
mpvPlayer.volume(vol);
}
},
}));
return <div id="mpv-player-engine" style={{ display: 'none' }} />;
};
MpvPlayerEngine.displayName = 'MpvPlayerEngine';
@@ -3,17 +3,10 @@ import type { RefObject } from 'react';
import { useImperativeHandle, useRef, useState } from 'react';
import ReactPlayer from 'react-player';
import { AudioPlayer } from '/@/renderer/features/player/audio-player/types';
import { AudioPlayer, PlayerOnProgressProps } from '/@/renderer/features/player/audio-player/types';
import { convertToLogVolume } from '/@/renderer/features/player/audio-player/utils/player-utils';
import { PlayerStatus } from '/@/shared/types/types';
export interface OnProgressProps {
loaded: number;
loadedSeconds: number;
played: number;
playedSeconds: number;
}
export interface WebPlayerEngineHandle extends AudioPlayer {
player1(): {
ref: null | ReactPlayer;
@@ -30,8 +23,8 @@ interface WebPlayerEngineProps {
isTransitioning: boolean;
onEndedPlayer1: () => void;
onEndedPlayer2: () => void;
onProgressPlayer1: (e: OnProgressProps) => void;
onProgressPlayer2: (e: OnProgressProps) => void;
onProgressPlayer1: (e: PlayerOnProgressProps) => void;
onProgressPlayer2: (e: PlayerOnProgressProps) => void;
playerNum: number;
playerRef: RefObject<WebPlayerEngineHandle>;
playerStatus: PlayerStatus;
@@ -0,0 +1,147 @@
import { t } from 'i18next';
import isElectron from 'is-electron';
import { useCallback, useEffect } from 'react';
import { usePlayerActions } from '/@/renderer/store';
import { toast } from '/@/shared/components/toast/toast';
const mpvPlayer = isElectron() ? window.api.mpvPlayer : null;
const mpvPlayerListener = isElectron() ? window.api.mpvPlayerListener : null;
const ipc = isElectron() ? window.api.ipc : null;
export const useMainPlayerListener = () => {
const {
decreaseVolume,
increaseVolume,
mediaAutoNext,
mediaNext,
mediaPause,
mediaPlay,
mediaPrevious,
mediaSkipBackward,
mediaSkipForward,
mediaStop,
mediaToggleMute,
mediaTogglePlayPause,
toggleRepeat,
toggleShuffle,
} = usePlayerActions();
const handleMpvError = useCallback(
(message: string) => {
toast.error({
id: 'mpv-error',
message,
title: t('error.playbackError', { postProcess: 'sentenceCase' }) as string,
});
mediaPause();
mpvPlayer!.pause();
},
[mediaPause],
);
useEffect(() => {
if (!mpvPlayerListener) {
return;
}
mpvPlayerListener.rendererPlayPause(() => {
mediaTogglePlayPause();
});
mpvPlayerListener.rendererNext(() => {
mediaNext();
});
mpvPlayerListener.rendererPrevious(() => {
mediaPrevious();
});
mpvPlayerListener.rendererPlayPause(() => {
mediaTogglePlayPause();
});
mpvPlayerListener.rendererPlay(() => {
mediaPlay();
});
mpvPlayerListener.rendererPause(() => {
mediaPause();
});
mpvPlayerListener.rendererStop(() => {
mediaStop();
});
mpvPlayerListener.rendererSkipForward(() => {
mediaSkipForward();
});
mpvPlayerListener.rendererSkipBackward(() => {
mediaSkipBackward();
});
mpvPlayerListener.rendererAutoNext(() => {
mediaAutoNext();
});
mpvPlayerListener.rendererToggleShuffle(() => {
toggleShuffle();
});
mpvPlayerListener.rendererToggleRepeat(() => {
toggleRepeat();
});
mpvPlayerListener.rendererVolumeMute(() => {
mediaToggleMute();
});
mpvPlayerListener.rendererVolumeUp(() => {
increaseVolume(1);
});
mpvPlayerListener.rendererVolumeDown(() => {
decreaseVolume(1);
});
mpvPlayerListener.rendererError((_event: any, message: string) => {
handleMpvError(message);
});
return () => {
ipc?.removeAllListeners('renderer-player-play-pause');
ipc?.removeAllListeners('renderer-player-next');
ipc?.removeAllListeners('renderer-player-previous');
ipc?.removeAllListeners('renderer-player-play-pause');
ipc?.removeAllListeners('renderer-player-play');
ipc?.removeAllListeners('renderer-player-pause');
ipc?.removeAllListeners('renderer-player-stop');
ipc?.removeAllListeners('renderer-player-skip-forward');
ipc?.removeAllListeners('renderer-player-skip-backward');
ipc?.removeAllListeners('renderer-player-auto-next');
ipc?.removeAllListeners('renderer-player-toggle-shuffle');
ipc?.removeAllListeners('renderer-player-toggle-repeat');
ipc?.removeAllListeners('renderer-player-volume-mute');
ipc?.removeAllListeners('renderer-player-volume-up');
ipc?.removeAllListeners('renderer-player-volume-down');
ipc?.removeAllListeners('renderer-player-error');
};
}, [
decreaseVolume,
handleMpvError,
increaseVolume,
mediaAutoNext,
mediaNext,
mediaPause,
mediaPlay,
mediaPrevious,
mediaSkipForward,
mediaSkipBackward,
mediaStop,
mediaToggleMute,
mediaTogglePlayPause,
toggleRepeat,
toggleShuffle,
]);
};
@@ -1,5 +1,6 @@
import { useEffect } from 'react';
import {
QueueData,
subscribeCurrentTrack,
subscribePlayerMute,
subscribePlayerProgress,
@@ -9,14 +10,14 @@ import {
subscribePlayerStatus,
subscribePlayerVolume,
} from '/@/renderer/store';
import { QueueSong } from '/@/shared/types/domain-types';
import { QueueData, QueueSong } from '/@/shared/types/domain-types';
import { PlayerStatus } from '/@/shared/types/types';
export interface PlayerEvents {
interface PlayerEvents {
cleanup: () => void;
}
export interface PlayerEventsCallbacks {
interface PlayerEventsCallbacks {
onCurrentSongChange?: (
properties: { index: number; song: QueueSong | undefined },
prev: { index: number; song: QueueSong | undefined },
@@ -34,7 +35,18 @@ export interface PlayerEventsCallbacks {
onPlayerVolume?: (properties: { volume: number }, prev: { volume: number }) => void;
}
export function createPlayerEvents(callbacks: PlayerEventsCallbacks): PlayerEvents {
export function usePlayerEvents(callbacks: PlayerEventsCallbacks, deps: React.DependencyList) {
useEffect(() => {
const engine = createPlayerEvents(callbacks);
return () => {
engine.cleanup();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [...deps]);
}
function createPlayerEvents(callbacks: PlayerEventsCallbacks): PlayerEvents {
const unsubscribers: (() => void)[] = [];
// Subscribe to current track changes
@@ -1,17 +0,0 @@
import { useEffect } from 'react';
import {
createPlayerEvents,
PlayerEventsCallbacks,
} from '/@/renderer/features/player/audio-player/listener/player-events';
export function usePlayerEvents(callbacks: PlayerEventsCallbacks, deps: React.DependencyList) {
useEffect(() => {
const engine = createPlayerEvents(callbacks);
return () => {
engine.cleanup();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [...deps]);
}
@@ -0,0 +1,126 @@
import { useCallback, useRef, useState } from 'react';
import { MpvPlayerEngine, MpvPlayerEngineHandle } from './engine/mpv-player-engine';
import { useMainPlayerListener } from '/@/renderer/features/player/audio-player/hooks/use-main-player-listener';
import { usePlayerEvents } from '/@/renderer/features/player/audio-player/hooks/use-player-events';
import { PlayerOnProgressProps } from '/@/renderer/features/player/audio-player/types';
import {
usePlayerActions,
usePlayerData,
usePlayerMuted,
usePlayerProperties,
usePlayerVolume,
} from '/@/renderer/store';
import { PlayerStatus } from '/@/shared/types/types';
const PLAY_PAUSE_FADE_DURATION = 300;
const PLAY_PAUSE_FADE_INTERVAL = 10;
export function MpvPlayer() {
const playerRef = useRef<MpvPlayerEngineHandle>(null);
const { currentSong, nextSong, status } = usePlayerData();
const { mediaAutoNext, setTimestamp } = usePlayerActions();
const { speed } = usePlayerProperties();
const isMuted = usePlayerMuted();
const volume = usePlayerVolume();
const [localPlayerStatus, setLocalPlayerStatus] = useState<PlayerStatus>(status);
const [isTransitioning, setIsTransitioning] = useState(false);
const fadeAndSetStatus = useCallback(
async (startVolume: number, endVolume: number, duration: number, status: PlayerStatus) => {
if (isTransitioning) {
return setLocalPlayerStatus(status);
}
const steps = duration / PLAY_PAUSE_FADE_INTERVAL;
const volumeStep = (endVolume - startVolume) / steps;
let currentStep = 0;
const promise = new Promise((resolve) => {
const interval = setInterval(() => {
currentStep++;
const newVolume = startVolume + volumeStep * currentStep;
playerRef.current?.setVolume(newVolume);
if (currentStep >= steps) {
clearInterval(interval);
setIsTransitioning(false);
resolve(true);
}
}, PLAY_PAUSE_FADE_INTERVAL);
});
if (status === PlayerStatus.PAUSED) {
await promise;
setLocalPlayerStatus(status);
} else if (status === PlayerStatus.PLAYING) {
setLocalPlayerStatus(status);
await promise;
}
},
[isTransitioning],
);
const onProgress = useCallback(
(e: PlayerOnProgressProps) => {
setTimestamp(Number(e.playedSeconds.toFixed(0)));
},
[setTimestamp],
);
const handleOnEnded = useCallback(() => {
// When mpv auto-advances to the next song (position 1 becomes position 0),
// we need to update the player store first, then update the mpv queue with the new next song
// This follows the same pattern as the old useCenterControls implementation
const playerData = mediaAutoNext();
// Update the mpv queue with the new next song
// The engine will handle the queue update through the useEffect when nextSong changes
playerRef.current?.setVolume(volume);
setIsTransitioning(false);
return playerData;
}, [mediaAutoNext, volume, setIsTransitioning]);
usePlayerEvents(
{
onPlayerSeekToTimestamp: (properties) => {
const timestamp = properties.timestamp;
playerRef.current?.seekTo(timestamp);
},
onPlayerStatus: async (properties) => {
const status = properties.status;
if (status === PlayerStatus.PAUSED) {
fadeAndSetStatus(volume, 0, PLAY_PAUSE_FADE_DURATION, PlayerStatus.PAUSED);
} else if (status === PlayerStatus.PLAYING) {
fadeAndSetStatus(0, volume, PLAY_PAUSE_FADE_DURATION, PlayerStatus.PLAYING);
}
},
onPlayerVolume: (properties) => {
const volume = properties.volume;
playerRef.current?.setVolume(volume);
},
},
[volume, isTransitioning, fadeAndSetStatus],
);
useMainPlayerListener();
return (
<MpvPlayerEngine
currentSrc={currentSong?.streamUrl}
isMuted={isMuted}
isTransitioning={isTransitioning}
nextSrc={nextSong?.streamUrl}
onEnded={handleOnEnded}
onProgress={onProgress}
playerRef={playerRef}
playerStatus={localPlayerStatus}
speed={speed}
volume={volume}
/>
);
}
@@ -6,3 +6,8 @@ export interface AudioPlayer {
seekTo(seekTo: number): void;
setVolume(volume: number): void;
}
export interface PlayerOnProgressProps {
played: number;
playedSeconds: number;
}
@@ -2,11 +2,14 @@ import type { Dispatch } from 'react';
import type ReactPlayer from 'react-player';
import { useCallback, useRef, useState } from 'react';
import { OnProgressProps } from 'react-player/base';
import { WebPlayerEngine, WebPlayerEngineHandle } from './engine/web-player-engine';
import { usePlayerEvents } from '/@/renderer/features/player/audio-player/listener/use-player-events';
import {
WebPlayerEngine,
WebPlayerEngineHandle,
} from '/@/renderer/features/player/audio-player/engine/web-player-engine';
import { useMainPlayerListener } from '/@/renderer/features/player/audio-player/hooks/use-main-player-listener';
import { usePlayerEvents } from '/@/renderer/features/player/audio-player/hooks/use-player-events';
import { PlayerOnProgressProps } from '/@/renderer/features/player/audio-player/types';
import {
usePlayerActions,
usePlayerData,
@@ -22,7 +25,7 @@ const PLAY_PAUSE_FADE_INTERVAL = 10;
export function WebPlayer() {
const playerRef = useRef<WebPlayerEngineHandle>(null);
const { num, player1, player2, status } = usePlayerData();
const { mediaAutoNext, setProgress } = usePlayerActions();
const { mediaAutoNext, setTimestamp } = usePlayerActions();
const { crossfadeDuration, speed, transitionType } = usePlayerProperties();
const isMuted = usePlayerMuted();
const volume = usePlayerVolume();
@@ -67,11 +70,11 @@ export function WebPlayer() {
);
const onProgressPlayer1 = useCallback(
(e: OnProgressProps) => {
(e: PlayerOnProgressProps) => {
if (transitionType === 'crossfade' && num === 1) {
setProgress(Number(e.playedSeconds.toFixed(0)));
setTimestamp(Number(e.playedSeconds.toFixed(0)));
} else if (transitionType === 'gapless') {
setProgress(Number(e.playedSeconds.toFixed(0)));
setTimestamp(Number(e.playedSeconds.toFixed(0)));
}
if (!playerRef.current?.player1()) {
@@ -105,15 +108,15 @@ export function WebPlayer() {
break;
}
},
[crossfadeDuration, isTransitioning, num, setProgress, transitionType, volume],
[crossfadeDuration, isTransitioning, num, setTimestamp, transitionType, volume],
);
const onProgressPlayer2 = useCallback(
(e: OnProgressProps) => {
(e: PlayerOnProgressProps) => {
if (transitionType === PlayerStyle.CROSSFADE && num === 2) {
setProgress(Number(e.playedSeconds.toFixed(0)));
setTimestamp(Number(e.playedSeconds.toFixed(0)));
} else if (transitionType === PlayerStyle.GAPLESS) {
setProgress(Number(e.playedSeconds.toFixed(0)));
setTimestamp(Number(e.playedSeconds.toFixed(0)));
}
if (!playerRef.current?.player2()) {
@@ -147,7 +150,7 @@ export function WebPlayer() {
break;
}
},
[crossfadeDuration, isTransitioning, num, setProgress, transitionType, volume],
[crossfadeDuration, isTransitioning, num, setTimestamp, transitionType, volume],
);
const handleOnEndedPlayer1 = useCallback(() => {
@@ -202,6 +205,8 @@ export function WebPlayer() {
[volume, num, isTransitioning],
);
useMainPlayerListener();
return (
<WebPlayerEngine
isMuted={isMuted}
@@ -3,6 +3,7 @@ import { useEffect, useRef, useState } from 'react';
import styles from './playerbar-slider.module.css';
import { MpvPlayer } from '/@/renderer/features/player/audio-player/mpv-player';
import { WebPlayer } from '/@/renderer/features/player/audio-player/web-player';
import { usePlayerContext } from '/@/renderer/features/player/context/player-context';
import {
@@ -113,6 +114,7 @@ export const PlayerbarSlider = ({ ...props }: SliderProps) => {
</div>
</div>
{playbackType === PlayerType.WEB && <WebPlayer />}
{playbackType === PlayerType.LOCAL && <MpvPlayer />}
</>
);
};
@@ -4,7 +4,7 @@
// import { useTranslation } from 'react-i18next';
// import { useScrobble } from '/@/renderer/features/player/hooks/use-scrobble';
// import { updateSong } from '/@/renderer/features/player/update-remote-song';
// import { updateSong } from '/@/renderer/features/plaayer/update-remote-song';
// import {
// usePlayerNum,
// usePlayerStatus,
@@ -6,14 +6,13 @@ import {
SettingOption,
SettingsSection,
} from '/@/renderer/features/settings/components/settings-section';
import { usePlayerStatus, usePlayerStore } from '/@/renderer/store';
import { usePlayerStatus } from '/@/renderer/store';
import { usePlaybackSettings, useSettingsStoreActions } from '/@/renderer/store/settings.store';
import { setQueue } from '/@/renderer/utils/set-transcoded-queue-data';
import { Select } from '/@/shared/components/select/select';
import { Slider } from '/@/shared/components/slider/slider';
import { Switch } from '/@/shared/components/switch/switch';
import { toast } from '/@/shared/components/toast/toast';
import { CrossfadeStyle, PlayerStyle, PlayerType, PlayerStatus } from '/@/shared/types/types';
import { CrossfadeStyle, PlayerStatus, PlayerStyle, PlayerType } from '/@/shared/types/types';
const ipc = isElectron() ? window.api.ipc : null;
@@ -65,10 +64,6 @@ export const AudioSettings = ({ hasFancyAudio }: { hasFancyAudio: boolean }) =>
onChange={(e) => {
setSettings({ playback: { ...settings, type: e as PlayerType } });
ipc?.send('settings-set', { property: 'playbackType', value: e });
if (isElectron() && e === PlayerType.LOCAL) {
const queueData = usePlayerStore.getState().actions.getPlayerData();
setQueue(queueData);
}
}}
/>
),