Add ability to add/remove songs from playlist (#17)

* Add api for add/remove playlist items

* Add playlistItemId property to normalized Song

- This is used for Navidrome to delete songs from playlists

* Add mutations for add/remove from playlist

* Add context modal for playlist add

* Add remove from playlist from context menu

* Set jellyfin to use playlistItemId

* Adjust font sizing

* Add playlist add from detail pages

* Bump mantine to v6-alpha.2
This commit is contained in:
Jeff
2023-01-29 18:40:26 -08:00
committed by GitHub
parent be39c2bc1f
commit 59f4f43e84
23 changed files with 1120 additions and 982 deletions
+48
View File
@@ -1,6 +1,8 @@
import ky from 'ky';
import { nanoid } from 'nanoid/non-secure';
import type {
JFAddToPlaylist,
JFAddToPlaylistParams,
JFAlbum,
JFAlbumArtist,
JFAlbumArtistDetail,
@@ -27,6 +29,8 @@ import type {
JFPlaylistDetailResponse,
JFPlaylistList,
JFPlaylistListResponse,
JFRemoveFromPlaylist,
JFRemoveFromPlaylistParams,
JFSong,
JFSongList,
JFSongListParams,
@@ -64,6 +68,8 @@ import {
UpdatePlaylistArgs,
UpdatePlaylistResponse,
LibraryItem,
RemoveFromPlaylistArgs,
AddToPlaylistArgs,
} from '/@/renderer/api/types';
import { useAuthStore } from '/@/renderer/store';
import { ServerListItem, ServerType } from '/@/renderer/types';
@@ -362,6 +368,45 @@ const getSongList = async (args: SongListArgs): Promise<JFSongList> => {
};
};
const addToPlaylist = async (args: AddToPlaylistArgs): Promise<JFAddToPlaylist> => {
const { query, body, server, signal } = args;
const searchParams: JFAddToPlaylistParams = {
ids: body.songId,
userId: server?.userId || '',
};
await api
.post(`playlists/${query.id}/items`, {
headers: { 'X-MediaBrowser-Token': server?.credential },
prefixUrl: server?.url,
searchParams: parseSearchParams(searchParams),
signal,
})
.json<JFPlaylistDetailResponse>();
return null;
};
const removeFromPlaylist = async (args: RemoveFromPlaylistArgs): Promise<JFRemoveFromPlaylist> => {
const { query, server, signal } = args;
const searchParams: JFRemoveFromPlaylistParams = {
entryIds: query.songId,
};
await api
.delete(`playlists/${query.id}/items`, {
headers: { 'X-MediaBrowser-Token': server?.credential },
prefixUrl: server?.url,
searchParams: parseSearchParams(searchParams),
signal,
})
.json<JFPlaylistDetailResponse>();
return null;
};
const getPlaylistDetail = async (args: PlaylistDetailArgs): Promise<JFPlaylistDetail> => {
const { query, server, signal } = args;
@@ -677,6 +722,7 @@ const normalizeSong = (
name: item.Name,
path: (item.MediaSources && item.MediaSources[0]?.Path) || null,
playCount: (item.UserData && item.UserData.PlayCount) || 0,
playlistItemId: item.PlaylistItemId,
// releaseDate: (item.ProductionYear && new Date(item.ProductionYear, 0, 1).toISOString()) || null,
releaseDate: null,
releaseYear: item.ProductionYear ? String(item.ProductionYear) : null,
@@ -863,6 +909,7 @@ const normalizePlaylist = (
// };
export const jellyfinApi = {
addToPlaylist,
authenticate,
createFavorite,
createPlaylist,
@@ -879,6 +926,7 @@ export const jellyfinApi = {
getPlaylistList,
getPlaylistSongList,
getSongList,
removeFromPlaylist,
updatePlaylist,
};