mirror of
https://github.com/jeffvli/feishin.git
synced 2024-11-20 06:27:09 +01:00
Allow initialIndex on queue add (#67)
- Clean up play queue handler - Split out functions to utils
This commit is contained in:
parent
02caf896ff
commit
3df2915f5f
@ -1,18 +1,25 @@
|
||||
import { useCallback } from 'react';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { api } from '/@/renderer/api/index';
|
||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
||||
import { useCurrentServer, usePlayerControls, usePlayerStore } from '/@/renderer/store';
|
||||
import { usePlayerType } from '/@/renderer/store/settings.store';
|
||||
import { PlayQueueAddOptions, Play, PlaybackType } from '/@/renderer/types';
|
||||
import { toast } from '/@/renderer/components/toast/index';
|
||||
import isElectron from 'is-electron';
|
||||
import { nanoid } from 'nanoid/non-secure';
|
||||
import { LibraryItem, SongListSort, SortOrder, Song } from '/@/renderer/api/types';
|
||||
import { LibraryItem, QueueSong, Song, SongListResponse } from '/@/renderer/api/types';
|
||||
import {
|
||||
getPlaylistSongsById,
|
||||
getSongById,
|
||||
getAlbumSongsById,
|
||||
getAlbumArtistSongsById,
|
||||
} from '/@/renderer/features/player/utils';
|
||||
|
||||
const mpvPlayer = isElectron() ? window.electron.mpvPlayer : null;
|
||||
const utils = isElectron() ? window.electron.utils : null;
|
||||
const mpris = isElectron() && utils?.isLinux() ? window.electron.mpris : null;
|
||||
|
||||
const addToQueue = usePlayerStore.getState().actions.addToQueue;
|
||||
|
||||
export const useHandlePlayQueueAdd = () => {
|
||||
const queryClient = useQueryClient();
|
||||
const playerType = usePlayerType();
|
||||
@ -22,129 +29,22 @@ export const useHandlePlayQueueAdd = () => {
|
||||
const handlePlayQueueAdd = useCallback(
|
||||
async (options: PlayQueueAddOptions) => {
|
||||
if (!server) return toast.error({ message: 'No server selected', type: 'error' });
|
||||
let songs = null;
|
||||
const { initialIndex, playType, byData, byItemType } = options;
|
||||
let songs: QueueSong[] | null = null;
|
||||
|
||||
// const itemCount = options.byItemType?.id?.length || 0;
|
||||
// const fetchId = itemCount > 1 ? nanoid() : null;
|
||||
|
||||
if (options.byItemType) {
|
||||
let songsList: any;
|
||||
let queryFilter: any;
|
||||
let queryKey: any;
|
||||
|
||||
if (options.byItemType.type === LibraryItem.PLAYLIST) {
|
||||
// if (fetchId) {
|
||||
// toast.success({
|
||||
// autoClose: false,
|
||||
// id: fetchId,
|
||||
// loading: true,
|
||||
// message: `This may take a while...`,
|
||||
// title: `Adding ${itemCount} albums to the queue`,
|
||||
// });
|
||||
// }
|
||||
|
||||
queryFilter = {
|
||||
id: options.byItemType?.id || [],
|
||||
sortBy: 'id',
|
||||
sortOrder: SortOrder.ASC,
|
||||
startIndex: 0,
|
||||
};
|
||||
|
||||
queryKey = queryKeys.playlists.songList(
|
||||
server?.id,
|
||||
options.byItemType?.id?.[0] || '',
|
||||
queryFilter,
|
||||
);
|
||||
} else if (options.byItemType.type === LibraryItem.ALBUM) {
|
||||
// if (fetchId) {
|
||||
// toast.success({
|
||||
// autoClose: false,
|
||||
// id: fetchId,
|
||||
// loading: true,
|
||||
// message: `This may take a while...`,
|
||||
// title: `Adding ${itemCount} albums to the queue`,
|
||||
// });
|
||||
// }
|
||||
|
||||
queryFilter = {
|
||||
albumIds: options.byItemType?.id || [],
|
||||
sortBy: SongListSort.ALBUM,
|
||||
sortOrder: SortOrder.ASC,
|
||||
startIndex: 0,
|
||||
};
|
||||
|
||||
queryKey = queryKeys.songs.list(server?.id, queryFilter);
|
||||
} else if (options.byItemType.type === LibraryItem.ALBUM_ARTIST) {
|
||||
// if (fetchId) {
|
||||
// toast.success({
|
||||
// autoClose: false,
|
||||
// id: fetchId,
|
||||
// loading: true,
|
||||
// message: `This may take a while...`,
|
||||
// title: `Adding ${itemCount} album artists to the queue`,
|
||||
// });
|
||||
// }
|
||||
|
||||
queryFilter = {
|
||||
artistIds: options.byItemType?.id || [],
|
||||
sortBy: SongListSort.ALBUM_ARTIST,
|
||||
sortOrder: SortOrder.ASC,
|
||||
startIndex: 0,
|
||||
};
|
||||
|
||||
queryKey = queryKeys.songs.list(server?.id, queryFilter);
|
||||
} else if (options.byItemType.type === LibraryItem.SONG) {
|
||||
queryFilter = { id: options.byItemType.id };
|
||||
queryKey = queryKeys.songs.detail(server?.id, queryFilter);
|
||||
}
|
||||
if (byItemType) {
|
||||
let songList: SongListResponse | undefined;
|
||||
const { type: itemType, id } = byItemType;
|
||||
|
||||
try {
|
||||
if (options.byItemType?.type === LibraryItem.PLAYLIST) {
|
||||
songsList = await queryClient.fetchQuery(
|
||||
queryKey,
|
||||
async ({ signal }) =>
|
||||
api.controller.getPlaylistSongList({
|
||||
apiClientProps: {
|
||||
server,
|
||||
signal,
|
||||
},
|
||||
query: queryFilter,
|
||||
}),
|
||||
{
|
||||
cacheTime: 1000 * 60,
|
||||
staleTime: 1000 * 60,
|
||||
},
|
||||
);
|
||||
} else if (options.byItemType?.type === LibraryItem.SONG) {
|
||||
const song = (await queryClient.fetchQuery(queryKey, async ({ signal }) =>
|
||||
api.controller.getSongDetail({
|
||||
apiClientProps: {
|
||||
server,
|
||||
signal,
|
||||
},
|
||||
query: queryFilter,
|
||||
}),
|
||||
)) as Song;
|
||||
|
||||
if (song) {
|
||||
songsList = { items: [song], startIndex: 0, totalRecordCount: 1 };
|
||||
}
|
||||
if (itemType === LibraryItem.PLAYLIST) {
|
||||
songList = await getPlaylistSongsById({ id, queryClient, server });
|
||||
} else if (itemType === LibraryItem.ALBUM) {
|
||||
songList = await getAlbumSongsById({ id, queryClient, server });
|
||||
} else if (itemType === LibraryItem.ALBUM_ARTIST) {
|
||||
songList = await getAlbumArtistSongsById({ id, queryClient, server });
|
||||
} else {
|
||||
songsList = await queryClient.fetchQuery(
|
||||
queryKey,
|
||||
async ({ signal }) =>
|
||||
api.controller.getSongList({
|
||||
apiClientProps: {
|
||||
server,
|
||||
signal,
|
||||
},
|
||||
query: queryFilter,
|
||||
}),
|
||||
{
|
||||
cacheTime: 1000 * 60,
|
||||
staleTime: 1000 * 60,
|
||||
},
|
||||
);
|
||||
songList = await getSongById({ id, queryClient, server });
|
||||
}
|
||||
} catch (err: any) {
|
||||
return toast.error({
|
||||
@ -153,24 +53,25 @@ export const useHandlePlayQueueAdd = () => {
|
||||
});
|
||||
}
|
||||
|
||||
if (!songsList) return toast.warn({ message: 'No songs found' });
|
||||
songs = songsList.items?.map((song: Song) => ({ ...song, uniqueId: nanoid() }));
|
||||
} else if (options.byData) {
|
||||
songs = options.byData.map((song) => ({ ...song, uniqueId: nanoid() }));
|
||||
songs = songList?.items?.map((song: Song) => ({ ...song, uniqueId: nanoid() })) || null;
|
||||
} else if (byData) {
|
||||
songs = byData.map((song) => ({ ...song, uniqueId: nanoid() }));
|
||||
}
|
||||
|
||||
if (!songs) return toast.warn({ message: 'No songs found' });
|
||||
|
||||
const playerData = usePlayerStore.getState().actions.addToQueue(songs, options.play);
|
||||
const playerData = addToQueue({ initialIndex: initialIndex || 0, playType, songs });
|
||||
|
||||
if (playerType === PlaybackType.LOCAL) {
|
||||
if (options.play === Play.NEXT || options.play === Play.LAST) {
|
||||
mpvPlayer.setQueueNext(playerData);
|
||||
mpvPlayer?.volume(usePlayerStore.getState().volume);
|
||||
|
||||
if (playType === Play.NEXT || playType === Play.LAST) {
|
||||
mpvPlayer?.setQueueNext(playerData);
|
||||
}
|
||||
|
||||
if (options.play === Play.NOW) {
|
||||
mpvPlayer.setQueue(playerData);
|
||||
mpvPlayer.play();
|
||||
if (playType === Play.NOW) {
|
||||
mpvPlayer?.setQueue(playerData);
|
||||
mpvPlayer?.play();
|
||||
}
|
||||
}
|
||||
|
||||
@ -184,21 +85,6 @@ export const useHandlePlayQueueAdd = () => {
|
||||
status: 'Playing',
|
||||
});
|
||||
|
||||
// if (fetchId) {
|
||||
// toast.update({
|
||||
// autoClose: 1000,
|
||||
// id: fetchId,
|
||||
// message: '',
|
||||
// title: `Added ${songs.length} items to the queue`,
|
||||
// });
|
||||
// // toast.hide(fetchId);
|
||||
// } else {
|
||||
// toast.success({
|
||||
// // message: 'Success',
|
||||
// title: `Added ${songs.length} items to the queue`,
|
||||
// });
|
||||
// }
|
||||
|
||||
return null;
|
||||
},
|
||||
[play, playerType, queryClient, server],
|
||||
|
@ -3,3 +3,4 @@ export * from './components/left-controls';
|
||||
export * from './components/playerbar';
|
||||
export * from './context/play-queue-handler-context';
|
||||
export * from './hooks/use-playqueue-add';
|
||||
export * from './utils';
|
||||
|
155
src/renderer/features/player/utils.ts
Normal file
155
src/renderer/features/player/utils.ts
Normal file
@ -0,0 +1,155 @@
|
||||
import { QueryClient } from '@tanstack/react-query';
|
||||
import { api } from '/@/renderer/api';
|
||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
||||
import {
|
||||
PlaylistSongListQuery,
|
||||
SongDetailQuery,
|
||||
SongListQuery,
|
||||
SongListResponse,
|
||||
SongListSort,
|
||||
SortOrder,
|
||||
} from '/@/renderer/api/types';
|
||||
import { ServerListItem } from '/@/renderer/types';
|
||||
|
||||
export const getPlaylistSongsById = async (args: {
|
||||
id: string;
|
||||
queryClient: QueryClient;
|
||||
server: ServerListItem;
|
||||
}) => {
|
||||
const { id, queryClient, server } = args;
|
||||
|
||||
const queryFilter: PlaylistSongListQuery = {
|
||||
id,
|
||||
sortBy: SongListSort.ID,
|
||||
sortOrder: SortOrder.ASC,
|
||||
startIndex: 0,
|
||||
};
|
||||
|
||||
const queryKey = queryKeys.playlists.songList(server?.id, id, queryFilter);
|
||||
|
||||
const res = await queryClient.fetchQuery(
|
||||
queryKey,
|
||||
async ({ signal }) =>
|
||||
api.controller.getPlaylistSongList({
|
||||
apiClientProps: {
|
||||
server,
|
||||
signal,
|
||||
},
|
||||
query: queryFilter,
|
||||
}),
|
||||
{
|
||||
cacheTime: 1000 * 60,
|
||||
staleTime: 1000 * 60,
|
||||
},
|
||||
);
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
export const getAlbumSongsById = async (args: {
|
||||
id: string[];
|
||||
orderByIds?: boolean;
|
||||
queryClient: QueryClient;
|
||||
server: ServerListItem;
|
||||
}) => {
|
||||
const { id, queryClient, server } = args;
|
||||
|
||||
const queryFilter: SongListQuery = {
|
||||
albumIds: id,
|
||||
sortBy: SongListSort.ALBUM,
|
||||
sortOrder: SortOrder.ASC,
|
||||
startIndex: 0,
|
||||
};
|
||||
|
||||
const queryKey = queryKeys.songs.list(server?.id, queryFilter);
|
||||
|
||||
const res = await queryClient.fetchQuery(
|
||||
queryKey,
|
||||
async ({ signal }) =>
|
||||
api.controller.getSongList({
|
||||
apiClientProps: {
|
||||
server,
|
||||
signal,
|
||||
},
|
||||
query: queryFilter,
|
||||
}),
|
||||
{
|
||||
cacheTime: 1000 * 60,
|
||||
staleTime: 1000 * 60,
|
||||
},
|
||||
);
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
export const getAlbumArtistSongsById = async (args: {
|
||||
id: string[];
|
||||
orderByIds?: boolean;
|
||||
queryClient: QueryClient;
|
||||
server: ServerListItem;
|
||||
}) => {
|
||||
const { id, queryClient, server } = args;
|
||||
|
||||
const queryFilter: SongListQuery = {
|
||||
artistIds: id || [],
|
||||
sortBy: SongListSort.ALBUM_ARTIST,
|
||||
sortOrder: SortOrder.ASC,
|
||||
startIndex: 0,
|
||||
};
|
||||
|
||||
const queryKey = queryKeys.songs.list(server?.id, queryFilter);
|
||||
|
||||
const res = await queryClient.fetchQuery(
|
||||
queryKey,
|
||||
async ({ signal }) =>
|
||||
api.controller.getSongList({
|
||||
apiClientProps: {
|
||||
server,
|
||||
signal,
|
||||
},
|
||||
query: queryFilter,
|
||||
}),
|
||||
{
|
||||
cacheTime: 1000 * 60,
|
||||
staleTime: 1000 * 60,
|
||||
},
|
||||
);
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
export const getSongById = async (args: {
|
||||
id: string;
|
||||
queryClient: QueryClient;
|
||||
server: ServerListItem;
|
||||
}): Promise<SongListResponse> => {
|
||||
const { id, queryClient, server } = args;
|
||||
|
||||
const queryFilter: SongDetailQuery = { id };
|
||||
|
||||
const queryKey = queryKeys.songs.detail(server?.id, queryFilter);
|
||||
|
||||
const res = await queryClient.fetchQuery(
|
||||
queryKey,
|
||||
async ({ signal }) =>
|
||||
api.controller.getSongDetail({
|
||||
apiClientProps: {
|
||||
server,
|
||||
signal,
|
||||
},
|
||||
query: queryFilter,
|
||||
}),
|
||||
{
|
||||
cacheTime: 1000 * 60,
|
||||
staleTime: 1000 * 60,
|
||||
},
|
||||
);
|
||||
|
||||
if (!res) throw new Error('Song not found');
|
||||
|
||||
return {
|
||||
items: [res],
|
||||
startIndex: 0,
|
||||
totalRecordCount: 1,
|
||||
};
|
||||
};
|
@ -96,7 +96,7 @@ export const usePlayerStore = create<PlayerSlice>()(
|
||||
immer((set, get) => ({
|
||||
actions: {
|
||||
addToQueue: (args) => {
|
||||
const { playType, songs } = args;
|
||||
const { initialIndex, playType, songs } = args;
|
||||
const { shuffledIndex } = get().current;
|
||||
const shuffledQueue = get().queue.shuffled;
|
||||
const queueSongs = map(songs, (song) => ({
|
||||
@ -107,29 +107,30 @@ export const usePlayerStore = create<PlayerSlice>()(
|
||||
if (playType === Play.NOW) {
|
||||
if (get().shuffle === PlayerShuffle.TRACK) {
|
||||
const shuffledSongs = shuffle(queueSongs);
|
||||
const foundIndex = queueSongs.findIndex(
|
||||
(song) => song.uniqueId === shuffledSongs[0].uniqueId,
|
||||
const index = initialIndex || 0;
|
||||
const initialSongUniqueId = queueSongs[index].uniqueId;
|
||||
const initialSongIndex = shuffledSongs.findIndex(
|
||||
(song) => song.uniqueId === initialSongUniqueId,
|
||||
);
|
||||
set((state) => {
|
||||
state.queue.shuffled = shuffledSongs.map((song) => song.uniqueId);
|
||||
});
|
||||
|
||||
set((state) => {
|
||||
state.queue.shuffled = shuffledSongs.map((song) => song.uniqueId);
|
||||
state.queue.default = queueSongs;
|
||||
state.current.time = 0;
|
||||
state.current.player = 1;
|
||||
state.current.index = foundIndex;
|
||||
state.current.index = initialSongIndex;
|
||||
state.current.shuffledIndex = 0;
|
||||
state.current.song = shuffledSongs[0];
|
||||
state.current.song = shuffledSongs[initialSongIndex];
|
||||
});
|
||||
} else {
|
||||
const index = initialIndex || 0;
|
||||
set((state) => {
|
||||
state.queue.default = queueSongs;
|
||||
state.current.time = 0;
|
||||
state.current.player = 1;
|
||||
state.current.index = 0;
|
||||
state.current.index = index;
|
||||
state.current.shuffledIndex = 0;
|
||||
state.current.song = queueSongs[0];
|
||||
state.current.song = queueSongs[index];
|
||||
});
|
||||
}
|
||||
} else if (playType === Play.LAST) {
|
||||
|
Loading…
Reference in New Issue
Block a user