mirror of
https://github.com/antebudimir/feishin.git
synced 2026-01-01 10:23:33 +00:00
enable reordering non-smart playlists
This commit is contained in:
parent
0b383b758e
commit
10fca2dc12
11 changed files with 148 additions and 0 deletions
|
|
@ -57,6 +57,7 @@ import type {
|
|||
Song,
|
||||
ServerType,
|
||||
ShareItemResponse,
|
||||
MoveItemArgs,
|
||||
} from '/@/renderer/api/types';
|
||||
import { DeletePlaylistResponse, RandomSongListArgs } from './types';
|
||||
import { ndController } from '/@/renderer/api/navidrome/navidrome-controller';
|
||||
|
|
@ -100,6 +101,7 @@ export type ControllerEndpoint = Partial<{
|
|||
getStructuredLyrics: (args: StructuredLyricsArgs) => Promise<StructuredLyric[]>;
|
||||
getTopSongs: (args: TopSongListArgs) => Promise<TopSongListResponse>;
|
||||
getUserList: (args: UserListArgs) => Promise<UserListResponse>;
|
||||
movePlaylistItem: (args: MoveItemArgs) => Promise<void>;
|
||||
removeFromPlaylist: (args: RemoveFromPlaylistArgs) => Promise<RemoveFromPlaylistResponse>;
|
||||
scrobble: (args: ScrobbleArgs) => Promise<ScrobbleResponse>;
|
||||
search: (args: SearchArgs) => Promise<SearchResponse>;
|
||||
|
|
@ -148,6 +150,7 @@ const endpoints: ApiController = {
|
|||
getStructuredLyrics: undefined,
|
||||
getTopSongs: jfController.getTopSongList,
|
||||
getUserList: undefined,
|
||||
movePlaylistItem: jfController.movePlaylistItem,
|
||||
removeFromPlaylist: jfController.removeFromPlaylist,
|
||||
scrobble: jfController.scrobble,
|
||||
search: jfController.search,
|
||||
|
|
@ -188,6 +191,7 @@ const endpoints: ApiController = {
|
|||
getStructuredLyrics: ssController.getStructuredLyrics,
|
||||
getTopSongs: ssController.getTopSongList,
|
||||
getUserList: ndController.getUserList,
|
||||
movePlaylistItem: ndController.movePlaylistItem,
|
||||
removeFromPlaylist: ndController.removeFromPlaylist,
|
||||
scrobble: ssController.scrobble,
|
||||
search: ssController.search3,
|
||||
|
|
@ -541,6 +545,15 @@ const getSimilarSongs = async (args: SimilarSongsArgs) => {
|
|||
)?.(args);
|
||||
};
|
||||
|
||||
const movePlaylistItem = async (args: MoveItemArgs) => {
|
||||
return (
|
||||
apiController(
|
||||
'movePlaylistItem',
|
||||
args.apiClientProps.server?.type,
|
||||
) as ControllerEndpoint['movePlaylistItem']
|
||||
)?.(args);
|
||||
};
|
||||
|
||||
export const controller = {
|
||||
addToPlaylist,
|
||||
authenticate,
|
||||
|
|
@ -567,6 +580,7 @@ export const controller = {
|
|||
getStructuredLyrics,
|
||||
getTopSongList,
|
||||
getUserList,
|
||||
movePlaylistItem,
|
||||
removeFromPlaylist,
|
||||
scrobble,
|
||||
search,
|
||||
|
|
|
|||
|
|
@ -226,6 +226,15 @@ export const contract = c.router({
|
|||
400: jfType._response.error,
|
||||
},
|
||||
},
|
||||
movePlaylistItem: {
|
||||
body: null,
|
||||
method: 'POST',
|
||||
path: 'playlists/:playlistId/items/:itemId/move/:newIdx',
|
||||
responses: {
|
||||
200: jfType._response.moveItem,
|
||||
400: jfType._response.error,
|
||||
},
|
||||
},
|
||||
removeFavorite: {
|
||||
body: jfType._parameters.favorite,
|
||||
method: 'DELETE',
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ import {
|
|||
ServerInfoArgs,
|
||||
SimilarSongsArgs,
|
||||
Song,
|
||||
MoveItemArgs,
|
||||
} from '/@/renderer/api/types';
|
||||
import { jfApiClient } from '/@/renderer/api/jellyfin/jellyfin-api';
|
||||
import { jfNormalize } from './jellyfin-normalize';
|
||||
|
|
@ -1025,6 +1026,23 @@ const getSimilarSongs = async (args: SimilarSongsArgs): Promise<Song[]> => {
|
|||
}, []);
|
||||
};
|
||||
|
||||
const movePlaylistItem = async (args: MoveItemArgs): Promise<void> => {
|
||||
const { apiClientProps, query } = args;
|
||||
|
||||
const res = await jfApiClient(apiClientProps).movePlaylistItem({
|
||||
body: null,
|
||||
params: {
|
||||
itemId: query.trackId,
|
||||
newIdx: query.endingIndex.toString(),
|
||||
playlistId: query.playlistId,
|
||||
},
|
||||
});
|
||||
|
||||
if (res.status !== 204) {
|
||||
throw new Error('Failed to move item in playlist');
|
||||
}
|
||||
};
|
||||
|
||||
export const jfController = {
|
||||
addToPlaylist,
|
||||
authenticate,
|
||||
|
|
@ -1049,6 +1067,7 @@ export const jfController = {
|
|||
getSongDetail,
|
||||
getSongList,
|
||||
getTopSongList,
|
||||
movePlaylistItem,
|
||||
removeFromPlaylist,
|
||||
scrobble,
|
||||
search,
|
||||
|
|
|
|||
|
|
@ -681,6 +681,8 @@ export enum JellyfinExtensions {
|
|||
SONG_LYRICS = 'songLyrics',
|
||||
}
|
||||
|
||||
const moveItem = z.null();
|
||||
|
||||
export const jfType = {
|
||||
_enum: {
|
||||
albumArtistList: albumArtistListSort,
|
||||
|
|
@ -729,6 +731,7 @@ export const jfType = {
|
|||
genre,
|
||||
genreList,
|
||||
lyrics,
|
||||
moveItem,
|
||||
musicFolderList,
|
||||
playlist,
|
||||
playlistList,
|
||||
|
|
|
|||
|
|
@ -147,6 +147,15 @@ export const contract = c.router({
|
|||
500: resultWithHeaders(ndType._response.error),
|
||||
},
|
||||
},
|
||||
movePlaylistItem: {
|
||||
body: ndType._parameters.moveItem,
|
||||
method: 'PUT',
|
||||
path: 'playlist/:playlistId/tracks/:trackNumber',
|
||||
responses: {
|
||||
200: resultWithHeaders(ndType._response.moveItem),
|
||||
400: resultWithHeaders(ndType._response.error),
|
||||
},
|
||||
},
|
||||
removeFromPlaylist: {
|
||||
body: null,
|
||||
method: 'DELETE',
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ import {
|
|||
ShareItemResponse,
|
||||
SimilarSongsArgs,
|
||||
Song,
|
||||
MoveItemArgs,
|
||||
} from '../types';
|
||||
import { VersionInfo, getFeatures, hasFeature } from '/@/renderer/api/utils';
|
||||
import { ServerFeature, ServerFeatures } from '/@/renderer/api/features-types';
|
||||
|
|
@ -613,6 +614,24 @@ const getSimilarSongs = async (args: SimilarSongsArgs): Promise<Song[]> => {
|
|||
}, []);
|
||||
};
|
||||
|
||||
const movePlaylistItem = async (args: MoveItemArgs): Promise<void> => {
|
||||
const { apiClientProps, query } = args;
|
||||
|
||||
const res = await ndApiClient(apiClientProps).movePlaylistItem({
|
||||
body: {
|
||||
insert_before: (query.endingIndex + 1).toString(),
|
||||
},
|
||||
params: {
|
||||
playlistId: query.playlistId,
|
||||
trackNumber: query.startingIndex.toString(),
|
||||
},
|
||||
});
|
||||
|
||||
if (res.status !== 200) {
|
||||
throw new Error('Failed to move item in playlist');
|
||||
}
|
||||
};
|
||||
|
||||
export const ndController = {
|
||||
addToPlaylist,
|
||||
authenticate,
|
||||
|
|
@ -631,6 +650,7 @@ export const ndController = {
|
|||
getSongDetail,
|
||||
getSongList,
|
||||
getUserList,
|
||||
movePlaylistItem,
|
||||
removeFromPlaylist,
|
||||
shareItem,
|
||||
updatePlaylist,
|
||||
|
|
|
|||
|
|
@ -355,6 +355,12 @@ const shareItemParameters = z.object({
|
|||
resourceType: z.string(),
|
||||
});
|
||||
|
||||
const moveItemParameters = z.object({
|
||||
insert_before: z.string(),
|
||||
});
|
||||
|
||||
const moveItem = z.null();
|
||||
|
||||
export const ndType = {
|
||||
_enum: {
|
||||
albumArtistList: ndAlbumArtistListSort,
|
||||
|
|
@ -371,6 +377,7 @@ export const ndType = {
|
|||
authenticate: authenticateParameters,
|
||||
createPlaylist: createPlaylistParameters,
|
||||
genreList: genreListParameters,
|
||||
moveItem: moveItemParameters,
|
||||
playlistList: playlistListParameters,
|
||||
removeFromPlaylist: removeFromPlaylistParameters,
|
||||
shareItem: shareItemParameters,
|
||||
|
|
@ -390,6 +397,7 @@ export const ndType = {
|
|||
error,
|
||||
genre,
|
||||
genreList,
|
||||
moveItem,
|
||||
playlist,
|
||||
playlistList,
|
||||
playlistSong,
|
||||
|
|
|
|||
|
|
@ -1191,3 +1191,14 @@ export type SimilarSongsQuery = {
|
|||
export type SimilarSongsArgs = {
|
||||
query: SimilarSongsQuery;
|
||||
} & BaseEndpointArgs;
|
||||
|
||||
export type MoveItemQuery = {
|
||||
endingIndex: number;
|
||||
playlistId: string;
|
||||
startingIndex: number;
|
||||
trackId: string;
|
||||
};
|
||||
|
||||
export type MoveItemArgs = {
|
||||
query: MoveItemQuery;
|
||||
} & BaseEndpointArgs;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue