Files
feishin/src/renderer/store/player.store.ts
T
2022-10-26 16:21:51 -07:00

281 lines
7.2 KiB
TypeScript

/* eslint-disable prefer-destructuring */
/* eslint-disable @typescript-eslint/no-unused-vars */
import produce from 'immer';
import map from 'lodash/map';
import { nanoid } from 'nanoid/non-secure';
import create from 'zustand';
import { devtools, persist } from 'zustand/middleware';
import { Song } from '@/renderer/api/types';
import {
Play,
CrossfadeStyle,
PlaybackStyle,
PlaybackType,
PlayerRepeat,
PlayerStatus,
UniqueId,
} from '@/renderer/types';
type QueueSong = Song & UniqueId;
export interface PlayerState {
current: {
index: number;
player: 1 | 2;
song: QueueSong;
status: PlayerStatus;
time: number;
};
queue: {
default: QueueSong[];
previousNode: QueueSong;
shuffled: QueueSong[];
sorted: QueueSong[];
};
settings: {
crossfadeDuration: number;
crossfadeStyle: CrossfadeStyle;
muted: boolean;
repeat: PlayerRepeat;
shuffle: boolean;
style: PlaybackStyle;
type: PlaybackType;
volume: number;
};
}
export interface PlayerData {
current: {
index: number;
player: 1 | 2;
song: QueueSong;
status: PlayerStatus;
};
player1: QueueSong;
player2: QueueSong;
queue: QueueData;
}
export interface QueueData {
current: QueueSong;
next: QueueSong;
previous: QueueSong;
}
export interface PlayerSlice extends PlayerState {
addToQueue: (songs: Song[], type: Play) => PlayerData;
autoNext: () => PlayerData;
getPlayerData: () => PlayerData;
getQueueData: () => QueueData;
next: () => PlayerData;
pause: () => void;
play: () => void;
player1: () => QueueSong;
player2: () => QueueSong;
prev: () => PlayerData;
setCurrentIndex: (index: number) => PlayerData;
setCurrentTime: (time: number) => void;
setSettings: (settings: Partial<PlayerState['settings']>) => void;
}
export const usePlayerStore = create<PlayerSlice>()(
persist(
devtools((set, get) => ({
addToQueue: (songs, type) => {
const queueSongs = map(songs, (song) => ({
...song,
uniqueId: nanoid(),
}));
if (type === Play.NOW) {
set(
produce((state) => {
state.queue.default = queueSongs;
state.current.time = 0;
state.current.player = 1;
state.current.index = 0;
state.current.song = queueSongs[0];
})
);
} else if (type === Play.LAST) {
set(
produce((state) => {
state.queue.default = [...get().queue.default, ...queueSongs];
})
);
} else if (type === Play.NEXT) {
const queue = get().queue.default;
const currentIndex = get().current.index;
set(
produce((state) => {
state.queue.default = [
...queue.slice(0, currentIndex + 1),
...queueSongs,
...queue.slice(currentIndex + 1),
];
})
);
}
return get().getPlayerData();
},
autoNext: () => {
set(
produce((state) => {
state.current.time = 0;
state.current.index += 1;
state.current.player = state.current.player === 1 ? 2 : 1;
state.current.song = state.queue.default[state.current.index];
state.queue.previousNode = get().current.song;
})
);
return get().getPlayerData();
},
current: {
index: 0,
player: 1,
song: {} as QueueSong,
status: PlayerStatus.PAUSED,
time: 0,
},
getPlayerData: () => {
const queue = get().queue.default;
const currentPlayer = get().current.player;
const player1 =
currentPlayer === 1
? queue[get().current.index]
: queue[get().current.index + 1];
const player2 =
currentPlayer === 1
? queue[get().current.index + 1]
: queue[get().current.index];
return {
current: {
index: get().current.index,
player: get().current.player,
song: get().current.song,
status: get().current.status,
},
player1,
player2,
queue: {
current: queue[get().current.index],
next: queue[get().current.index + 1],
previous: queue[get().current.index - 1],
},
};
},
getQueueData: () => {
const queue = get().queue.default;
return {
current: queue[get().current.index],
next: queue[get().current.index + 1],
previous: queue[get().current.index - 1],
};
},
next: () => {
set(
produce((state) => {
state.current.time = 0;
state.current.index += 1;
state.current.player = 1;
state.current.song = state.queue.default[state.current.index];
state.queue.previousNode = get().current.song;
})
);
return get().getPlayerData();
},
pause: () => {
set(
produce((state) => {
state.current.status = PlayerStatus.PAUSED;
})
);
},
play: () => {
set(
produce((state) => {
state.current.status = PlayerStatus.PLAYING;
})
);
},
player1: () => {
return get().getPlayerData().player1;
},
player2: () => {
return get().getPlayerData().player2;
},
prev: () => {
set(
produce((state) => {
state.current.time = 0;
state.current.index =
state.current.index - 1 < 0 ? 0 : state.current.index - 1;
state.current.player = 1;
state.current.song = state.queue.default[state.current.index];
state.queue.previousNode = get().current.song;
})
);
return get().getPlayerData();
},
queue: {
default: [],
previousNode: {} as QueueSong,
shuffled: [],
sorted: [],
},
setCurrentIndex: (index) => {
set(
produce((state) => {
state.current.time = 0;
state.current.index = index;
state.current.player = 1;
state.current.song = state.queue.default[index];
state.queue.previousNode = get().current.song;
})
);
return get().getPlayerData();
},
setCurrentTime: (time) => {
set(
produce((state) => {
state.current.time = time;
})
);
},
setSettings: (settings) => {
set(
produce((state) => {
state.settings = { ...get().settings, ...settings };
})
);
// try {
// setLocalStorageSettings('player', get().settings);
// } catch (err) {
// console.log('none');
// }
},
settings: {
crossfadeDuration: 5,
crossfadeStyle: CrossfadeStyle.EQUALPOWER,
muted: false,
repeat: PlayerRepeat.NONE,
shuffle: false,
style: PlaybackStyle.GAPLESS,
type: PlaybackType.LOCAL,
volume: 50,
},
})),
{ name: 'player' }
)
);