From 633c9f59d94735a4da30869b391dde671bdc1d7f Mon Sep 17 00:00:00 2001 From: jeffvli Date: Tue, 3 Jan 2023 03:25:21 -0800 Subject: [PATCH] Add update playlist for jellyfin --- src/renderer/api/controller.ts | 2 +- src/renderer/api/jellyfin.api.ts | 38 ++++++++++++-- src/renderer/api/navidrome.api.ts | 1 + src/renderer/api/types.ts | 2 + .../components/playlist-detail-header.tsx | 49 ++++++++++++++----- 5 files changed, 74 insertions(+), 18 deletions(-) diff --git a/src/renderer/api/controller.ts b/src/renderer/api/controller.ts index 51dbb5ea..7f0ca36e 100644 --- a/src/renderer/api/controller.ts +++ b/src/renderer/api/controller.ts @@ -96,7 +96,7 @@ const endpoints: ApiController = { getPlaylistSongList: jellyfinApi.getPlaylistSongList, getSongDetail: undefined, getSongList: jellyfinApi.getSongList, - updatePlaylist: undefined, + updatePlaylist: jellyfinApi.updatePlaylist, updateRating: undefined, }, navidrome: { diff --git a/src/renderer/api/jellyfin.api.ts b/src/renderer/api/jellyfin.api.ts index 148e192a..91c5b224 100644 --- a/src/renderer/api/jellyfin.api.ts +++ b/src/renderer/api/jellyfin.api.ts @@ -61,6 +61,8 @@ import { artistListSortMap, sortOrderMap, albumArtistListSortMap, + UpdatePlaylistArgs, + UpdatePlaylistResponse, } from '/@/renderer/api/types'; import { useAuthStore } from '/@/renderer/store'; import { ServerListItem, ServerType } from '/@/renderer/types'; @@ -312,9 +314,6 @@ const getSongList = async (args: SongListArgs): Promise => { } } - console.log('yearsGroup :>> ', yearsGroup); - console.log('albumIds', query.albumIds); - console.log('artistIds :>> ', query.artistIds); const yearsFilter = yearsGroup.length ? getCommaDelimitedString(yearsGroup) : undefined; const albumIdsFilter = query.albumIds ? getCommaDelimitedString(query.albumIds) : undefined; const artistIdsFilter = query.artistIds ? getCommaDelimitedString(query.artistIds) : undefined; @@ -457,6 +456,33 @@ const createPlaylist = async (args: CreatePlaylistArgs): Promise => { + const { query, body, server } = args; + + const json = { + Genres: body.genres?.map((item) => ({ Id: item.id, Name: item.name })) || [], + MediaType: 'Audio', + Name: body.name, + Overview: body.comment || '', + PremiereDate: null, + ProviderIds: {}, + Tags: [], + UserId: server?.userId, // Required + }; + + await api + .post(`items/${query.id}`, { + headers: { 'X-MediaBrowser-Token': server?.credential }, + json, + prefixUrl: server?.url, + }) + .json(); + + return { + id: query.id, + }; +}; + const deletePlaylist = async (args: DeletePlaylistArgs): Promise => { const { query, server } = args; @@ -728,10 +754,11 @@ const normalizePlaylist = ( return { description: item.Overview || null, - duration: item.RunTimeTicks / 10000000, + duration: item.RunTimeTicks / 10000, + genres: item.GenreItems?.map((entry) => ({ id: entry.Id, name: entry.Name })), id: item.Id, imagePlaceholderUrl, - imageUrl, + imageUrl: imageUrl || null, name: item.Name, public: null, rules: null, @@ -809,6 +836,7 @@ export const jellyfinApi = { getPlaylistList, getPlaylistSongList, getSongList, + updatePlaylist, }; export const jfNormalize = { diff --git a/src/renderer/api/navidrome.api.ts b/src/renderer/api/navidrome.api.ts index 03e7df62..9ee4bd0d 100644 --- a/src/renderer/api/navidrome.api.ts +++ b/src/renderer/api/navidrome.api.ts @@ -578,6 +578,7 @@ const normalizePlaylist = ( return { description: item.comment, duration: item.duration * 1000, + genres: [], id: item.id, imagePlaceholderUrl, imageUrl, diff --git a/src/renderer/api/types.ts b/src/renderer/api/types.ts index 8003080f..190aec59 100644 --- a/src/renderer/api/types.ts +++ b/src/renderer/api/types.ts @@ -237,6 +237,7 @@ export type MusicFolder = { export type Playlist = { description: string | null; duration: number | null; + genres: Genre[]; id: string; imagePlaceholderUrl: string | null; imageUrl: string | null; @@ -758,6 +759,7 @@ export type UpdatePlaylistQuery = { export type UpdatePlaylistBody = { comment?: string; + genres?: Genre[]; name: string; public?: boolean; rules?: Record; diff --git a/src/renderer/features/playlists/components/playlist-detail-header.tsx b/src/renderer/features/playlists/components/playlist-detail-header.tsx index 55da7f3e..8a3df147 100644 --- a/src/renderer/features/playlists/components/playlist-detail-header.tsx +++ b/src/renderer/features/playlists/components/playlist-detail-header.tsx @@ -1,10 +1,10 @@ import { Group, Stack } from '@mantine/core'; import { closeAllModals, openModal } from '@mantine/modals'; -import { forwardRef, Ref } from 'react'; +import { forwardRef, Fragment, Ref } from 'react'; import { RiMoreFill } from 'react-icons/ri'; import { generatePath, useNavigate, useParams } from 'react-router'; import { Link } from 'react-router-dom'; -import { DropdownMenu, Button, ConfirmModal, toast } from '/@/renderer/components'; +import { DropdownMenu, Button, ConfirmModal, toast, Text } from '/@/renderer/components'; import { usePlayQueueAdd } from '/@/renderer/features/player'; import { UpdatePlaylistForm } from './update-playlist-form'; import { useDeletePlaylist } from '/@/renderer/features/playlists/mutations/delete-playlist-mutation'; @@ -13,6 +13,7 @@ import { LibraryHeader, PlayButton, PLAY_TYPES } from '/@/renderer/features/shar import { AppRoute } from '/@/renderer/router/routes'; import { usePlayButtonBehavior } from '/@/renderer/store/settings.store'; import { LibraryItem, Play } from '/@/renderer/types'; +import { formatDurationString } from '/@/renderer/utils'; interface PlaylistDetailHeaderProps { background: string; @@ -47,6 +48,7 @@ export const PlaylistDetailHeader = forwardRef( - - - + + + {metadataItems.map((item, index) => ( + + {index > 0 && } + {item.value} + + ))} + + {detailQuery?.data?.description} + Delete playlist + +