mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-09 20:29:36 +02:00
temporarily remove old player implementations to prevent broken app
This commit is contained in:
@@ -3,7 +3,7 @@ import { BrowserWindow, globalShortcut, systemPreferences } from 'electron';
|
|||||||
import { isMacOS, isWindows } from '../../../utils';
|
import { isMacOS, isWindows } from '../../../utils';
|
||||||
import { store } from '../settings';
|
import { store } from '../settings';
|
||||||
|
|
||||||
import { PlaybackType } from '/@/shared/types/types';
|
import { PlayerType } from '/@/shared/types/types';
|
||||||
|
|
||||||
export const enableMediaKeys = (window: BrowserWindow | null) => {
|
export const enableMediaKeys = (window: BrowserWindow | null) => {
|
||||||
if (isMacOS()) {
|
if (isMacOS()) {
|
||||||
@@ -26,9 +26,9 @@ export const enableMediaKeys = (window: BrowserWindow | null) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const enableWindowsMediaSession = store.get('mediaSession', false) as boolean;
|
const enableWindowsMediaSession = store.get('mediaSession', false) as boolean;
|
||||||
const playbackType = store.get('playbackType', PlaybackType.WEB) as PlaybackType;
|
const playbackType = store.get('playbackType', PlayerType.WEB) as PlayerType;
|
||||||
|
|
||||||
if (!enableWindowsMediaSession || !isWindows() || playbackType !== PlaybackType.WEB) {
|
if (!enableWindowsMediaSession || !isWindows() || playbackType !== PlayerType.WEB) {
|
||||||
globalShortcut.register('MediaStop', () => {
|
globalShortcut.register('MediaStop', () => {
|
||||||
window?.webContents.send('renderer-player-stop');
|
window?.webContents.send('renderer-player-stop');
|
||||||
});
|
});
|
||||||
|
|||||||
+3
-3
@@ -38,7 +38,7 @@ import {
|
|||||||
} from './utils';
|
} from './utils';
|
||||||
import './features';
|
import './features';
|
||||||
|
|
||||||
import { PlaybackType, TitleTheme } from '/@/shared/types/types';
|
import { PlayerType, TitleTheme } from '/@/shared/types/types';
|
||||||
|
|
||||||
export default class AppUpdater {
|
export default class AppUpdater {
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -549,9 +549,9 @@ async function createWindow(first = true): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const enableWindowsMediaSession = store.get('mediaSession', false) as boolean;
|
const enableWindowsMediaSession = store.get('mediaSession', false) as boolean;
|
||||||
const playbackType = store.get('playbackType', PlaybackType.WEB) as PlaybackType;
|
const playbackType = store.get('playbackType', PlayerType.WEB) as PlayerType;
|
||||||
const shouldDisableMediaFeatures =
|
const shouldDisableMediaFeatures =
|
||||||
!isWindows() || !enableWindowsMediaSession || playbackType !== PlaybackType.WEB;
|
!isWindows() || !enableWindowsMediaSession || playbackType !== PlayerType.WEB;
|
||||||
if (shouldDisableMediaFeatures) {
|
if (shouldDisableMediaFeatures) {
|
||||||
app.commandLine.appendSwitch(
|
app.commandLine.appendSwitch(
|
||||||
'disable-features',
|
'disable-features',
|
||||||
|
|||||||
+42
-52
@@ -2,44 +2,37 @@ import { ClientSideRowModelModule } from '@ag-grid-community/client-side-row-mod
|
|||||||
import { ModuleRegistry } from '@ag-grid-community/core';
|
import { ModuleRegistry } from '@ag-grid-community/core';
|
||||||
import { InfiniteRowModelModule } from '@ag-grid-community/infinite-row-model';
|
import { InfiniteRowModelModule } from '@ag-grid-community/infinite-row-model';
|
||||||
import { MantineProvider } from '@mantine/core';
|
import { MantineProvider } from '@mantine/core';
|
||||||
|
import '@mantine/core/styles.css';
|
||||||
|
import '@mantine/dates/styles.css';
|
||||||
import { Notifications } from '@mantine/notifications';
|
import { Notifications } from '@mantine/notifications';
|
||||||
|
import '@mantine/notifications/styles.css';
|
||||||
import isElectron from 'is-electron';
|
import isElectron from 'is-electron';
|
||||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import '@mantine/core/styles.css';
|
|
||||||
import '@mantine/notifications/styles.css';
|
|
||||||
import '@mantine/dates/styles.css';
|
|
||||||
|
|
||||||
import '/@/shared/styles/global.css';
|
import '/@/shared/styles/global.css';
|
||||||
|
|
||||||
import '@ag-grid-community/styles/ag-grid.css';
|
import '@ag-grid-community/styles/ag-grid.css';
|
||||||
import 'overlayscrollbars/overlayscrollbars.css';
|
import 'overlayscrollbars/overlayscrollbars.css';
|
||||||
|
|
||||||
import '/styles/overlayscrollbars.css';
|
|
||||||
import i18n from '/@/i18n/i18n';
|
import i18n from '/@/i18n/i18n';
|
||||||
import { useDiscordRpc } from '/@/renderer/features/discord-rpc/use-discord-rpc';
|
import { useDiscordRpc } from '/@/renderer/features/discord-rpc/use-discord-rpc';
|
||||||
import { PlayQueueHandlerContext } from '/@/renderer/features/player/context/play-queue-handler-context';
|
|
||||||
import { WebAudioContext } from '/@/renderer/features/player/context/webaudio-context';
|
import { WebAudioContext } from '/@/renderer/features/player/context/webaudio-context';
|
||||||
import { useHandlePlayQueueAdd } from '/@/renderer/features/player/hooks/use-handle-playqueue-add';
|
|
||||||
import { updateSong } from '/@/renderer/features/player/update-remote-song';
|
|
||||||
import { getMpvProperties } from '/@/renderer/features/settings/components/playback/mpv-settings';
|
import { getMpvProperties } from '/@/renderer/features/settings/components/playback/mpv-settings';
|
||||||
import { useServerVersion } from '/@/renderer/hooks/use-server-version';
|
import { useServerVersion } from '/@/renderer/hooks/use-server-version';
|
||||||
import { IsUpdatedDialog } from '/@/renderer/is-updated-dialog';
|
import { IsUpdatedDialog } from '/@/renderer/is-updated-dialog';
|
||||||
import { AppRouter } from '/@/renderer/router/app-router';
|
import { AppRouter } from '/@/renderer/router/app-router';
|
||||||
import {
|
import {
|
||||||
PlayerState,
|
|
||||||
useCssSettings,
|
useCssSettings,
|
||||||
useHotkeySettings,
|
useHotkeySettings,
|
||||||
usePlaybackSettings,
|
usePlaybackSettings,
|
||||||
usePlayerStore,
|
|
||||||
useQueueControls,
|
|
||||||
useRemoteSettings,
|
useRemoteSettings,
|
||||||
useSettingsStore,
|
useSettingsStore,
|
||||||
} from '/@/renderer/store';
|
} from '/@/renderer/store';
|
||||||
import { useAppTheme } from '/@/renderer/themes/use-app-theme';
|
import { useAppTheme } from '/@/renderer/themes/use-app-theme';
|
||||||
import { sanitizeCss } from '/@/renderer/utils/sanitize';
|
import { sanitizeCss } from '/@/renderer/utils/sanitize';
|
||||||
import { setQueue } from '/@/renderer/utils/set-transcoded-queue-data';
|
|
||||||
import { toast } from '/@/shared/components/toast/toast';
|
import { toast } from '/@/shared/components/toast/toast';
|
||||||
import { PlaybackType, PlayerStatus, WebAudio } from '/@/shared/types/types';
|
import { PlayerType, WebAudio } from '/@/shared/types/types';
|
||||||
|
import '/styles/overlayscrollbars.css';
|
||||||
|
|
||||||
ModuleRegistry.registerModules([ClientSideRowModelModule, InfiniteRowModelModule]);
|
ModuleRegistry.registerModules([ClientSideRowModelModule, InfiniteRowModelModule]);
|
||||||
|
|
||||||
@@ -55,8 +48,8 @@ export const App = () => {
|
|||||||
const { content, enabled } = useCssSettings();
|
const { content, enabled } = useCssSettings();
|
||||||
const { type: playbackType } = usePlaybackSettings();
|
const { type: playbackType } = usePlaybackSettings();
|
||||||
const { bindings } = useHotkeySettings();
|
const { bindings } = useHotkeySettings();
|
||||||
const handlePlayQueueAdd = useHandlePlayQueueAdd();
|
// const handlePlayQueueAdd = useHandlePlayQueueAdd();
|
||||||
const { clearQueue, restoreQueue } = useQueueControls();
|
// const { clearQueue, restoreQueue } = useQueueControls();
|
||||||
const remoteSettings = useRemoteSettings();
|
const remoteSettings = useRemoteSettings();
|
||||||
const cssRef = useRef<HTMLStyleElement | null>(null);
|
const cssRef = useRef<HTMLStyleElement | null>(null);
|
||||||
useDiscordRpc();
|
useDiscordRpc();
|
||||||
@@ -84,9 +77,9 @@ export const App = () => {
|
|||||||
return () => {};
|
return () => {};
|
||||||
}, [content, enabled]);
|
}, [content, enabled]);
|
||||||
|
|
||||||
const providerValue = useMemo(() => {
|
// const providerValue = useMemo(() => {
|
||||||
return { handlePlayQueueAdd };
|
// return { handlePlayQueueAdd };
|
||||||
}, [handlePlayQueueAdd]);
|
// }, [handlePlayQueueAdd]);
|
||||||
|
|
||||||
const webAudioProvider = useMemo(() => {
|
const webAudioProvider = useMemo(() => {
|
||||||
return { setWebAudio, webAudio };
|
return { setWebAudio, webAudio };
|
||||||
@@ -95,7 +88,7 @@ export const App = () => {
|
|||||||
// Start the mpv instance on startup
|
// Start the mpv instance on startup
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const initializeMpv = async () => {
|
const initializeMpv = async () => {
|
||||||
if (playbackType === PlaybackType.LOCAL) {
|
if (playbackType === PlayerType.LOCAL) {
|
||||||
const isRunning: boolean | undefined = await mpvPlayer?.isRunning();
|
const isRunning: boolean | undefined = await mpvPlayer?.isRunning();
|
||||||
|
|
||||||
mpvPlayer?.stop();
|
mpvPlayer?.stop();
|
||||||
@@ -103,7 +96,7 @@ export const App = () => {
|
|||||||
if (!isRunning) {
|
if (!isRunning) {
|
||||||
const extraParameters = useSettingsStore.getState().playback.mpvExtraParameters;
|
const extraParameters = useSettingsStore.getState().playback.mpvExtraParameters;
|
||||||
const properties: Record<string, any> = {
|
const properties: Record<string, any> = {
|
||||||
speed: usePlayerStore.getState().speed,
|
// speed: usePlayerStore.getState().speed,
|
||||||
...getMpvProperties(useSettingsStore.getState().playback.mpvProperties),
|
...getMpvProperties(useSettingsStore.getState().playback.mpvProperties),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -124,11 +117,10 @@ export const App = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
clearQueue();
|
|
||||||
mpvPlayer?.stop();
|
mpvPlayer?.stop();
|
||||||
mpvPlayer?.cleanup();
|
mpvPlayer?.cleanup();
|
||||||
};
|
};
|
||||||
}, [clearQueue, playbackType]);
|
}, [playbackType]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isElectron()) {
|
if (isElectron()) {
|
||||||
@@ -136,34 +128,34 @@ export const App = () => {
|
|||||||
}
|
}
|
||||||
}, [bindings]);
|
}, [bindings]);
|
||||||
|
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
if (utils) {
|
// if (utils) {
|
||||||
utils.onSaveQueue(() => {
|
// utils.onSaveQueue(() => {
|
||||||
const { current, queue } = usePlayerStore.getState();
|
// const { current, queue } = usePlayerStore.getState();
|
||||||
const stateToSave: Partial<Pick<PlayerState, 'current' | 'queue'>> = {
|
// const stateToSave: Partial<Pick<PlayerState, 'current' | 'queue'>> = {
|
||||||
current: {
|
// current: {
|
||||||
...current,
|
// ...current,
|
||||||
status: PlayerStatus.PAUSED,
|
// status: PlayerStatus.PAUSED,
|
||||||
},
|
// },
|
||||||
queue,
|
// queue,
|
||||||
};
|
// };
|
||||||
utils.saveQueue(stateToSave);
|
// utils.saveQueue(stateToSave);
|
||||||
});
|
// });
|
||||||
|
|
||||||
utils.onRestoreQueue((_event: any, data) => {
|
// utils.onRestoreQueue((_event: any, data) => {
|
||||||
const playerData = restoreQueue(data);
|
// const playerData = restoreQueue(data);
|
||||||
if (playbackType === PlaybackType.LOCAL) {
|
// if (playbackType === PlaybackType.LOCAL) {
|
||||||
setQueue(playerData, true);
|
// setQueue(playerData, true);
|
||||||
}
|
// }
|
||||||
updateSong(playerData.current.song);
|
// updateSong(playerData.current.song);
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
return () => {
|
// return () => {
|
||||||
ipc?.removeAllListeners('renderer-restore-queue');
|
// ipc?.removeAllListeners('renderer-restore-queue');
|
||||||
ipc?.removeAllListeners('renderer-save-queue');
|
// ipc?.removeAllListeners('renderer-save-queue');
|
||||||
};
|
// };
|
||||||
}, [playbackType, restoreQueue]);
|
// }, [playbackType, restoreQueue]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (remote) {
|
if (remote) {
|
||||||
@@ -200,11 +192,9 @@ export const App = () => {
|
|||||||
}}
|
}}
|
||||||
zIndex={50000}
|
zIndex={50000}
|
||||||
/>
|
/>
|
||||||
<PlayQueueHandlerContext.Provider value={providerValue}>
|
<WebAudioContext.Provider value={webAudioProvider}>
|
||||||
<WebAudioContext.Provider value={webAudioProvider}>
|
<AppRouter />
|
||||||
<AppRouter />
|
</WebAudioContext.Provider>
|
||||||
</WebAudioContext.Provider>
|
|
||||||
</PlayQueueHandlerContext.Provider>
|
|
||||||
<IsUpdatedDialog />
|
<IsUpdatedDialog />
|
||||||
</MantineProvider>
|
</MantineProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -20,10 +20,15 @@ import {
|
|||||||
gaplessHandler,
|
gaplessHandler,
|
||||||
} from '/@/renderer/components/audio-player/utils/list-handlers';
|
} from '/@/renderer/components/audio-player/utils/list-handlers';
|
||||||
import { useWebAudio } from '/@/renderer/features/player/hooks/use-webaudio';
|
import { useWebAudio } from '/@/renderer/features/player/hooks/use-webaudio';
|
||||||
import { TranscodingConfig, usePlaybackSettings, useSpeed } from '/@/renderer/store';
|
import {
|
||||||
import { useSettingsStore, useSettingsStoreActions } from '/@/renderer/store/settings.store';
|
TranscodingConfig,
|
||||||
|
usePlaybackSettings,
|
||||||
|
usePlayerSpeed,
|
||||||
|
useSettingsStore,
|
||||||
|
useSettingsStoreActions,
|
||||||
|
} from '/@/renderer/store';
|
||||||
import { toast } from '/@/shared/components/toast/toast';
|
import { toast } from '/@/shared/components/toast/toast';
|
||||||
import { PlaybackStyle, PlayerStatus } from '/@/shared/types/types';
|
import { PlayerStatus, PlayerStyle } from '/@/shared/types/types';
|
||||||
|
|
||||||
export type AudioPlayerProgress = {
|
export type AudioPlayerProgress = {
|
||||||
loaded: number;
|
loaded: number;
|
||||||
@@ -38,7 +43,7 @@ interface AudioPlayerProps extends ReactPlayerProps {
|
|||||||
crossfadeStyle: CrossfadeStyle;
|
crossfadeStyle: CrossfadeStyle;
|
||||||
currentPlayer: 1 | 2;
|
currentPlayer: 1 | 2;
|
||||||
muted: boolean;
|
muted: boolean;
|
||||||
playbackStyle: PlaybackStyle;
|
playbackStyle: PlayerStyle;
|
||||||
player1?: Song;
|
player1?: Song;
|
||||||
player2?: Song;
|
player2?: Song;
|
||||||
status: PlayerStatus;
|
status: PlayerStatus;
|
||||||
@@ -122,7 +127,7 @@ export const AudioPlayer = forwardRef<AudioPlayerRef, AudioPlayerProps>((props,
|
|||||||
const shouldUseWebAudio = useSettingsStore((state) => state.playback.webAudio);
|
const shouldUseWebAudio = useSettingsStore((state) => state.playback.webAudio);
|
||||||
const preservesPitch = useSettingsStore((state) => state.playback.preservePitch);
|
const preservesPitch = useSettingsStore((state) => state.playback.preservePitch);
|
||||||
const { resetSampleRate } = useSettingsStoreActions();
|
const { resetSampleRate } = useSettingsStoreActions();
|
||||||
const playbackSpeed = useSpeed();
|
const playbackSpeed = usePlayerSpeed();
|
||||||
const { transcode } = usePlaybackSettings();
|
const { transcode } = usePlaybackSettings();
|
||||||
|
|
||||||
const stream1 = useSongUrl(transcode, currentPlayer === 1, player1);
|
const stream1 = useSongUrl(transcode, currentPlayer === 1, player1);
|
||||||
@@ -448,7 +453,7 @@ export const AudioPlayer = forwardRef<AudioPlayerRef, AudioPlayerProps>((props,
|
|||||||
onEnded={stream1 ? handleOnEnded : undefined}
|
onEnded={stream1 ? handleOnEnded : undefined}
|
||||||
onError={handleOnError(player1Ref)}
|
onError={handleOnError(player1Ref)}
|
||||||
onProgress={
|
onProgress={
|
||||||
playbackStyle === PlaybackStyle.GAPLESS ? handleGapless1 : handleCrossfade1
|
playbackStyle === PlayerStyle.GAPLESS ? handleGapless1 : handleCrossfade1
|
||||||
}
|
}
|
||||||
onReady={handlePlayer1Start}
|
onReady={handlePlayer1Start}
|
||||||
playbackRate={playbackSpeed}
|
playbackRate={playbackSpeed}
|
||||||
@@ -468,7 +473,7 @@ export const AudioPlayer = forwardRef<AudioPlayerRef, AudioPlayerProps>((props,
|
|||||||
onEnded={stream2 ? handleOnEnded : undefined}
|
onEnded={stream2 ? handleOnEnded : undefined}
|
||||||
onError={handleOnError(player2Ref)}
|
onError={handleOnError(player2Ref)}
|
||||||
onProgress={
|
onProgress={
|
||||||
playbackStyle === PlaybackStyle.GAPLESS ? handleGapless2 : handleCrossfade2
|
playbackStyle === PlayerStyle.GAPLESS ? handleGapless2 : handleCrossfade2
|
||||||
}
|
}
|
||||||
onReady={handlePlayer2Start}
|
onReady={handlePlayer2Start}
|
||||||
playbackRate={playbackSpeed}
|
playbackRate={playbackSpeed}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { RowClassRules, RowNode } from '@ag-grid-community/core';
|
|||||||
import { MutableRefObject, useEffect, useMemo, useRef } from 'react';
|
import { MutableRefObject, useEffect, useMemo, useRef } from 'react';
|
||||||
|
|
||||||
import { useAppFocus } from '/@/renderer/hooks';
|
import { useAppFocus } from '/@/renderer/hooks';
|
||||||
import { useCurrentSong, usePlayerStore } from '/@/renderer/store';
|
import { usePlayerSong, usePlayerStore } from '/@/renderer/store';
|
||||||
import { Song } from '/@/shared/types/domain-types';
|
import { Song } from '/@/shared/types/domain-types';
|
||||||
import { PlayerStatus } from '/@/shared/types/types';
|
import { PlayerStatus } from '/@/shared/types/types';
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@ interface UseCurrentSongRowStylesProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const useCurrentSongRowStyles = ({ tableRef }: UseCurrentSongRowStylesProps) => {
|
export const useCurrentSongRowStyles = ({ tableRef }: UseCurrentSongRowStylesProps) => {
|
||||||
const currentSong = useCurrentSong();
|
const currentSong = usePlayerSong();
|
||||||
const isFocused = useAppFocus();
|
const isFocused = useAppFocus();
|
||||||
const isFocusedRef = useRef<boolean>(isFocused);
|
const isFocusedRef = useRef<boolean>(isFocused);
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ import { useDeleteFavorite } from '/@/renderer/features/shared/mutations/delete-
|
|||||||
import { useAppFocus, useContainerQuery } from '/@/renderer/hooks';
|
import { useAppFocus, useContainerQuery } from '/@/renderer/hooks';
|
||||||
import { useGenreRoute } from '/@/renderer/hooks/use-genre-route';
|
import { useGenreRoute } from '/@/renderer/hooks/use-genre-route';
|
||||||
import { AppRoute } from '/@/renderer/router/routes';
|
import { AppRoute } from '/@/renderer/router/routes';
|
||||||
import { useCurrentServer, useCurrentSong, useCurrentStatus } from '/@/renderer/store';
|
import { useCurrentServer, usePlayerSong, usePlayerStatus } from '/@/renderer/store';
|
||||||
import {
|
import {
|
||||||
PersistedTableColumn,
|
PersistedTableColumn,
|
||||||
useGeneralSettings,
|
useGeneralSettings,
|
||||||
@@ -85,9 +85,9 @@ export const AlbumDetailContent = ({ background, tableRef }: AlbumDetailContentP
|
|||||||
const handlePlayQueueAdd = usePlayQueueAdd();
|
const handlePlayQueueAdd = usePlayQueueAdd();
|
||||||
const tableConfig = useTableSettings('albumDetail');
|
const tableConfig = useTableSettings('albumDetail');
|
||||||
const { setTable } = useSettingsStoreActions();
|
const { setTable } = useSettingsStoreActions();
|
||||||
const status = useCurrentStatus();
|
const status = usePlayerStatus();
|
||||||
const isFocused = useAppFocus();
|
const isFocused = useAppFocus();
|
||||||
const currentSong = useCurrentSong();
|
const currentSong = usePlayerSong();
|
||||||
const { externalLinks, lastFM, musicBrainz } = useGeneralSettings();
|
const { externalLinks, lastFM, musicBrainz } = useGeneralSettings();
|
||||||
const genreRoute = useGenreRoute();
|
const genreRoute = useGenreRoute();
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next';
|
|||||||
|
|
||||||
import { openLyricSearchModal } from '/@/renderer/features/lyrics/components/lyrics-search-form';
|
import { openLyricSearchModal } from '/@/renderer/features/lyrics/components/lyrics-search-form';
|
||||||
import {
|
import {
|
||||||
useCurrentSong,
|
usePlayerSong,
|
||||||
useLyricsSettings,
|
useLyricsSettings,
|
||||||
useSettingsStore,
|
useSettingsStore,
|
||||||
useSettingsStoreActions,
|
useSettingsStoreActions,
|
||||||
@@ -38,7 +38,7 @@ export const LyricsActions = ({
|
|||||||
setIndex,
|
setIndex,
|
||||||
}: LyricsActionsProps) => {
|
}: LyricsActionsProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const currentSong = useCurrentSong();
|
const currentSong = usePlayerSong();
|
||||||
const { setSettings } = useSettingsStoreActions();
|
const { setSettings } = useSettingsStoreActions();
|
||||||
const { delayMs, sources } = useLyricsSettings();
|
const { delayMs, sources } = useLyricsSettings();
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import {
|
|||||||
UnsynchronizedLyricsProps,
|
UnsynchronizedLyricsProps,
|
||||||
} from '/@/renderer/features/lyrics/unsynchronized-lyrics';
|
} from '/@/renderer/features/lyrics/unsynchronized-lyrics';
|
||||||
import { queryClient } from '/@/renderer/lib/react-query';
|
import { queryClient } from '/@/renderer/lib/react-query';
|
||||||
import { useCurrentSong, useLyricsSettings, usePlayerStore } from '/@/renderer/store';
|
import { usePlayerSong, useLyricsSettings, usePlayerStore } from '/@/renderer/store';
|
||||||
import { Center } from '/@/shared/components/center/center';
|
import { Center } from '/@/shared/components/center/center';
|
||||||
import { Group } from '/@/shared/components/group/group';
|
import { Group } from '/@/shared/components/group/group';
|
||||||
import { Icon } from '/@/shared/components/icon/icon';
|
import { Icon } from '/@/shared/components/icon/icon';
|
||||||
@@ -29,7 +29,7 @@ import { Text } from '/@/shared/components/text/text';
|
|||||||
import { FullLyricsMetadata, LyricSource, LyricsOverride } from '/@/shared/types/domain-types';
|
import { FullLyricsMetadata, LyricSource, LyricsOverride } from '/@/shared/types/domain-types';
|
||||||
|
|
||||||
export const Lyrics = () => {
|
export const Lyrics = () => {
|
||||||
const currentSong = useCurrentSong();
|
const currentSong = usePlayerSong();
|
||||||
const {
|
const {
|
||||||
enableAutoTranslation,
|
enableAutoTranslation,
|
||||||
translationApiKey,
|
translationApiKey,
|
||||||
|
|||||||
@@ -8,17 +8,16 @@ import { LyricLine } from '/@/renderer/features/lyrics/lyric-line';
|
|||||||
import { useScrobble } from '/@/renderer/features/player/hooks/use-scrobble';
|
import { useScrobble } from '/@/renderer/features/player/hooks/use-scrobble';
|
||||||
import { PlayersRef } from '/@/renderer/features/player/ref/players-ref';
|
import { PlayersRef } from '/@/renderer/features/player/ref/players-ref';
|
||||||
import {
|
import {
|
||||||
useCurrentPlayer,
|
|
||||||
useCurrentStatus,
|
|
||||||
useCurrentTime,
|
|
||||||
useLyricsSettings,
|
useLyricsSettings,
|
||||||
usePlaybackType,
|
usePlaybackType,
|
||||||
|
usePlayerActions,
|
||||||
usePlayerData,
|
usePlayerData,
|
||||||
useSeeked,
|
usePlayerNum,
|
||||||
useSetCurrentTime,
|
usePlayerStatus,
|
||||||
|
usePlayerTimestamp,
|
||||||
} from '/@/renderer/store';
|
} from '/@/renderer/store';
|
||||||
import { FullLyricsMetadata, SynchronizedLyricsArray } from '/@/shared/types/domain-types';
|
import { FullLyricsMetadata, SynchronizedLyricsArray } from '/@/shared/types/domain-types';
|
||||||
import { PlaybackType, PlayerStatus } from '/@/shared/types/types';
|
import { PlayerStatus, PlayerType } from '/@/shared/types/types';
|
||||||
|
|
||||||
const mpvPlayer = isElectron() ? window.api.mpvPlayer : null;
|
const mpvPlayer = isElectron() ? window.api.mpvPlayer : null;
|
||||||
const utils = isElectron() ? window.api.utils : null;
|
const utils = isElectron() ? window.api.utils : null;
|
||||||
@@ -38,33 +37,33 @@ export const SynchronizedLyrics = ({
|
|||||||
translatedLyrics,
|
translatedLyrics,
|
||||||
}: SynchronizedLyricsProps) => {
|
}: SynchronizedLyricsProps) => {
|
||||||
const playersRef = PlayersRef;
|
const playersRef = PlayersRef;
|
||||||
const status = useCurrentStatus();
|
const status = usePlayerStatus();
|
||||||
const playbackType = usePlaybackType();
|
const playbackType = usePlaybackType();
|
||||||
const playerData = usePlayerData();
|
const playerData = usePlayerData();
|
||||||
const now = useCurrentTime();
|
const now = usePlayerTimestamp();
|
||||||
const settings = useLyricsSettings();
|
const settings = useLyricsSettings();
|
||||||
const currentPlayer = useCurrentPlayer();
|
const currentPlayer = usePlayerNum();
|
||||||
const currentPlayerRef =
|
const currentPlayerRef =
|
||||||
currentPlayer === 1 ? playersRef.current?.player1 : playersRef.current?.player2;
|
currentPlayer === 1 ? playersRef.current?.player1 : playersRef.current?.player2;
|
||||||
const setCurrentTime = useSetCurrentTime();
|
|
||||||
const { handleScrobbleFromSeek } = useScrobble();
|
const { handleScrobbleFromSeek } = useScrobble();
|
||||||
|
|
||||||
const handleSeek = useCallback(
|
const handleSeek = useCallback(
|
||||||
(time: number) => {
|
(time: number) => {
|
||||||
if (playbackType === PlaybackType.LOCAL && mpvPlayer) {
|
if (playbackType === PlayerType.LOCAL && mpvPlayer) {
|
||||||
mpvPlayer.seekTo(time);
|
mpvPlayer.seekTo(time);
|
||||||
setCurrentTime(time, true);
|
// setCurrentTime(time, true);
|
||||||
} else {
|
} else {
|
||||||
setCurrentTime(time, true);
|
// setCurrentTime(time, true);
|
||||||
handleScrobbleFromSeek(time);
|
handleScrobbleFromSeek(time);
|
||||||
mpris?.updateSeek(time);
|
mpris?.updateSeek(time);
|
||||||
currentPlayerRef?.seekTo(time);
|
currentPlayerRef?.seekTo(time);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[currentPlayerRef, handleScrobbleFromSeek, playbackType, setCurrentTime],
|
[currentPlayerRef, handleScrobbleFromSeek, playbackType],
|
||||||
);
|
);
|
||||||
|
|
||||||
const seeked = useSeeked();
|
// const seeked = useSeeked();
|
||||||
|
|
||||||
// A reference to the timeout handler
|
// A reference to the timeout handler
|
||||||
const lyricTimer = useRef<null | ReturnType<typeof setTimeout>>(null);
|
const lyricTimer = useRef<null | ReturnType<typeof setTimeout>>(null);
|
||||||
@@ -97,7 +96,7 @@ export const SynchronizedLyrics = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getCurrentTime = useCallback(async () => {
|
const getCurrentTime = useCallback(async () => {
|
||||||
if (isElectron() && playbackType !== PlaybackType.WEB) {
|
if (isElectron() && playbackType !== PlayerType.WEB) {
|
||||||
if (mpvPlayer) {
|
if (mpvPlayer) {
|
||||||
return mpvPlayer.getCurrentTime();
|
return mpvPlayer.getCurrentTime();
|
||||||
}
|
}
|
||||||
@@ -109,7 +108,7 @@ export const SynchronizedLyrics = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const player =
|
const player =
|
||||||
playerData.current.player === 1
|
playerData.player.playerNum === 1
|
||||||
? playersRef.current.player1
|
? playersRef.current.player1
|
||||||
: playersRef.current.player2;
|
: playersRef.current.player2;
|
||||||
const underlying = player?.getInternalPlayer();
|
const underlying = player?.getInternalPlayer();
|
||||||
@@ -282,16 +281,16 @@ export const SynchronizedLyrics = ({
|
|||||||
// we may be playing the same track (repeat one). In this case, we also
|
// we may be playing the same track (repeat one). In this case, we also
|
||||||
// need to restart playback
|
// need to restart playback
|
||||||
const restarted = status === PlayerStatus.PLAYING && now === 0;
|
const restarted = status === PlayerStatus.PLAYING && now === 0;
|
||||||
if (!seeked && !restarted) {
|
// if (!seeked && !restarted) {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (lyricTimer.current) {
|
if (lyricTimer.current) {
|
||||||
clearTimeout(lyricTimer.current);
|
clearTimeout(lyricTimer.current);
|
||||||
}
|
}
|
||||||
|
|
||||||
setCurrentLyric(now * 1000 - delayMsRef.current);
|
setCurrentLyric(now * 1000 - delayMsRef.current);
|
||||||
}, [now, seeked, setCurrentLyric, status]);
|
}, [now, setCurrentLyric, status]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Guaranteed cleanup; stop the timer, and just in case also increment
|
// Guaranteed cleanup; stop the timer, and just in case also increment
|
||||||
|
|||||||
@@ -7,15 +7,12 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { TableConfigDropdown } from '/@/renderer/components/virtual-table';
|
import { TableConfigDropdown } from '/@/renderer/components/virtual-table';
|
||||||
import { updateSong } from '/@/renderer/features/player/update-remote-song';
|
import { updateSong } from '/@/renderer/features/player/update-remote-song';
|
||||||
import { SearchInput } from '/@/renderer/features/shared/components/search-input';
|
import { SearchInput } from '/@/renderer/features/shared/components/search-input';
|
||||||
import { usePlayerControls, useQueueControls } from '/@/renderer/store';
|
|
||||||
import { usePlayerStore, useSetCurrentTime } from '/@/renderer/store/player.store';
|
|
||||||
import { usePlaybackType } from '/@/renderer/store/settings.store';
|
import { usePlaybackType } from '/@/renderer/store/settings.store';
|
||||||
import { setQueue, setQueueNext } from '/@/renderer/utils/set-transcoded-queue-data';
|
|
||||||
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
|
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
|
||||||
import { Group } from '/@/shared/components/group/group';
|
import { Group } from '/@/shared/components/group/group';
|
||||||
import { Popover } from '/@/shared/components/popover/popover';
|
import { Popover } from '/@/shared/components/popover/popover';
|
||||||
import { Song } from '/@/shared/types/domain-types';
|
import { Song } from '/@/shared/types/domain-types';
|
||||||
import { PlaybackType, TableType } from '/@/shared/types/types';
|
import { TableType } from '/@/shared/types/types';
|
||||||
|
|
||||||
const mpvPlayer = isElectron() ? window.api.mpvPlayer : null;
|
const mpvPlayer = isElectron() ? window.api.mpvPlayer : null;
|
||||||
|
|
||||||
@@ -33,30 +30,30 @@ export const PlayQueueListControls = ({
|
|||||||
type,
|
type,
|
||||||
}: PlayQueueListOptionsProps) => {
|
}: PlayQueueListOptionsProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const {
|
// const {
|
||||||
clearQueue,
|
// clearQueue,
|
||||||
moveToBottomOfQueue,
|
// moveToBottomOfQueue,
|
||||||
moveToNextOfQueue,
|
// moveToNextOfQueue,
|
||||||
moveToTopOfQueue,
|
// moveToTopOfQueue,
|
||||||
removeFromQueue,
|
// removeFromQueue,
|
||||||
shuffleQueue,
|
// shuffleQueue,
|
||||||
} = useQueueControls();
|
// } = useQueueControls();
|
||||||
|
|
||||||
const { pause } = usePlayerControls();
|
// const { pause } = usePlayerControls();
|
||||||
|
|
||||||
const playbackType = usePlaybackType();
|
const playbackType = usePlaybackType();
|
||||||
const setCurrentTime = useSetCurrentTime();
|
// const setCurrentTime = useSetCurrentTime();
|
||||||
|
|
||||||
const handleMoveToNext = () => {
|
const handleMoveToNext = () => {
|
||||||
const selectedRows = tableRef?.current?.grid.api.getSelectedRows();
|
const selectedRows = tableRef?.current?.grid.api.getSelectedRows();
|
||||||
const uniqueIds = selectedRows?.map((row) => row.uniqueId);
|
const uniqueIds = selectedRows?.map((row) => row.uniqueId);
|
||||||
if (!uniqueIds?.length) return;
|
if (!uniqueIds?.length) return;
|
||||||
|
|
||||||
const playerData = moveToNextOfQueue(uniqueIds);
|
// const playerData = moveToNextOfQueue(uniqueIds);
|
||||||
|
|
||||||
if (playbackType === PlaybackType.LOCAL) {
|
// if (playbackType === PlaybackType.LOCAL) {
|
||||||
setQueueNext(playerData);
|
// setQueueNext(playerData);
|
||||||
}
|
// }
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMoveToBottom = () => {
|
const handleMoveToBottom = () => {
|
||||||
@@ -64,11 +61,11 @@ export const PlayQueueListControls = ({
|
|||||||
const uniqueIds = selectedRows?.map((row) => row.uniqueId);
|
const uniqueIds = selectedRows?.map((row) => row.uniqueId);
|
||||||
if (!uniqueIds?.length) return;
|
if (!uniqueIds?.length) return;
|
||||||
|
|
||||||
const playerData = moveToBottomOfQueue(uniqueIds);
|
// const playerData = moveToBottomOfQueue(uniqueIds);
|
||||||
|
|
||||||
if (playbackType === PlaybackType.LOCAL) {
|
// if (playbackType === PlaybackType.LOCAL) {
|
||||||
setQueueNext(playerData);
|
// setQueueNext(playerData);
|
||||||
}
|
// }
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMoveToTop = () => {
|
const handleMoveToTop = () => {
|
||||||
@@ -76,11 +73,11 @@ export const PlayQueueListControls = ({
|
|||||||
const uniqueIds = selectedRows?.map((row) => row.uniqueId);
|
const uniqueIds = selectedRows?.map((row) => row.uniqueId);
|
||||||
if (!uniqueIds?.length) return;
|
if (!uniqueIds?.length) return;
|
||||||
|
|
||||||
const playerData = moveToTopOfQueue(uniqueIds);
|
// const playerData = moveToTopOfQueue(uniqueIds);
|
||||||
|
|
||||||
if (playbackType === PlaybackType.LOCAL) {
|
// if (playbackType === PlaybackType.LOCAL) {
|
||||||
setQueueNext(playerData);
|
// setQueueNext(playerData);
|
||||||
}
|
// }
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRemoveSelected = () => {
|
const handleRemoveSelected = () => {
|
||||||
@@ -88,43 +85,42 @@ export const PlayQueueListControls = ({
|
|||||||
const uniqueIds = selectedRows?.map((row) => row.uniqueId);
|
const uniqueIds = selectedRows?.map((row) => row.uniqueId);
|
||||||
if (!uniqueIds?.length) return;
|
if (!uniqueIds?.length) return;
|
||||||
|
|
||||||
const currentSong = usePlayerStore.getState().current.song;
|
// const currentSong = usePlayerStore.getState().current.song;
|
||||||
const playerData = removeFromQueue(uniqueIds);
|
// const playerData = removeFromQueue(uniqueIds);
|
||||||
const isCurrentSongRemoved = currentSong && uniqueIds.includes(currentSong.uniqueId);
|
// const isCurrentSongRemoved = currentSong && uniqueIds.includes(currentSong.uniqueId);
|
||||||
|
|
||||||
if (playbackType === PlaybackType.LOCAL) {
|
// if (playbackType === PlaybackType.LOCAL) {
|
||||||
if (isCurrentSongRemoved) {
|
// if (isCurrentSongRemoved) {
|
||||||
setQueue(playerData);
|
// setQueue(playerData);
|
||||||
} else {
|
// } else {
|
||||||
setQueueNext(playerData);
|
// setQueueNext(playerData);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (isCurrentSongRemoved) {
|
// if (isCurrentSongRemoved) {
|
||||||
updateSong(playerData.current.song);
|
// updateSong(playerData.current.song);
|
||||||
}
|
// }
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleClearQueue = () => {
|
const handleClearQueue = () => {
|
||||||
const playerData = clearQueue();
|
// const playerData = clearQueue();
|
||||||
|
|
||||||
if (playbackType === PlaybackType.LOCAL) {
|
// if (playbackType === PlaybackType.LOCAL) {
|
||||||
setQueue(playerData);
|
// setQueue(playerData);
|
||||||
mpvPlayer!.pause();
|
// mpvPlayer!.pause();
|
||||||
}
|
// }
|
||||||
|
|
||||||
updateSong(undefined);
|
updateSong(undefined);
|
||||||
|
|
||||||
setCurrentTime(0);
|
// setCurrentTime(0);
|
||||||
pause();
|
// pause();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleShuffleQueue = () => {
|
const handleShuffleQueue = () => {
|
||||||
const playerData = shuffleQueue();
|
// const playerData = shuffleQueue();
|
||||||
|
// if (playbackType === PlaybackType.LOCAL) {
|
||||||
if (playbackType === PlaybackType.LOCAL) {
|
// setQueueNext(playerData);
|
||||||
setQueueNext(playerData);
|
// }
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSearchTerm = useCallback(
|
const handleSearchTerm = useCallback(
|
||||||
|
|||||||
@@ -24,13 +24,10 @@ import { updateSong } from '/@/renderer/features/player/update-remote-song';
|
|||||||
import { useAppFocus } from '/@/renderer/hooks';
|
import { useAppFocus } from '/@/renderer/hooks';
|
||||||
import {
|
import {
|
||||||
useAppStoreActions,
|
useAppStoreActions,
|
||||||
useCurrentSong,
|
usePlayerQueue,
|
||||||
useCurrentStatus,
|
usePlayerSong,
|
||||||
useDefaultQueue,
|
usePlayerStatus,
|
||||||
usePlayerControls,
|
usePlayerVolume,
|
||||||
usePreviousSong,
|
|
||||||
useQueueControls,
|
|
||||||
useVolume,
|
|
||||||
} from '/@/renderer/store';
|
} from '/@/renderer/store';
|
||||||
import {
|
import {
|
||||||
PersistedTableColumn,
|
PersistedTableColumn,
|
||||||
@@ -42,7 +39,7 @@ import {
|
|||||||
import { searchSongs } from '/@/renderer/utils/search-songs';
|
import { searchSongs } from '/@/renderer/utils/search-songs';
|
||||||
import { setQueue, setQueueNext } from '/@/renderer/utils/set-transcoded-queue-data';
|
import { setQueue, setQueueNext } from '/@/renderer/utils/set-transcoded-queue-data';
|
||||||
import { LibraryItem, QueueSong } from '/@/shared/types/domain-types';
|
import { LibraryItem, QueueSong } from '/@/shared/types/domain-types';
|
||||||
import { PlaybackType, TableType } from '/@/shared/types/types';
|
import { PlayerType, TableType } from '/@/shared/types/types';
|
||||||
|
|
||||||
const mpvPlayer = isElectron() ? window.api.mpvPlayer : null;
|
const mpvPlayer = isElectron() ? window.api.mpvPlayer : null;
|
||||||
|
|
||||||
@@ -54,18 +51,18 @@ type QueueProps = {
|
|||||||
export const PlayQueue = forwardRef(({ searchTerm, type }: QueueProps, ref: Ref<any>) => {
|
export const PlayQueue = forwardRef(({ searchTerm, type }: QueueProps, ref: Ref<any>) => {
|
||||||
const tableRef = useRef<AgGridReactType | null>(null);
|
const tableRef = useRef<AgGridReactType | null>(null);
|
||||||
const mergedRef = useMergedRef(ref, tableRef);
|
const mergedRef = useMergedRef(ref, tableRef);
|
||||||
const queue = useDefaultQueue();
|
const queue = usePlayerQueue();
|
||||||
const { reorderQueue, setCurrentTrack } = useQueueControls();
|
// const { reorderQueue, setCurrentTrack } = useQueueControls();
|
||||||
const currentSong = useCurrentSong();
|
const currentSong = usePlayerSong();
|
||||||
const previousSong = usePreviousSong();
|
// const previousSong = usePreviousSong();
|
||||||
const status = useCurrentStatus();
|
const status = usePlayerStatus();
|
||||||
const { setSettings } = useSettingsStoreActions();
|
const { setSettings } = useSettingsStoreActions();
|
||||||
const { setAppStore } = useAppStoreActions();
|
const { setAppStore } = useAppStoreActions();
|
||||||
const tableConfig = useTableSettings(type);
|
const tableConfig = useTableSettings(type);
|
||||||
const [gridApi, setGridApi] = useState<AgGridReactType | undefined>();
|
const [gridApi, setGridApi] = useState<AgGridReactType | undefined>();
|
||||||
const playbackType = usePlaybackType();
|
const playbackType = usePlaybackType();
|
||||||
const { play } = usePlayerControls();
|
// const { play } = usePlayerControls();
|
||||||
const volume = useVolume();
|
const volume = usePlayerVolume();
|
||||||
const isFocused = useAppFocus();
|
const isFocused = useAppFocus();
|
||||||
const isFocusedRef = useRef<boolean>(isFocused);
|
const isFocusedRef = useRef<boolean>(isFocused);
|
||||||
|
|
||||||
@@ -94,26 +91,26 @@ export const PlayQueue = forwardRef(({ searchTerm, type }: QueueProps, ref: Ref<
|
|||||||
[tableConfig.columns],
|
[tableConfig.columns],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleDoubleClick = (e: CellDoubleClickedEvent) => {
|
// const handleDoubleClick = (e: CellDoubleClickedEvent) => {
|
||||||
const playerData = setCurrentTrack(e.data.uniqueId);
|
// const playerData = setCurrentTrack(e.data.uniqueId);
|
||||||
updateSong(playerData.current.song);
|
// updateSong(playerData.current.song);
|
||||||
|
|
||||||
if (playbackType === PlaybackType.LOCAL) {
|
// if (playbackType === PlaybackType.LOCAL) {
|
||||||
mpvPlayer!.volume(volume);
|
// mpvPlayer!.volume(volume);
|
||||||
setQueue(playerData, false);
|
// setQueue(playerData, false);
|
||||||
} else {
|
// } else {
|
||||||
const player =
|
// const player =
|
||||||
playerData.current.player === 1
|
// playerData.current.player === 1
|
||||||
? PlayersRef.current?.player1
|
// ? PlayersRef.current?.player1
|
||||||
: PlayersRef.current?.player2;
|
// : PlayersRef.current?.player2;
|
||||||
const underlying = player?.getInternalPlayer();
|
// const underlying = player?.getInternalPlayer();
|
||||||
if (underlying) {
|
// if (underlying) {
|
||||||
underlying.currentTime = 0;
|
// underlying.currentTime = 0;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
play();
|
// play();
|
||||||
};
|
// };
|
||||||
|
|
||||||
const handleDragStart = () => {
|
const handleDragStart = () => {
|
||||||
if (type === 'sideDrawerQueue') {
|
if (type === 'sideDrawerQueue') {
|
||||||
@@ -128,11 +125,11 @@ export const PlayQueue = forwardRef(({ searchTerm, type }: QueueProps, ref: Ref<
|
|||||||
.map((node) => node.data?.uniqueId)
|
.map((node) => node.data?.uniqueId)
|
||||||
.filter((e) => e !== undefined);
|
.filter((e) => e !== undefined);
|
||||||
|
|
||||||
const playerData = reorderQueue(selectedUniqueIds as string[], e.overNode?.data?.uniqueId);
|
// const playerData = reorderQueue(selectedUniqueIds as string[], e.overNode?.data?.uniqueId);
|
||||||
|
|
||||||
if (playbackType === PlaybackType.LOCAL) {
|
// if (playbackType === PlaybackType.LOCAL) {
|
||||||
setQueueNext(playerData);
|
// setQueueNext(playerData);
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (type === 'sideDrawerQueue') {
|
if (type === 'sideDrawerQueue') {
|
||||||
setAppStore({ isReorderingQueue: false });
|
setAppStore({ isReorderingQueue: false });
|
||||||
@@ -204,6 +201,14 @@ export const PlayQueue = forwardRef(({ searchTerm, type }: QueueProps, ref: Ref<
|
|||||||
};
|
};
|
||||||
}, [currentSong?.uniqueId]);
|
}, [currentSong?.uniqueId]);
|
||||||
|
|
||||||
|
const previousSongRef = useRef<QueueSong | undefined>(undefined);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (currentSong) {
|
||||||
|
previousSongRef.current = currentSong;
|
||||||
|
}
|
||||||
|
}, [currentSong]);
|
||||||
|
|
||||||
// Redraw the current song row when the previous song changes
|
// Redraw the current song row when the previous song changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (tableRef?.current) {
|
if (tableRef?.current) {
|
||||||
@@ -215,8 +220,8 @@ export const PlayQueue = forwardRef(({ searchTerm, type }: QueueProps, ref: Ref<
|
|||||||
const currentNode = currentSong?.uniqueId
|
const currentNode = currentSong?.uniqueId
|
||||||
? api.getRowNode(currentSong.uniqueId)
|
? api.getRowNode(currentSong.uniqueId)
|
||||||
: undefined;
|
: undefined;
|
||||||
const previousNode = previousSong?.uniqueId
|
const previousNode = previousSongRef.current?.uniqueId
|
||||||
? api.getRowNode(previousSong?.uniqueId)
|
? api.getRowNode(previousSongRef.current?.uniqueId)
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
const rowNodes = [currentNode, previousNode].filter(
|
const rowNodes = [currentNode, previousNode].filter(
|
||||||
@@ -231,7 +236,7 @@ export const PlayQueue = forwardRef(({ searchTerm, type }: QueueProps, ref: Ref<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [currentSong, previousSong, tableConfig.followCurrentSong, status]);
|
}, [currentSong, previousSongRef, tableConfig.followCurrentSong, status]);
|
||||||
|
|
||||||
// As a separate rule, update the current row when focus changes. This is
|
// As a separate rule, update the current row when focus changes. This is
|
||||||
// to prevent queue scrolling when the application loses and then gains focus.
|
// to prevent queue scrolling when the application loses and then gains focus.
|
||||||
@@ -266,7 +271,7 @@ export const PlayQueue = forwardRef(({ searchTerm, type }: QueueProps, ref: Ref<
|
|||||||
columnDefs={columnDefs}
|
columnDefs={columnDefs}
|
||||||
context={{
|
context={{
|
||||||
currentSong,
|
currentSong,
|
||||||
handleDoubleClick,
|
// handleDoubleClick,
|
||||||
isFocused,
|
isFocused,
|
||||||
isQueue: true,
|
isQueue: true,
|
||||||
itemType: LibraryItem.SONG,
|
itemType: LibraryItem.SONG,
|
||||||
@@ -276,7 +281,7 @@ export const PlayQueue = forwardRef(({ searchTerm, type }: QueueProps, ref: Ref<
|
|||||||
deselectOnClickOutside={type === 'fullScreen'}
|
deselectOnClickOutside={type === 'fullScreen'}
|
||||||
getRowId={(data) => data.data.uniqueId}
|
getRowId={(data) => data.data.uniqueId}
|
||||||
onCellContextMenu={onCellContextMenu}
|
onCellContextMenu={onCellContextMenu}
|
||||||
onCellDoubleClicked={handleDoubleClick}
|
// onCellDoubleClicked={handleDoubleClick}
|
||||||
onColumnMoved={handleColumnChange}
|
onColumnMoved={handleColumnChange}
|
||||||
onColumnResized={debouncedColumnChange}
|
onColumnResized={debouncedColumnChange}
|
||||||
onDragStarted={handleDragStart}
|
onDragStarted={handleDragStart}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { useHotkeys } from '@mantine/hooks';
|
|
||||||
import { useQueryClient } from '@tanstack/react-query';
|
import { useQueryClient } from '@tanstack/react-query';
|
||||||
import formatDuration from 'format-duration';
|
import formatDuration from 'format-duration';
|
||||||
import isElectron from 'is-electron';
|
import isElectron from 'is-electron';
|
||||||
@@ -10,27 +9,24 @@ import styles from './center-controls.module.css';
|
|||||||
import { PlayButton, PlayerButton } from '/@/renderer/features/player/components/player-button';
|
import { PlayButton, PlayerButton } from '/@/renderer/features/player/components/player-button';
|
||||||
import { PlayerbarSlider } from '/@/renderer/features/player/components/playerbar-slider';
|
import { PlayerbarSlider } from '/@/renderer/features/player/components/playerbar-slider';
|
||||||
import { openShuffleAllModal } from '/@/renderer/features/player/components/shuffle-all-modal';
|
import { openShuffleAllModal } from '/@/renderer/features/player/components/shuffle-all-modal';
|
||||||
import { useCenterControls } from '/@/renderer/features/player/hooks/use-center-controls';
|
|
||||||
import { useMediaSession } from '/@/renderer/features/player/hooks/use-media-session';
|
|
||||||
import { usePlayQueueAdd } from '/@/renderer/features/player/hooks/use-playqueue-add';
|
import { usePlayQueueAdd } from '/@/renderer/features/player/hooks/use-playqueue-add';
|
||||||
import {
|
import {
|
||||||
useAppStore,
|
useAppStore,
|
||||||
useAppStoreActions,
|
useAppStoreActions,
|
||||||
useCurrentPlayer,
|
|
||||||
useCurrentSong,
|
|
||||||
useCurrentStatus,
|
|
||||||
useCurrentTime,
|
|
||||||
useHotkeySettings,
|
useHotkeySettings,
|
||||||
usePlaybackType,
|
usePlaybackType,
|
||||||
useRepeatStatus,
|
usePlayerNum,
|
||||||
useSetCurrentTime,
|
usePlayerRepeat,
|
||||||
|
usePlayerShuffle,
|
||||||
|
usePlayerSong,
|
||||||
|
usePlayerStatus,
|
||||||
|
usePlayerTimestamp,
|
||||||
useSettingsStore,
|
useSettingsStore,
|
||||||
useShuffleStatus,
|
|
||||||
} from '/@/renderer/store';
|
} from '/@/renderer/store';
|
||||||
import { Icon } from '/@/shared/components/icon/icon';
|
import { Icon } from '/@/shared/components/icon/icon';
|
||||||
import { Text } from '/@/shared/components/text/text';
|
import { Text } from '/@/shared/components/text/text';
|
||||||
import { PlaybackSelectors } from '/@/shared/constants/playback-selectors';
|
import { PlaybackSelectors } from '/@/shared/constants/playback-selectors';
|
||||||
import { PlaybackType, PlayerRepeat, PlayerShuffle, PlayerStatus } from '/@/shared/types/types';
|
import { PlayerRepeat, PlayerShuffle, PlayerStatus, PlayerType } from '/@/shared/types/types';
|
||||||
|
|
||||||
interface CenterControlsProps {
|
interface CenterControlsProps {
|
||||||
playersRef: any;
|
playersRef: any;
|
||||||
@@ -40,38 +36,38 @@ export const CenterControls = ({ playersRef }: CenterControlsProps) => {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const [isSeeking, setIsSeeking] = useState(false);
|
const [isSeeking, setIsSeeking] = useState(false);
|
||||||
const currentSong = useCurrentSong();
|
const currentSong = usePlayerSong();
|
||||||
const skip = useSettingsStore((state) => state.general.skipButtons);
|
const skip = useSettingsStore((state) => state.general.skipButtons);
|
||||||
const buttonSize = useSettingsStore((state) => state.general.buttonSize);
|
const buttonSize = useSettingsStore((state) => state.general.buttonSize);
|
||||||
const playbackType = usePlaybackType();
|
const playbackType = usePlaybackType();
|
||||||
const player1 = playersRef?.current?.player1;
|
const player1 = playersRef?.current?.player1;
|
||||||
const player2 = playersRef?.current?.player2;
|
const player2 = playersRef?.current?.player2;
|
||||||
const status = useCurrentStatus();
|
const status = usePlayerStatus();
|
||||||
const player = useCurrentPlayer();
|
const player = usePlayerNum();
|
||||||
const setCurrentTime = useSetCurrentTime();
|
// const setCurrentTime = useSetCurrentTime();
|
||||||
const repeat = useRepeatStatus();
|
const repeat = usePlayerRepeat();
|
||||||
const shuffle = useShuffleStatus();
|
const shuffle = usePlayerShuffle();
|
||||||
const { bindings } = useHotkeySettings();
|
const { bindings } = useHotkeySettings();
|
||||||
const { showTimeRemaining } = useAppStore();
|
const { showTimeRemaining } = useAppStore();
|
||||||
const { setShowTimeRemaining } = useAppStoreActions();
|
const { setShowTimeRemaining } = useAppStoreActions();
|
||||||
|
|
||||||
const {
|
// const {
|
||||||
handleNextTrack,
|
// handleNextTrack,
|
||||||
handlePause,
|
// handlePause,
|
||||||
handlePlay,
|
// handlePlay,
|
||||||
handlePlayPause,
|
// handlePlayPause,
|
||||||
handlePrevTrack,
|
// handlePrevTrack,
|
||||||
handleSeekSlider,
|
// handleSeekSlider,
|
||||||
handleSkipBackward,
|
// handleSkipBackward,
|
||||||
handleSkipForward,
|
// handleSkipForward,
|
||||||
handleStop,
|
// handleStop,
|
||||||
handleToggleRepeat,
|
// handleToggleRepeat,
|
||||||
handleToggleShuffle,
|
// handleToggleShuffle,
|
||||||
} = useCenterControls({ playersRef });
|
// } = useCenterControls({ playersRef });
|
||||||
const handlePlayQueueAdd = usePlayQueueAdd();
|
const handlePlayQueueAdd = usePlayQueueAdd();
|
||||||
|
|
||||||
const songDuration = currentSong?.duration ? currentSong.duration / 1000 : 0;
|
const songDuration = currentSong?.duration ? currentSong.duration / 1000 : 0;
|
||||||
const currentTime = useCurrentTime();
|
const currentTime = usePlayerTimestamp();
|
||||||
const currentPlayerRef = player === 1 ? player1 : player2;
|
const currentPlayerRef = player === 1 ? player1 : player2;
|
||||||
const formattedDuration = formatDuration(songDuration * 1000 || 0);
|
const formattedDuration = formatDuration(songDuration * 1000 || 0);
|
||||||
const formattedTimeRemaining = formatDuration((currentTime - songDuration) * 1000 || 0);
|
const formattedTimeRemaining = formatDuration((currentTime - songDuration) * 1000 || 0);
|
||||||
@@ -81,50 +77,50 @@ export const CenterControls = ({ playersRef }: CenterControlsProps) => {
|
|||||||
let interval: ReturnType<typeof setInterval>;
|
let interval: ReturnType<typeof setInterval>;
|
||||||
|
|
||||||
if (status === PlayerStatus.PLAYING && !isSeeking) {
|
if (status === PlayerStatus.PLAYING && !isSeeking) {
|
||||||
if (!isElectron() || playbackType === PlaybackType.WEB) {
|
if (!isElectron() || playbackType === PlayerType.WEB) {
|
||||||
// Update twice a second for slightly better performance
|
// Update twice a second for slightly better performance
|
||||||
interval = setInterval(() => {
|
interval = setInterval(() => {
|
||||||
if (currentPlayerRef) {
|
if (currentPlayerRef) {
|
||||||
setCurrentTime(currentPlayerRef.getCurrentTime());
|
// setCurrentTime(currentPlayerRef.getCurrentTime());
|
||||||
}
|
}
|
||||||
}, 500);
|
}, 500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => clearInterval(interval);
|
return () => clearInterval(interval);
|
||||||
}, [currentPlayerRef, isSeeking, setCurrentTime, playbackType, status]);
|
}, [currentPlayerRef, isSeeking, playbackType, status]);
|
||||||
|
|
||||||
const [seekValue, setSeekValue] = useState(0);
|
const [seekValue, setSeekValue] = useState(0);
|
||||||
|
|
||||||
useHotkeys([
|
// useHotkeys([
|
||||||
[bindings.playPause.isGlobal ? '' : bindings.playPause.hotkey, handlePlayPause],
|
// [bindings.playPause.isGlobal ? '' : bindings.playPause.hotkey, handlePlayPause],
|
||||||
[bindings.play.isGlobal ? '' : bindings.play.hotkey, handlePlay],
|
// [bindings.play.isGlobal ? '' : bindings.play.hotkey, handlePlay],
|
||||||
[bindings.pause.isGlobal ? '' : bindings.pause.hotkey, handlePause],
|
// [bindings.pause.isGlobal ? '' : bindings.pause.hotkey, handlePause],
|
||||||
[bindings.stop.isGlobal ? '' : bindings.stop.hotkey, handleStop],
|
// [bindings.stop.isGlobal ? '' : bindings.stop.hotkey, handleStop],
|
||||||
[bindings.next.isGlobal ? '' : bindings.next.hotkey, handleNextTrack],
|
// [bindings.next.isGlobal ? '' : bindings.next.hotkey, handleNextTrack],
|
||||||
[bindings.previous.isGlobal ? '' : bindings.previous.hotkey, handlePrevTrack],
|
// [bindings.previous.isGlobal ? '' : bindings.previous.hotkey, handlePrevTrack],
|
||||||
[bindings.toggleRepeat.isGlobal ? '' : bindings.toggleRepeat.hotkey, handleToggleRepeat],
|
// [bindings.toggleRepeat.isGlobal ? '' : bindings.toggleRepeat.hotkey, handleToggleRepeat],
|
||||||
[bindings.toggleShuffle.isGlobal ? '' : bindings.toggleShuffle.hotkey, handleToggleShuffle],
|
// [bindings.toggleShuffle.isGlobal ? '' : bindings.toggleShuffle.hotkey, handleToggleShuffle],
|
||||||
[
|
// [
|
||||||
bindings.skipBackward.isGlobal ? '' : bindings.skipBackward.hotkey,
|
// bindings.skipBackward.isGlobal ? '' : bindings.skipBackward.hotkey,
|
||||||
() => handleSkipBackward(skip?.skipBackwardSeconds || 5),
|
// () => handleSkipBackward(skip?.skipBackwardSeconds || 5),
|
||||||
],
|
// ],
|
||||||
[
|
// [
|
||||||
bindings.skipForward.isGlobal ? '' : bindings.skipForward.hotkey,
|
// bindings.skipForward.isGlobal ? '' : bindings.skipForward.hotkey,
|
||||||
() => handleSkipForward(skip?.skipForwardSeconds || 5),
|
// () => handleSkipForward(skip?.skipForwardSeconds || 5),
|
||||||
],
|
// ],
|
||||||
]);
|
// ]);
|
||||||
|
|
||||||
useMediaSession({
|
// useMediaSession({
|
||||||
handleNextTrack,
|
// handleNextTrack,
|
||||||
handlePause,
|
// handlePause,
|
||||||
handlePlay,
|
// handlePlay,
|
||||||
handlePrevTrack,
|
// handlePrevTrack,
|
||||||
handleSeekSlider,
|
// handleSeekSlider,
|
||||||
handleSkipBackward,
|
// handleSkipBackward,
|
||||||
handleSkipForward,
|
// handleSkipForward,
|
||||||
handleStop,
|
// handleStop,
|
||||||
});
|
// });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -132,7 +128,7 @@ export const CenterControls = ({ playersRef }: CenterControlsProps) => {
|
|||||||
<div className={styles.buttonsContainer}>
|
<div className={styles.buttonsContainer}>
|
||||||
<PlayerButton
|
<PlayerButton
|
||||||
icon={<Icon fill="default" icon="mediaStop" size={buttonSize - 2} />}
|
icon={<Icon fill="default" icon="mediaStop" size={buttonSize - 2} />}
|
||||||
onClick={handleStop}
|
// onClick={handleStop}
|
||||||
tooltip={{
|
tooltip={{
|
||||||
label: t('player.stop', { postProcess: 'sentenceCase' }),
|
label: t('player.stop', { postProcess: 'sentenceCase' }),
|
||||||
openDelay: 0,
|
openDelay: 0,
|
||||||
@@ -148,7 +144,7 @@ export const CenterControls = ({ playersRef }: CenterControlsProps) => {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
isActive={shuffle !== PlayerShuffle.NONE}
|
isActive={shuffle !== PlayerShuffle.NONE}
|
||||||
onClick={handleToggleShuffle}
|
// onClick={handleToggleShuffle}
|
||||||
tooltip={{
|
tooltip={{
|
||||||
label:
|
label:
|
||||||
shuffle === PlayerShuffle.NONE
|
shuffle === PlayerShuffle.NONE
|
||||||
@@ -163,7 +159,7 @@ export const CenterControls = ({ playersRef }: CenterControlsProps) => {
|
|||||||
/>
|
/>
|
||||||
<PlayerButton
|
<PlayerButton
|
||||||
icon={<Icon fill="default" icon="mediaPrevious" size={buttonSize} />}
|
icon={<Icon fill="default" icon="mediaPrevious" size={buttonSize} />}
|
||||||
onClick={handlePrevTrack}
|
// onClick={handlePrevTrack}
|
||||||
tooltip={{
|
tooltip={{
|
||||||
label: t('player.previous', { postProcess: 'sentenceCase' }),
|
label: t('player.previous', { postProcess: 'sentenceCase' }),
|
||||||
openDelay: 0,
|
openDelay: 0,
|
||||||
@@ -175,7 +171,7 @@ export const CenterControls = ({ playersRef }: CenterControlsProps) => {
|
|||||||
icon={
|
icon={
|
||||||
<Icon fill="default" icon="mediaStepBackward" size={buttonSize} />
|
<Icon fill="default" icon="mediaStepBackward" size={buttonSize} />
|
||||||
}
|
}
|
||||||
onClick={() => handleSkipBackward(skip?.skipBackwardSeconds)}
|
// onClick={() => handleSkipBackward(skip?.skipBackwardSeconds)}
|
||||||
tooltip={{
|
tooltip={{
|
||||||
label: t('player.skip', {
|
label: t('player.skip', {
|
||||||
context: 'back',
|
context: 'back',
|
||||||
@@ -190,12 +186,12 @@ export const CenterControls = ({ playersRef }: CenterControlsProps) => {
|
|||||||
<PlayButton
|
<PlayButton
|
||||||
disabled={currentSong?.id === undefined}
|
disabled={currentSong?.id === undefined}
|
||||||
isPaused={status === PlayerStatus.PAUSED}
|
isPaused={status === PlayerStatus.PAUSED}
|
||||||
onClick={handlePlayPause}
|
// onClick={handlePlayPause}
|
||||||
/>
|
/>
|
||||||
{skip?.enabled && (
|
{skip?.enabled && (
|
||||||
<PlayerButton
|
<PlayerButton
|
||||||
icon={<Icon fill="default" icon="mediaStepForward" size={buttonSize} />}
|
icon={<Icon fill="default" icon="mediaStepForward" size={buttonSize} />}
|
||||||
onClick={() => handleSkipForward(skip?.skipForwardSeconds)}
|
// onClick={() => handleSkipForward(skip?.skipForwardSeconds)}
|
||||||
tooltip={{
|
tooltip={{
|
||||||
label: t('player.skip', {
|
label: t('player.skip', {
|
||||||
context: 'forward',
|
context: 'forward',
|
||||||
@@ -209,7 +205,7 @@ export const CenterControls = ({ playersRef }: CenterControlsProps) => {
|
|||||||
)}
|
)}
|
||||||
<PlayerButton
|
<PlayerButton
|
||||||
icon={<Icon fill="default" icon="mediaNext" size={buttonSize} />}
|
icon={<Icon fill="default" icon="mediaNext" size={buttonSize} />}
|
||||||
onClick={handleNextTrack}
|
// onClick={handleNextTrack}
|
||||||
tooltip={{
|
tooltip={{
|
||||||
label: t('player.next', { postProcess: 'sentenceCase' }),
|
label: t('player.next', { postProcess: 'sentenceCase' }),
|
||||||
openDelay: 0,
|
openDelay: 0,
|
||||||
@@ -229,7 +225,7 @@ export const CenterControls = ({ playersRef }: CenterControlsProps) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
isActive={repeat !== PlayerRepeat.NONE}
|
isActive={repeat !== PlayerRepeat.NONE}
|
||||||
onClick={handleToggleRepeat}
|
// onClick={handleToggleRepeat}
|
||||||
tooltip={{
|
tooltip={{
|
||||||
label: `${
|
label: `${
|
||||||
repeat === PlayerRepeat.NONE
|
repeat === PlayerRepeat.NONE
|
||||||
@@ -294,7 +290,7 @@ export const CenterControls = ({ playersRef }: CenterControlsProps) => {
|
|||||||
// event fires before onChange. Add a small delay to force
|
// event fires before onChange. Add a small delay to force
|
||||||
// onChangeEnd to happen after onCHange
|
// onChangeEnd to happen after onCHange
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
handleSeekSlider(e);
|
// handleSeekSlider(e);
|
||||||
setIsSeeking(false);
|
setIsSeeking(false);
|
||||||
}, 50);
|
}, 50);
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import {
|
|||||||
} from '/@/renderer/store/full-screen-player.store';
|
} from '/@/renderer/store/full-screen-player.store';
|
||||||
import { Button } from '/@/shared/components/button/button';
|
import { Button } from '/@/shared/components/button/button';
|
||||||
import { Group } from '/@/shared/components/group/group';
|
import { Group } from '/@/shared/components/group/group';
|
||||||
import { PlaybackType } from '/@/shared/types/types';
|
import { PlayerType } from '/@/shared/types/types';
|
||||||
|
|
||||||
const Visualizer = lazy(() =>
|
const Visualizer = lazy(() =>
|
||||||
import('/@/renderer/features/player/components/visualizer').then((module) => ({
|
import('/@/renderer/features/player/components/visualizer').then((module) => ({
|
||||||
@@ -48,7 +48,7 @@ export const FullScreenPlayerQueue = () => {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
if (type === PlaybackType.WEB && webAudio) {
|
if (type === PlayerType.WEB && webAudio) {
|
||||||
items.push({
|
items.push({
|
||||||
active: activeTab === 'visualizer',
|
active: activeTab === 'visualizer',
|
||||||
label: t('page.fullscreenPlayer.visualizer', { postProcess: 'titleCase' }),
|
label: t('page.fullscreenPlayer.visualizer', { postProcess: 'titleCase' }),
|
||||||
@@ -107,7 +107,7 @@ export const FullScreenPlayerQueue = () => {
|
|||||||
</div>
|
</div>
|
||||||
) : activeTab === 'lyrics' ? (
|
) : activeTab === 'lyrics' ? (
|
||||||
<Lyrics />
|
<Lyrics />
|
||||||
) : activeTab === 'visualizer' && type === PlaybackType.WEB && webAudio ? (
|
) : activeTab === 'visualizer' && type === PlayerType.WEB && webAudio ? (
|
||||||
<Suspense fallback={<></>}>
|
<Suspense fallback={<></>}>
|
||||||
<Visualizer />
|
<Visualizer />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { FullScreenPlayerImage } from '/@/renderer/features/player/components/fu
|
|||||||
import { FullScreenPlayerQueue } from '/@/renderer/features/player/components/full-screen-player-queue';
|
import { FullScreenPlayerQueue } from '/@/renderer/features/player/components/full-screen-player-queue';
|
||||||
import { useFastAverageColor } from '/@/renderer/hooks';
|
import { useFastAverageColor } from '/@/renderer/hooks';
|
||||||
import {
|
import {
|
||||||
useCurrentSong,
|
usePlayerSong,
|
||||||
useFullScreenPlayerStore,
|
useFullScreenPlayerStore,
|
||||||
useFullScreenPlayerStoreActions,
|
useFullScreenPlayerStoreActions,
|
||||||
useLyricsSettings,
|
useLyricsSettings,
|
||||||
@@ -421,7 +421,7 @@ export const FullScreenPlayer = () => {
|
|||||||
isOpenedRef.current = true;
|
isOpenedRef.current = true;
|
||||||
}, [location, setStore]);
|
}, [location, setStore]);
|
||||||
|
|
||||||
const currentSong = useCurrentSong();
|
const currentSong = usePlayerSong();
|
||||||
const { background } = useFastAverageColor({
|
const { background } = useFastAverageColor({
|
||||||
algorithm: 'dominant',
|
algorithm: 'dominant',
|
||||||
src: currentSong?.imageUrl,
|
src: currentSong?.imageUrl,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { SimilarSongsList } from '/@/renderer/features/similar-songs/components/similar-songs-list';
|
import { SimilarSongsList } from '/@/renderer/features/similar-songs/components/similar-songs-list';
|
||||||
import { useCurrentSong } from '/@/renderer/store';
|
import { usePlayerSong } from '/@/renderer/store';
|
||||||
|
|
||||||
export const FullScreenSimilarSongs = () => {
|
export const FullScreenSimilarSongs = () => {
|
||||||
const currentSong = useCurrentSong();
|
const currentSong = usePlayerSong();
|
||||||
|
|
||||||
return currentSong?.id ? <SimilarSongsList fullScreen song={currentSong} /> : null;
|
return currentSong?.id ? <SimilarSongsList fullScreen song={currentSong} /> : null;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { useHandleGeneralContextMenu } from '/@/renderer/features/context-menu/h
|
|||||||
import { AppRoute } from '/@/renderer/router/routes';
|
import { AppRoute } from '/@/renderer/router/routes';
|
||||||
import {
|
import {
|
||||||
useAppStoreActions,
|
useAppStoreActions,
|
||||||
useCurrentSong,
|
usePlayerSong,
|
||||||
useFullScreenPlayerStore,
|
useFullScreenPlayerStore,
|
||||||
useHotkeySettings,
|
useHotkeySettings,
|
||||||
useSetFullScreenPlayerStore,
|
useSetFullScreenPlayerStore,
|
||||||
@@ -34,7 +34,7 @@ export const LeftControls = () => {
|
|||||||
const setFullScreenPlayerStore = useSetFullScreenPlayerStore();
|
const setFullScreenPlayerStore = useSetFullScreenPlayerStore();
|
||||||
const { collapsed, image } = useSidebarStore();
|
const { collapsed, image } = useSidebarStore();
|
||||||
const hideImage = image && !collapsed;
|
const hideImage = image && !collapsed;
|
||||||
const currentSong = useCurrentSong();
|
const currentSong = usePlayerSong();
|
||||||
const title = currentSong?.name;
|
const title = currentSong?.name;
|
||||||
const artists = currentSong?.artists;
|
const artists = currentSong?.artists;
|
||||||
const { bindings } = useHotkeySettings();
|
const { bindings } = useHotkeySettings();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { MouseEvent, useCallback } from 'react';
|
import { MouseEvent } from 'react';
|
||||||
|
|
||||||
import styles from './playerbar.module.css';
|
import styles from './playerbar.module.css';
|
||||||
|
|
||||||
@@ -9,17 +9,17 @@ import { LeftControls } from '/@/renderer/features/player/components/left-contro
|
|||||||
import { RightControls } from '/@/renderer/features/player/components/right-controls';
|
import { RightControls } from '/@/renderer/features/player/components/right-controls';
|
||||||
import { usePowerSaveBlocker } from '/@/renderer/features/player/hooks/use-power-save-blocker';
|
import { usePowerSaveBlocker } from '/@/renderer/features/player/hooks/use-power-save-blocker';
|
||||||
import { PlayersRef } from '/@/renderer/features/player/ref/players-ref';
|
import { PlayersRef } from '/@/renderer/features/player/ref/players-ref';
|
||||||
import { updateSong } from '/@/renderer/features/player/update-remote-song';
|
|
||||||
import {
|
import {
|
||||||
useCurrentPlayer,
|
|
||||||
useCurrentStatus,
|
|
||||||
useFullScreenPlayerStore,
|
useFullScreenPlayerStore,
|
||||||
useMuted,
|
usePlayerData,
|
||||||
usePlayer1Data,
|
// usePlayer1Data,
|
||||||
usePlayer2Data,
|
// usePlayer2Data,
|
||||||
usePlayerControls,
|
// usePlayerControls,
|
||||||
|
usePlayerMuted,
|
||||||
|
usePlayerNum,
|
||||||
|
usePlayerStatus,
|
||||||
|
usePlayerVolume,
|
||||||
useSetFullScreenPlayerStore,
|
useSetFullScreenPlayerStore,
|
||||||
useVolume,
|
|
||||||
} from '/@/renderer/store';
|
} from '/@/renderer/store';
|
||||||
import {
|
import {
|
||||||
useGeneralSettings,
|
useGeneralSettings,
|
||||||
@@ -27,20 +27,20 @@ import {
|
|||||||
useSettingsStore,
|
useSettingsStore,
|
||||||
} from '/@/renderer/store/settings.store';
|
} from '/@/renderer/store/settings.store';
|
||||||
import { PlaybackSelectors } from '/@/shared/constants/playback-selectors';
|
import { PlaybackSelectors } from '/@/shared/constants/playback-selectors';
|
||||||
import { PlaybackType } from '/@/shared/types/types';
|
import { PlayerType } from '/@/shared/types/types';
|
||||||
|
|
||||||
export const Playerbar = () => {
|
export const Playerbar = () => {
|
||||||
const playersRef = PlayersRef;
|
const playersRef = PlayersRef;
|
||||||
const settings = useSettingsStore((state) => state.playback);
|
const settings = useSettingsStore((state) => state.playback);
|
||||||
const { playerbarOpenDrawer } = useGeneralSettings();
|
const { playerbarOpenDrawer } = useGeneralSettings();
|
||||||
const playbackType = usePlaybackType();
|
const playbackType = usePlaybackType();
|
||||||
const volume = useVolume();
|
const volume = usePlayerVolume();
|
||||||
const player1 = usePlayer1Data();
|
// const player1 = usePlayer1Data();
|
||||||
const player2 = usePlayer2Data();
|
// const player2 = usePlayer2Data();
|
||||||
const status = useCurrentStatus();
|
const status = usePlayerStatus();
|
||||||
const player = useCurrentPlayer();
|
const player = usePlayerNum();
|
||||||
const muted = useMuted();
|
const muted = usePlayerMuted();
|
||||||
const { autoNext } = usePlayerControls();
|
// const { autoNext } = usePlayerControls();
|
||||||
const { expanded: isFullScreenPlayerExpanded } = useFullScreenPlayerStore();
|
const { expanded: isFullScreenPlayerExpanded } = useFullScreenPlayerStore();
|
||||||
const setFullScreenPlayerStore = useSetFullScreenPlayerStore();
|
const setFullScreenPlayerStore = useSetFullScreenPlayerStore();
|
||||||
|
|
||||||
@@ -51,10 +51,12 @@ export const Playerbar = () => {
|
|||||||
setFullScreenPlayerStore({ expanded: !isFullScreenPlayerExpanded });
|
setFullScreenPlayerStore({ expanded: !isFullScreenPlayerExpanded });
|
||||||
};
|
};
|
||||||
|
|
||||||
const autoNextFn = useCallback(() => {
|
const { player1, player2 } = usePlayerData();
|
||||||
const playerData = autoNext();
|
|
||||||
updateSong(playerData.current.song);
|
// const autoNextFn = useCallback(() => {
|
||||||
}, [autoNext]);
|
// const playerData = autoNext();
|
||||||
|
// updateSong(playerData.current.song);
|
||||||
|
// }, [autoNext]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -72,9 +74,9 @@ export const Playerbar = () => {
|
|||||||
<RightControls />
|
<RightControls />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{playbackType === PlaybackType.WEB && (
|
{playbackType === PlayerType.WEB && (
|
||||||
<AudioPlayer
|
<AudioPlayer
|
||||||
autoNext={autoNextFn}
|
// autoNext={autoNextFn}
|
||||||
crossfadeDuration={settings.crossfadeDuration}
|
crossfadeDuration={settings.crossfadeDuration}
|
||||||
crossfadeStyle={settings.crossfadeStyle}
|
crossfadeStyle={settings.crossfadeStyle}
|
||||||
currentPlayer={player}
|
currentPlayer={player}
|
||||||
|
|||||||
@@ -11,17 +11,16 @@ import { useSetRating } from '/@/renderer/features/shared/mutations/set-rating-m
|
|||||||
import {
|
import {
|
||||||
useAppStoreActions,
|
useAppStoreActions,
|
||||||
useCurrentServer,
|
useCurrentServer,
|
||||||
useCurrentSong,
|
|
||||||
useHotkeySettings,
|
useHotkeySettings,
|
||||||
useMuted,
|
|
||||||
usePlaybackSettings,
|
usePlaybackSettings,
|
||||||
usePlaybackType,
|
usePlaybackType,
|
||||||
usePreviousSong,
|
usePlayerMuted,
|
||||||
|
usePlayerSong,
|
||||||
|
usePlayerSpeed,
|
||||||
|
usePlayerVolume,
|
||||||
useSettingsStore,
|
useSettingsStore,
|
||||||
useSettingsStoreActions,
|
useSettingsStoreActions,
|
||||||
useSidebarStore,
|
useSidebarStore,
|
||||||
useSpeed,
|
|
||||||
useVolume,
|
|
||||||
} from '/@/renderer/store';
|
} from '/@/renderer/store';
|
||||||
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
|
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
|
||||||
import { DropdownMenu } from '/@/shared/components/dropdown-menu/dropdown-menu';
|
import { DropdownMenu } from '/@/shared/components/dropdown-menu/dropdown-menu';
|
||||||
@@ -40,11 +39,11 @@ const remote = isElectron() ? window.api.remote : null;
|
|||||||
export const RightControls = () => {
|
export const RightControls = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const isMinWidth = useMediaQuery('(max-width: 480px)');
|
const isMinWidth = useMediaQuery('(max-width: 480px)');
|
||||||
const volume = useVolume();
|
const volume = usePlayerVolume();
|
||||||
const muted = useMuted();
|
const muted = usePlayerMuted();
|
||||||
const server = useCurrentServer();
|
const server = useCurrentServer();
|
||||||
const currentSong = useCurrentSong();
|
const currentSong = usePlayerSong();
|
||||||
const previousSong = usePreviousSong();
|
// const previousSong = usePreviousSong();
|
||||||
const { setSideBar } = useAppStoreActions();
|
const { setSideBar } = useAppStoreActions();
|
||||||
const { rightExpanded: isQueueExpanded } = useSidebarStore();
|
const { rightExpanded: isQueueExpanded } = useSidebarStore();
|
||||||
const { bindings } = useHotkeySettings();
|
const { bindings } = useHotkeySettings();
|
||||||
@@ -60,7 +59,7 @@ export const RightControls = () => {
|
|||||||
const playbackSettings = usePlaybackSettings();
|
const playbackSettings = usePlaybackSettings();
|
||||||
const playbackType = usePlaybackType();
|
const playbackType = usePlaybackType();
|
||||||
|
|
||||||
const speed = useSpeed();
|
const speed = usePlayerSpeed();
|
||||||
const volumeWidth = useSettingsStore((state) => state.general.volumeWidth);
|
const volumeWidth = useSettingsStore((state) => state.general.volumeWidth);
|
||||||
const speedPreservePitch = useSettingsStore((state) => state.playback.preservePitch);
|
const speedPreservePitch = useSettingsStore((state) => state.playback.preservePitch);
|
||||||
|
|
||||||
@@ -148,18 +147,18 @@ export const RightControls = () => {
|
|||||||
bindings.favoriteCurrentToggle.isGlobal ? '' : bindings.favoriteCurrentToggle.hotkey,
|
bindings.favoriteCurrentToggle.isGlobal ? '' : bindings.favoriteCurrentToggle.hotkey,
|
||||||
() => handleToggleFavorite(currentSong),
|
() => handleToggleFavorite(currentSong),
|
||||||
],
|
],
|
||||||
[
|
// [
|
||||||
bindings.favoritePreviousAdd.isGlobal ? '' : bindings.favoritePreviousAdd.hotkey,
|
// bindings.favoritePreviousAdd.isGlobal ? '' : bindings.favoritePreviousAdd.hotkey,
|
||||||
() => handleAddToFavorites(previousSong),
|
// () => handleAddToFavorites(previousSong),
|
||||||
],
|
// ],
|
||||||
[
|
// [
|
||||||
bindings.favoritePreviousRemove.isGlobal ? '' : bindings.favoritePreviousRemove.hotkey,
|
// bindings.favoritePreviousRemove.isGlobal ? '' : bindings.favoritePreviousRemove.hotkey,
|
||||||
() => handleRemoveFromFavorites(previousSong),
|
// () => handleRemoveFromFavorites(previousSong),
|
||||||
],
|
// ],
|
||||||
[
|
// [
|
||||||
bindings.favoritePreviousToggle.isGlobal ? '' : bindings.favoritePreviousToggle.hotkey,
|
// bindings.favoritePreviousToggle.isGlobal ? '' : bindings.favoritePreviousToggle.hotkey,
|
||||||
() => handleToggleFavorite(previousSong),
|
// () => handleToggleFavorite(previousSong),
|
||||||
],
|
// ],
|
||||||
[bindings.rate0.isGlobal ? '' : bindings.rate0.hotkey, () => handleUpdateRating(0)],
|
[bindings.rate0.isGlobal ? '' : bindings.rate0.hotkey, () => handleUpdateRating(0)],
|
||||||
[bindings.rate1.isGlobal ? '' : bindings.rate1.hotkey, () => handleUpdateRating(1)],
|
[bindings.rate1.isGlobal ? '' : bindings.rate1.hotkey, () => handleUpdateRating(1)],
|
||||||
[bindings.rate2.isGlobal ? '' : bindings.rate2.hotkey, () => handleUpdateRating(2)],
|
[bindings.rate2.isGlobal ? '' : bindings.rate2.hotkey, () => handleUpdateRating(2)],
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,226 +1,226 @@
|
|||||||
import { useQueryClient } from '@tanstack/react-query';
|
// import { useQueryClient } from '@tanstack/react-query';
|
||||||
import isElectron from 'is-electron';
|
// import isElectron from 'is-electron';
|
||||||
import { nanoid } from 'nanoid/non-secure';
|
// import { nanoid } from 'nanoid/non-secure';
|
||||||
import { useCallback, useRef } from 'react';
|
// import { useCallback, useRef } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
// import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
// import { queryKeys } from '/@/renderer/api/query-keys';
|
||||||
import { PlayersRef } from '/@/renderer/features/player/ref/players-ref';
|
// import { PlayersRef } from '/@/renderer/features/player/ref/players-ref';
|
||||||
import { updateSong } from '/@/renderer/features/player/update-remote-song';
|
// import { updateSong } from '/@/renderer/features/player/update-remote-song';
|
||||||
import {
|
// import {
|
||||||
getAlbumArtistSongsById,
|
// getAlbumArtistSongsById,
|
||||||
getAlbumSongsById,
|
// getAlbumSongsById,
|
||||||
getArtistSongsById,
|
// getArtistSongsById,
|
||||||
getGenreSongsById,
|
// getGenreSongsById,
|
||||||
getPlaylistSongsById,
|
// getPlaylistSongsById,
|
||||||
getSongById,
|
// getSongById,
|
||||||
getSongsByQuery,
|
// getSongsByQuery,
|
||||||
} from '/@/renderer/features/player/utils';
|
// } from '/@/renderer/features/player/utils';
|
||||||
import { useCurrentServer, usePlayerControls, usePlayerStore } from '/@/renderer/store';
|
// import { useCurrentServer, usePlayerStore } from '/@/renderer/store';
|
||||||
import { useGeneralSettings, usePlaybackType } from '/@/renderer/store/settings.store';
|
// import { useGeneralSettings, usePlaybackType } from '/@/renderer/store/settings.store';
|
||||||
import { setQueue, setQueueNext } from '/@/renderer/utils/set-transcoded-queue-data';
|
// import { setQueue, setQueueNext } from '/@/renderer/utils/set-transcoded-queue-data';
|
||||||
import { toast } from '/@/shared/components/toast/toast';
|
// import { toast } from '/@/shared/components/toast/toast';
|
||||||
import {
|
// import {
|
||||||
instanceOfCancellationError,
|
// instanceOfCancellationError,
|
||||||
LibraryItem,
|
// LibraryItem,
|
||||||
QueueSong,
|
// QueueSong,
|
||||||
Song,
|
// Song,
|
||||||
SongListResponse,
|
// SongListResponse,
|
||||||
} from '/@/shared/types/domain-types';
|
// } from '/@/shared/types/domain-types';
|
||||||
import { Play, PlaybackType, PlayQueueAddOptions } from '/@/shared/types/types';
|
// import { Play, PlaybackType, PlayQueueAddOptions } from '/@/shared/types/types';
|
||||||
|
|
||||||
const getRootQueryKey = (itemType: LibraryItem, serverId: string) => {
|
// const getRootQueryKey = (itemType: LibraryItem, serverId: string) => {
|
||||||
let queryKey;
|
// let queryKey;
|
||||||
|
|
||||||
switch (itemType) {
|
// switch (itemType) {
|
||||||
case LibraryItem.ALBUM:
|
// case LibraryItem.ALBUM:
|
||||||
queryKey = queryKeys.songs.list(serverId);
|
// queryKey = queryKeys.songs.list(serverId);
|
||||||
break;
|
// break;
|
||||||
case LibraryItem.ALBUM_ARTIST:
|
// case LibraryItem.ALBUM_ARTIST:
|
||||||
queryKey = queryKeys.songs.list(serverId);
|
// queryKey = queryKeys.songs.list(serverId);
|
||||||
break;
|
// break;
|
||||||
case LibraryItem.GENRE:
|
// case LibraryItem.GENRE:
|
||||||
queryKey = queryKeys.songs.list(serverId);
|
// queryKey = queryKeys.songs.list(serverId);
|
||||||
break;
|
// break;
|
||||||
case LibraryItem.PLAYLIST:
|
// case LibraryItem.PLAYLIST:
|
||||||
queryKey = queryKeys.playlists.songList(serverId);
|
// queryKey = queryKeys.playlists.songList(serverId);
|
||||||
break;
|
// break;
|
||||||
case LibraryItem.SONG:
|
// case LibraryItem.SONG:
|
||||||
queryKey = queryKeys.songs.list(serverId);
|
// queryKey = queryKeys.songs.list(serverId);
|
||||||
break;
|
// break;
|
||||||
default:
|
// default:
|
||||||
queryKey = queryKeys.songs.list(serverId);
|
// queryKey = queryKeys.songs.list(serverId);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
|
|
||||||
return queryKey;
|
// return queryKey;
|
||||||
};
|
// };
|
||||||
|
|
||||||
const mpvPlayer = isElectron() ? window.api.mpvPlayer : null;
|
// const mpvPlayer = isElectron() ? window.api.mpvPlayer : null;
|
||||||
|
|
||||||
const addToQueue = usePlayerStore.getState().actions.addToQueue;
|
// const addToQueue = usePlayerStore.getState().actions.addToQueue;
|
||||||
|
|
||||||
export const useHandlePlayQueueAdd = () => {
|
// export const useHandlePlayQueueAdd = () => {
|
||||||
const { t } = useTranslation();
|
// const { t } = useTranslation();
|
||||||
const queryClient = useQueryClient();
|
// const queryClient = useQueryClient();
|
||||||
const playbackType = usePlaybackType();
|
// const playbackType = usePlaybackType();
|
||||||
const server = useCurrentServer();
|
// const server = useCurrentServer();
|
||||||
const { play } = usePlayerControls();
|
// const { play } = usePlayerControls();
|
||||||
const timeoutIds = useRef<null | Record<string, ReturnType<typeof setTimeout>>>({});
|
// const timeoutIds = useRef<null | Record<string, ReturnType<typeof setTimeout>>>({});
|
||||||
|
|
||||||
const { doubleClickQueueAll } = useGeneralSettings();
|
// const { doubleClickQueueAll } = useGeneralSettings();
|
||||||
|
|
||||||
const handlePlayQueueAdd = useCallback(
|
// const handlePlayQueueAdd = useCallback(
|
||||||
async (options: PlayQueueAddOptions) => {
|
// async (options: PlayQueueAddOptions) => {
|
||||||
if (!server) return toast.error({ message: 'No server selected', type: 'error' });
|
// if (!server) return toast.error({ message: 'No server selected', type: 'error' });
|
||||||
const { byData, byItemType, initialIndex, initialSongId, playType, query } = options;
|
// const { byData, byItemType, initialIndex, initialSongId, playType, query } = options;
|
||||||
let songs: null | QueueSong[] = null;
|
// let songs: null | QueueSong[] = null;
|
||||||
// Allow this to be undefined for "play shuffled". If undefined, default to 0,
|
// // Allow this to be undefined for "play shuffled". If undefined, default to 0,
|
||||||
// otherwise, choose the selected item in the queue
|
// // otherwise, choose the selected item in the queue
|
||||||
let initialSongIndex: number | undefined;
|
// let initialSongIndex: number | undefined;
|
||||||
let toastId: null | string = null;
|
// let toastId: null | string = null;
|
||||||
|
|
||||||
if (byItemType) {
|
// if (byItemType) {
|
||||||
let songList: SongListResponse | undefined;
|
// let songList: SongListResponse | undefined;
|
||||||
const { id, type: itemType } = byItemType;
|
// const { id, type: itemType } = byItemType;
|
||||||
|
|
||||||
const fetchId = nanoid();
|
// const fetchId = nanoid();
|
||||||
timeoutIds.current = {
|
// timeoutIds.current = {
|
||||||
...timeoutIds.current,
|
// ...timeoutIds.current,
|
||||||
[fetchId]: setTimeout(() => {
|
// [fetchId]: setTimeout(() => {
|
||||||
toastId = toast.info({
|
// toastId = toast.info({
|
||||||
autoClose: false,
|
// autoClose: false,
|
||||||
message: t('player.playbackFetchCancel', {
|
// message: t('player.playbackFetchCancel', {
|
||||||
postProcess: 'sentenceCase',
|
// postProcess: 'sentenceCase',
|
||||||
}),
|
// }),
|
||||||
onClose: () => {
|
// onClose: () => {
|
||||||
queryClient.cancelQueries({
|
// queryClient.cancelQueries({
|
||||||
exact: false,
|
// exact: false,
|
||||||
queryKey: getRootQueryKey(itemType, server?.id),
|
// queryKey: getRootQueryKey(itemType, server?.id),
|
||||||
});
|
// });
|
||||||
},
|
// },
|
||||||
title: t('player.playbackFetchInProgress', {
|
// title: t('player.playbackFetchInProgress', {
|
||||||
postProcess: 'sentenceCase',
|
// postProcess: 'sentenceCase',
|
||||||
}),
|
// }),
|
||||||
});
|
// });
|
||||||
}, 2000),
|
// }, 2000),
|
||||||
};
|
// };
|
||||||
|
|
||||||
try {
|
// try {
|
||||||
if (itemType === LibraryItem.PLAYLIST) {
|
// if (itemType === LibraryItem.PLAYLIST) {
|
||||||
songList = await getPlaylistSongsById({
|
// songList = await getPlaylistSongsById({
|
||||||
id: id?.[0],
|
// id: id?.[0],
|
||||||
query,
|
// query,
|
||||||
queryClient,
|
// queryClient,
|
||||||
server,
|
// server,
|
||||||
});
|
// });
|
||||||
} else if (itemType === LibraryItem.ALBUM) {
|
// } else if (itemType === LibraryItem.ALBUM) {
|
||||||
songList = await getAlbumSongsById({ id, query, queryClient, server });
|
// songList = await getAlbumSongsById({ id, query, queryClient, server });
|
||||||
} else if (itemType === LibraryItem.ALBUM_ARTIST) {
|
// } else if (itemType === LibraryItem.ALBUM_ARTIST) {
|
||||||
songList = await getAlbumArtistSongsById({
|
// songList = await getAlbumArtistSongsById({
|
||||||
id,
|
// id,
|
||||||
query,
|
// query,
|
||||||
queryClient,
|
// queryClient,
|
||||||
server,
|
// server,
|
||||||
});
|
// });
|
||||||
} else if (itemType === LibraryItem.ARTIST) {
|
// } else if (itemType === LibraryItem.ARTIST) {
|
||||||
songList = await getArtistSongsById({
|
// songList = await getArtistSongsById({
|
||||||
id,
|
// id,
|
||||||
query,
|
// query,
|
||||||
queryClient,
|
// queryClient,
|
||||||
server,
|
// server,
|
||||||
});
|
// });
|
||||||
} else if (itemType === LibraryItem.GENRE) {
|
// } else if (itemType === LibraryItem.GENRE) {
|
||||||
songList = await getGenreSongsById({ id, query, queryClient, server });
|
// songList = await getGenreSongsById({ id, query, queryClient, server });
|
||||||
} else if (itemType === LibraryItem.SONG) {
|
// } else if (itemType === LibraryItem.SONG) {
|
||||||
if (id?.length === 1) {
|
// if (id?.length === 1) {
|
||||||
songList = await getSongById({ id: id?.[0], queryClient, server });
|
// songList = await getSongById({ id: id?.[0], queryClient, server });
|
||||||
} else if (!doubleClickQueueAll && initialSongId) {
|
// } else if (!doubleClickQueueAll && initialSongId) {
|
||||||
songList = await getSongById({
|
// songList = await getSongById({
|
||||||
id: initialSongId,
|
// id: initialSongId,
|
||||||
queryClient,
|
// queryClient,
|
||||||
server,
|
// server,
|
||||||
});
|
// });
|
||||||
} else {
|
// } else {
|
||||||
songList = await getSongsByQuery({ query, queryClient, server });
|
// songList = await getSongsByQuery({ query, queryClient, server });
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
clearTimeout(timeoutIds.current[fetchId] as ReturnType<typeof setTimeout>);
|
// clearTimeout(timeoutIds.current[fetchId] as ReturnType<typeof setTimeout>);
|
||||||
delete timeoutIds.current[fetchId];
|
// delete timeoutIds.current[fetchId];
|
||||||
if (toastId) {
|
// if (toastId) {
|
||||||
toast.hide(toastId);
|
// toast.hide(toastId);
|
||||||
}
|
// }
|
||||||
} catch (err: any) {
|
// } catch (err: any) {
|
||||||
if (instanceOfCancellationError(err)) {
|
// if (instanceOfCancellationError(err)) {
|
||||||
return null;
|
// return null;
|
||||||
}
|
// }
|
||||||
|
|
||||||
clearTimeout(timeoutIds.current[fetchId] as ReturnType<typeof setTimeout>);
|
// clearTimeout(timeoutIds.current[fetchId] as ReturnType<typeof setTimeout>);
|
||||||
delete timeoutIds.current[fetchId];
|
// delete timeoutIds.current[fetchId];
|
||||||
toast.hide(fetchId);
|
// toast.hide(fetchId);
|
||||||
|
|
||||||
return toast.error({
|
// return toast.error({
|
||||||
message: err.message,
|
// message: err.message,
|
||||||
title: t('error.genericError', { postProcess: 'sentenceCase' }) as string,
|
// title: t('error.genericError', { postProcess: 'sentenceCase' }) as string,
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
songs =
|
// songs =
|
||||||
songList?.items?.map((song: Song) => ({ ...song, uniqueId: nanoid() })) || null;
|
// songList?.items?.map((song: Song) => ({ ...song, uniqueId: nanoid() })) || null;
|
||||||
} else if (byData) {
|
// } else if (byData) {
|
||||||
songs = byData.map((song) => ({ ...song, uniqueId: nanoid() })) || null;
|
// songs = byData.map((song) => ({ ...song, uniqueId: nanoid() })) || null;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (!songs || songs?.length === 0)
|
// if (!songs || songs?.length === 0)
|
||||||
return toast.warn({
|
// return toast.warn({
|
||||||
message: t('common.noResultsFromQuery', { postProcess: 'sentenceCase' }),
|
// message: t('common.noResultsFromQuery', { postProcess: 'sentenceCase' }),
|
||||||
title: t('player.playbackFetchNoResults', { postProcess: 'sentenceCase' }),
|
// title: t('player.playbackFetchNoResults', { postProcess: 'sentenceCase' }),
|
||||||
});
|
// });
|
||||||
|
|
||||||
if (initialIndex) {
|
// if (initialIndex) {
|
||||||
initialSongIndex = initialIndex;
|
// initialSongIndex = initialIndex;
|
||||||
} else if (initialSongId) {
|
// } else if (initialSongId) {
|
||||||
initialSongIndex = songs.findIndex((song) => song.id === initialSongId);
|
// initialSongIndex = songs.findIndex((song) => song.id === initialSongId);
|
||||||
}
|
// }
|
||||||
|
|
||||||
const hadSong = usePlayerStore.getState().queue.default.length > 0;
|
// const hadSong = usePlayerStore.getState().queue.default.length > 0;
|
||||||
const playerData = addToQueue({ initialIndex: initialSongIndex, playType, songs });
|
// const playerData = addToQueue({ initialIndex: initialSongIndex, playType, songs });
|
||||||
|
|
||||||
updateSong(playerData.current.song);
|
// updateSong(playerData.current.song);
|
||||||
|
|
||||||
const replacesQueue = playType === Play.NOW || playType === Play.SHUFFLE;
|
// const replacesQueue = playType === Play.NOW || playType === Play.SHUFFLE;
|
||||||
|
|
||||||
if (playbackType === PlaybackType.LOCAL) {
|
// if (playbackType === PlaybackType.LOCAL) {
|
||||||
mpvPlayer!.volume(usePlayerStore.getState().volume);
|
// mpvPlayer!.volume(usePlayerStore.getState().volume);
|
||||||
|
|
||||||
if (replacesQueue || !hadSong) {
|
// if (replacesQueue || !hadSong) {
|
||||||
mpvPlayer!.pause();
|
// mpvPlayer!.pause();
|
||||||
setQueue(playerData, false);
|
// setQueue(playerData, false);
|
||||||
} else {
|
// } else {
|
||||||
setQueueNext(playerData);
|
// setQueueNext(playerData);
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
const player =
|
// const player =
|
||||||
playerData.current.player === 1
|
// playerData.current.player === 1
|
||||||
? PlayersRef.current?.player1
|
// ? PlayersRef.current?.player1
|
||||||
: PlayersRef.current?.player2;
|
// : PlayersRef.current?.player2;
|
||||||
const underlying = player?.getInternalPlayer();
|
// const underlying = player?.getInternalPlayer();
|
||||||
if (underlying && replacesQueue) {
|
// if (underlying && replacesQueue) {
|
||||||
underlying.currentTime = 0;
|
// underlying.currentTime = 0;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
// We should only play if the queue was empty, or we are doing play NOW
|
// // We should only play if the queue was empty, or we are doing play NOW
|
||||||
// (override the queue).
|
// // (override the queue).
|
||||||
if (replacesQueue || !hadSong) {
|
// if (replacesQueue || !hadSong) {
|
||||||
play();
|
// play();
|
||||||
}
|
// }
|
||||||
|
|
||||||
return null;
|
// return null;
|
||||||
},
|
// },
|
||||||
[doubleClickQueueAll, play, playbackType, queryClient, server, t],
|
// [doubleClickQueueAll, play, playbackType, queryClient, server, t],
|
||||||
);
|
// );
|
||||||
|
|
||||||
return handlePlayQueueAdd;
|
// return handlePlayQueueAdd;
|
||||||
};
|
// };
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
useCurrentSong,
|
usePlayerSong,
|
||||||
useCurrentStatus,
|
usePlayerStatus,
|
||||||
usePlaybackSettings,
|
usePlaybackSettings,
|
||||||
useSettingsStore,
|
useSettingsStore,
|
||||||
} from '/@/renderer/store';
|
} from '/@/renderer/store';
|
||||||
@@ -28,8 +28,8 @@ export const useMediaSession = ({
|
|||||||
handleStop: () => void;
|
handleStop: () => void;
|
||||||
}) => {
|
}) => {
|
||||||
const { mediaSession: mediaSessionEnabled } = usePlaybackSettings();
|
const { mediaSession: mediaSessionEnabled } = usePlaybackSettings();
|
||||||
const playerStatus = useCurrentStatus();
|
const playerStatus = usePlayerStatus();
|
||||||
const currentSong = useCurrentSong();
|
const currentSong = usePlayerSong();
|
||||||
const mediaSession = navigator.mediaSession;
|
const mediaSession = navigator.mediaSession;
|
||||||
const skip = useSettingsStore((state) => state.general.skipButtons);
|
const skip = useSettingsStore((state) => state.general.skipButtons);
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import isElectron from 'is-electron';
|
import isElectron from 'is-electron';
|
||||||
import { useCallback, useEffect } from 'react';
|
import { useCallback, useEffect } from 'react';
|
||||||
|
|
||||||
import { useCurrentStatus } from '/@/renderer/store';
|
import { usePlayerStatus } from '/@/renderer/store';
|
||||||
import { useWindowSettings } from '/@/renderer/store';
|
import { useWindowSettings } from '/@/renderer/store';
|
||||||
import { PlayerStatus } from '/@/shared/types/types';
|
import { PlayerStatus } from '/@/shared/types/types';
|
||||||
|
|
||||||
const ipc = isElectron() ? window.api.ipc : null;
|
const ipc = isElectron() ? window.api.ipc : null;
|
||||||
|
|
||||||
export const usePowerSaveBlocker = () => {
|
export const usePowerSaveBlocker = () => {
|
||||||
const status = useCurrentStatus();
|
const status = usePlayerStatus();
|
||||||
const { preventSleepOnPlayback } = useWindowSettings();
|
const { preventSleepOnPlayback } = useWindowSettings();
|
||||||
|
|
||||||
const startPowerSaveBlocker = useCallback(async () => {
|
const startPowerSaveBlocker = useCallback(async () => {
|
||||||
|
|||||||
@@ -1,13 +1,7 @@
|
|||||||
import isElectron from 'is-electron';
|
import isElectron from 'is-electron';
|
||||||
import { useCallback, useEffect, WheelEvent } from 'react';
|
import { useCallback, useEffect, WheelEvent } from 'react';
|
||||||
|
|
||||||
import {
|
import { usePlayerMuted, usePlayerSpeed, usePlayerVolume } from '/@/renderer/store';
|
||||||
useMuted,
|
|
||||||
usePlayerControls,
|
|
||||||
useSetCurrentSpeed,
|
|
||||||
useSpeed,
|
|
||||||
useVolume,
|
|
||||||
} from '/@/renderer/store';
|
|
||||||
import { useGeneralSettings } from '/@/renderer/store/settings.store';
|
import { useGeneralSettings } from '/@/renderer/store/settings.store';
|
||||||
|
|
||||||
const mpvPlayer = isElectron() ? window.api.mpvPlayer : null;
|
const mpvPlayer = isElectron() ? window.api.mpvPlayer : null;
|
||||||
@@ -40,12 +34,12 @@ const calculateVolumeDown = (volume: number, volumeWheelStep: number) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const useRightControls = () => {
|
export const useRightControls = () => {
|
||||||
const { setMuted, setVolume } = usePlayerControls();
|
// const { setMuted, setVolume } = usePlayerControls();
|
||||||
const volume = useVolume();
|
const volume = usePlayerVolume();
|
||||||
const muted = useMuted();
|
const muted = usePlayerMuted();
|
||||||
const { volumeWheelStep } = useGeneralSettings();
|
const { volumeWheelStep } = useGeneralSettings();
|
||||||
const speed = useSpeed();
|
const speed = usePlayerSpeed();
|
||||||
const setCurrentSpeed = useSetCurrentSpeed();
|
// const setCurrentSpeed = useSetCurrentSpeed();
|
||||||
|
|
||||||
// Ensure that the mpv player volume is set on startup
|
// Ensure that the mpv player volume is set on startup
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -63,40 +57,37 @@ export const useRightControls = () => {
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleSpeed = useCallback(
|
const handleSpeed = useCallback((e: number) => {
|
||||||
(e: number) => {
|
// setCurrentSpeed(e);
|
||||||
setCurrentSpeed(e);
|
if (mpvPlayer) {
|
||||||
if (mpvPlayer) {
|
mpvPlayer?.setProperties({ speed: e });
|
||||||
mpvPlayer?.setProperties({ speed: e });
|
}
|
||||||
}
|
}, []);
|
||||||
},
|
|
||||||
[setCurrentSpeed],
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleVolumeSlider = (e: number) => {
|
const handleVolumeSlider = (e: number) => {
|
||||||
mpvPlayer?.volume(e);
|
mpvPlayer?.volume(e);
|
||||||
remote?.updateVolume(e);
|
remote?.updateVolume(e);
|
||||||
setVolume(e);
|
// setVolume(e);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleVolumeSliderState = (e: number) => {
|
const handleVolumeSliderState = (e: number) => {
|
||||||
remote?.updateVolume(e);
|
remote?.updateVolume(e);
|
||||||
setVolume(e);
|
// setVolume(e);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleVolumeDown = useCallback(() => {
|
const handleVolumeDown = useCallback(() => {
|
||||||
const volumeToSet = calculateVolumeDown(volume, volumeWheelStep);
|
const volumeToSet = calculateVolumeDown(volume, volumeWheelStep);
|
||||||
mpvPlayer?.volume(volumeToSet);
|
mpvPlayer?.volume(volumeToSet);
|
||||||
remote?.updateVolume(volumeToSet);
|
remote?.updateVolume(volumeToSet);
|
||||||
setVolume(volumeToSet);
|
// setVolume(volumeToSet);
|
||||||
}, [setVolume, volume, volumeWheelStep]);
|
}, [volume, volumeWheelStep]);
|
||||||
|
|
||||||
const handleVolumeUp = useCallback(() => {
|
const handleVolumeUp = useCallback(() => {
|
||||||
const volumeToSet = calculateVolumeUp(volume, volumeWheelStep);
|
const volumeToSet = calculateVolumeUp(volume, volumeWheelStep);
|
||||||
mpvPlayer?.volume(volumeToSet);
|
mpvPlayer?.volume(volumeToSet);
|
||||||
remote?.updateVolume(volumeToSet);
|
remote?.updateVolume(volumeToSet);
|
||||||
setVolume(volumeToSet);
|
// setVolume(volumeToSet);
|
||||||
}, [setVolume, volume, volumeWheelStep]);
|
}, [volume, volumeWheelStep]);
|
||||||
|
|
||||||
const handleVolumeWheel = useCallback(
|
const handleVolumeWheel = useCallback(
|
||||||
(e: WheelEvent<HTMLButtonElement | HTMLDivElement>) => {
|
(e: WheelEvent<HTMLButtonElement | HTMLDivElement>) => {
|
||||||
@@ -109,15 +100,15 @@ export const useRightControls = () => {
|
|||||||
|
|
||||||
mpvPlayer?.volume(volumeToSet);
|
mpvPlayer?.volume(volumeToSet);
|
||||||
remote?.updateVolume(volumeToSet);
|
remote?.updateVolume(volumeToSet);
|
||||||
setVolume(volumeToSet);
|
// setVolume(volumeToSet);
|
||||||
},
|
},
|
||||||
[setVolume, volume, volumeWheelStep],
|
[volume, volumeWheelStep],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleMute = useCallback(() => {
|
const handleMute = useCallback(() => {
|
||||||
setMuted(!muted);
|
// setMuted(!muted);
|
||||||
mpvPlayer?.mute(!muted);
|
mpvPlayer?.mute(!muted);
|
||||||
}, [muted, setMuted]);
|
}, [muted]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isElectron()) {
|
if (isElectron()) {
|
||||||
|
|||||||
@@ -3,12 +3,11 @@ import { AxiosError } from 'axios';
|
|||||||
|
|
||||||
import { api } from '/@/renderer/api';
|
import { api } from '/@/renderer/api';
|
||||||
import { MutationOptions } from '/@/renderer/lib/react-query';
|
import { MutationOptions } from '/@/renderer/lib/react-query';
|
||||||
import { useIncrementQueuePlayCount } from '/@/renderer/store';
|
|
||||||
import { usePlayEvent } from '/@/renderer/store/event.store';
|
import { usePlayEvent } from '/@/renderer/store/event.store';
|
||||||
import { ScrobbleArgs, ScrobbleResponse } from '/@/shared/types/domain-types';
|
import { ScrobbleArgs, ScrobbleResponse } from '/@/shared/types/domain-types';
|
||||||
|
|
||||||
export const useSendScrobble = (options?: MutationOptions) => {
|
export const useSendScrobble = (options?: MutationOptions) => {
|
||||||
const incrementPlayCount = useIncrementQueuePlayCount();
|
// const incrementPlayCount = useIncrementQueuePlayCount();
|
||||||
const sendPlayEvent = usePlayEvent();
|
const sendPlayEvent = usePlayEvent();
|
||||||
|
|
||||||
return useMutation<ScrobbleResponse, AxiosError, ScrobbleArgs, null>({
|
return useMutation<ScrobbleResponse, AxiosError, ScrobbleArgs, null>({
|
||||||
@@ -21,7 +20,7 @@ export const useSendScrobble = (options?: MutationOptions) => {
|
|||||||
onSuccess: (_data, variables) => {
|
onSuccess: (_data, variables) => {
|
||||||
// Manually increment the play count for the song in the queue if scrobble was submitted
|
// Manually increment the play count for the song in the queue if scrobble was submitted
|
||||||
if (variables.query.submission) {
|
if (variables.query.submission) {
|
||||||
incrementPlayCount([variables.query.id]);
|
// incrementPlayCount([variables.query.id]);
|
||||||
sendPlayEvent(variables.query.id);
|
sendPlayEvent(variables.query.id);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ import { playlistsQueries } from '/@/renderer/features/playlists/api/playlists-a
|
|||||||
import { useAppFocus } from '/@/renderer/hooks';
|
import { useAppFocus } from '/@/renderer/hooks';
|
||||||
import {
|
import {
|
||||||
useCurrentServer,
|
useCurrentServer,
|
||||||
useCurrentSong,
|
usePlayerSong,
|
||||||
useCurrentStatus,
|
usePlayerStatus,
|
||||||
usePlaylistDetailStore,
|
usePlaylistDetailStore,
|
||||||
usePlaylistDetailTablePagination,
|
usePlaylistDetailTablePagination,
|
||||||
useSetPlaylistDetailTable,
|
useSetPlaylistDetailTable,
|
||||||
@@ -58,9 +58,9 @@ interface PlaylistDetailContentProps {
|
|||||||
export const PlaylistDetailSongListContent = ({ songs, tableRef }: PlaylistDetailContentProps) => {
|
export const PlaylistDetailSongListContent = ({ songs, tableRef }: PlaylistDetailContentProps) => {
|
||||||
const { playlistId } = useParams() as { playlistId: string };
|
const { playlistId } = useParams() as { playlistId: string };
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const status = useCurrentStatus();
|
const status = usePlayerStatus();
|
||||||
const isFocused = useAppFocus();
|
const isFocused = useAppFocus();
|
||||||
const currentSong = useCurrentSong();
|
const currentSong = usePlayerSong();
|
||||||
const server = useCurrentServer();
|
const server = useCurrentServer();
|
||||||
const page = usePlaylistDetailStore();
|
const page = usePlaylistDetailStore();
|
||||||
const filters: PlaylistSongListQueryClientSide = useMemo(() => {
|
const filters: PlaylistSongListQueryClientSide = useMemo(() => {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
} from '/@/renderer/features/settings/components/settings-section';
|
} from '/@/renderer/features/settings/components/settings-section';
|
||||||
import { useHotkeySettings, usePlaybackSettings, useSettingsStoreActions } from '/@/renderer/store';
|
import { useHotkeySettings, usePlaybackSettings, useSettingsStoreActions } from '/@/renderer/store';
|
||||||
import { Switch } from '/@/shared/components/switch/switch';
|
import { Switch } from '/@/shared/components/switch/switch';
|
||||||
import { PlaybackType } from '/@/shared/types/types';
|
import { PlayerType } from '/@/shared/types/types';
|
||||||
|
|
||||||
const localSettings = isElectron() ? window.api.localSettings : null;
|
const localSettings = isElectron() ? window.api.localSettings : null;
|
||||||
const isWindows = isElectron() ? window.api.utils.isWindows() : false;
|
const isWindows = isElectron() ? window.api.utils.isWindows() : false;
|
||||||
@@ -25,9 +25,7 @@ export const WindowHotkeySettings = () => {
|
|||||||
defaultChecked={settings.globalMediaHotkeys}
|
defaultChecked={settings.globalMediaHotkeys}
|
||||||
disabled={
|
disabled={
|
||||||
!isElectron() ||
|
!isElectron() ||
|
||||||
(enableWindowsMediaSession &&
|
(enableWindowsMediaSession && isWindows && playbackType === PlayerType.WEB)
|
||||||
isWindows &&
|
|
||||||
playbackType === PlaybackType.WEB)
|
|
||||||
}
|
}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setSettings({
|
setSettings({
|
||||||
|
|||||||
@@ -6,14 +6,14 @@ import {
|
|||||||
SettingOption,
|
SettingOption,
|
||||||
SettingsSection,
|
SettingsSection,
|
||||||
} from '/@/renderer/features/settings/components/settings-section';
|
} from '/@/renderer/features/settings/components/settings-section';
|
||||||
import { useCurrentStatus, usePlayerStore } from '/@/renderer/store';
|
import { usePlayerStatus, usePlayerStore } from '/@/renderer/store';
|
||||||
import { usePlaybackSettings, useSettingsStoreActions } from '/@/renderer/store/settings.store';
|
import { usePlaybackSettings, useSettingsStoreActions } from '/@/renderer/store/settings.store';
|
||||||
import { setQueue } from '/@/renderer/utils/set-transcoded-queue-data';
|
import { setQueue } from '/@/renderer/utils/set-transcoded-queue-data';
|
||||||
import { Select } from '/@/shared/components/select/select';
|
import { Select } from '/@/shared/components/select/select';
|
||||||
import { Slider } from '/@/shared/components/slider/slider';
|
import { Slider } from '/@/shared/components/slider/slider';
|
||||||
import { Switch } from '/@/shared/components/switch/switch';
|
import { Switch } from '/@/shared/components/switch/switch';
|
||||||
import { toast } from '/@/shared/components/toast/toast';
|
import { toast } from '/@/shared/components/toast/toast';
|
||||||
import { CrossfadeStyle, PlaybackStyle, PlaybackType, PlayerStatus } from '/@/shared/types/types';
|
import { CrossfadeStyle, PlayerStyle, PlayerType, PlayerStatus } from '/@/shared/types/types';
|
||||||
|
|
||||||
const ipc = isElectron() ? window.api.ipc : null;
|
const ipc = isElectron() ? window.api.ipc : null;
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ export const AudioSettings = ({ hasFancyAudio }: { hasFancyAudio: boolean }) =>
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const settings = usePlaybackSettings();
|
const settings = usePlaybackSettings();
|
||||||
const { setSettings } = useSettingsStoreActions();
|
const { setSettings } = useSettingsStoreActions();
|
||||||
const status = useCurrentStatus();
|
const status = usePlayerStatus();
|
||||||
|
|
||||||
const [audioDevices, setAudioDevices] = useState<{ label: string; value: string }[]>([]);
|
const [audioDevices, setAudioDevices] = useState<{ label: string; value: string }[]>([]);
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ export const AudioSettings = ({ hasFancyAudio }: { hasFancyAudio: boolean }) =>
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (settings.type === PlaybackType.WEB) {
|
if (settings.type === PlayerType.WEB) {
|
||||||
getAudioDevices();
|
getAudioDevices();
|
||||||
}
|
}
|
||||||
}, [settings.type, t]);
|
}, [settings.type, t]);
|
||||||
@@ -56,16 +56,16 @@ export const AudioSettings = ({ hasFancyAudio }: { hasFancyAudio: boolean }) =>
|
|||||||
{
|
{
|
||||||
disabled: !isElectron(),
|
disabled: !isElectron(),
|
||||||
label: 'MPV',
|
label: 'MPV',
|
||||||
value: PlaybackType.LOCAL,
|
value: PlayerType.LOCAL,
|
||||||
},
|
},
|
||||||
{ label: 'Web', value: PlaybackType.WEB },
|
{ label: 'Web', value: PlayerType.WEB },
|
||||||
]}
|
]}
|
||||||
defaultValue={settings.type}
|
defaultValue={settings.type}
|
||||||
disabled={status === PlayerStatus.PLAYING}
|
disabled={status === PlayerStatus.PLAYING}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setSettings({ playback: { ...settings, type: e as PlaybackType } });
|
setSettings({ playback: { ...settings, type: e as PlayerType } });
|
||||||
ipc?.send('settings-set', { property: 'playbackType', value: e });
|
ipc?.send('settings-set', { property: 'playbackType', value: e });
|
||||||
if (isElectron() && e === PlaybackType.LOCAL) {
|
if (isElectron() && e === PlayerType.LOCAL) {
|
||||||
const queueData = usePlayerStore.getState().actions.getPlayerData();
|
const queueData = usePlayerStore.getState().actions.getPlayerData();
|
||||||
setQueue(queueData);
|
setQueue(queueData);
|
||||||
}
|
}
|
||||||
@@ -89,7 +89,7 @@ export const AudioSettings = ({ hasFancyAudio }: { hasFancyAudio: boolean }) =>
|
|||||||
clearable
|
clearable
|
||||||
data={audioDevices}
|
data={audioDevices}
|
||||||
defaultValue={settings.audioDeviceId}
|
defaultValue={settings.audioDeviceId}
|
||||||
disabled={settings.type !== PlaybackType.WEB}
|
disabled={settings.type !== PlayerType.WEB}
|
||||||
onChange={(e) => setSettings({ playback: { ...settings, audioDeviceId: e } })}
|
onChange={(e) => setSettings({ playback: { ...settings, audioDeviceId: e } })}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
@@ -97,7 +97,7 @@ export const AudioSettings = ({ hasFancyAudio }: { hasFancyAudio: boolean }) =>
|
|||||||
context: 'description',
|
context: 'description',
|
||||||
postProcess: 'sentenceCase',
|
postProcess: 'sentenceCase',
|
||||||
}),
|
}),
|
||||||
isHidden: !isElectron() || settings.type !== PlaybackType.WEB,
|
isHidden: !isElectron() || settings.type !== PlayerType.WEB,
|
||||||
title: t('setting.audioDevice', { postProcess: 'sentenceCase' }),
|
title: t('setting.audioDevice', { postProcess: 'sentenceCase' }),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -109,20 +109,20 @@ export const AudioSettings = ({ hasFancyAudio }: { hasFancyAudio: boolean }) =>
|
|||||||
context: 'optionNormal',
|
context: 'optionNormal',
|
||||||
postProcess: 'titleCase',
|
postProcess: 'titleCase',
|
||||||
}),
|
}),
|
||||||
value: PlaybackStyle.GAPLESS,
|
value: PlayerStyle.GAPLESS,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('setting.playbackStyle', {
|
label: t('setting.playbackStyle', {
|
||||||
context: 'optionCrossFade',
|
context: 'optionCrossFade',
|
||||||
postProcess: 'titleCase',
|
postProcess: 'titleCase',
|
||||||
}),
|
}),
|
||||||
value: PlaybackStyle.CROSSFADE,
|
value: PlayerStyle.CROSSFADE,
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
defaultValue={settings.style}
|
defaultValue={settings.style}
|
||||||
disabled={settings.type !== PlaybackType.WEB || status === PlayerStatus.PLAYING}
|
disabled={settings.type !== PlayerType.WEB || status === PlayerStatus.PLAYING}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setSettings({ playback: { ...settings, style: e as PlaybackStyle } })
|
setSettings({ playback: { ...settings, style: e as PlayerStyle } })
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
@@ -130,7 +130,7 @@ export const AudioSettings = ({ hasFancyAudio }: { hasFancyAudio: boolean }) =>
|
|||||||
context: 'description',
|
context: 'description',
|
||||||
postProcess: 'sentenceCase',
|
postProcess: 'sentenceCase',
|
||||||
}),
|
}),
|
||||||
isHidden: settings.type !== PlaybackType.WEB,
|
isHidden: settings.type !== PlayerType.WEB,
|
||||||
note: status === PlayerStatus.PLAYING ? 'Player must be paused' : undefined,
|
note: status === PlayerStatus.PLAYING ? 'Player must be paused' : undefined,
|
||||||
title: t('setting.playbackStyle', {
|
title: t('setting.playbackStyle', {
|
||||||
context: 'description',
|
context: 'description',
|
||||||
@@ -152,7 +152,7 @@ export const AudioSettings = ({ hasFancyAudio }: { hasFancyAudio: boolean }) =>
|
|||||||
context: 'description',
|
context: 'description',
|
||||||
postProcess: 'sentenceCase',
|
postProcess: 'sentenceCase',
|
||||||
}),
|
}),
|
||||||
isHidden: settings.type !== PlaybackType.WEB,
|
isHidden: settings.type !== PlayerType.WEB,
|
||||||
note: t('common.restartRequired', { postProcess: 'sentenceCase' }),
|
note: t('common.restartRequired', { postProcess: 'sentenceCase' }),
|
||||||
title: t('setting.webAudio', {
|
title: t('setting.webAudio', {
|
||||||
postProcess: 'sentenceCase',
|
postProcess: 'sentenceCase',
|
||||||
@@ -173,7 +173,7 @@ export const AudioSettings = ({ hasFancyAudio }: { hasFancyAudio: boolean }) =>
|
|||||||
context: 'description',
|
context: 'description',
|
||||||
postProcess: 'sentenceCase',
|
postProcess: 'sentenceCase',
|
||||||
}),
|
}),
|
||||||
isHidden: settings.type !== PlaybackType.WEB,
|
isHidden: settings.type !== PlayerType.WEB,
|
||||||
title: t('setting.preservePitch', {
|
title: t('setting.preservePitch', {
|
||||||
postProcess: 'sentenceCase',
|
postProcess: 'sentenceCase',
|
||||||
}),
|
}),
|
||||||
@@ -183,8 +183,8 @@ export const AudioSettings = ({ hasFancyAudio }: { hasFancyAudio: boolean }) =>
|
|||||||
<Slider
|
<Slider
|
||||||
defaultValue={settings.crossfadeDuration}
|
defaultValue={settings.crossfadeDuration}
|
||||||
disabled={
|
disabled={
|
||||||
settings.type !== PlaybackType.WEB ||
|
settings.type !== PlayerType.WEB ||
|
||||||
settings.style !== PlaybackStyle.CROSSFADE ||
|
settings.style !== PlayerStyle.CROSSFADE ||
|
||||||
status === PlayerStatus.PLAYING
|
status === PlayerStatus.PLAYING
|
||||||
}
|
}
|
||||||
max={15}
|
max={15}
|
||||||
@@ -199,7 +199,7 @@ export const AudioSettings = ({ hasFancyAudio }: { hasFancyAudio: boolean }) =>
|
|||||||
context: 'description',
|
context: 'description',
|
||||||
postProcess: 'sentenceCase',
|
postProcess: 'sentenceCase',
|
||||||
}),
|
}),
|
||||||
isHidden: settings.type !== PlaybackType.WEB,
|
isHidden: settings.type !== PlayerType.WEB,
|
||||||
note: status === PlayerStatus.PLAYING ? 'Player must be paused' : undefined,
|
note: status === PlayerStatus.PLAYING ? 'Player must be paused' : undefined,
|
||||||
title: t('setting.crossfadeDuration', {
|
title: t('setting.crossfadeDuration', {
|
||||||
postProcess: 'sentenceCase',
|
postProcess: 'sentenceCase',
|
||||||
@@ -224,8 +224,8 @@ export const AudioSettings = ({ hasFancyAudio }: { hasFancyAudio: boolean }) =>
|
|||||||
]}
|
]}
|
||||||
defaultValue={settings.crossfadeStyle}
|
defaultValue={settings.crossfadeStyle}
|
||||||
disabled={
|
disabled={
|
||||||
settings.type !== PlaybackType.WEB ||
|
settings.type !== PlayerType.WEB ||
|
||||||
settings.style !== PlaybackStyle.CROSSFADE ||
|
settings.style !== PlayerStyle.CROSSFADE ||
|
||||||
status === PlayerStatus.PLAYING
|
status === PlayerStatus.PLAYING
|
||||||
}
|
}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
@@ -241,7 +241,7 @@ export const AudioSettings = ({ hasFancyAudio }: { hasFancyAudio: boolean }) =>
|
|||||||
context: 'description',
|
context: 'description',
|
||||||
postProcess: 'sentenceCase',
|
postProcess: 'sentenceCase',
|
||||||
}),
|
}),
|
||||||
isHidden: settings.type !== PlaybackType.WEB,
|
isHidden: settings.type !== PlayerType.WEB,
|
||||||
note: status === PlayerStatus.PLAYING ? 'Player must be paused' : undefined,
|
note: status === PlayerStatus.PLAYING ? 'Player must be paused' : undefined,
|
||||||
title: t('setting.crossfadeStyle', { postProcess: 'sentenceCase' }),
|
title: t('setting.crossfadeStyle', { postProcess: 'sentenceCase' }),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
} from '/@/renderer/features/settings/components/settings-section';
|
} from '/@/renderer/features/settings/components/settings-section';
|
||||||
import { usePlaybackSettings, useSettingsStoreActions } from '/@/renderer/store/settings.store';
|
import { usePlaybackSettings, useSettingsStoreActions } from '/@/renderer/store/settings.store';
|
||||||
import { Switch } from '/@/shared/components/switch/switch';
|
import { Switch } from '/@/shared/components/switch/switch';
|
||||||
import { PlaybackType } from '/@/shared/types/types';
|
import { PlayerType } from '/@/shared/types/types';
|
||||||
|
|
||||||
const isWindows = isElectron() ? window.api.utils.isWindows() : null;
|
const isWindows = isElectron() ? window.api.utils.isWindows() : null;
|
||||||
const isDesktop = isElectron();
|
const isDesktop = isElectron();
|
||||||
@@ -30,7 +30,7 @@ export const MediaSessionSettings = () => {
|
|||||||
<Switch
|
<Switch
|
||||||
aria-label="Toggle media Session"
|
aria-label="Toggle media Session"
|
||||||
defaultChecked={mediaSession}
|
defaultChecked={mediaSession}
|
||||||
disabled={!isWindows || !isDesktop || playbackType !== PlaybackType.WEB}
|
disabled={!isWindows || !isDesktop || playbackType !== PlayerType.WEB}
|
||||||
onChange={handleMediaSessionChange}
|
onChange={handleMediaSessionChange}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -6,11 +6,9 @@ import {
|
|||||||
SettingOption,
|
SettingOption,
|
||||||
SettingsSection,
|
SettingsSection,
|
||||||
} from '/@/renderer/features/settings/components/settings-section';
|
} from '/@/renderer/features/settings/components/settings-section';
|
||||||
import { usePlayerControls, usePlayerStore, useQueueControls } from '/@/renderer/store';
|
|
||||||
import {
|
import {
|
||||||
SettingsState,
|
SettingsState,
|
||||||
usePlaybackSettings,
|
usePlaybackSettings,
|
||||||
useSettingsStore,
|
|
||||||
useSettingsStoreActions,
|
useSettingsStoreActions,
|
||||||
} from '/@/renderer/store/settings.store';
|
} from '/@/renderer/store/settings.store';
|
||||||
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
|
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
|
||||||
@@ -22,7 +20,7 @@ import { Switch } from '/@/shared/components/switch/switch';
|
|||||||
import { TextInput } from '/@/shared/components/text-input/text-input';
|
import { TextInput } from '/@/shared/components/text-input/text-input';
|
||||||
import { Text } from '/@/shared/components/text/text';
|
import { Text } from '/@/shared/components/text/text';
|
||||||
import { Textarea } from '/@/shared/components/textarea/textarea';
|
import { Textarea } from '/@/shared/components/textarea/textarea';
|
||||||
import { PlaybackType } from '/@/shared/types/types';
|
import { PlayerType } from '/@/shared/types/types';
|
||||||
|
|
||||||
const localSettings = isElectron() ? window.api.localSettings : null;
|
const localSettings = isElectron() ? window.api.localSettings : null;
|
||||||
const mpvPlayer = isElectron() ? window.api.mpvPlayer : null;
|
const mpvPlayer = isElectron() ? window.api.mpvPlayer : null;
|
||||||
@@ -74,8 +72,8 @@ export const MpvSettings = () => {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const settings = usePlaybackSettings();
|
const settings = usePlaybackSettings();
|
||||||
const { setSettings } = useSettingsStoreActions();
|
const { setSettings } = useSettingsStoreActions();
|
||||||
const { pause } = usePlayerControls();
|
// const { pause } = usePlayerControls();
|
||||||
const { clearQueue } = useQueueControls();
|
// const { clearQueue } = useQueueControls();
|
||||||
|
|
||||||
const [mpvPath, setMpvPath] = useState(
|
const [mpvPath, setMpvPath] = useState(
|
||||||
(localSettings?.get('mpv_path') as string | undefined) || '',
|
(localSettings?.get('mpv_path') as string | undefined) || '',
|
||||||
@@ -129,21 +127,21 @@ export const MpvSettings = () => {
|
|||||||
mpvPlayer?.setProperties(mpvSetting);
|
mpvPlayer?.setProperties(mpvSetting);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleReloadMpv = () => {
|
// const handleReloadMpv = () => {
|
||||||
pause();
|
// pause();
|
||||||
clearQueue();
|
// clearQueue();
|
||||||
|
|
||||||
const extraParameters = useSettingsStore.getState().playback.mpvExtraParameters;
|
// const extraParameters = useSettingsStore.getState().playback.mpvExtraParameters;
|
||||||
const properties: Record<string, any> = {
|
// const properties: Record<string, any> = {
|
||||||
speed: usePlayerStore.getState().speed,
|
// speed: usePlayerStore.getState().speed,
|
||||||
...getMpvProperties(useSettingsStore.getState().playback.mpvProperties),
|
// ...getMpvProperties(useSettingsStore.getState().playback.mpvProperties),
|
||||||
};
|
// };
|
||||||
mpvPlayer?.restart({
|
// mpvPlayer?.restart({
|
||||||
binaryPath: mpvPath || undefined,
|
// binaryPath: mpvPath || undefined,
|
||||||
extraParameters,
|
// extraParameters,
|
||||||
properties,
|
// properties,
|
||||||
});
|
// });
|
||||||
};
|
// };
|
||||||
|
|
||||||
const handleSetExtraParameters = (data: string[]) => {
|
const handleSetExtraParameters = (data: string[]) => {
|
||||||
setSettings({
|
setSettings({
|
||||||
@@ -160,7 +158,7 @@ export const MpvSettings = () => {
|
|||||||
<Group gap="sm">
|
<Group gap="sm">
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
icon="refresh"
|
icon="refresh"
|
||||||
onClick={handleReloadMpv}
|
// onClick={handleReloadMpv}
|
||||||
tooltip={{
|
tooltip={{
|
||||||
label: t('common.reload', { postProcess: 'titleCase' }),
|
label: t('common.reload', { postProcess: 'titleCase' }),
|
||||||
openDelay: 0,
|
openDelay: 0,
|
||||||
@@ -194,7 +192,7 @@ export const MpvSettings = () => {
|
|||||||
context: 'description',
|
context: 'description',
|
||||||
postProcess: 'sentenceCase',
|
postProcess: 'sentenceCase',
|
||||||
}),
|
}),
|
||||||
isHidden: settings.type !== PlaybackType.LOCAL,
|
isHidden: settings.type !== PlayerType.LOCAL,
|
||||||
note: 'Restart required',
|
note: 'Restart required',
|
||||||
title: t('setting.mpvExecutablePath', { postProcess: 'sentenceCase' }),
|
title: t('setting.mpvExecutablePath', { postProcess: 'sentenceCase' }),
|
||||||
},
|
},
|
||||||
@@ -235,7 +233,7 @@ export const MpvSettings = () => {
|
|||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
),
|
),
|
||||||
isHidden: settings.type !== PlaybackType.LOCAL,
|
isHidden: settings.type !== PlayerType.LOCAL,
|
||||||
note: t('common.restartRequired', {
|
note: t('common.restartRequired', {
|
||||||
postProcess: 'sentenceCase',
|
postProcess: 'sentenceCase',
|
||||||
}),
|
}),
|
||||||
@@ -268,7 +266,7 @@ export const MpvSettings = () => {
|
|||||||
context: 'description',
|
context: 'description',
|
||||||
postProcess: 'sentenceCase',
|
postProcess: 'sentenceCase',
|
||||||
}),
|
}),
|
||||||
isHidden: settings.type !== PlaybackType.LOCAL,
|
isHidden: settings.type !== PlayerType.LOCAL,
|
||||||
title: t('setting.gaplessAudio', { postProcess: 'sentenceCase' }),
|
title: t('setting.gaplessAudio', { postProcess: 'sentenceCase' }),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -311,7 +309,7 @@ export const MpvSettings = () => {
|
|||||||
context: 'description',
|
context: 'description',
|
||||||
postProcess: 'sentenceCase',
|
postProcess: 'sentenceCase',
|
||||||
}),
|
}),
|
||||||
isHidden: settings.type !== PlaybackType.LOCAL,
|
isHidden: settings.type !== PlayerType.LOCAL,
|
||||||
title: t('setting.audioExclusiveMode', { postProcess: 'sentenceCase' }),
|
title: t('setting.audioExclusiveMode', { postProcess: 'sentenceCase' }),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { ScrobbleSettings } from '/@/renderer/features/settings/components/playb
|
|||||||
import { TranscodeSettings } from '/@/renderer/features/settings/components/playback/transcode-settings';
|
import { TranscodeSettings } from '/@/renderer/features/settings/components/playback/transcode-settings';
|
||||||
import { useSettingsStore } from '/@/renderer/store';
|
import { useSettingsStore } from '/@/renderer/store';
|
||||||
import { Stack } from '/@/shared/components/stack/stack';
|
import { Stack } from '/@/shared/components/stack/stack';
|
||||||
import { PlaybackType } from '/@/shared/types/types';
|
import { PlayerType } from '/@/shared/types/types';
|
||||||
|
|
||||||
const MpvSettings = lazy(() =>
|
const MpvSettings = lazy(() =>
|
||||||
import('/@/renderer/features/settings/components/playback/mpv-settings').then((module) => {
|
import('/@/renderer/features/settings/components/playback/mpv-settings').then((module) => {
|
||||||
@@ -22,7 +22,7 @@ export const PlaybackTab = () => {
|
|||||||
|
|
||||||
const hasFancyAudio = useMemo(() => {
|
const hasFancyAudio = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
(isElectron() && audioType === PlaybackType.LOCAL) ||
|
(isElectron() && audioType === PlayerType.LOCAL) ||
|
||||||
(useWebAudio && 'AudioContext' in window)
|
(useWebAudio && 'AudioContext' in window)
|
||||||
);
|
);
|
||||||
}, [audioType, useWebAudio]);
|
}, [audioType, useWebAudio]);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import isElectron from 'is-electron';
|
|||||||
import { api } from '/@/renderer/api';
|
import { api } from '/@/renderer/api';
|
||||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
import { queryKeys } from '/@/renderer/api/query-keys';
|
||||||
import { MutationHookArgs } from '/@/renderer/lib/react-query';
|
import { MutationHookArgs } from '/@/renderer/lib/react-query';
|
||||||
import { useSetAlbumListItemDataById, useSetQueueFavorite } from '/@/renderer/store';
|
import { useSetAlbumListItemDataById } from '/@/renderer/store';
|
||||||
import { useFavoriteEvent } from '/@/renderer/store/event.store';
|
import { useFavoriteEvent } from '/@/renderer/store/event.store';
|
||||||
import {
|
import {
|
||||||
AlbumArtistDetailResponse,
|
AlbumArtistDetailResponse,
|
||||||
@@ -21,7 +21,7 @@ export const useCreateFavorite = (args: MutationHookArgs) => {
|
|||||||
const { options } = args || {};
|
const { options } = args || {};
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const setAlbumListData = useSetAlbumListItemDataById();
|
const setAlbumListData = useSetAlbumListItemDataById();
|
||||||
const setQueueFavorite = useSetQueueFavorite();
|
// const setQueueFavorite = useSetQueueFavorite();
|
||||||
const setFavoriteEvent = useFavoriteEvent();
|
const setFavoriteEvent = useFavoriteEvent();
|
||||||
|
|
||||||
return useMutation<FavoriteResponse, AxiosError, FavoriteArgs, null>({
|
return useMutation<FavoriteResponse, AxiosError, FavoriteArgs, null>({
|
||||||
@@ -46,7 +46,7 @@ export const useCreateFavorite = (args: MutationHookArgs) => {
|
|||||||
|
|
||||||
if (variables.query.type === LibraryItem.SONG) {
|
if (variables.query.type === LibraryItem.SONG) {
|
||||||
remote?.updateFavorite(true, serverId, variables.query.id);
|
remote?.updateFavorite(true, serverId, variables.query.id);
|
||||||
setQueueFavorite(variables.query.id, true);
|
// setQueueFavorite(variables.query.id, true);
|
||||||
setFavoriteEvent(variables.query.id, true);
|
setFavoriteEvent(variables.query.id, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import isElectron from 'is-electron';
|
|||||||
import { api } from '/@/renderer/api';
|
import { api } from '/@/renderer/api';
|
||||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
import { queryKeys } from '/@/renderer/api/query-keys';
|
||||||
import { MutationHookArgs } from '/@/renderer/lib/react-query';
|
import { MutationHookArgs } from '/@/renderer/lib/react-query';
|
||||||
import { useSetAlbumListItemDataById, useSetQueueFavorite } from '/@/renderer/store';
|
import { useSetAlbumListItemDataById } from '/@/renderer/store';
|
||||||
import { useFavoriteEvent } from '/@/renderer/store/event.store';
|
import { useFavoriteEvent } from '/@/renderer/store/event.store';
|
||||||
import {
|
import {
|
||||||
AlbumArtistDetailResponse,
|
AlbumArtistDetailResponse,
|
||||||
@@ -21,7 +21,7 @@ export const useDeleteFavorite = (args: MutationHookArgs) => {
|
|||||||
const { options } = args || {};
|
const { options } = args || {};
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const setAlbumListData = useSetAlbumListItemDataById();
|
const setAlbumListData = useSetAlbumListItemDataById();
|
||||||
const setQueueFavorite = useSetQueueFavorite();
|
// const setQueueFavorite = useSetQueueFavorite();
|
||||||
const setFavoriteEvent = useFavoriteEvent();
|
const setFavoriteEvent = useFavoriteEvent();
|
||||||
|
|
||||||
return useMutation<FavoriteResponse, AxiosError, FavoriteArgs, null>({
|
return useMutation<FavoriteResponse, AxiosError, FavoriteArgs, null>({
|
||||||
@@ -44,7 +44,7 @@ export const useDeleteFavorite = (args: MutationHookArgs) => {
|
|||||||
|
|
||||||
if (variables.query.type === LibraryItem.SONG) {
|
if (variables.query.type === LibraryItem.SONG) {
|
||||||
remote?.updateFavorite(false, serverId, variables.query.id);
|
remote?.updateFavorite(false, serverId, variables.query.id);
|
||||||
setQueueFavorite(variables.query.id, false);
|
// setQueueFavorite(variables.query.id, false);
|
||||||
setFavoriteEvent(variables.query.id, false);
|
setFavoriteEvent(variables.query.id, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import isElectron from 'is-electron';
|
|||||||
import { api } from '/@/renderer/api';
|
import { api } from '/@/renderer/api';
|
||||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
import { queryKeys } from '/@/renderer/api/query-keys';
|
||||||
import { MutationHookArgs } from '/@/renderer/lib/react-query';
|
import { MutationHookArgs } from '/@/renderer/lib/react-query';
|
||||||
import { useSetAlbumListItemDataById, useSetQueueRating } from '/@/renderer/store';
|
import { useSetAlbumListItemDataById } from '/@/renderer/store';
|
||||||
import { useRatingEvent } from '/@/renderer/store/event.store';
|
import { useRatingEvent } from '/@/renderer/store/event.store';
|
||||||
import {
|
import {
|
||||||
Album,
|
Album,
|
||||||
@@ -24,7 +24,7 @@ export const useSetRating = (args: MutationHookArgs) => {
|
|||||||
const { options } = args || {};
|
const { options } = args || {};
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const setAlbumListData = useSetAlbumListItemDataById();
|
const setAlbumListData = useSetAlbumListItemDataById();
|
||||||
const setQueueRating = useSetQueueRating();
|
// const setQueueRating = useSetQueueRating();
|
||||||
const setRatingEvent = useRatingEvent();
|
const setRatingEvent = useRatingEvent();
|
||||||
|
|
||||||
return useMutation<
|
return useMutation<
|
||||||
@@ -46,7 +46,7 @@ export const useSetRating = (args: MutationHookArgs) => {
|
|||||||
setAlbumListData(item.id, { userRating: item.userRating });
|
setAlbumListData(item.id, { userRating: item.userRating });
|
||||||
break;
|
break;
|
||||||
case LibraryItem.SONG:
|
case LibraryItem.SONG:
|
||||||
setQueueRating([item.id], item.userRating);
|
// setQueueRating([item.id], item.userRating);
|
||||||
setRatingEvent([item.id], item.userRating);
|
setRatingEvent([item.id], item.userRating);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -67,7 +67,7 @@ export const useSetRating = (args: MutationHookArgs) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (songIds.length > 0) {
|
if (songIds.length > 0) {
|
||||||
setQueueRating(songIds, variables.query.rating);
|
// setQueueRating(songIds, variables.query.rating);
|
||||||
setRatingEvent(songIds, variables.query.rating);
|
setRatingEvent(songIds, variables.query.rating);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import {
|
|||||||
} from '/@/renderer/features/sidebar/components/sidebar-playlist-list';
|
} from '/@/renderer/features/sidebar/components/sidebar-playlist-list';
|
||||||
import {
|
import {
|
||||||
useAppStoreActions,
|
useAppStoreActions,
|
||||||
useCurrentSong,
|
usePlayerSong,
|
||||||
useFullScreenPlayerStore,
|
useFullScreenPlayerStore,
|
||||||
useSetFullScreenPlayerStore,
|
useSetFullScreenPlayerStore,
|
||||||
useSidebarStore,
|
useSidebarStore,
|
||||||
@@ -42,7 +42,7 @@ export const Sidebar = () => {
|
|||||||
const sidebar = useSidebarStore();
|
const sidebar = useSidebarStore();
|
||||||
const { setSideBar } = useAppStoreActions();
|
const { setSideBar } = useAppStoreActions();
|
||||||
const { sidebarPlaylistList } = useGeneralSettings();
|
const { sidebarPlaylistList } = useGeneralSettings();
|
||||||
const currentSong = useCurrentSong();
|
const currentSong = usePlayerSong();
|
||||||
|
|
||||||
const translatedSidebarItemMap = useMemo(
|
const translatedSidebarItemMap = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import { getColumnDefs, VirtualTable } from '/@/renderer/components/virtual-tabl
|
|||||||
import { ErrorFallback } from '/@/renderer/features/action-required/components/error-fallback';
|
import { ErrorFallback } from '/@/renderer/features/action-required/components/error-fallback';
|
||||||
import { SONG_CONTEXT_MENU_ITEMS } from '/@/renderer/features/context-menu/context-menu-items';
|
import { SONG_CONTEXT_MENU_ITEMS } from '/@/renderer/features/context-menu/context-menu-items';
|
||||||
import { useHandleTableContextMenu } from '/@/renderer/features/context-menu/hooks/use-handle-context-menu';
|
import { useHandleTableContextMenu } from '/@/renderer/features/context-menu/hooks/use-handle-context-menu';
|
||||||
import { useHandlePlayQueueAdd } from '/@/renderer/features/player/hooks/use-handle-playqueue-add';
|
|
||||||
import { songsQueries } from '/@/renderer/features/songs/api/songs-api';
|
import { songsQueries } from '/@/renderer/features/songs/api/songs-api';
|
||||||
import { usePlayButtonBehavior, useTableSettings } from '/@/renderer/store';
|
import { usePlayButtonBehavior, useTableSettings } from '/@/renderer/store';
|
||||||
import { Spinner } from '/@/shared/components/spinner/spinner';
|
import { Spinner } from '/@/shared/components/spinner/spinner';
|
||||||
@@ -24,8 +23,6 @@ export type SimilarSongsListProps = {
|
|||||||
export const SimilarSongsList = ({ count, fullScreen, song }: SimilarSongsListProps) => {
|
export const SimilarSongsList = ({ count, fullScreen, song }: SimilarSongsListProps) => {
|
||||||
const tableRef = useRef<AgGridReact<Song> | null>(null);
|
const tableRef = useRef<AgGridReact<Song> | null>(null);
|
||||||
const tableConfig = useTableSettings(fullScreen ? 'fullScreen' : 'songs');
|
const tableConfig = useTableSettings(fullScreen ? 'fullScreen' : 'songs');
|
||||||
const handlePlayQueueAdd = useHandlePlayQueueAdd();
|
|
||||||
const playButtonBehavior = usePlayButtonBehavior();
|
|
||||||
|
|
||||||
const songQuery = useQuery(
|
const songQuery = useQuery(
|
||||||
songsQueries.similar({
|
songsQueries.similar({
|
||||||
@@ -51,11 +48,11 @@ export const SimilarSongsList = ({ count, fullScreen, song }: SimilarSongsListPr
|
|||||||
const handleRowDoubleClick = (e: RowDoubleClickedEvent<Song>) => {
|
const handleRowDoubleClick = (e: RowDoubleClickedEvent<Song>) => {
|
||||||
if (!e.data || !songQuery.data) return;
|
if (!e.data || !songQuery.data) return;
|
||||||
|
|
||||||
handlePlayQueueAdd?.({
|
// handlePlayQueueAdd?.({
|
||||||
byData: songQuery.data,
|
// byData: songQuery.data,
|
||||||
initialSongId: e.data.id,
|
// initialSongId: e.data.id,
|
||||||
playType: playButtonBehavior,
|
// playType: playButtonBehavior,
|
||||||
});
|
// });
|
||||||
};
|
};
|
||||||
|
|
||||||
return songQuery.isLoading ? (
|
return songQuery.isLoading ? (
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ import { SONG_CONTEXT_MENU_ITEMS } from '/@/renderer/features/context-menu/conte
|
|||||||
import { useAppFocus } from '/@/renderer/hooks';
|
import { useAppFocus } from '/@/renderer/hooks';
|
||||||
import {
|
import {
|
||||||
useCurrentServer,
|
useCurrentServer,
|
||||||
useCurrentSong,
|
usePlayerSong,
|
||||||
useCurrentStatus,
|
usePlayerStatus,
|
||||||
usePlayButtonBehavior,
|
usePlayButtonBehavior,
|
||||||
} from '/@/renderer/store';
|
} from '/@/renderer/store';
|
||||||
import { LibraryItem, QueueSong, SongListQuery } from '/@/shared/types/domain-types';
|
import { LibraryItem, QueueSong, SongListQuery } from '/@/shared/types/domain-types';
|
||||||
@@ -27,8 +27,8 @@ export const SongListTableView = ({ itemCount, tableRef }: SongListTableViewProp
|
|||||||
const server = useCurrentServer();
|
const server = useCurrentServer();
|
||||||
const { customFilters, handlePlay, id, pageKey } = useListContext();
|
const { customFilters, handlePlay, id, pageKey } = useListContext();
|
||||||
const isFocused = useAppFocus();
|
const isFocused = useAppFocus();
|
||||||
const currentSong = useCurrentSong();
|
const currentSong = usePlayerSong();
|
||||||
const status = useCurrentStatus();
|
const status = usePlayerStatus();
|
||||||
|
|
||||||
const { rowClassRules } = useCurrentSongRowStyles({ tableRef });
|
const { rowClassRules } = useCurrentSongRowStyles({ tableRef });
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,16 @@
|
|||||||
import { HotkeyItem, useHotkeys } from '@mantine/hooks';
|
import { HotkeyItem, useHotkeys } from '@mantine/hooks';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import isElectron from 'is-electron';
|
import isElectron from 'is-electron';
|
||||||
import { lazy, useMemo } from 'react';
|
import { lazy } from 'react';
|
||||||
import { useNavigate } from 'react-router';
|
import { useNavigate } from 'react-router';
|
||||||
|
|
||||||
import styles from './default-layout.module.css';
|
import styles from './default-layout.module.css';
|
||||||
|
|
||||||
import { ContextMenuProvider } from '/@/renderer/features/context-menu/context-menu-provider';
|
|
||||||
import { CommandPalette } from '/@/renderer/features/search/components/command-palette';
|
import { CommandPalette } from '/@/renderer/features/search/components/command-palette';
|
||||||
import { MainContent } from '/@/renderer/layouts/default-layout/main-content';
|
import { MainContent } from '/@/renderer/layouts/default-layout/main-content';
|
||||||
import { PlayerBar } from '/@/renderer/layouts/default-layout/player-bar';
|
import { PlayerBar } from '/@/renderer/layouts/default-layout/player-bar';
|
||||||
import { AppRoute } from '/@/renderer/router/routes';
|
import { AppRoute } from '/@/renderer/router/routes';
|
||||||
import {
|
import { useAppStore, useCommandPalette } from '/@/renderer/store';
|
||||||
useAppStore,
|
|
||||||
useCommandPalette,
|
|
||||||
useCurrentStatus,
|
|
||||||
useQueueStatus,
|
|
||||||
} from '/@/renderer/store';
|
|
||||||
import {
|
import {
|
||||||
useGeneralSettings,
|
useGeneralSettings,
|
||||||
useHotkeySettings,
|
useHotkeySettings,
|
||||||
@@ -24,13 +18,13 @@ import {
|
|||||||
useSettingsStoreActions,
|
useSettingsStoreActions,
|
||||||
useWindowSettings,
|
useWindowSettings,
|
||||||
} from '/@/renderer/store/settings.store';
|
} from '/@/renderer/store/settings.store';
|
||||||
import { Platform, PlaybackType, PlayerStatus } from '/@/shared/types/types';
|
import { Platform, PlayerType } from '/@/shared/types/types';
|
||||||
|
|
||||||
if (!isElectron()) {
|
if (!isElectron()) {
|
||||||
useSettingsStore.getState().actions.setSettings({
|
useSettingsStore.getState().actions.setSettings({
|
||||||
playback: {
|
playback: {
|
||||||
...useSettingsStore.getState().playback,
|
...useSettingsStore.getState().playback,
|
||||||
type: PlaybackType.WEB,
|
type: PlayerType.WEB,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -53,8 +47,7 @@ export const DefaultLayout = ({ shell }: DefaultLayoutProps) => {
|
|||||||
const localSettings = isElectron() ? window.api.localSettings : null;
|
const localSettings = isElectron() ? window.api.localSettings : null;
|
||||||
const settings = useGeneralSettings();
|
const settings = useGeneralSettings();
|
||||||
const { setSettings } = useSettingsStoreActions();
|
const { setSettings } = useSettingsStoreActions();
|
||||||
const playerStatus = useCurrentStatus();
|
|
||||||
const { currentSong, index, length } = useQueueStatus();
|
|
||||||
const { privateMode } = useAppStore();
|
const { privateMode } = useAppStore();
|
||||||
|
|
||||||
const updateZoom = (increase: number) => {
|
const updateZoom = (increase: number) => {
|
||||||
@@ -83,21 +76,21 @@ export const DefaultLayout = ({ shell }: DefaultLayoutProps) => {
|
|||||||
...(isElectron() ? zoomHotkeys : []),
|
...(isElectron() ? zoomHotkeys : []),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const title = useMemo(() => {
|
// const title = useMemo(() => {
|
||||||
const statusString = playerStatus === PlayerStatus.PAUSED ? '(Paused) ' : '';
|
// const statusString = playerStatus === PlayerStatus.PAUSED ? '(Paused) ' : '';
|
||||||
const queueString = length ? `(${index + 1} / ${length}) ` : '';
|
// const queueString = length ? `(${index + 1} / ${length}) ` : '';
|
||||||
const privateModeString = privateMode ? '(Private mode)' : '';
|
// const privateModeString = privateMode ? '(Private mode)' : '';
|
||||||
const title = `${
|
// const title = `${
|
||||||
length
|
// length
|
||||||
? `${statusString}${queueString}${currentSong?.name}${currentSong?.artistName ? ` — ${currentSong?.artistName} — Feishin` : ''}`
|
// ? `${statusString}${queueString}${currentSong?.name}${currentSong?.artistName ? ` — ${currentSong?.artistName} — Feishin` : ''}`
|
||||||
: 'Feishin'
|
// : 'Feishin'
|
||||||
}${privateMode ? ` ${privateModeString}` : ''}`;
|
// }${privateMode ? ` ${privateModeString}` : ''}`;
|
||||||
document.title = title;
|
// document.title = title;
|
||||||
return title;
|
// return title;
|
||||||
}, [currentSong?.artistName, currentSong?.name, index, length, playerStatus, privateMode]);
|
// }, [currentSong?.artistName, currentSong?.name, index, length, playerStatus, privateMode]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ContextMenuProvider>
|
<>
|
||||||
<div
|
<div
|
||||||
className={clsx(styles.layout, {
|
className={clsx(styles.layout, {
|
||||||
[styles.macos]: windowBarStyle === Platform.MACOS,
|
[styles.macos]: windowBarStyle === Platform.MACOS,
|
||||||
@@ -105,11 +98,11 @@ export const DefaultLayout = ({ shell }: DefaultLayoutProps) => {
|
|||||||
})}
|
})}
|
||||||
id="default-layout"
|
id="default-layout"
|
||||||
>
|
>
|
||||||
{windowBarStyle !== Platform.WEB && <WindowBar title={title} />}
|
{windowBarStyle !== Platform.WEB && <WindowBar title="" />}
|
||||||
<MainContent shell={shell} />
|
<MainContent shell={shell} />
|
||||||
<PlayerBar />
|
<PlayerBar />
|
||||||
</div>
|
</div>
|
||||||
<CommandPalette modalProps={{ handlers, opened }} />
|
<CommandPalette modalProps={{ handlers, opened }} />
|
||||||
</ContextMenuProvider>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { Navigate, Outlet } from 'react-router-dom';
|
|||||||
|
|
||||||
import { useServerAuthenticated } from '/@/renderer/hooks/use-server-authenticated';
|
import { useServerAuthenticated } from '/@/renderer/hooks/use-server-authenticated';
|
||||||
import { AppRoute } from '/@/renderer/router/routes';
|
import { AppRoute } from '/@/renderer/router/routes';
|
||||||
import { useCurrentServer, useSetPlayerFallback } from '/@/renderer/store';
|
import { useCurrentServer } from '/@/renderer/store';
|
||||||
import { Center } from '/@/shared/components/center/center';
|
import { Center } from '/@/shared/components/center/center';
|
||||||
import { Spinner } from '/@/shared/components/spinner/spinner';
|
import { Spinner } from '/@/shared/components/spinner/spinner';
|
||||||
import { toast } from '/@/shared/components/toast/toast';
|
import { toast } from '/@/shared/components/toast/toast';
|
||||||
@@ -16,7 +16,7 @@ const mpvPlayerListener = isElectron() ? window.api.mpvPlayerListener : null;
|
|||||||
|
|
||||||
export const AppOutlet = () => {
|
export const AppOutlet = () => {
|
||||||
const currentServer = useCurrentServer();
|
const currentServer = useCurrentServer();
|
||||||
const setFallback = useSetPlayerFallback();
|
// const setFallback = useSetPlayerFallback();
|
||||||
const authState = useServerAuthenticated();
|
const authState = useServerAuthenticated();
|
||||||
|
|
||||||
const isActionsRequired = useMemo(() => {
|
const isActionsRequired = useMemo(() => {
|
||||||
@@ -28,20 +28,20 @@ export const AppOutlet = () => {
|
|||||||
return isActionRequired;
|
return isActionRequired;
|
||||||
}, [currentServer]);
|
}, [currentServer]);
|
||||||
|
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
utils?.mainMessageListener((_event, data) => {
|
// utils?.mainMessageListener((_event, data) => {
|
||||||
toast.show(data);
|
// toast.show(data);
|
||||||
});
|
// });
|
||||||
|
|
||||||
mpvPlayerListener?.rendererPlayerFallback((_event, data) => {
|
// mpvPlayerListener?.rendererPlayerFallback((_event, data) => {
|
||||||
setFallback(data);
|
// setFallback(data);
|
||||||
});
|
// });
|
||||||
|
|
||||||
return () => {
|
// return () => {
|
||||||
ipc?.removeAllListeners('toast-from-main');
|
// ipc?.removeAllListeners('toast-from-main');
|
||||||
ipc?.removeAllListeners('renderer-player-fallback');
|
// ipc?.removeAllListeners('renderer-player-fallback');
|
||||||
};
|
// };
|
||||||
}, [setFallback]);
|
// }, [setFallback]);
|
||||||
|
|
||||||
if (authState === AuthState.LOADING) {
|
if (authState === AuthState.LOADING) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -10,40 +10,14 @@ import { useShallow } from 'zustand/react/shallow';
|
|||||||
import { createSelectors } from '/@/renderer/lib/zustand';
|
import { createSelectors } from '/@/renderer/lib/zustand';
|
||||||
import { shuffleInPlace } from '/@/renderer/utils/shuffle';
|
import { shuffleInPlace } from '/@/renderer/utils/shuffle';
|
||||||
import { QueueSong, Song } from '/@/shared/types/domain-types';
|
import { QueueSong, Song } from '/@/shared/types/domain-types';
|
||||||
|
import {
|
||||||
export enum PlayerRepeat {
|
Play,
|
||||||
ALBUM = 'album',
|
PlayerQueueType,
|
||||||
ALL = 'all',
|
PlayerRepeat,
|
||||||
OFF = 'off',
|
PlayerShuffle,
|
||||||
ONE = 'one',
|
PlayerStatus,
|
||||||
}
|
PlayerStyle,
|
||||||
|
} from '/@/shared/types/types';
|
||||||
export enum PlayerShuffle {
|
|
||||||
OFF = 'off',
|
|
||||||
TRACK = 'track',
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum PlayerStatus {
|
|
||||||
PAUSED = 'paused',
|
|
||||||
PLAYING = 'playing',
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum PlayerTransition {
|
|
||||||
CROSSFADE = 'crossfade',
|
|
||||||
GAPLESS = 'gapless',
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum PlayType {
|
|
||||||
INDEX = 'index',
|
|
||||||
LAST = 'last',
|
|
||||||
NEXT = 'next',
|
|
||||||
NOW = 'now',
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum QueueType {
|
|
||||||
DEFAULT = 'default',
|
|
||||||
PRIORITY = 'priority',
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PlayerData {
|
export interface PlayerData {
|
||||||
currentTrack: QueueSong | undefined;
|
currentTrack: QueueSong | undefined;
|
||||||
@@ -56,7 +30,7 @@ export interface PlayerData {
|
|||||||
shuffle: PlayerShuffle;
|
shuffle: PlayerShuffle;
|
||||||
speed: number;
|
speed: number;
|
||||||
status: PlayerStatus;
|
status: PlayerStatus;
|
||||||
transitionType: PlayerTransition;
|
transitionType: PlayerStyle;
|
||||||
volume: number;
|
volume: number;
|
||||||
};
|
};
|
||||||
player1: QueueSong | undefined;
|
player1: QueueSong | undefined;
|
||||||
@@ -75,7 +49,7 @@ export interface QueueData {
|
|||||||
export type QueueGroupingProperty = keyof QueueSong;
|
export type QueueGroupingProperty = keyof QueueSong;
|
||||||
|
|
||||||
interface Actions {
|
interface Actions {
|
||||||
addToQueueByType: (items: Song[], playType: PlayType) => void;
|
addToQueueByType: (items: Song[], playType: Play) => void;
|
||||||
addToQueueByUniqueId: (items: Song[], uniqueId: string, edge: 'bottom' | 'top') => void;
|
addToQueueByUniqueId: (items: Song[], uniqueId: string, edge: 'bottom' | 'top') => void;
|
||||||
clearQueue: () => void;
|
clearQueue: () => void;
|
||||||
clearSelected: (items: QueueSong[]) => void;
|
clearSelected: (items: QueueSong[]) => void;
|
||||||
@@ -103,11 +77,11 @@ interface Actions {
|
|||||||
moveSelectedToTop: (items: QueueSong[]) => void;
|
moveSelectedToTop: (items: QueueSong[]) => void;
|
||||||
setCrossfadeDuration: (duration: number) => void;
|
setCrossfadeDuration: (duration: number) => void;
|
||||||
setProgress: (timestamp: number) => void;
|
setProgress: (timestamp: number) => void;
|
||||||
setQueueType: (queueType: QueueType) => void;
|
setQueueType: (queueType: PlayerQueueType) => void;
|
||||||
setRepeat: (repeat: PlayerRepeat) => void;
|
setRepeat: (repeat: PlayerRepeat) => void;
|
||||||
setShuffle: (shuffle: PlayerShuffle) => void;
|
setShuffle: (shuffle: PlayerShuffle) => void;
|
||||||
setSpeed: (speed: number) => void;
|
setSpeed: (speed: number) => void;
|
||||||
setTransitionType: (transitionType: PlayerTransition) => void;
|
setTransitionType: (transitionType: PlayerStyle) => void;
|
||||||
setVolume: (volume: number) => void;
|
setVolume: (volume: number) => void;
|
||||||
shuffle: () => void;
|
shuffle: () => void;
|
||||||
shuffleAll: () => void;
|
shuffleAll: () => void;
|
||||||
@@ -125,7 +99,7 @@ interface State {
|
|||||||
index: number;
|
index: number;
|
||||||
muted: boolean;
|
muted: boolean;
|
||||||
playerNum: 1 | 2;
|
playerNum: 1 | 2;
|
||||||
queueType: QueueType;
|
queueType: PlayerQueueType;
|
||||||
repeat: PlayerRepeat;
|
repeat: PlayerRepeat;
|
||||||
seekToTimestamp: string;
|
seekToTimestamp: string;
|
||||||
shuffle: PlayerShuffle;
|
shuffle: PlayerShuffle;
|
||||||
@@ -134,7 +108,7 @@ interface State {
|
|||||||
stepBackward: number;
|
stepBackward: number;
|
||||||
stepForward: number;
|
stepForward: number;
|
||||||
timestamp: number;
|
timestamp: number;
|
||||||
transitionType: PlayerTransition;
|
transitionType: PlayerStyle;
|
||||||
volume: number;
|
volume: number;
|
||||||
};
|
};
|
||||||
queue: QueueData;
|
queue: QueueData;
|
||||||
@@ -150,9 +124,9 @@ export const usePlayerStoreBase = create<PlayerState>()(
|
|||||||
const queueType = getQueueType();
|
const queueType = getQueueType();
|
||||||
|
|
||||||
switch (queueType) {
|
switch (queueType) {
|
||||||
case QueueType.DEFAULT: {
|
case PlayerQueueType.DEFAULT: {
|
||||||
switch (playType) {
|
switch (playType) {
|
||||||
case PlayType.LAST: {
|
case Play.LAST: {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const currentIndex = state.player.index;
|
const currentIndex = state.player.index;
|
||||||
|
|
||||||
@@ -171,7 +145,7 @@ export const usePlayerStoreBase = create<PlayerState>()(
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PlayType.NEXT: {
|
case Play.NEXT: {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const currentIndex = state.player.index;
|
const currentIndex = state.player.index;
|
||||||
|
|
||||||
@@ -194,7 +168,7 @@ export const usePlayerStoreBase = create<PlayerState>()(
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PlayType.NOW: {
|
case Play.NOW: {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
state.queue.default = [];
|
state.queue.default = [];
|
||||||
state.player.index = 0;
|
state.player.index = 0;
|
||||||
@@ -214,9 +188,9 @@ export const usePlayerStoreBase = create<PlayerState>()(
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case QueueType.PRIORITY: {
|
case PlayerQueueType.PRIORITY: {
|
||||||
switch (playType) {
|
switch (playType) {
|
||||||
case PlayType.LAST: {
|
case Play.LAST: {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
state.queue.priority = [
|
state.queue.priority = [
|
||||||
...state.queue.priority,
|
...state.queue.priority,
|
||||||
@@ -230,7 +204,7 @@ export const usePlayerStoreBase = create<PlayerState>()(
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PlayType.NEXT: {
|
case Play.NEXT: {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const currentIndex = state.player.index;
|
const currentIndex = state.player.index;
|
||||||
const isInPriority =
|
const isInPriority =
|
||||||
@@ -260,7 +234,7 @@ export const usePlayerStoreBase = create<PlayerState>()(
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PlayType.NOW: {
|
case Play.NOW: {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
state.queue.default = [];
|
state.queue.default = [];
|
||||||
state.player.status = PlayerStatus.PLAYING;
|
state.player.status = PlayerStatus.PLAYING;
|
||||||
@@ -337,7 +311,7 @@ export const usePlayerStoreBase = create<PlayerState>()(
|
|||||||
const queueType = getQueueType();
|
const queueType = getQueueType();
|
||||||
|
|
||||||
set((state) => {
|
set((state) => {
|
||||||
if (queueType === QueueType.DEFAULT) {
|
if (queueType === PlayerQueueType.DEFAULT) {
|
||||||
const index = state.queue.default.findIndex(
|
const index = state.queue.default.findIndex(
|
||||||
(item) => item.uniqueId === uniqueId,
|
(item) => item.uniqueId === uniqueId,
|
||||||
);
|
);
|
||||||
@@ -445,7 +419,7 @@ export const usePlayerStoreBase = create<PlayerState>()(
|
|||||||
const queue = get().getQueueOrder();
|
const queue = get().getQueueOrder();
|
||||||
const queueType = getQueueType();
|
const queueType = getQueueType();
|
||||||
|
|
||||||
if (!groupBy || queueType === QueueType.PRIORITY) {
|
if (!groupBy || queueType === PlayerQueueType.PRIORITY) {
|
||||||
return queue;
|
return queue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -483,7 +457,7 @@ export const usePlayerStoreBase = create<PlayerState>()(
|
|||||||
getQueueOrder: () => {
|
getQueueOrder: () => {
|
||||||
const queueType = getQueueType();
|
const queueType = getQueueType();
|
||||||
|
|
||||||
if (queueType === QueueType.PRIORITY) {
|
if (queueType === PlayerQueueType.PRIORITY) {
|
||||||
const defaultQueue = get().queue.default;
|
const defaultQueue = get().queue.default;
|
||||||
const priorityQueue = get().queue.priority;
|
const priorityQueue = get().queue.priority;
|
||||||
|
|
||||||
@@ -645,7 +619,7 @@ export const usePlayerStoreBase = create<PlayerState>()(
|
|||||||
set((state) => {
|
set((state) => {
|
||||||
const uniqueIdMap = new Map(items.map((item) => [item.uniqueId, item]));
|
const uniqueIdMap = new Map(items.map((item) => [item.uniqueId, item]));
|
||||||
|
|
||||||
if (queueType == QueueType.DEFAULT) {
|
if (queueType == PlayerQueueType.DEFAULT) {
|
||||||
// Find the index of the drop target
|
// Find the index of the drop target
|
||||||
const index = state.queue.default.findIndex(
|
const index = state.queue.default.findIndex(
|
||||||
(item) => item.uniqueId === uniqueId,
|
(item) => item.uniqueId === uniqueId,
|
||||||
@@ -738,7 +712,7 @@ export const usePlayerStoreBase = create<PlayerState>()(
|
|||||||
set((state) => {
|
set((state) => {
|
||||||
const uniqueIds = items.map((item) => item.uniqueId);
|
const uniqueIds = items.map((item) => item.uniqueId);
|
||||||
|
|
||||||
if (state.player.queueType === QueueType.PRIORITY) {
|
if (state.player.queueType === PlayerQueueType.PRIORITY) {
|
||||||
const priorityFiltered = state.queue.priority.filter(
|
const priorityFiltered = state.queue.priority.filter(
|
||||||
(item) => !uniqueIds.includes(item.uniqueId),
|
(item) => !uniqueIds.includes(item.uniqueId),
|
||||||
);
|
);
|
||||||
@@ -779,7 +753,7 @@ export const usePlayerStoreBase = create<PlayerState>()(
|
|||||||
|
|
||||||
const uniqueIds = items.map((item) => item.uniqueId);
|
const uniqueIds = items.map((item) => item.uniqueId);
|
||||||
|
|
||||||
if (queueType === QueueType.DEFAULT) {
|
if (queueType === PlayerQueueType.DEFAULT) {
|
||||||
const currentIndex = state.player.index;
|
const currentIndex = state.player.index;
|
||||||
const filtered = state.queue.default.filter(
|
const filtered = state.queue.default.filter(
|
||||||
(item) => !uniqueIds.includes(item.uniqueId),
|
(item) => !uniqueIds.includes(item.uniqueId),
|
||||||
@@ -861,7 +835,7 @@ export const usePlayerStoreBase = create<PlayerState>()(
|
|||||||
set((state) => {
|
set((state) => {
|
||||||
const uniqueIds = items.map((item) => item.uniqueId);
|
const uniqueIds = items.map((item) => item.uniqueId);
|
||||||
|
|
||||||
if (state.player.queueType === QueueType.PRIORITY) {
|
if (state.player.queueType === PlayerQueueType.PRIORITY) {
|
||||||
const priorityFiltered = state.queue.priority.filter(
|
const priorityFiltered = state.queue.priority.filter(
|
||||||
(item) => !uniqueIds.includes(item.uniqueId),
|
(item) => !uniqueIds.includes(item.uniqueId),
|
||||||
);
|
);
|
||||||
@@ -896,16 +870,16 @@ export const usePlayerStoreBase = create<PlayerState>()(
|
|||||||
index: -1,
|
index: -1,
|
||||||
muted: false,
|
muted: false,
|
||||||
playerNum: 1,
|
playerNum: 1,
|
||||||
queueType: QueueType.DEFAULT,
|
queueType: PlayerQueueType.DEFAULT,
|
||||||
repeat: PlayerRepeat.OFF,
|
repeat: PlayerRepeat.NONE,
|
||||||
seekToTimestamp: uniqueSeekToTimestamp(0),
|
seekToTimestamp: uniqueSeekToTimestamp(0),
|
||||||
shuffle: PlayerShuffle.OFF,
|
shuffle: PlayerShuffle.NONE,
|
||||||
speed: 1,
|
speed: 1,
|
||||||
status: PlayerStatus.PAUSED,
|
status: PlayerStatus.PAUSED,
|
||||||
stepBackward: 10,
|
stepBackward: 10,
|
||||||
stepForward: 10,
|
stepForward: 10,
|
||||||
timestamp: 0,
|
timestamp: 0,
|
||||||
transitionType: PlayerTransition.GAPLESS,
|
transitionType: PlayerStyle.GAPLESS,
|
||||||
volume: 30,
|
volume: 30,
|
||||||
},
|
},
|
||||||
queue: {
|
queue: {
|
||||||
@@ -924,10 +898,10 @@ export const usePlayerStoreBase = create<PlayerState>()(
|
|||||||
state.player.timestamp = timestamp;
|
state.player.timestamp = timestamp;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
setQueueType: (queueType: QueueType) => {
|
setQueueType: (queueType: PlayerQueueType) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
// From default -> priority, move all items from default to priority
|
// From default -> priority, move all items from default to priority
|
||||||
if (queueType === QueueType.PRIORITY) {
|
if (queueType === PlayerQueueType.PRIORITY) {
|
||||||
state.queue.priority = [
|
state.queue.priority = [
|
||||||
...state.queue.default,
|
...state.queue.default,
|
||||||
...state.queue.priority,
|
...state.queue.priority,
|
||||||
@@ -960,7 +934,7 @@ export const usePlayerStoreBase = create<PlayerState>()(
|
|||||||
state.player.speed = normalizedSpeed;
|
state.player.speed = normalizedSpeed;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
setTransitionType: (transitionType: PlayerTransition) => {
|
setTransitionType: (transitionType: PlayerStyle) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
state.player.transitionType = transitionType;
|
state.player.transitionType = transitionType;
|
||||||
});
|
});
|
||||||
@@ -1053,7 +1027,7 @@ export const usePlayerActions = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export type AddToQueueByPlayType = PlayType;
|
export type AddToQueueByPlayType = Play;
|
||||||
|
|
||||||
export type AddToQueueByUniqueId = {
|
export type AddToQueueByUniqueId = {
|
||||||
edge: 'bottom' | 'left' | 'right' | 'top' | null;
|
edge: 'bottom' | 'left' | 'right' | 'top' | null;
|
||||||
@@ -1254,16 +1228,6 @@ export const usePlayerProperties = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useCurrentTrack = () => {
|
|
||||||
return usePlayerStoreBase(
|
|
||||||
useShallow((state) => {
|
|
||||||
const queue = state.getQueue();
|
|
||||||
const index = state.player.index;
|
|
||||||
return { index, length: queue.items.length, track: queue.items[index] };
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const usePlayerProgress = () => {
|
export const usePlayerProgress = () => {
|
||||||
return usePlayerStoreBase((state) => state.player.timestamp);
|
return usePlayerStoreBase((state) => state.player.timestamp);
|
||||||
};
|
};
|
||||||
@@ -1321,32 +1285,67 @@ export const updateQueueFavorites = (ids: string[], favorite: boolean) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export function usePlayerMuted() {
|
export const usePlayerMuted = () => {
|
||||||
return usePlayerStoreBase((state) => state.player.muted);
|
return usePlayerStoreBase((state) => state.player.muted);
|
||||||
}
|
};
|
||||||
|
|
||||||
export function usePlayerQueueType() {
|
export const usePlayerQueueType = () => {
|
||||||
return usePlayerStoreBase((state) => state.player.queueType);
|
return usePlayerStoreBase((state) => state.player.queueType);
|
||||||
}
|
};
|
||||||
|
|
||||||
export function usePlayerRepeat() {
|
export const usePlayerRepeat = () => {
|
||||||
return usePlayerStoreBase((state) => state.player.repeat);
|
return usePlayerStoreBase((state) => state.player.repeat);
|
||||||
}
|
};
|
||||||
|
|
||||||
export function usePlayerShuffle() {
|
export const usePlayerShuffle = () => {
|
||||||
return usePlayerStoreBase((state) => state.player.shuffle);
|
return usePlayerStoreBase((state) => state.player.shuffle);
|
||||||
}
|
};
|
||||||
|
|
||||||
export function usePlayerStatus() {
|
export const usePlayerStatus = () => {
|
||||||
return usePlayerStoreBase((state) => state.player.status);
|
return usePlayerStoreBase((state) => state.player.status);
|
||||||
}
|
};
|
||||||
|
|
||||||
export function usePlayerVolume() {
|
export const usePlayerVolume = () => {
|
||||||
return usePlayerStoreBase((state) => state.player.volume);
|
return usePlayerStoreBase((state) => state.player.volume);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
export const usePlayerSpeed = () => {
|
||||||
|
return usePlayerStoreBase((state) => state.player.speed);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const usePlayerTimestamp = () => {
|
||||||
|
return usePlayerStoreBase((state) => state.player.timestamp);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const usePlayerSong = () => {
|
||||||
|
return usePlayerStoreBase((state) => {
|
||||||
|
const queue = state.getQueue();
|
||||||
|
const index = state.player.index;
|
||||||
|
return queue.items[index];
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const usePlayerNum = () => {
|
||||||
|
return usePlayerStoreBase((state) => state.player.playerNum);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const usePlayerQueue = () => {
|
||||||
|
return usePlayerStoreBase((state) => {
|
||||||
|
const queueType = state.player.queueType;
|
||||||
|
|
||||||
|
switch (queueType) {
|
||||||
|
case PlayerQueueType.DEFAULT:
|
||||||
|
return state.queue.default;
|
||||||
|
case PlayerQueueType.PRIORITY:
|
||||||
|
return state.queue.priority;
|
||||||
|
default:
|
||||||
|
return state.queue.default;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
function getQueueType() {
|
function getQueueType() {
|
||||||
const queueType: QueueType = usePlayerStore.getState().player.queueType;
|
const queueType: PlayerQueueType = usePlayerStore.getState().player.queueType;
|
||||||
return queueType;
|
return queueType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ import {
|
|||||||
FontType,
|
FontType,
|
||||||
Platform,
|
Platform,
|
||||||
Play,
|
Play,
|
||||||
PlaybackStyle,
|
PlayerStyle,
|
||||||
PlaybackType,
|
PlayerType,
|
||||||
TableColumn,
|
TableColumn,
|
||||||
TableType,
|
TableType,
|
||||||
} from '/@/shared/types/types';
|
} from '/@/shared/types/types';
|
||||||
@@ -258,9 +258,9 @@ const PlaybackSettingsSchema = z.object({
|
|||||||
muted: z.boolean(),
|
muted: z.boolean(),
|
||||||
preservePitch: z.boolean(),
|
preservePitch: z.boolean(),
|
||||||
scrobble: ScrobbleSettingsSchema,
|
scrobble: ScrobbleSettingsSchema,
|
||||||
style: z.nativeEnum(PlaybackStyle),
|
style: z.nativeEnum(PlayerStyle),
|
||||||
transcode: TranscodingConfigSchema,
|
transcode: TranscodingConfigSchema,
|
||||||
type: z.nativeEnum(PlaybackType),
|
type: z.nativeEnum(PlayerType),
|
||||||
webAudio: z.boolean(),
|
webAudio: z.boolean(),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -652,11 +652,11 @@ const initialState: SettingsState = {
|
|||||||
scrobbleAtDuration: 240,
|
scrobbleAtDuration: 240,
|
||||||
scrobbleAtPercentage: 75,
|
scrobbleAtPercentage: 75,
|
||||||
},
|
},
|
||||||
style: PlaybackStyle.GAPLESS,
|
style: PlayerStyle.GAPLESS,
|
||||||
transcode: {
|
transcode: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
},
|
},
|
||||||
type: PlaybackType.WEB,
|
type: PlayerType.WEB,
|
||||||
webAudio: true,
|
webAudio: true,
|
||||||
},
|
},
|
||||||
remote: {
|
remote: {
|
||||||
@@ -843,7 +843,7 @@ export const useSettingsStore = createWithEqualityFn<SettingsSlice>()(
|
|||||||
...initialState,
|
...initialState,
|
||||||
playback: {
|
playback: {
|
||||||
...initialState.playback,
|
...initialState.playback,
|
||||||
type: PlaybackType.WEB,
|
type: PlayerType.WEB,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -970,7 +970,7 @@ export const usePlaybackType = () =>
|
|||||||
const isFallback = usePlayerStore.getState().fallback;
|
const isFallback = usePlayerStore.getState().fallback;
|
||||||
|
|
||||||
if (isFallback) {
|
if (isFallback) {
|
||||||
return PlaybackType.WEB;
|
return PlayerType.WEB;
|
||||||
}
|
}
|
||||||
|
|
||||||
return state.playback.type;
|
return state.playback.type;
|
||||||
|
|||||||
@@ -101,20 +101,16 @@ export enum FontType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export enum Play {
|
export enum Play {
|
||||||
|
INDEX = 'index',
|
||||||
LAST = 'last',
|
LAST = 'last',
|
||||||
NEXT = 'next',
|
NEXT = 'next',
|
||||||
NOW = 'now',
|
NOW = 'now',
|
||||||
SHUFFLE = 'shuffle',
|
SHUFFLE = 'shuffle',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum PlaybackStyle {
|
export enum PlayerQueueType {
|
||||||
CROSSFADE = 'crossfade',
|
DEFAULT = 'default',
|
||||||
GAPLESS = 'gapless',
|
PRIORITY = 'priority',
|
||||||
}
|
|
||||||
|
|
||||||
export enum PlaybackType {
|
|
||||||
LOCAL = 'local',
|
|
||||||
WEB = 'web',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum PlayerRepeat {
|
export enum PlayerRepeat {
|
||||||
@@ -134,6 +130,16 @@ export enum PlayerStatus {
|
|||||||
PLAYING = 'playing',
|
PLAYING = 'playing',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum PlayerStyle {
|
||||||
|
CROSSFADE = 'crossfade',
|
||||||
|
GAPLESS = 'gapless',
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum PlayerType {
|
||||||
|
LOCAL = 'local',
|
||||||
|
WEB = 'web',
|
||||||
|
}
|
||||||
|
|
||||||
export enum TableColumn {
|
export enum TableColumn {
|
||||||
ACTIONS = 'actions',
|
ACTIONS = 'actions',
|
||||||
ALBUM = 'album',
|
ALBUM = 'album',
|
||||||
|
|||||||
Reference in New Issue
Block a user