mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-10 04:30:25 +02:00
clean up player repeat behavior
This commit is contained in:
@@ -8,7 +8,12 @@ import styles from './full-screen-player-image.module.css';
|
|||||||
|
|
||||||
import { useFastAverageColor } from '/@/renderer/hooks';
|
import { useFastAverageColor } from '/@/renderer/hooks';
|
||||||
import { AppRoute } from '/@/renderer/router/routes';
|
import { AppRoute } from '/@/renderer/router/routes';
|
||||||
import { subscribeCurrentTrack, usePlayerData, usePlayerStoreBase } from '/@/renderer/store';
|
import {
|
||||||
|
calculateNextSong,
|
||||||
|
subscribeCurrentTrack,
|
||||||
|
usePlayerData,
|
||||||
|
usePlayerStoreBase,
|
||||||
|
} from '/@/renderer/store';
|
||||||
import { useSettingsStore } from '/@/renderer/store/settings.store';
|
import { useSettingsStore } from '/@/renderer/store/settings.store';
|
||||||
import { Badge } from '/@/shared/components/badge/badge';
|
import { Badge } from '/@/shared/components/badge/badge';
|
||||||
import { Center } from '/@/shared/components/center/center';
|
import { Center } from '/@/shared/components/center/center';
|
||||||
@@ -109,7 +114,7 @@ export const FullScreenPlayerImage = () => {
|
|||||||
const playerData = state.getQueue();
|
const playerData = state.getQueue();
|
||||||
const currentIndex = state.player.index;
|
const currentIndex = state.player.index;
|
||||||
const current = playerData.items[currentIndex];
|
const current = playerData.items[currentIndex];
|
||||||
const next = playerData.items[currentIndex + 1];
|
const next = calculateNextSong(currentIndex, playerData.items, state.player.repeat);
|
||||||
|
|
||||||
setMainImageDimensions({
|
setMainImageDimensions({
|
||||||
idealSize:
|
idealSize:
|
||||||
@@ -147,7 +152,7 @@ export const FullScreenPlayerImage = () => {
|
|||||||
const state = usePlayerStoreBase.getState();
|
const state = usePlayerStoreBase.getState();
|
||||||
const queue = state.getQueue();
|
const queue = state.getQueue();
|
||||||
const currentSong = queue.items[index];
|
const currentSong = queue.items[index];
|
||||||
const nextSong = queue.items[index + 1];
|
const nextSong = calculateNextSong(index, queue.items, state.player.repeat);
|
||||||
|
|
||||||
const currentImageUrl = scaleImageUrl(
|
const currentImageUrl = scaleImageUrl(
|
||||||
mainImageDimensions.idealSize,
|
mainImageDimensions.idealSize,
|
||||||
|
|||||||
@@ -98,6 +98,61 @@ interface State {
|
|||||||
queue: QueueData;
|
queue: QueueData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculates the next song based on repeat mode and current position
|
||||||
|
export function calculateNextSong(
|
||||||
|
currentIndex: number,
|
||||||
|
queueItems: QueueSong[],
|
||||||
|
repeat: PlayerRepeat,
|
||||||
|
): QueueSong | undefined {
|
||||||
|
if (queueItems.length === 0) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (repeat === PlayerRepeat.ONE) {
|
||||||
|
// When repeating one, next song is the same as current
|
||||||
|
return queueItems[currentIndex];
|
||||||
|
} else if (repeat === PlayerRepeat.ALL) {
|
||||||
|
// When repeating all, next song wraps to first if at the end
|
||||||
|
const isLastTrack = currentIndex === queueItems.length - 1;
|
||||||
|
if (isLastTrack) {
|
||||||
|
return queueItems[0];
|
||||||
|
} else {
|
||||||
|
return queueItems[currentIndex + 1];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// When repeat is none, next song is undefined if at the end
|
||||||
|
return queueItems[currentIndex + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculates the next index based on repeat mode and current position
|
||||||
|
function calculateNextIndex(
|
||||||
|
currentIndex: number,
|
||||||
|
queueLength: number,
|
||||||
|
repeat: PlayerRepeat,
|
||||||
|
): { nextIndex: number; shouldPause: boolean } {
|
||||||
|
const isLastTrack = currentIndex === queueLength - 1;
|
||||||
|
|
||||||
|
if (repeat === PlayerRepeat.ONE) {
|
||||||
|
// Repeat one: stay on the same track
|
||||||
|
return { nextIndex: currentIndex, shouldPause: false };
|
||||||
|
} else if (repeat === PlayerRepeat.ALL) {
|
||||||
|
// Repeat all: loop to first track if at the end
|
||||||
|
if (isLastTrack) {
|
||||||
|
return { nextIndex: 0, shouldPause: false };
|
||||||
|
} else {
|
||||||
|
return { nextIndex: currentIndex + 1, shouldPause: false };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Repeat none: move to next track, or pause if at the end
|
||||||
|
if (isLastTrack) {
|
||||||
|
return { nextIndex: 0, shouldPause: true };
|
||||||
|
} else {
|
||||||
|
return { nextIndex: currentIndex + 1, shouldPause: false };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const initialState: State = {
|
const initialState: State = {
|
||||||
player: {
|
player: {
|
||||||
crossfadeDuration: 5,
|
crossfadeDuration: 5,
|
||||||
@@ -743,35 +798,31 @@ export const usePlayerStoreBase = create<PlayerState>()(
|
|||||||
const queue = get().getQueueOrder();
|
const queue = get().getQueueOrder();
|
||||||
|
|
||||||
const newPlayerNum = player.playerNum === 1 ? 2 : 1;
|
const newPlayerNum = player.playerNum === 1 ? 2 : 1;
|
||||||
let newIndex = Math.min(queue.items.length - 1, currentIndex + 1);
|
const { nextIndex, shouldPause } = calculateNextIndex(
|
||||||
let newStatus = PlayerStatus.PLAYING;
|
currentIndex,
|
||||||
|
queue.items.length,
|
||||||
if (repeat === PlayerRepeat.ONE) {
|
repeat,
|
||||||
newIndex = currentIndex;
|
);
|
||||||
}
|
const newStatus = shouldPause ? PlayerStatus.PAUSED : PlayerStatus.PLAYING;
|
||||||
|
|
||||||
if (newIndex === queue.items.length - 1) {
|
|
||||||
newStatus = PlayerStatus.PAUSED;
|
|
||||||
}
|
|
||||||
|
|
||||||
set((state) => {
|
set((state) => {
|
||||||
state.player.index = newIndex;
|
state.player.index = nextIndex;
|
||||||
state.player.playerNum = newPlayerNum;
|
state.player.playerNum = newPlayerNum;
|
||||||
setTimestampStore(0);
|
setTimestampStore(0);
|
||||||
state.player.status = newStatus;
|
state.player.status = newStatus;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const nextSong = calculateNextSong(nextIndex, queue.items, repeat);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
currentSong: queue.items[newIndex],
|
currentSong: queue.items[nextIndex],
|
||||||
index: newIndex,
|
index: nextIndex,
|
||||||
muted: player.muted,
|
muted: player.muted,
|
||||||
nextSong: queue.items[newIndex + 1],
|
nextSong,
|
||||||
num: newPlayerNum,
|
num: newPlayerNum,
|
||||||
player1:
|
player1: newPlayerNum === 1 ? queue.items[nextIndex] : nextSong,
|
||||||
newPlayerNum === 1 ? queue.items[newIndex] : queue.items[newIndex + 1],
|
player2: newPlayerNum === 2 ? queue.items[nextIndex] : nextSong,
|
||||||
player2:
|
previousSong: queue.items[nextIndex - 1],
|
||||||
newPlayerNum === 2 ? queue.items[newIndex] : queue.items[newIndex + 1],
|
|
||||||
previousSong: queue.items[newIndex - 1],
|
|
||||||
queue: get().queue,
|
queue: get().queue,
|
||||||
queueLength: queue.items.length,
|
queueLength: queue.items.length,
|
||||||
repeat: player.repeat,
|
repeat: player.repeat,
|
||||||
@@ -784,10 +835,25 @@ export const usePlayerStoreBase = create<PlayerState>()(
|
|||||||
},
|
},
|
||||||
mediaNext: () => {
|
mediaNext: () => {
|
||||||
const currentIndex = get().player.index;
|
const currentIndex = get().player.index;
|
||||||
|
const player = get().player;
|
||||||
const queue = get().getQueueOrder();
|
const queue = get().getQueueOrder();
|
||||||
|
const isLastTrack = currentIndex === queue.items.length - 1;
|
||||||
|
|
||||||
|
let nextIndex: number;
|
||||||
|
|
||||||
|
if (player.repeat === PlayerRepeat.ALL && isLastTrack) {
|
||||||
|
// Repeat all: wrap to first track when on last track
|
||||||
|
nextIndex = 0;
|
||||||
|
} else if (player.repeat === PlayerRepeat.NONE && isLastTrack) {
|
||||||
|
// Repeat none: stay on last track if already there
|
||||||
|
nextIndex = currentIndex;
|
||||||
|
} else {
|
||||||
|
// Otherwise, advance to next track (including repeat ONE for manual navigation)
|
||||||
|
nextIndex = Math.min(queue.items.length - 1, currentIndex + 1);
|
||||||
|
}
|
||||||
|
|
||||||
set((state) => {
|
set((state) => {
|
||||||
state.player.index = Math.min(queue.items.length - 1, currentIndex + 1);
|
state.player.index = nextIndex;
|
||||||
state.player.playerNum = 1;
|
state.player.playerNum = 1;
|
||||||
setTimestampStore(0);
|
setTimestampStore(0);
|
||||||
});
|
});
|
||||||
@@ -830,10 +896,35 @@ export const usePlayerStoreBase = create<PlayerState>()(
|
|||||||
},
|
},
|
||||||
mediaPrevious: () => {
|
mediaPrevious: () => {
|
||||||
const currentIndex = get().player.index;
|
const currentIndex = get().player.index;
|
||||||
|
const player = get().player;
|
||||||
|
const queue = get().getQueueOrder();
|
||||||
|
const currentTimestamp = useTimestampStoreBase.getState().timestamp;
|
||||||
|
const isFirstTrack = currentIndex === 0;
|
||||||
|
|
||||||
|
// If timestamp is greater than 10 seconds, restart current song
|
||||||
|
if (currentTimestamp > 10) {
|
||||||
|
set((state) => {
|
||||||
|
state.player.seekToTimestamp = uniqueSeekToTimestamp(0);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let previousIndex: number;
|
||||||
|
|
||||||
|
if (player.repeat === PlayerRepeat.ALL && isFirstTrack) {
|
||||||
|
// Repeat all: wrap to last track when on first track
|
||||||
|
previousIndex = queue.items.length - 1;
|
||||||
|
} else if (player.repeat === PlayerRepeat.NONE && isFirstTrack) {
|
||||||
|
// Repeat none: stay on first track if already there
|
||||||
|
previousIndex = currentIndex;
|
||||||
|
} else {
|
||||||
|
// Otherwise, go to previous track
|
||||||
|
previousIndex = Math.max(0, currentIndex - 1);
|
||||||
|
}
|
||||||
|
|
||||||
set((state) => {
|
set((state) => {
|
||||||
// Only decrement if we're not at the start
|
state.player.index = previousIndex;
|
||||||
state.player.index = Math.max(0, currentIndex - 1);
|
state.player.playerNum = 1;
|
||||||
setTimestampStore(0);
|
setTimestampStore(0);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -1615,8 +1706,10 @@ export const usePlayerData = (): PlayerData => {
|
|||||||
const queue = state.getQueue();
|
const queue = state.getQueue();
|
||||||
const index = state.player.index;
|
const index = state.player.index;
|
||||||
const currentSong = queue.items[index];
|
const currentSong = queue.items[index];
|
||||||
const nextSong = queue.items[index + 1];
|
|
||||||
const previousSong = queue.items[index - 1];
|
const previousSong = queue.items[index - 1];
|
||||||
|
const repeat = state.player.repeat;
|
||||||
|
|
||||||
|
const nextSong = calculateNextSong(index, queue.items, repeat);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
currentSong,
|
currentSong,
|
||||||
|
|||||||
Reference in New Issue
Block a user