mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-07 20:40:15 +02:00
feat(player): add server-side autosave capability
This commit is contained in:
@@ -721,6 +721,10 @@
|
||||
"autoDJ_itemCount_description": "the number of items attempted to be added to the queue when auto DJ is enabled",
|
||||
"autoDJ_timing": "timing",
|
||||
"autoDJ_timing_description": "the number of songs remaining in the queue before auto DJ is triggered",
|
||||
"autosave": "automatically save play queue",
|
||||
"autosave_description": "enable automatically saving the play queue to your server. this is only possible when using Navidrome/Subsonic, and you cannot have a mixed play queue.",
|
||||
"autosaveCount": "automatic play queue save frequency",
|
||||
"autosaveCount_description": "how many track changes before the queue is saved. 1 (minimum) means every song change",
|
||||
"accentColor_description": "sets the accent color for the application",
|
||||
"accentColor": "accent color",
|
||||
"useThemeAccentColor": "use theme accent color",
|
||||
|
||||
@@ -9,6 +9,7 @@ import { MpvPlayer } from '/@/renderer/features/player/audio-player/mpv-player';
|
||||
import { WebPlayer } from '/@/renderer/features/player/audio-player/web-player';
|
||||
import { SleepTimerHook } from '/@/renderer/features/player/components/sleep-timer-button';
|
||||
import { AutoDJHook } from '/@/renderer/features/player/hooks/use-auto-dj';
|
||||
import { AutosaveHook } from '/@/renderer/features/player/hooks/use-autosave';
|
||||
import { MediaSessionHook } from '/@/renderer/features/player/hooks/use-media-session';
|
||||
import { MPRISHook } from '/@/renderer/features/player/hooks/use-mpris';
|
||||
import { PlaybackHotkeysHook } from '/@/renderer/features/player/hooks/use-playback-hotkeys';
|
||||
@@ -64,6 +65,7 @@ export const AudioPlayers = () => {
|
||||
<UpdateCurrentSongHook />
|
||||
<RadioAudioInstanceHook />
|
||||
<RadioMetadataHook />
|
||||
<AutosaveHook />
|
||||
<AudioPlayersContent
|
||||
audioContext={audioContext}
|
||||
audioDeviceId={audioDeviceId}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
|
||||
import { useSaveQueue } from '/@/renderer/features/player/hooks/use-queue-restore';
|
||||
import { useCurrentServer, usePlayerSong, useSettingsStore } from '/@/renderer/store';
|
||||
import { ServerType } from '/@/shared/types/domain-types';
|
||||
|
||||
export const useAutosave = () => {
|
||||
const server = useCurrentServer();
|
||||
const currentSong = usePlayerSong();
|
||||
const priorSongId = useRef<string | undefined>(undefined);
|
||||
const songCount = useRef(0);
|
||||
const { count, enabled } = useSettingsStore((state) => state.general.autoSave);
|
||||
const { mutate: savePlayQueue } = useSaveQueue();
|
||||
|
||||
useEffect(() => {
|
||||
if (enabled && server.type !== ServerType.JELLYFIN) {
|
||||
if (currentSong?._uniqueId !== priorSongId.current) {
|
||||
if (songCount.current === count) {
|
||||
savePlayQueue();
|
||||
songCount.current = 1;
|
||||
} else {
|
||||
songCount.current += 1;
|
||||
}
|
||||
|
||||
priorSongId.current = currentSong?._uniqueId;
|
||||
}
|
||||
}
|
||||
}, [enabled, count, currentSong?._uniqueId, savePlayQueue, server.type]);
|
||||
};
|
||||
|
||||
export const AutosaveHook = () => {
|
||||
useAutosave();
|
||||
return null;
|
||||
};
|
||||
@@ -89,8 +89,7 @@ export const useSaveQueue = () => {
|
||||
});
|
||||
|
||||
toast.success({
|
||||
message: '',
|
||||
title: t('form.saveQueue.success', { postProcess: 'sentenceCase' }),
|
||||
message: t('form.saveQueue.success', { postProcess: 'sentenceCase' }),
|
||||
});
|
||||
} catch (error) {
|
||||
toast.error({
|
||||
|
||||
@@ -688,6 +688,59 @@ export const ApplicationSettings = memo(() => {
|
||||
isHidden: false,
|
||||
title: t('setting.playerbarOpenDrawer', { postProcess: 'sentenceCase' }),
|
||||
},
|
||||
{
|
||||
control: (
|
||||
<Switch
|
||||
aria-label={t('setting.autosave', { postProcess: 'sentenceCase' })}
|
||||
defaultChecked={settings.autoSave.enabled}
|
||||
onChange={(e) => {
|
||||
setSettings({
|
||||
general: {
|
||||
...settings,
|
||||
autoSave: {
|
||||
...settings.autoSave,
|
||||
enabled: e.currentTarget.checked,
|
||||
},
|
||||
},
|
||||
});
|
||||
}}
|
||||
/>
|
||||
),
|
||||
description: t('setting.autosave', {
|
||||
context: 'description',
|
||||
postProcess: 'sentenceCase',
|
||||
}),
|
||||
title: t('setting.autosave', { postProcess: 'sentenceCase' }),
|
||||
},
|
||||
{
|
||||
control: (
|
||||
<NumberInput
|
||||
min={1}
|
||||
onBlur={(e) => {
|
||||
if (!e) return;
|
||||
const newVal = e.currentTarget.value
|
||||
? Math.max(Number(e.currentTarget.value), 1)
|
||||
: settings.autoSave.count;
|
||||
setSettings({
|
||||
general: {
|
||||
...settings,
|
||||
autoSave: {
|
||||
...settings.autoSave,
|
||||
count: newVal,
|
||||
},
|
||||
},
|
||||
});
|
||||
}}
|
||||
value={settings.autoSave.count}
|
||||
/>
|
||||
),
|
||||
description: t('setting.autosaveCount', {
|
||||
context: 'description',
|
||||
postProcess: 'sentenceCase',
|
||||
}),
|
||||
isHidden: !settings.autoSave.enabled,
|
||||
title: t('setting.autosaveCount', { postProcess: 'sentenceCase' }),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
|
||||
@@ -430,6 +430,11 @@ export enum HomeFeatureStyle {
|
||||
SINGLE = 'single',
|
||||
}
|
||||
|
||||
const AutoSaveSchema = z.object({
|
||||
count: z.number().min(0),
|
||||
enabled: z.boolean(),
|
||||
});
|
||||
|
||||
export const GeneralSettingsSchema = z.object({
|
||||
accent: z
|
||||
.string()
|
||||
@@ -446,6 +451,7 @@ export const GeneralSettingsSchema = z.object({
|
||||
artistItems: z.array(SortableItemSchema(ArtistItemSchema)),
|
||||
artistRadioCount: z.number(),
|
||||
artistReleaseTypeItems: z.array(SortableItemSchema(ArtistReleaseTypeItemSchema)),
|
||||
autoSave: AutoSaveSchema,
|
||||
blurExplicitImages: z.boolean(),
|
||||
buttonSize: z.number(),
|
||||
collections: z.array(CollectionSchema),
|
||||
@@ -1094,6 +1100,10 @@ const initialState: SettingsState = {
|
||||
artistItems,
|
||||
artistRadioCount: 20,
|
||||
artistReleaseTypeItems,
|
||||
autoSave: {
|
||||
count: 10,
|
||||
enabled: false,
|
||||
},
|
||||
blurExplicitImages: false,
|
||||
buttonSize: 15,
|
||||
collections: [],
|
||||
|
||||
Reference in New Issue
Block a user