mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-09 20:29:36 +02:00
move player timestamp to separate store
- for performance related issue
This commit is contained in:
@@ -7,3 +7,4 @@ export * from './list.store';
|
|||||||
export * from './player.store';
|
export * from './player.store';
|
||||||
export * from './playlist.store';
|
export * from './playlist.store';
|
||||||
export * from './settings.store';
|
export * from './settings.store';
|
||||||
|
export * from './timestamp.store';
|
||||||
|
|||||||
@@ -7,6 +7,10 @@ import { useShallow } from 'zustand/react/shallow';
|
|||||||
|
|
||||||
import { createSelectors } from '/@/renderer/lib/zustand';
|
import { createSelectors } from '/@/renderer/lib/zustand';
|
||||||
import { useSettingsStore } from '/@/renderer/store/settings.store';
|
import { useSettingsStore } from '/@/renderer/store/settings.store';
|
||||||
|
import {
|
||||||
|
setTimestamp as setTimestampStore,
|
||||||
|
useTimestampStoreBase,
|
||||||
|
} from '/@/renderer/store/timestamp.store';
|
||||||
import { idbStateStorage } from '/@/renderer/store/utils';
|
import { idbStateStorage } from '/@/renderer/store/utils';
|
||||||
import { shuffleInPlace } from '/@/renderer/utils/shuffle';
|
import { shuffleInPlace } from '/@/renderer/utils/shuffle';
|
||||||
import { PlayerData, QueueData, QueueSong, Song } from '/@/shared/types/domain-types';
|
import { PlayerData, QueueData, QueueSong, Song } from '/@/shared/types/domain-types';
|
||||||
@@ -56,7 +60,6 @@ interface Actions {
|
|||||||
setRepeat: (repeat: PlayerRepeat) => void;
|
setRepeat: (repeat: PlayerRepeat) => void;
|
||||||
setShuffle: (shuffle: PlayerShuffle) => void;
|
setShuffle: (shuffle: PlayerShuffle) => void;
|
||||||
setSpeed: (speed: number) => void;
|
setSpeed: (speed: number) => void;
|
||||||
setTimestamp: (timestamp: number) => void;
|
|
||||||
setTransitionType: (transitionType: PlayerStyle) => void;
|
setTransitionType: (transitionType: PlayerStyle) => void;
|
||||||
setVolume: (volume: number) => void;
|
setVolume: (volume: number) => void;
|
||||||
shuffle: () => void;
|
shuffle: () => void;
|
||||||
@@ -83,7 +86,6 @@ interface State {
|
|||||||
shuffle: PlayerShuffle;
|
shuffle: PlayerShuffle;
|
||||||
speed: number;
|
speed: number;
|
||||||
status: PlayerStatus;
|
status: PlayerStatus;
|
||||||
timestamp: number;
|
|
||||||
transitionType: PlayerStyle;
|
transitionType: PlayerStyle;
|
||||||
volume: number;
|
volume: number;
|
||||||
};
|
};
|
||||||
@@ -102,7 +104,6 @@ const initialState: State = {
|
|||||||
shuffle: PlayerShuffle.NONE,
|
shuffle: PlayerShuffle.NONE,
|
||||||
speed: 1,
|
speed: 1,
|
||||||
status: PlayerStatus.PAUSED,
|
status: PlayerStatus.PAUSED,
|
||||||
timestamp: 0,
|
|
||||||
transitionType: PlayerStyle.GAPLESS,
|
transitionType: PlayerStyle.GAPLESS,
|
||||||
volume: 30,
|
volume: 30,
|
||||||
},
|
},
|
||||||
@@ -191,7 +192,7 @@ export const usePlayerStoreBase = create<PlayerState>()(
|
|||||||
state.player.index = 0;
|
state.player.index = 0;
|
||||||
state.player.status = PlayerStatus.PLAYING;
|
state.player.status = PlayerStatus.PLAYING;
|
||||||
state.player.playerNum = 1;
|
state.player.playerNum = 1;
|
||||||
state.player.timestamp = 0;
|
setTimestampStore(0);
|
||||||
state.queue.default = newUniqueIds;
|
state.queue.default = newUniqueIds;
|
||||||
|
|
||||||
if (state.player.shuffle === PlayerShuffle.TRACK) {
|
if (state.player.shuffle === PlayerShuffle.TRACK) {
|
||||||
@@ -215,7 +216,7 @@ export const usePlayerStoreBase = create<PlayerState>()(
|
|||||||
state.player.index = 0;
|
state.player.index = 0;
|
||||||
state.player.status = PlayerStatus.PLAYING;
|
state.player.status = PlayerStatus.PLAYING;
|
||||||
state.player.playerNum = 1;
|
state.player.playerNum = 1;
|
||||||
state.player.timestamp = 0;
|
setTimestampStore(0);
|
||||||
state.queue.default = shuffledIds;
|
state.queue.default = shuffledIds;
|
||||||
|
|
||||||
// Always maintain shuffled array when using Play.SHUFFLE
|
// Always maintain shuffled array when using Play.SHUFFLE
|
||||||
@@ -293,7 +294,7 @@ export const usePlayerStoreBase = create<PlayerState>()(
|
|||||||
state.queue.default = [];
|
state.queue.default = [];
|
||||||
state.player.status = PlayerStatus.PLAYING;
|
state.player.status = PlayerStatus.PLAYING;
|
||||||
state.player.playerNum = 1;
|
state.player.playerNum = 1;
|
||||||
state.player.timestamp = 0;
|
setTimestampStore(0);
|
||||||
|
|
||||||
// Add the first item after the current playing track
|
// Add the first item after the current playing track
|
||||||
|
|
||||||
@@ -369,7 +370,7 @@ export const usePlayerStoreBase = create<PlayerState>()(
|
|||||||
state.player.index = 0;
|
state.player.index = 0;
|
||||||
state.player.status = PlayerStatus.PLAYING;
|
state.player.status = PlayerStatus.PLAYING;
|
||||||
state.player.playerNum = 1;
|
state.player.playerNum = 1;
|
||||||
state.player.timestamp = 0;
|
setTimestampStore(0);
|
||||||
|
|
||||||
// Add first item to priority queue, rest to default
|
// Add first item to priority queue, rest to default
|
||||||
state.queue.priority = [shuffledIds[0]];
|
state.queue.priority = [shuffledIds[0]];
|
||||||
@@ -612,7 +613,7 @@ export const usePlayerStoreBase = create<PlayerState>()(
|
|||||||
set((state) => {
|
set((state) => {
|
||||||
state.player.index = newIndex;
|
state.player.index = newIndex;
|
||||||
state.player.playerNum = newPlayerNum;
|
state.player.playerNum = newPlayerNum;
|
||||||
state.player.timestamp = 0;
|
setTimestampStore(0);
|
||||||
state.player.status = newStatus;
|
state.player.status = newStatus;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -644,7 +645,7 @@ export const usePlayerStoreBase = create<PlayerState>()(
|
|||||||
set((state) => {
|
set((state) => {
|
||||||
state.player.index = Math.min(queue.items.length - 1, currentIndex + 1);
|
state.player.index = Math.min(queue.items.length - 1, currentIndex + 1);
|
||||||
state.player.playerNum = 1;
|
state.player.playerNum = 1;
|
||||||
state.player.timestamp = 0;
|
setTimestampStore(0);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
mediaPause: () => {
|
mediaPause: () => {
|
||||||
@@ -661,7 +662,7 @@ export const usePlayerStoreBase = create<PlayerState>()(
|
|||||||
|
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
state.player.index = index;
|
state.player.index = index;
|
||||||
state.player.timestamp = 0;
|
setTimestampStore(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -674,7 +675,7 @@ export const usePlayerStoreBase = create<PlayerState>()(
|
|||||||
set((state) => {
|
set((state) => {
|
||||||
// Only decrement if we're not at the start
|
// Only decrement if we're not at the start
|
||||||
state.player.index = Math.max(0, currentIndex - 1);
|
state.player.index = Math.max(0, currentIndex - 1);
|
||||||
state.player.timestamp = 0;
|
setTimestampStore(0);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
mediaSeekToTimestamp: (timestamp: number) => {
|
mediaSeekToTimestamp: (timestamp: number) => {
|
||||||
@@ -683,41 +684,41 @@ export const usePlayerStoreBase = create<PlayerState>()(
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
mediaSkipBackward: (offset?: number) => {
|
mediaSkipBackward: (offset?: number) => {
|
||||||
set((state) => {
|
const offsetFromSettings =
|
||||||
const offsetFromSettings =
|
useSettingsStore.getState().general.skipButtons.skipBackwardSeconds;
|
||||||
useSettingsStore.getState().general.skipButtons.skipBackwardSeconds;
|
const timeToSkip = offset ?? offsetFromSettings ?? 5;
|
||||||
const timeToSkip = offset ?? offsetFromSettings ?? 5;
|
const currentTimestamp = useTimestampStoreBase.getState().timestamp;
|
||||||
const newTimestamp = Math.max(0, state.player.timestamp - timeToSkip);
|
const newTimestamp = Math.max(0, currentTimestamp - timeToSkip);
|
||||||
|
|
||||||
|
set((state) => {
|
||||||
state.player.seekToTimestamp = uniqueSeekToTimestamp(newTimestamp);
|
state.player.seekToTimestamp = uniqueSeekToTimestamp(newTimestamp);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
mediaSkipForward: (offset?: number) => {
|
mediaSkipForward: (offset?: number) => {
|
||||||
|
const state = get();
|
||||||
|
const queue = state.getQueue();
|
||||||
|
const index = state.player.index;
|
||||||
|
const currentTrack = queue.items[index];
|
||||||
|
const duration = currentTrack?.duration;
|
||||||
|
const offsetFromSettings =
|
||||||
|
useSettingsStore.getState().general.skipButtons.skipForwardSeconds;
|
||||||
|
const timeToSkip = offset ?? offsetFromSettings ?? 5;
|
||||||
|
|
||||||
|
if (!duration) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentTimestamp = useTimestampStoreBase.getState().timestamp;
|
||||||
|
const newTimestamp = Math.min(duration - 1, currentTimestamp + timeToSkip);
|
||||||
|
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const queue = state.getQueue();
|
|
||||||
const index = state.player.index;
|
|
||||||
const currentTrack = queue.items[index];
|
|
||||||
const duration = currentTrack?.duration;
|
|
||||||
const offsetFromSettings =
|
|
||||||
useSettingsStore.getState().general.skipButtons.skipForwardSeconds;
|
|
||||||
const timeToSkip = offset ?? offsetFromSettings ?? 5;
|
|
||||||
|
|
||||||
if (!duration) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const newTimestamp = Math.min(
|
|
||||||
duration - 1,
|
|
||||||
state.player.timestamp + timeToSkip,
|
|
||||||
);
|
|
||||||
|
|
||||||
state.player.seekToTimestamp = uniqueSeekToTimestamp(newTimestamp);
|
state.player.seekToTimestamp = uniqueSeekToTimestamp(newTimestamp);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
mediaStop: () => {
|
mediaStop: () => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
state.player.status = PlayerStatus.PAUSED;
|
state.player.status = PlayerStatus.PAUSED;
|
||||||
state.player.timestamp = 0;
|
setTimestampStore(0);
|
||||||
state.player.index = -1;
|
state.player.index = -1;
|
||||||
state.queue.default = [];
|
state.queue.default = [];
|
||||||
state.queue.priority = [];
|
state.queue.priority = [];
|
||||||
@@ -1056,11 +1057,6 @@ export const usePlayerStoreBase = create<PlayerState>()(
|
|||||||
state.player.speed = normalizedSpeed;
|
state.player.speed = normalizedSpeed;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
setTimestamp: (timestamp: number) => {
|
|
||||||
set((state) => {
|
|
||||||
state.player.timestamp = timestamp;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
setTransitionType: (transitionType: PlayerStyle) => {
|
setTransitionType: (transitionType: PlayerStyle) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
state.player.transitionType = transitionType;
|
state.player.transitionType = transitionType;
|
||||||
@@ -1154,9 +1150,10 @@ export const usePlayerStoreBase = create<PlayerState>()(
|
|||||||
partialize: (state) => {
|
partialize: (state) => {
|
||||||
const shouldRestorePlayQueue = useSettingsStore.getState().general.resume;
|
const shouldRestorePlayQueue = useSettingsStore.getState().general.resume;
|
||||||
|
|
||||||
// Exclude playerNum, seekToTimestamp, status, and timestamp from stored player object
|
// Exclude playerNum, seekToTimestamp, and status from stored player object
|
||||||
// These are not needed to be stored since they are ephemeral properties
|
// These are not needed to be stored since they are ephemeral properties
|
||||||
const excludedPlayerKeys = ['playerNum', 'seekToTimestamp', 'status', 'timestamp'];
|
// Note: timestamp is now in a separate store and doesn't need to be excluded here
|
||||||
|
const excludedPlayerKeys = ['playerNum', 'seekToTimestamp', 'status'];
|
||||||
|
|
||||||
// If we're not restoring the play queue, we don't need the index property
|
// If we're not restoring the play queue, we don't need the index property
|
||||||
if (!shouldRestorePlayQueue) {
|
if (!shouldRestorePlayQueue) {
|
||||||
@@ -1196,7 +1193,7 @@ export const usePlayerStoreBase = create<PlayerState>()(
|
|||||||
export const usePlayerStore = createSelectors(usePlayerStoreBase);
|
export const usePlayerStore = createSelectors(usePlayerStoreBase);
|
||||||
|
|
||||||
export const usePlayerActions = () => {
|
export const usePlayerActions = () => {
|
||||||
return usePlayerStoreBase(
|
const actions = usePlayerStoreBase(
|
||||||
useShallow((state) => ({
|
useShallow((state) => ({
|
||||||
addToQueueByType: state.addToQueueByType,
|
addToQueueByType: state.addToQueueByType,
|
||||||
addToQueueByUniqueId: state.addToQueueByUniqueId,
|
addToQueueByUniqueId: state.addToQueueByUniqueId,
|
||||||
@@ -1224,7 +1221,6 @@ export const usePlayerActions = () => {
|
|||||||
setRepeat: state.setRepeat,
|
setRepeat: state.setRepeat,
|
||||||
setShuffle: state.setShuffle,
|
setShuffle: state.setShuffle,
|
||||||
setSpeed: state.setSpeed,
|
setSpeed: state.setSpeed,
|
||||||
setTimestamp: state.setTimestamp,
|
|
||||||
setTransitionType: state.setTransitionType,
|
setTransitionType: state.setTransitionType,
|
||||||
setVolume: state.setVolume,
|
setVolume: state.setVolume,
|
||||||
shuffle: state.shuffle,
|
shuffle: state.shuffle,
|
||||||
@@ -1234,6 +1230,11 @@ export const usePlayerActions = () => {
|
|||||||
toggleShuffle: state.toggleShuffle,
|
toggleShuffle: state.toggleShuffle,
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...actions,
|
||||||
|
setTimestamp: setTimestampStore,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export type AddToQueueByPlayType = Play;
|
export type AddToQueueByPlayType = Play;
|
||||||
@@ -1290,17 +1291,6 @@ export const subscribeCurrentTrack = (
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const subscribePlayerProgress = (
|
|
||||||
onChange: (properties: { timestamp: number }, prev: { timestamp: number }) => void,
|
|
||||||
) => {
|
|
||||||
return usePlayerStoreBase.subscribe(
|
|
||||||
(state) => state.player.timestamp,
|
|
||||||
(timestamp, prevTimestamp) => {
|
|
||||||
onChange({ timestamp }, { timestamp: prevTimestamp });
|
|
||||||
},
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const subscribePlayerVolume = (
|
export const subscribePlayerVolume = (
|
||||||
onChange: (properties: { volume: number }, prev: { volume: number }) => void,
|
onChange: (properties: { volume: number }, prev: { volume: number }) => void,
|
||||||
) => {
|
) => {
|
||||||
@@ -1398,10 +1388,6 @@ export const usePlayerProperties = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const usePlayerProgress = () => {
|
|
||||||
return usePlayerStoreBase((state) => state.player.timestamp);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const usePlayerDuration = () => {
|
export const usePlayerDuration = () => {
|
||||||
return usePlayerStoreBase((state) => {
|
return usePlayerStoreBase((state) => {
|
||||||
const queue = state.getQueue();
|
const queue = state.getQueue();
|
||||||
@@ -1481,10 +1467,6 @@ export const usePlayerSpeed = () => {
|
|||||||
return usePlayerStoreBase((state) => state.player.speed);
|
return usePlayerStoreBase((state) => state.player.speed);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const usePlayerTimestamp = () => {
|
|
||||||
return usePlayerStoreBase((state) => state.player.timestamp);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const usePlayerSong = () => {
|
export const usePlayerSong = () => {
|
||||||
return usePlayerStoreBase((state) => {
|
return usePlayerStoreBase((state) => {
|
||||||
const queue = state.getQueue();
|
const queue = state.getQueue();
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import { subscribeWithSelector } from 'zustand/middleware';
|
||||||
|
import { createWithEqualityFn } from 'zustand/traditional';
|
||||||
|
|
||||||
|
interface TimestampState {
|
||||||
|
setTimestamp: (timestamp: number) => void;
|
||||||
|
timestamp: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useTimestampStoreBase = createWithEqualityFn<TimestampState>()(
|
||||||
|
subscribeWithSelector((set) => ({
|
||||||
|
setTimestamp: (timestamp: number) => {
|
||||||
|
set({ timestamp });
|
||||||
|
},
|
||||||
|
timestamp: 0,
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
|
||||||
|
export const subscribePlayerProgress = (
|
||||||
|
onChange: (properties: { timestamp: number }, prev: { timestamp: number }) => void,
|
||||||
|
) => {
|
||||||
|
return useTimestampStoreBase.subscribe(
|
||||||
|
(state) => state.timestamp,
|
||||||
|
(timestamp, prevTimestamp) => {
|
||||||
|
onChange({ timestamp }, { timestamp: prevTimestamp });
|
||||||
|
},
|
||||||
|
{
|
||||||
|
equalityFn: (a, b) => {
|
||||||
|
return a === b;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const usePlayerProgress = () => {
|
||||||
|
return useTimestampStoreBase((state) => state.timestamp);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const usePlayerTimestamp = () => {
|
||||||
|
return useTimestampStoreBase((state) => state.timestamp);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const setTimestamp = (timestamp: number) => {
|
||||||
|
useTimestampStoreBase.getState().setTimestamp(timestamp);
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user