mirror of
https://github.com/jeffvli/feishin.git
synced 2026-06-19 18:04:22 +02:00
feat: persist player timestamp (#2043)
* feat: persist player timestamp
This commit is contained in:
@@ -14,7 +14,10 @@ import { MediaSessionHook } from '/@/renderer/features/player/hooks/use-media-se
|
|||||||
import { MPRISHook } from '/@/renderer/features/player/hooks/use-mpris';
|
import { MPRISHook } from '/@/renderer/features/player/hooks/use-mpris';
|
||||||
import { PlaybackHotkeysHook } from '/@/renderer/features/player/hooks/use-playback-hotkeys';
|
import { PlaybackHotkeysHook } from '/@/renderer/features/player/hooks/use-playback-hotkeys';
|
||||||
import { PowerSaveBlockerHook } from '/@/renderer/features/player/hooks/use-power-save-blocker';
|
import { PowerSaveBlockerHook } from '/@/renderer/features/player/hooks/use-power-save-blocker';
|
||||||
import { QueueRestoreTimestampHook } from '/@/renderer/features/player/hooks/use-queue-restore';
|
import {
|
||||||
|
InitialTimestampRestoreHook,
|
||||||
|
QueueRestoreTimestampHook,
|
||||||
|
} from '/@/renderer/features/player/hooks/use-queue-restore';
|
||||||
import { ScrobbleHook } from '/@/renderer/features/player/hooks/use-scrobble';
|
import { ScrobbleHook } from '/@/renderer/features/player/hooks/use-scrobble';
|
||||||
import { UpdateCurrentSongHook } from '/@/renderer/features/player/hooks/use-update-current-song';
|
import { UpdateCurrentSongHook } from '/@/renderer/features/player/hooks/use-update-current-song';
|
||||||
import { useWebAudio } from '/@/renderer/features/player/hooks/use-webaudio';
|
import { useWebAudio } from '/@/renderer/features/player/hooks/use-webaudio';
|
||||||
@@ -134,6 +137,7 @@ export const AudioPlayers = () => {
|
|||||||
<RemoteHook />
|
<RemoteHook />
|
||||||
<AutoDJHook />
|
<AutoDJHook />
|
||||||
<QueueRestoreTimestampHook />
|
<QueueRestoreTimestampHook />
|
||||||
|
<InitialTimestampRestoreHook />
|
||||||
<UpdateCurrentSongHook />
|
<UpdateCurrentSongHook />
|
||||||
<RadioAudioInstanceHook />
|
<RadioAudioInstanceHook />
|
||||||
<RadioMetadataHook />
|
<RadioMetadataHook />
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||||
import { t } from 'i18next';
|
import { t } from 'i18next';
|
||||||
import { useCallback } from 'react';
|
import { useCallback, useEffect, useRef } from 'react';
|
||||||
|
|
||||||
import { api } from '/@/renderer/api';
|
import { api } from '/@/renderer/api';
|
||||||
import { usePlayerEvents } from '/@/renderer/features/player/audio-player/hooks/use-player-events';
|
import { usePlayerEvents } from '/@/renderer/features/player/audio-player/hooks/use-player-events';
|
||||||
@@ -9,13 +9,18 @@ import { songsQueries } from '/@/renderer/features/songs/api/songs-api';
|
|||||||
import {
|
import {
|
||||||
setTimestamp,
|
setTimestamp,
|
||||||
useCurrentServerId,
|
useCurrentServerId,
|
||||||
|
usePlayerActions,
|
||||||
|
usePlayerHydrated,
|
||||||
|
usePlayerSong,
|
||||||
|
usePlayerStatus,
|
||||||
usePlayerStore,
|
usePlayerStore,
|
||||||
useTimestampStoreBase,
|
useTimestampStoreBase,
|
||||||
} from '/@/renderer/store';
|
} from '/@/renderer/store';
|
||||||
import { toast } from '/@/shared/components/toast/toast';
|
import { toast } from '/@/shared/components/toast/toast';
|
||||||
|
import { PlayerStatus } from '/@/shared/types/types';
|
||||||
|
|
||||||
export const useQueueRestoreTimestamp = () => {
|
export const useQueueRestoreTimestamp = () => {
|
||||||
const player = usePlayerStore();
|
const { mediaSeekToTimestamp } = usePlayerActions();
|
||||||
|
|
||||||
usePlayerEvents(
|
usePlayerEvents(
|
||||||
{
|
{
|
||||||
@@ -24,7 +29,7 @@ export const useQueueRestoreTimestamp = () => {
|
|||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setTimestamp(position);
|
setTimestamp(position);
|
||||||
player.mediaSeekToTimestamp(position);
|
mediaSeekToTimestamp(position);
|
||||||
}, 100);
|
}, 100);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -37,6 +42,72 @@ export const QueueRestoreTimestampHook = () => {
|
|||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useInitialTimestampRestore = () => {
|
||||||
|
const { mediaSeekToTimestamp } = usePlayerActions();
|
||||||
|
const playerHydrated = usePlayerHydrated();
|
||||||
|
const currentSong = usePlayerSong();
|
||||||
|
const playerStatus = usePlayerStatus();
|
||||||
|
const timestamp = useTimestampStoreBase((state) => state.timestamp);
|
||||||
|
|
||||||
|
const startupRestoreInitializedRef = useRef(false);
|
||||||
|
const startupSeekArmedRef = useRef<null | number>(null);
|
||||||
|
const startupSeekAppliedRef = useRef(false);
|
||||||
|
|
||||||
|
const applyStartupSeek = useCallback(() => {
|
||||||
|
if (startupSeekAppliedRef.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const seekTimestamp = startupSeekArmedRef.current;
|
||||||
|
if (!seekTimestamp || seekTimestamp <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
startupSeekAppliedRef.current = true;
|
||||||
|
startupSeekArmedRef.current = null;
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
mediaSeekToTimestamp(seekTimestamp);
|
||||||
|
}, 100);
|
||||||
|
}, [mediaSeekToTimestamp]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (startupRestoreInitializedRef.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!playerHydrated || !currentSong) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
startupRestoreInitializedRef.current = true;
|
||||||
|
|
||||||
|
if (timestamp > 0) {
|
||||||
|
startupSeekArmedRef.current = timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (playerStatus === PlayerStatus.PLAYING) {
|
||||||
|
applyStartupSeek();
|
||||||
|
}
|
||||||
|
}, [applyStartupSeek, currentSong, playerHydrated, playerStatus, timestamp]);
|
||||||
|
|
||||||
|
usePlayerEvents(
|
||||||
|
{
|
||||||
|
onPlayerStatus: (properties) => {
|
||||||
|
if (properties.status === PlayerStatus.PLAYING) {
|
||||||
|
applyStartupSeek();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[applyStartupSeek],
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const InitialTimestampRestoreHook = () => {
|
||||||
|
useInitialTimestampRestore();
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
export const useSaveQueue = () => {
|
export const useSaveQueue = () => {
|
||||||
const serverId = useCurrentServerId();
|
const serverId = useCurrentServerId();
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { subscribeWithSelector } from 'zustand/middleware';
|
import { del, get, set } from 'idb-keyval';
|
||||||
|
import { persist, subscribeWithSelector } from 'zustand/middleware';
|
||||||
import { createWithEqualityFn } from 'zustand/traditional';
|
import { createWithEqualityFn } from 'zustand/traditional';
|
||||||
|
|
||||||
interface TimestampState {
|
interface TimestampState {
|
||||||
@@ -6,13 +7,36 @@ interface TimestampState {
|
|||||||
timestamp: number;
|
timestamp: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const timestampStorage = {
|
||||||
|
getItem: async (name: string) => {
|
||||||
|
const value = await get(name);
|
||||||
|
if (value === undefined) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return { state: { timestamp: value }, version: 1 } as const;
|
||||||
|
},
|
||||||
|
removeItem: async (name: string) => {
|
||||||
|
await del(name);
|
||||||
|
},
|
||||||
|
setItem: async (name: string, value: { state: { timestamp: number }; version?: number }) => {
|
||||||
|
await set(name, value.state.timestamp);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export const useTimestampStoreBase = createWithEqualityFn<TimestampState>()(
|
export const useTimestampStoreBase = createWithEqualityFn<TimestampState>()(
|
||||||
subscribeWithSelector((set) => ({
|
persist(
|
||||||
setTimestamp: (timestamp: number) => {
|
subscribeWithSelector((set) => ({
|
||||||
set({ timestamp });
|
setTimestamp: (timestamp: number) => {
|
||||||
|
set({ timestamp });
|
||||||
|
},
|
||||||
|
timestamp: 0,
|
||||||
|
})),
|
||||||
|
{
|
||||||
|
name: 'player-timestamp',
|
||||||
|
storage: timestampStorage,
|
||||||
|
version: 1,
|
||||||
},
|
},
|
||||||
timestamp: 0,
|
),
|
||||||
})),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
export const subscribePlayerProgress = (
|
export const subscribePlayerProgress = (
|
||||||
|
|||||||
Reference in New Issue
Block a user