mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-14 20:40:21 +02:00
support navidrome playlist image upload
This commit is contained in:
@@ -8,6 +8,8 @@ import { useListContext } from '/@/renderer/context/list-context';
|
||||
import { usePlayer } from '/@/renderer/features/player/context/player-context';
|
||||
import { playlistsQueries } from '/@/renderer/features/playlists/api/playlists-api';
|
||||
import { PlaylistDetailSongListHeaderFilters } from '/@/renderer/features/playlists/components/playlist-detail-song-list-header-filters';
|
||||
import { useDeletePlaylistImage } from '/@/renderer/features/playlists/mutations/delete-playlist-image-mutation';
|
||||
import { useUploadPlaylistImage } from '/@/renderer/features/playlists/mutations/upload-playlist-image-mutation';
|
||||
import { FilterBar } from '/@/renderer/features/shared/components/filter-bar';
|
||||
import {
|
||||
LibraryHeader,
|
||||
@@ -18,9 +20,14 @@ import { ListSearchInput } from '/@/renderer/features/shared/components/list-sea
|
||||
import { AppRoute } from '/@/renderer/router/routes';
|
||||
import { useCurrentServer } from '/@/renderer/store';
|
||||
import { formatDurationString } from '/@/renderer/utils';
|
||||
import { hasFeature } from '/@/shared/api/utils';
|
||||
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
|
||||
import { FileButton } from '/@/shared/components/file-button/file-button';
|
||||
import { Group } from '/@/shared/components/group/group';
|
||||
import { Stack } from '/@/shared/components/stack/stack';
|
||||
import { useLocalStorage } from '/@/shared/hooks/use-local-storage';
|
||||
import { LibraryItem, Song } from '/@/shared/types/domain-types';
|
||||
import { LibraryItem, Playlist, Song } from '/@/shared/types/domain-types';
|
||||
import { ServerFeature } from '/@/shared/types/features-types';
|
||||
import { Play } from '/@/shared/types/types';
|
||||
|
||||
interface PlaylistDetailSongListHeaderProps {
|
||||
@@ -30,6 +37,64 @@ interface PlaylistDetailSongListHeaderProps {
|
||||
onToggleQueryBuilder?: () => void;
|
||||
}
|
||||
|
||||
function ImageUploadOverlay({ data }: { data?: Playlist }) {
|
||||
const uploadPlaylistImageMutation = useUploadPlaylistImage({});
|
||||
const deletePlaylistImageMutation = useDeletePlaylistImage({});
|
||||
const server = useCurrentServer();
|
||||
|
||||
if (!data) return null;
|
||||
if (!hasFeature(server, ServerFeature.PLAYLIST_IMAGE_UPLOAD)) return null;
|
||||
|
||||
return (
|
||||
<Group gap="xs">
|
||||
<FileButton
|
||||
accept="image/*"
|
||||
onChange={async (file) => {
|
||||
if (!file || !data?._serverId) return;
|
||||
|
||||
const buffer = await file.arrayBuffer();
|
||||
uploadPlaylistImageMutation.mutate({
|
||||
apiClientProps: {
|
||||
serverId: data._serverId,
|
||||
},
|
||||
body: { image: new Uint8Array(buffer) },
|
||||
query: { id: data.id },
|
||||
});
|
||||
}}
|
||||
>
|
||||
{(props) => (
|
||||
<ActionIcon
|
||||
icon="uploadImage"
|
||||
iconProps={{ size: 'lg' }}
|
||||
radius="xl"
|
||||
size="xs"
|
||||
variant="default"
|
||||
{...props}
|
||||
/>
|
||||
)}
|
||||
</FileButton>
|
||||
<ActionIcon
|
||||
disabled={!data?.uploadedImage}
|
||||
icon="delete"
|
||||
iconProps={{ size: 'lg' }}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
if (!data?._serverId) return;
|
||||
deletePlaylistImageMutation.mutate({
|
||||
apiClientProps: {
|
||||
serverId: data._serverId,
|
||||
},
|
||||
query: { id: data.id },
|
||||
});
|
||||
}}
|
||||
radius="xl"
|
||||
size="xs"
|
||||
variant="default"
|
||||
/>
|
||||
</Group>
|
||||
);
|
||||
}
|
||||
|
||||
export const PlaylistDetailSongListHeader = ({
|
||||
isSmartPlaylist,
|
||||
}: PlaylistDetailSongListHeaderProps) => {
|
||||
@@ -94,6 +159,7 @@ export const PlaylistDetailSongListHeader = ({
|
||||
) : (
|
||||
<LibraryHeader
|
||||
compact
|
||||
imageOverlay={<ImageUploadOverlay data={detailQuery?.data} />}
|
||||
imageUrl={imageUrl}
|
||||
item={{
|
||||
imageId: detailQuery?.data?.imageId,
|
||||
|
||||
Reference in New Issue
Block a user