mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-09 20:29:36 +02:00
move all domain types to separate files
This commit is contained in:
@@ -1,517 +0,0 @@
|
|||||||
import orderBy from 'lodash/orderBy';
|
|
||||||
import reverse from 'lodash/reverse';
|
|
||||||
import shuffle from 'lodash/shuffle';
|
|
||||||
|
|
||||||
import {
|
|
||||||
AlbumArtistDetailArgs,
|
|
||||||
AlbumArtistDetailResponse,
|
|
||||||
AlbumArtistListArgs,
|
|
||||||
AlbumArtistListResponse,
|
|
||||||
AlbumArtistListSort,
|
|
||||||
ArtistListArgs,
|
|
||||||
ArtistListResponse,
|
|
||||||
ArtistListSort,
|
|
||||||
} from './domain/artist-domain-types';
|
|
||||||
|
|
||||||
import { JFSortOrder } from '/@/shared/api/jellyfin.types';
|
|
||||||
import { NDSortOrder } from '/@/shared/api/navidrome.types';
|
|
||||||
import {
|
|
||||||
Album,
|
|
||||||
AlbumDetailArgs,
|
|
||||||
AlbumDetailResponse,
|
|
||||||
AlbumInfo,
|
|
||||||
AlbumListArgs,
|
|
||||||
AlbumListResponse,
|
|
||||||
AlbumListSort,
|
|
||||||
} from '/@/shared/types/domain/album-domain-types';
|
|
||||||
import { AlbumArtist, Artist } from '/@/shared/types/domain/artist-domain-types';
|
|
||||||
import { GenreListArgs, GenreListResponse } from '/@/shared/types/domain/genre-domain-types';
|
|
||||||
import {
|
|
||||||
LyricsArgs,
|
|
||||||
LyricsResponse,
|
|
||||||
StructuredLyric,
|
|
||||||
StructuredLyricsArgs,
|
|
||||||
} from '/@/shared/types/domain/lyric-domain-types';
|
|
||||||
import {
|
|
||||||
AddToPlaylistArgs,
|
|
||||||
AddToPlaylistResponse,
|
|
||||||
CreatePlaylistArgs,
|
|
||||||
CreatePlaylistResponse,
|
|
||||||
DeletePlaylistArgs,
|
|
||||||
DeletePlaylistResponse,
|
|
||||||
Playlist,
|
|
||||||
PlaylistDetailArgs,
|
|
||||||
PlaylistDetailResponse,
|
|
||||||
PlaylistListArgs,
|
|
||||||
PlaylistListResponse,
|
|
||||||
PlaylistSongListArgs,
|
|
||||||
RemoveFromPlaylistArgs,
|
|
||||||
RemoveFromPlaylistResponse,
|
|
||||||
UpdatePlaylistArgs,
|
|
||||||
UpdatePlaylistResponse,
|
|
||||||
} from '/@/shared/types/domain/playlist-domain-types';
|
|
||||||
import { SearchArgs, SearchResponse } from '/@/shared/types/domain/search-domain-types';
|
|
||||||
import {
|
|
||||||
ServerInfo,
|
|
||||||
ServerInfoArgs,
|
|
||||||
ServerListItem,
|
|
||||||
ServerMusicFolderListArgs,
|
|
||||||
ServerMusicFolderListResponse,
|
|
||||||
} from '/@/shared/types/domain/server-domain-types';
|
|
||||||
import { ListSortOrder } from '/@/shared/types/domain/shared-domain-types';
|
|
||||||
import {
|
|
||||||
RandomSongListArgs,
|
|
||||||
SimilarSongsArgs,
|
|
||||||
Song,
|
|
||||||
SongDetailArgs,
|
|
||||||
SongDetailResponse,
|
|
||||||
SongListArgs,
|
|
||||||
SongListResponse,
|
|
||||||
SongListSort,
|
|
||||||
TopSongListArgs,
|
|
||||||
TopSongListResponse,
|
|
||||||
} from '/@/shared/types/domain/song-domain-types';
|
|
||||||
import {
|
|
||||||
FavoriteArgs,
|
|
||||||
FavoriteResponse,
|
|
||||||
RatingResponse,
|
|
||||||
ScrobbleArgs,
|
|
||||||
ScrobbleResponse,
|
|
||||||
SetRatingArgs,
|
|
||||||
UserListArgs,
|
|
||||||
UserListResponse,
|
|
||||||
} from '/@/shared/types/domain/user-domain-types';
|
|
||||||
import { PlayerStatus } from '/@/shared/types/types';
|
|
||||||
|
|
||||||
export enum LibraryItem {
|
|
||||||
ALBUM = 'album',
|
|
||||||
ALBUM_ARTIST = 'albumArtist',
|
|
||||||
ARTIST = 'artist',
|
|
||||||
GENRE = 'genre',
|
|
||||||
PLAYLIST = 'playlist',
|
|
||||||
SONG = 'song',
|
|
||||||
}
|
|
||||||
|
|
||||||
export type AnyLibraryItem = Album | AlbumArtist | Artist | Playlist | QueueSong | Song;
|
|
||||||
|
|
||||||
export type AnyLibraryItems =
|
|
||||||
| Album[]
|
|
||||||
| AlbumArtist[]
|
|
||||||
| Artist[]
|
|
||||||
| Playlist[]
|
|
||||||
| QueueSong[]
|
|
||||||
| Song[];
|
|
||||||
|
|
||||||
export interface PlayerData {
|
|
||||||
current: {
|
|
||||||
index: number;
|
|
||||||
nextIndex?: number;
|
|
||||||
player: 1 | 2;
|
|
||||||
previousIndex?: number;
|
|
||||||
shuffledIndex: number;
|
|
||||||
song?: QueueSong;
|
|
||||||
status: PlayerStatus;
|
|
||||||
};
|
|
||||||
player1?: QueueSong;
|
|
||||||
player2?: QueueSong;
|
|
||||||
queue: QueueData;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface QueueData {
|
|
||||||
current?: QueueSong;
|
|
||||||
length: number;
|
|
||||||
next?: QueueSong;
|
|
||||||
previous?: QueueSong;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type QueueSong = Song & {
|
|
||||||
uniqueId: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type SortOrderMap = {
|
|
||||||
jellyfin: Record<ListSortOrder, JFSortOrder>;
|
|
||||||
navidrome: Record<ListSortOrder, NDSortOrder>;
|
|
||||||
subsonic: Record<ListSortOrder, undefined>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const sortOrderMap: SortOrderMap = {
|
|
||||||
jellyfin: {
|
|
||||||
ASC: JFSortOrder.ASC,
|
|
||||||
DESC: JFSortOrder.DESC,
|
|
||||||
},
|
|
||||||
navidrome: {
|
|
||||||
ASC: NDSortOrder.ASC,
|
|
||||||
DESC: NDSortOrder.DESC,
|
|
||||||
},
|
|
||||||
subsonic: {
|
|
||||||
ASC: undefined,
|
|
||||||
DESC: undefined,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export enum ExternalSource {
|
|
||||||
LASTFM = 'LASTFM',
|
|
||||||
MUSICBRAINZ = 'MUSICBRAINZ',
|
|
||||||
SPOTIFY = 'SPOTIFY',
|
|
||||||
THEAUDIODB = 'THEAUDIODB',
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum ExternalType {
|
|
||||||
ID = 'ID',
|
|
||||||
LINK = 'LINK',
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum ImageType {
|
|
||||||
BACKDROP = 'BACKDROP',
|
|
||||||
LOGO = 'LOGO',
|
|
||||||
PRIMARY = 'PRIMARY',
|
|
||||||
SCREENSHOT = 'SCREENSHOT',
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum Played {
|
|
||||||
All = 'all',
|
|
||||||
Never = 'never',
|
|
||||||
Played = 'played',
|
|
||||||
}
|
|
||||||
|
|
||||||
export type AuthenticationResponse = {
|
|
||||||
credential: string;
|
|
||||||
ndCredential?: string;
|
|
||||||
userId: null | string;
|
|
||||||
username: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type BaseEndpointArgs = {
|
|
||||||
apiClientProps: {
|
|
||||||
server: null | ServerListItem;
|
|
||||||
signal?: AbortSignal;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface BasePaginatedResponse<T> {
|
|
||||||
error?: any | string;
|
|
||||||
items: T;
|
|
||||||
startIndex: number;
|
|
||||||
totalRecordCount: null | number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface BaseQuery<T> {
|
|
||||||
sortBy: T;
|
|
||||||
sortOrder: ListSortOrder;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type EndpointDetails = {
|
|
||||||
server: ServerListItem;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type GainInfo = {
|
|
||||||
album?: number;
|
|
||||||
track?: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ShareItemArgs = BaseEndpointArgs & { body: ShareItemBody; serverId?: string };
|
|
||||||
|
|
||||||
export type ShareItemBody = {
|
|
||||||
description: string;
|
|
||||||
downloadable: boolean;
|
|
||||||
expires: number;
|
|
||||||
resourceIds: string;
|
|
||||||
resourceType: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ShareItemResponse = undefined | { id: string };
|
|
||||||
|
|
||||||
export const instanceOfCancellationError = (error: any) => {
|
|
||||||
return 'revert' in error;
|
|
||||||
};
|
|
||||||
|
|
||||||
export enum LyricSource {
|
|
||||||
GENIUS = 'Genius',
|
|
||||||
LRCLIB = 'lrclib.net',
|
|
||||||
NETEASE = 'NetEase',
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ControllerEndpoint = {
|
|
||||||
addToPlaylist: (args: AddToPlaylistArgs) => Promise<AddToPlaylistResponse>;
|
|
||||||
authenticate: (
|
|
||||||
url: string,
|
|
||||||
body: { legacy?: boolean; password: string; username: string },
|
|
||||||
) => Promise<AuthenticationResponse>;
|
|
||||||
createFavorite: (args: FavoriteArgs) => Promise<FavoriteResponse>;
|
|
||||||
createPlaylist: (args: CreatePlaylistArgs) => Promise<CreatePlaylistResponse>;
|
|
||||||
deleteFavorite: (args: FavoriteArgs) => Promise<FavoriteResponse>;
|
|
||||||
deletePlaylist: (args: DeletePlaylistArgs) => Promise<DeletePlaylistResponse>;
|
|
||||||
getAlbumArtistDetail: (args: AlbumArtistDetailArgs) => Promise<AlbumArtistDetailResponse>;
|
|
||||||
getAlbumArtistList: (args: AlbumArtistListArgs) => Promise<AlbumArtistListResponse>;
|
|
||||||
getAlbumArtistListCount: (args: AlbumArtistListArgs) => Promise<number>;
|
|
||||||
getAlbumDetail: (args: AlbumDetailArgs) => Promise<AlbumDetailResponse>;
|
|
||||||
getAlbumInfo?: (args: AlbumDetailArgs) => Promise<AlbumInfo>;
|
|
||||||
getAlbumList: (args: AlbumListArgs) => Promise<AlbumListResponse>;
|
|
||||||
getAlbumListCount: (args: AlbumListArgs) => Promise<number>;
|
|
||||||
// getArtistInfo?: (args: any) => void;
|
|
||||||
getArtistList: (args: ArtistListArgs) => Promise<ArtistListResponse>;
|
|
||||||
getArtistListCount: (args: ArtistListArgs) => Promise<number>;
|
|
||||||
getDownloadUrl: (args: DownloadArgs) => string;
|
|
||||||
getGenreList: (args: GenreListArgs) => Promise<GenreListResponse>;
|
|
||||||
getLyrics?: (args: LyricsArgs) => Promise<LyricsResponse>;
|
|
||||||
getMusicFolderList: (args: ServerMusicFolderListArgs) => Promise<ServerMusicFolderListResponse>;
|
|
||||||
getPlaylistDetail: (args: PlaylistDetailArgs) => Promise<PlaylistDetailResponse>;
|
|
||||||
getPlaylistList: (args: PlaylistListArgs) => Promise<PlaylistListResponse>;
|
|
||||||
getPlaylistListCount: (args: PlaylistListArgs) => Promise<number>;
|
|
||||||
getPlaylistSongList: (args: PlaylistSongListArgs) => Promise<SongListResponse>;
|
|
||||||
getRandomSongList: (args: RandomSongListArgs) => Promise<SongListResponse>;
|
|
||||||
getRoles: (args: BaseEndpointArgs) => Promise<Array<string | { label: string; value: string }>>;
|
|
||||||
getServerInfo: (args: ServerInfoArgs) => Promise<ServerInfo>;
|
|
||||||
getSimilarSongs: (args: SimilarSongsArgs) => Promise<Song[]>;
|
|
||||||
getSongDetail: (args: SongDetailArgs) => Promise<SongDetailResponse>;
|
|
||||||
getSongList: (args: SongListArgs) => Promise<SongListResponse>;
|
|
||||||
getSongListCount: (args: SongListArgs) => Promise<number>;
|
|
||||||
getStructuredLyrics?: (args: StructuredLyricsArgs) => Promise<StructuredLyric[]>;
|
|
||||||
getTags?: (args: TagArgs) => Promise<TagResponses>;
|
|
||||||
getTopSongs: (args: TopSongListArgs) => Promise<TopSongListResponse>;
|
|
||||||
getTranscodingUrl: (args: TranscodingArgs) => string;
|
|
||||||
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>;
|
|
||||||
setRating?: (args: SetRatingArgs) => Promise<RatingResponse>;
|
|
||||||
shareItem?: (args: ShareItemArgs) => Promise<ShareItemResponse>;
|
|
||||||
updatePlaylist: (args: UpdatePlaylistArgs) => Promise<UpdatePlaylistResponse>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type DownloadArgs = BaseEndpointArgs & {
|
|
||||||
query: DownloadQuery;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type DownloadQuery = {
|
|
||||||
id: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
// This type from https://wicg.github.io/local-font-access/#fontdata
|
|
||||||
// NOTE: it is still experimental, so this should be updates as appropriate
|
|
||||||
export type FontData = {
|
|
||||||
family: string;
|
|
||||||
fullName: string;
|
|
||||||
postscriptName: string;
|
|
||||||
style: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type MoveItemArgs = BaseEndpointArgs & {
|
|
||||||
query: MoveItemQuery;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type MoveItemQuery = {
|
|
||||||
endingIndex: number;
|
|
||||||
playlistId: string;
|
|
||||||
startingIndex: number;
|
|
||||||
trackId: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Tag = {
|
|
||||||
name: string;
|
|
||||||
options: string[];
|
|
||||||
};
|
|
||||||
|
|
||||||
export type TagArgs = BaseEndpointArgs & {
|
|
||||||
query: TagQuery;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type TagQuery = {
|
|
||||||
folder?: string;
|
|
||||||
type: LibraryItem.ALBUM | LibraryItem.SONG;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type TagResponses = {
|
|
||||||
boolTags?: string[];
|
|
||||||
enumTags?: Tag[];
|
|
||||||
};
|
|
||||||
|
|
||||||
export type TranscodingArgs = BaseEndpointArgs & {
|
|
||||||
query: TranscodingQuery;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type TranscodingQuery = {
|
|
||||||
base: string;
|
|
||||||
bitrate?: number;
|
|
||||||
format?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const sortAlbumList = (albums: Album[], sortBy: AlbumListSort, sortOrder: ListSortOrder) => {
|
|
||||||
let results = albums;
|
|
||||||
|
|
||||||
const order = sortOrder === ListSortOrder.ASC ? 'asc' : 'desc';
|
|
||||||
|
|
||||||
switch (sortBy) {
|
|
||||||
case AlbumListSort.ALBUM_ARTIST:
|
|
||||||
results = orderBy(
|
|
||||||
results,
|
|
||||||
['albumArtist', (v) => v.name.toLowerCase()],
|
|
||||||
[order, 'asc'],
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case AlbumListSort.DURATION:
|
|
||||||
results = orderBy(results, ['duration'], [order]);
|
|
||||||
break;
|
|
||||||
case AlbumListSort.FAVORITED:
|
|
||||||
results = orderBy(results, ['starred'], [order]);
|
|
||||||
break;
|
|
||||||
case AlbumListSort.NAME:
|
|
||||||
results = orderBy(results, [(v) => v.name.toLowerCase()], [order]);
|
|
||||||
break;
|
|
||||||
case AlbumListSort.PLAY_COUNT:
|
|
||||||
results = orderBy(results, ['playCount'], [order]);
|
|
||||||
break;
|
|
||||||
case AlbumListSort.RANDOM:
|
|
||||||
results = shuffle(results);
|
|
||||||
break;
|
|
||||||
case AlbumListSort.RATING:
|
|
||||||
results = orderBy(results, ['userRating'], [order]);
|
|
||||||
break;
|
|
||||||
case AlbumListSort.RECENTLY_ADDED:
|
|
||||||
results = orderBy(results, ['createdAt'], [order]);
|
|
||||||
break;
|
|
||||||
case AlbumListSort.RECENTLY_PLAYED:
|
|
||||||
results = orderBy(results, ['lastPlayedAt'], [order]);
|
|
||||||
break;
|
|
||||||
case AlbumListSort.SONG_COUNT:
|
|
||||||
results = orderBy(results, ['songCount'], [order]);
|
|
||||||
break;
|
|
||||||
case AlbumListSort.YEAR:
|
|
||||||
results = orderBy(results, ['releaseYear'], [order]);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return results;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const sortSongList = (
|
|
||||||
songs: QueueSong[],
|
|
||||||
sortBy: SongListSort,
|
|
||||||
sortOrder: ListSortOrder,
|
|
||||||
) => {
|
|
||||||
let results = songs;
|
|
||||||
|
|
||||||
const order = sortOrder === ListSortOrder.ASC ? 'asc' : 'desc';
|
|
||||||
|
|
||||||
switch (sortBy) {
|
|
||||||
case SongListSort.ALBUM:
|
|
||||||
results = orderBy(
|
|
||||||
results,
|
|
||||||
[(v) => v.album?.toLowerCase(), 'discNumber', 'trackNumber'],
|
|
||||||
[order, 'asc', 'asc'],
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SongListSort.ALBUM_ARTIST:
|
|
||||||
results = orderBy(
|
|
||||||
results,
|
|
||||||
['albumArtist', (v) => v.album?.toLowerCase(), 'discNumber', 'trackNumber'],
|
|
||||||
[order, order, 'asc', 'asc'],
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SongListSort.ARTIST:
|
|
||||||
results = orderBy(
|
|
||||||
results,
|
|
||||||
['artist', (v) => v.album?.toLowerCase(), 'discNumber', 'trackNumber'],
|
|
||||||
[order, order, 'asc', 'asc'],
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SongListSort.DURATION:
|
|
||||||
results = orderBy(results, ['duration'], [order]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SongListSort.FAVORITED:
|
|
||||||
results = orderBy(results, ['userFavorite', (v) => v.name.toLowerCase()], [order]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SongListSort.GENRE:
|
|
||||||
results = orderBy(
|
|
||||||
results,
|
|
||||||
[
|
|
||||||
(v) => v.genres?.[0].name.toLowerCase(),
|
|
||||||
(v) => v.album?.toLowerCase(),
|
|
||||||
'discNumber',
|
|
||||||
'trackNumber',
|
|
||||||
],
|
|
||||||
[order, order, 'asc', 'asc'],
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SongListSort.ID:
|
|
||||||
if (order === 'desc') {
|
|
||||||
results = reverse(results as any);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SongListSort.NAME:
|
|
||||||
results = orderBy(results, [(v) => v.name.toLowerCase()], [order]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SongListSort.PLAY_COUNT:
|
|
||||||
results = orderBy(results, ['playCount'], [order]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SongListSort.RANDOM:
|
|
||||||
results = shuffle(results);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SongListSort.RATING:
|
|
||||||
results = orderBy(results, ['userRating', (v) => v.name.toLowerCase()], [order]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SongListSort.RECENTLY_ADDED:
|
|
||||||
results = orderBy(results, ['created'], [order]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SongListSort.YEAR:
|
|
||||||
results = orderBy(
|
|
||||||
results,
|
|
||||||
['year', (v) => v.album?.toLowerCase(), 'discNumber', 'track'],
|
|
||||||
[order, 'asc', 'asc', 'asc'],
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return results;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const sortAlbumArtistList = (
|
|
||||||
artists: AlbumArtist[],
|
|
||||||
sortBy: AlbumArtistListSort | ArtistListSort,
|
|
||||||
sortOrder: ListSortOrder,
|
|
||||||
) => {
|
|
||||||
const order = sortOrder === ListSortOrder.ASC ? 'asc' : 'desc';
|
|
||||||
|
|
||||||
let results = artists;
|
|
||||||
|
|
||||||
switch (sortBy) {
|
|
||||||
case AlbumArtistListSort.ALBUM_COUNT:
|
|
||||||
results = orderBy(artists, ['albumCount', (v) => v.name.toLowerCase()], [order, 'asc']);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case AlbumArtistListSort.FAVORITED:
|
|
||||||
results = orderBy(artists, ['starred'], [order]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case AlbumArtistListSort.NAME:
|
|
||||||
results = orderBy(artists, [(v) => v.name.toLowerCase()], [order]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case AlbumArtistListSort.RATING:
|
|
||||||
results = orderBy(artists, ['userRating'], [order]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return results;
|
|
||||||
};
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import i18n from 'src/i18n/i18n';
|
import { orderBy, shuffle } from 'lodash';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
import i18n from '/@/i18n/i18n';
|
||||||
import { JFAlbumListSort } from '/@/shared/api/jellyfin.types';
|
import { JFAlbumListSort } from '/@/shared/api/jellyfin.types';
|
||||||
import { jfType } from '/@/shared/api/jellyfin/jellyfin-types';
|
import { jfType } from '/@/shared/api/jellyfin/jellyfin-types';
|
||||||
import { NDAlbumListSort } from '/@/shared/api/navidrome.types';
|
import { NDAlbumListSort } from '/@/shared/api/navidrome.types';
|
||||||
@@ -9,11 +10,11 @@ import {
|
|||||||
BaseEndpointArgs,
|
BaseEndpointArgs,
|
||||||
BasePaginatedResponse,
|
BasePaginatedResponse,
|
||||||
BaseQuery,
|
BaseQuery,
|
||||||
LibraryItem,
|
} from '/@/shared/types/domain/api-domain-types';
|
||||||
} from '/@/shared/types/domain-types';
|
|
||||||
import { RelatedArtist } from '/@/shared/types/domain/artist-domain-types';
|
import { RelatedArtist } from '/@/shared/types/domain/artist-domain-types';
|
||||||
import { Genre } from '/@/shared/types/domain/genre-domain-types';
|
import { Genre } from '/@/shared/types/domain/genre-domain-types';
|
||||||
import { ServerType } from '/@/shared/types/domain/server-domain-types';
|
import { ServerType } from '/@/shared/types/domain/server-domain-types';
|
||||||
|
import { LibraryItem, ListSortOrder } from '/@/shared/types/domain/shared-domain-types';
|
||||||
import { Song } from '/@/shared/types/domain/song-domain-types';
|
import { Song } from '/@/shared/types/domain/song-domain-types';
|
||||||
|
|
||||||
export enum AlbumListSortOptions {
|
export enum AlbumListSortOptions {
|
||||||
@@ -51,6 +52,7 @@ export const AlbumListSortOptionsLabels = {
|
|||||||
[AlbumListSortOptions.TRACK_COUNT]: i18n.t('filter.trackCount'),
|
[AlbumListSortOptions.TRACK_COUNT]: i18n.t('filter.trackCount'),
|
||||||
[AlbumListSortOptions.YEAR]: i18n.t('filter.year'),
|
[AlbumListSortOptions.YEAR]: i18n.t('filter.year'),
|
||||||
};
|
};
|
||||||
|
|
||||||
export enum AlbumListSort {
|
export enum AlbumListSort {
|
||||||
ALBUM_ARTIST = 'albumArtist',
|
ALBUM_ARTIST = 'albumArtist',
|
||||||
ARTIST = 'artist',
|
ARTIST = 'artist',
|
||||||
@@ -87,7 +89,6 @@ export interface AlbumListQuery extends BaseQuery<AlbumListSort> {
|
|||||||
searchTerm?: string;
|
searchTerm?: string;
|
||||||
startIndex: number;
|
startIndex: number;
|
||||||
}
|
}
|
||||||
// Album List
|
|
||||||
|
|
||||||
export type AlbumListResponse = BasePaginatedResponse<Album[]> | null | undefined;
|
export type AlbumListResponse = BasePaginatedResponse<Album[]> | null | undefined;
|
||||||
type AlbumListSortMap = {
|
type AlbumListSortMap = {
|
||||||
@@ -150,13 +151,20 @@ export const albumListSortMap: AlbumListSortMap = {
|
|||||||
year: undefined,
|
year: undefined,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Album = {
|
export type Album = {
|
||||||
albumArtist: string;
|
albumArtist: string;
|
||||||
albumArtists: RelatedArtist[];
|
albumArtists: RelatedArtist[];
|
||||||
artists: RelatedArtist[];
|
artists: RelatedArtist[];
|
||||||
backdropImageUrl: null | string;
|
backdropImageUrl: null | string;
|
||||||
comment: null | string;
|
comment: null | string;
|
||||||
createdAt: string;
|
createdDate: string;
|
||||||
|
description: null | string;
|
||||||
|
discTitles: {
|
||||||
|
disc: number;
|
||||||
|
title: string;
|
||||||
|
}[];
|
||||||
|
displayArtist: null | string;
|
||||||
duration: null | number;
|
duration: null | number;
|
||||||
genres: Genre[];
|
genres: Genre[];
|
||||||
id: string;
|
id: string;
|
||||||
@@ -164,33 +172,91 @@ export type Album = {
|
|||||||
imageUrl: null | string;
|
imageUrl: null | string;
|
||||||
isCompilation: boolean | null;
|
isCompilation: boolean | null;
|
||||||
itemType: LibraryItem.ALBUM;
|
itemType: LibraryItem.ALBUM;
|
||||||
lastPlayedAt: null | string;
|
mbzAlbumId: null | string;
|
||||||
mbzId: null | string;
|
mbzReleaseGroupId: null | string;
|
||||||
|
missing: boolean;
|
||||||
name: string;
|
name: string;
|
||||||
originalDate: null | string;
|
originalReleaseDate: null | string;
|
||||||
participants: null | Record<string, RelatedArtist[]>;
|
participants: null | Record<string, RelatedArtist[]>;
|
||||||
playCount: null | number;
|
|
||||||
releaseDate: null | string;
|
releaseDate: null | string;
|
||||||
|
releaseTypes: {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
}[];
|
||||||
releaseYear: null | number;
|
releaseYear: null | number;
|
||||||
serverId: string;
|
serverId: string;
|
||||||
serverType: ServerType;
|
serverType: ServerType;
|
||||||
size: null | number;
|
size: null | number;
|
||||||
songCount: null | number;
|
songCount: null | number;
|
||||||
songs?: Song[];
|
songs?: Song[];
|
||||||
tags: null | Record<string, string[]>;
|
sortName: string;
|
||||||
|
tags: Record<string, string[]>;
|
||||||
uniqueId: string;
|
uniqueId: string;
|
||||||
updatedAt: string;
|
updatedDate: string;
|
||||||
userFavorite: boolean;
|
userFavorite: boolean;
|
||||||
|
userFavoriteDate: null | string;
|
||||||
|
userLastPlayedDate: null | string;
|
||||||
|
userPlayCount: null | number;
|
||||||
userRating: null | number;
|
userRating: null | number;
|
||||||
} & { songs?: Song[] };
|
} & { songs?: Song[] };
|
||||||
|
|
||||||
export type AlbumDetailArgs = BaseEndpointArgs & { query: AlbumDetailQuery };
|
export type AlbumDetailArgs = BaseEndpointArgs & { query: AlbumDetailQuery };
|
||||||
// Album Detail
|
|
||||||
|
|
||||||
export type AlbumDetailQuery = { id: string };
|
export type AlbumDetailQuery = { id: string };
|
||||||
|
|
||||||
export type AlbumDetailResponse = Album | null | undefined;
|
export type AlbumDetailResponse = Album | null | undefined;
|
||||||
|
|
||||||
export type AlbumInfo = {
|
export type AlbumInfo = {
|
||||||
imageUrl: null | string;
|
imageUrl: null | string;
|
||||||
notes: null | string;
|
notes: null | string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const sortAlbumList = (albums: Album[], sortBy: AlbumListSort, sortOrder: ListSortOrder) => {
|
||||||
|
let results = albums;
|
||||||
|
|
||||||
|
const order = sortOrder === ListSortOrder.ASC ? 'asc' : 'desc';
|
||||||
|
|
||||||
|
switch (sortBy) {
|
||||||
|
case AlbumListSort.ALBUM_ARTIST:
|
||||||
|
results = orderBy(
|
||||||
|
results,
|
||||||
|
['albumArtist', (v) => v.name.toLowerCase()],
|
||||||
|
[order, 'asc'],
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case AlbumListSort.DURATION:
|
||||||
|
results = orderBy(results, ['duration'], [order]);
|
||||||
|
break;
|
||||||
|
case AlbumListSort.FAVORITED:
|
||||||
|
results = orderBy(results, ['starred'], [order]);
|
||||||
|
break;
|
||||||
|
case AlbumListSort.NAME:
|
||||||
|
results = orderBy(results, [(v) => v.name.toLowerCase()], [order]);
|
||||||
|
break;
|
||||||
|
case AlbumListSort.PLAY_COUNT:
|
||||||
|
results = orderBy(results, ['playCount'], [order]);
|
||||||
|
break;
|
||||||
|
case AlbumListSort.RANDOM:
|
||||||
|
results = shuffle(results);
|
||||||
|
break;
|
||||||
|
case AlbumListSort.RATING:
|
||||||
|
results = orderBy(results, ['userRating'], [order]);
|
||||||
|
break;
|
||||||
|
case AlbumListSort.RECENTLY_ADDED:
|
||||||
|
results = orderBy(results, ['createdAt'], [order]);
|
||||||
|
break;
|
||||||
|
case AlbumListSort.RECENTLY_PLAYED:
|
||||||
|
results = orderBy(results, ['lastPlayedAt'], [order]);
|
||||||
|
break;
|
||||||
|
case AlbumListSort.SONG_COUNT:
|
||||||
|
results = orderBy(results, ['songCount'], [order]);
|
||||||
|
break;
|
||||||
|
case AlbumListSort.YEAR:
|
||||||
|
results = orderBy(results, ['releaseYear'], [order]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|||||||
@@ -0,0 +1,151 @@
|
|||||||
|
import {
|
||||||
|
AlbumDetailArgs,
|
||||||
|
AlbumDetailResponse,
|
||||||
|
AlbumInfo,
|
||||||
|
AlbumListArgs,
|
||||||
|
AlbumListResponse,
|
||||||
|
} from '/@/shared/types/domain/album-domain-types';
|
||||||
|
import {
|
||||||
|
AlbumArtistDetailArgs,
|
||||||
|
AlbumArtistDetailResponse,
|
||||||
|
AlbumArtistListArgs,
|
||||||
|
AlbumArtistListResponse,
|
||||||
|
ArtistListArgs,
|
||||||
|
ArtistListResponse,
|
||||||
|
} from '/@/shared/types/domain/artist-domain-types';
|
||||||
|
import { AuthenticationResponse } from '/@/shared/types/domain/auth-domain-types';
|
||||||
|
import { GenreListArgs, GenreListResponse } from '/@/shared/types/domain/genre-domain-types';
|
||||||
|
import {
|
||||||
|
LyricsArgs,
|
||||||
|
LyricsResponse,
|
||||||
|
StructuredLyric,
|
||||||
|
StructuredLyricsArgs,
|
||||||
|
} from '/@/shared/types/domain/lyric-domain-types';
|
||||||
|
import { TranscodingArgs } from '/@/shared/types/domain/player-domain-types';
|
||||||
|
import {
|
||||||
|
AddToPlaylistArgs,
|
||||||
|
AddToPlaylistResponse,
|
||||||
|
CreatePlaylistArgs,
|
||||||
|
CreatePlaylistResponse,
|
||||||
|
DeletePlaylistArgs,
|
||||||
|
DeletePlaylistResponse,
|
||||||
|
MoveItemArgs,
|
||||||
|
PlaylistDetailArgs,
|
||||||
|
PlaylistDetailResponse,
|
||||||
|
PlaylistListArgs,
|
||||||
|
PlaylistListResponse,
|
||||||
|
PlaylistSongListArgs,
|
||||||
|
RemoveFromPlaylistArgs,
|
||||||
|
RemoveFromPlaylistResponse,
|
||||||
|
UpdatePlaylistArgs,
|
||||||
|
UpdatePlaylistResponse,
|
||||||
|
} from '/@/shared/types/domain/playlist-domain-types';
|
||||||
|
import { SearchArgs, SearchResponse } from '/@/shared/types/domain/search-domain-types';
|
||||||
|
import {
|
||||||
|
ServerInfo,
|
||||||
|
ServerInfoArgs,
|
||||||
|
ServerListItem,
|
||||||
|
ServerMusicFolderListArgs,
|
||||||
|
ServerMusicFolderListResponse,
|
||||||
|
} from '/@/shared/types/domain/server-domain-types';
|
||||||
|
import { ListSortOrder } from '/@/shared/types/domain/shared-domain-types';
|
||||||
|
import {
|
||||||
|
RandomSongListArgs,
|
||||||
|
SimilarSongsArgs,
|
||||||
|
Song,
|
||||||
|
SongDetailArgs,
|
||||||
|
SongDetailResponse,
|
||||||
|
SongListArgs,
|
||||||
|
SongListResponse,
|
||||||
|
TopSongListArgs,
|
||||||
|
TopSongListResponse,
|
||||||
|
} from '/@/shared/types/domain/song-domain-types';
|
||||||
|
import { TagArgs, TagsResponse } from '/@/shared/types/domain/tag-domain-types';
|
||||||
|
import {
|
||||||
|
DownloadArgs,
|
||||||
|
FavoriteArgs,
|
||||||
|
FavoriteResponse,
|
||||||
|
RatingResponse,
|
||||||
|
ScrobbleArgs,
|
||||||
|
ScrobbleResponse,
|
||||||
|
SetRatingArgs,
|
||||||
|
ShareItemArgs,
|
||||||
|
ShareItemResponse,
|
||||||
|
UserListArgs,
|
||||||
|
UserListResponse,
|
||||||
|
} from '/@/shared/types/domain/user-domain-types';
|
||||||
|
|
||||||
|
export type BaseEndpointArgs = {
|
||||||
|
apiClientProps: {
|
||||||
|
server: null | ServerListItem;
|
||||||
|
signal?: AbortSignal;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface BasePaginatedResponse<T> {
|
||||||
|
error?: any | string;
|
||||||
|
items: T;
|
||||||
|
startIndex: number;
|
||||||
|
totalRecordCount: null | number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BaseQuery<T> {
|
||||||
|
sortBy: T;
|
||||||
|
sortOrder: ListSortOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type EndpointDetails = {
|
||||||
|
server: ServerListItem;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const instanceOfCancellationError = (error: any) => {
|
||||||
|
return 'revert' in error;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ControllerEndpoint = {
|
||||||
|
addToPlaylist: (args: AddToPlaylistArgs) => Promise<AddToPlaylistResponse>;
|
||||||
|
authenticate: (
|
||||||
|
url: string,
|
||||||
|
body: { legacy?: boolean; password: string; username: string },
|
||||||
|
) => Promise<AuthenticationResponse>;
|
||||||
|
createFavorite: (args: FavoriteArgs) => Promise<FavoriteResponse>;
|
||||||
|
createPlaylist: (args: CreatePlaylistArgs) => Promise<CreatePlaylistResponse>;
|
||||||
|
deleteFavorite: (args: FavoriteArgs) => Promise<FavoriteResponse>;
|
||||||
|
deletePlaylist: (args: DeletePlaylistArgs) => Promise<DeletePlaylistResponse>;
|
||||||
|
getAlbumArtistDetail: (args: AlbumArtistDetailArgs) => Promise<AlbumArtistDetailResponse>;
|
||||||
|
getAlbumArtistList: (args: AlbumArtistListArgs) => Promise<AlbumArtistListResponse>;
|
||||||
|
getAlbumArtistListCount: (args: AlbumArtistListArgs) => Promise<number>;
|
||||||
|
getAlbumDetail: (args: AlbumDetailArgs) => Promise<AlbumDetailResponse>;
|
||||||
|
getAlbumInfo?: (args: AlbumDetailArgs) => Promise<AlbumInfo>;
|
||||||
|
getAlbumList: (args: AlbumListArgs) => Promise<AlbumListResponse>;
|
||||||
|
getAlbumListCount: (args: AlbumListArgs) => Promise<number>;
|
||||||
|
getArtistList: (args: ArtistListArgs) => Promise<ArtistListResponse>;
|
||||||
|
getArtistListCount: (args: ArtistListArgs) => Promise<number>;
|
||||||
|
getDownloadUrl: (args: DownloadArgs) => string;
|
||||||
|
getGenreList: (args: GenreListArgs) => Promise<GenreListResponse>;
|
||||||
|
getLyrics?: (args: LyricsArgs) => Promise<LyricsResponse>;
|
||||||
|
getMusicFolderList: (args: ServerMusicFolderListArgs) => Promise<ServerMusicFolderListResponse>;
|
||||||
|
getPlaylistDetail: (args: PlaylistDetailArgs) => Promise<PlaylistDetailResponse>;
|
||||||
|
getPlaylistList: (args: PlaylistListArgs) => Promise<PlaylistListResponse>;
|
||||||
|
getPlaylistListCount: (args: PlaylistListArgs) => Promise<number>;
|
||||||
|
getPlaylistSongList: (args: PlaylistSongListArgs) => Promise<SongListResponse>;
|
||||||
|
getRandomSongList: (args: RandomSongListArgs) => Promise<SongListResponse>;
|
||||||
|
getRoles: (args: BaseEndpointArgs) => Promise<Array<string | { label: string; value: string }>>;
|
||||||
|
getServerInfo: (args: ServerInfoArgs) => Promise<ServerInfo>;
|
||||||
|
getSimilarSongs: (args: SimilarSongsArgs) => Promise<Song[]>;
|
||||||
|
getSongDetail: (args: SongDetailArgs) => Promise<SongDetailResponse>;
|
||||||
|
getSongList: (args: SongListArgs) => Promise<SongListResponse>;
|
||||||
|
getSongListCount: (args: SongListArgs) => Promise<number>;
|
||||||
|
getStructuredLyrics?: (args: StructuredLyricsArgs) => Promise<StructuredLyric[]>;
|
||||||
|
getTags?: (args: TagArgs) => Promise<TagsResponse>;
|
||||||
|
getTopSongs: (args: TopSongListArgs) => Promise<TopSongListResponse>;
|
||||||
|
getTranscodingUrl: (args: TranscodingArgs) => string;
|
||||||
|
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>;
|
||||||
|
setRating?: (args: SetRatingArgs) => Promise<RatingResponse>;
|
||||||
|
shareItem?: (args: ShareItemArgs) => Promise<ShareItemResponse>;
|
||||||
|
updatePlaylist: (args: UpdatePlaylistArgs) => Promise<UpdatePlaylistResponse>;
|
||||||
|
};
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import i18n from 'src/i18n/i18n';
|
import { orderBy } from 'lodash';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
import i18n from '/@/i18n/i18n';
|
||||||
import { JFAlbumArtistListSort, JFArtistListSort } from '/@/shared/api/jellyfin.types';
|
import { JFAlbumArtistListSort, JFArtistListSort } from '/@/shared/api/jellyfin.types';
|
||||||
import { jfType } from '/@/shared/api/jellyfin/jellyfin-types';
|
import { jfType } from '/@/shared/api/jellyfin/jellyfin-types';
|
||||||
import { NDAlbumArtistListSort } from '/@/shared/api/navidrome.types';
|
import { NDAlbumArtistListSort } from '/@/shared/api/navidrome.types';
|
||||||
@@ -9,10 +10,10 @@ import {
|
|||||||
BaseEndpointArgs,
|
BaseEndpointArgs,
|
||||||
BasePaginatedResponse,
|
BasePaginatedResponse,
|
||||||
BaseQuery,
|
BaseQuery,
|
||||||
LibraryItem,
|
} from '/@/shared/types/domain/api-domain-types';
|
||||||
} from '/@/shared/types/domain-types';
|
|
||||||
import { Genre } from '/@/shared/types/domain/genre-domain-types';
|
import { Genre } from '/@/shared/types/domain/genre-domain-types';
|
||||||
import { ServerType } from '/@/shared/types/domain/server-domain-types';
|
import { ServerType } from '/@/shared/types/domain/server-domain-types';
|
||||||
|
import { LibraryItem, ListSortOrder } from '/@/shared/types/domain/shared-domain-types';
|
||||||
|
|
||||||
export enum ArtistListSortOptions {
|
export enum ArtistListSortOptions {
|
||||||
ALBUM_COUNT = 'albumCount',
|
ALBUM_COUNT = 'albumCount',
|
||||||
@@ -243,3 +244,35 @@ export type ArtistInfoQuery = {
|
|||||||
limit: number;
|
limit: number;
|
||||||
musicFolderId?: string;
|
musicFolderId?: string;
|
||||||
};
|
};
|
||||||
|
export const sortAlbumArtistList = (
|
||||||
|
artists: AlbumArtist[],
|
||||||
|
sortBy: AlbumArtistListSort | ArtistListSort,
|
||||||
|
sortOrder: ListSortOrder,
|
||||||
|
) => {
|
||||||
|
const order = sortOrder === ListSortOrder.ASC ? 'asc' : 'desc';
|
||||||
|
|
||||||
|
let results = artists;
|
||||||
|
|
||||||
|
switch (sortBy) {
|
||||||
|
case AlbumArtistListSort.ALBUM_COUNT:
|
||||||
|
results = orderBy(artists, ['albumCount', (v) => v.name.toLowerCase()], [order, 'asc']);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AlbumArtistListSort.FAVORITED:
|
||||||
|
results = orderBy(artists, ['starred'], [order]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AlbumArtistListSort.NAME:
|
||||||
|
results = orderBy(artists, [(v) => v.name.toLowerCase()], [order]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AlbumArtistListSort.RATING:
|
||||||
|
results = orderBy(artists, ['userRating'], [order]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
export type AuthenticationResponse = {
|
||||||
|
credential: string;
|
||||||
|
ndCredential?: string;
|
||||||
|
userId: null | string;
|
||||||
|
username: string;
|
||||||
|
};
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
export enum ExternalSource {
|
||||||
|
LASTFM = 'LASTFM',
|
||||||
|
MUSICBRAINZ = 'MUSICBRAINZ',
|
||||||
|
SPOTIFY = 'SPOTIFY',
|
||||||
|
THEAUDIODB = 'THEAUDIODB',
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum ExternalType {
|
||||||
|
ID = 'ID',
|
||||||
|
LINK = 'LINK',
|
||||||
|
}
|
||||||
@@ -1,15 +1,13 @@
|
|||||||
import i18n from 'src/i18n/i18n';
|
import i18n from '/@/i18n/i18n';
|
||||||
|
|
||||||
import { UserListSort } from './user-domain-types';
|
|
||||||
|
|
||||||
import { JFGenreListSort } from '/@/shared/api/jellyfin.types';
|
import { JFGenreListSort } from '/@/shared/api/jellyfin.types';
|
||||||
import { NDGenreListSort } from '/@/shared/api/navidrome.types';
|
import { NDGenreListSort } from '/@/shared/api/navidrome.types';
|
||||||
import {
|
import {
|
||||||
BaseEndpointArgs,
|
BaseEndpointArgs,
|
||||||
BasePaginatedResponse,
|
BasePaginatedResponse,
|
||||||
BaseQuery,
|
BaseQuery,
|
||||||
LibraryItem,
|
} from '/@/shared/types/domain/api-domain-types';
|
||||||
} from '/@/shared/types/domain-types';
|
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||||
|
import { UserListSort } from '/@/shared/types/domain/user-domain-types';
|
||||||
|
|
||||||
export enum GenreListSortOptions {
|
export enum GenreListSortOptions {
|
||||||
ALBUM_COUNT = 'albumCount',
|
ALBUM_COUNT = 'albumCount',
|
||||||
@@ -22,6 +20,7 @@ export const GenreListSortOptionsLabels = {
|
|||||||
[GenreListSortOptions.NAME]: i18n.t('filter.name'),
|
[GenreListSortOptions.NAME]: i18n.t('filter.name'),
|
||||||
[GenreListSortOptions.TRACK_COUNT]: i18n.t('filter.trackCount'),
|
[GenreListSortOptions.TRACK_COUNT]: i18n.t('filter.trackCount'),
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Genre = {
|
export type Genre = {
|
||||||
albumCount?: number;
|
albumCount?: number;
|
||||||
id: string;
|
id: string;
|
||||||
@@ -43,7 +42,6 @@ export interface GenreListQuery extends BaseQuery<GenreListSort> {
|
|||||||
searchTerm?: string;
|
searchTerm?: string;
|
||||||
startIndex: number;
|
startIndex: number;
|
||||||
}
|
}
|
||||||
// Genre List
|
|
||||||
|
|
||||||
export type GenreListResponse = BasePaginatedResponse<Genre[]> | null | undefined;
|
export type GenreListResponse = BasePaginatedResponse<Genre[]> | null | undefined;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
export enum ImageType {
|
||||||
|
BACKDROP = 'BACKDROP',
|
||||||
|
LOGO = 'LOGO',
|
||||||
|
PRIMARY = 'PRIMARY',
|
||||||
|
SCREENSHOT = 'SCREENSHOT',
|
||||||
|
}
|
||||||
@@ -1,12 +1,17 @@
|
|||||||
import { BaseEndpointArgs, LyricSource } from '/@/shared/types/domain-types';
|
import { BaseEndpointArgs } from './api-domain-types';
|
||||||
import { Song } from '/@/shared/types/domain/song-domain-types';
|
import { Song } from '/@/shared/types/domain/song-domain-types';
|
||||||
|
|
||||||
|
export enum LyricSource {
|
||||||
|
GENIUS = 'Genius',
|
||||||
|
LRCLIB = 'lrclib.net',
|
||||||
|
NETEASE = 'NetEase',
|
||||||
|
}
|
||||||
|
|
||||||
export type FullLyricsMetadata = Omit<InternetProviderLyricResponse, 'id' | 'lyrics' | 'source'> & {
|
export type FullLyricsMetadata = Omit<InternetProviderLyricResponse, 'id' | 'lyrics' | 'source'> & {
|
||||||
lyrics: LyricsResponse;
|
lyrics: LyricsResponse;
|
||||||
remote: boolean;
|
remote: boolean;
|
||||||
source: string;
|
source: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type InternetProviderLyricResponse = {
|
export type InternetProviderLyricResponse = {
|
||||||
artist: string;
|
artist: string;
|
||||||
id: string;
|
id: string;
|
||||||
@@ -21,6 +26,7 @@ export type InternetProviderLyricSearchResponse = {
|
|||||||
score?: number;
|
score?: number;
|
||||||
source: LyricSource;
|
source: LyricSource;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type LyricGetQuery = {
|
export type LyricGetQuery = {
|
||||||
remoteSongId: string;
|
remoteSongId: string;
|
||||||
remoteSource: LyricSource;
|
remoteSource: LyricSource;
|
||||||
@@ -32,7 +38,6 @@ export type LyricOverride = Omit<InternetProviderLyricResponse, 'lyrics'>;
|
|||||||
export type LyricsArgs = BaseEndpointArgs & {
|
export type LyricsArgs = BaseEndpointArgs & {
|
||||||
query: LyricsQuery;
|
query: LyricsQuery;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type LyricSearchQuery = {
|
export type LyricSearchQuery = {
|
||||||
album?: string;
|
album?: string;
|
||||||
artist?: string;
|
artist?: string;
|
||||||
@@ -40,6 +45,7 @@ export type LyricSearchQuery = {
|
|||||||
name?: string;
|
name?: string;
|
||||||
};
|
};
|
||||||
export type LyricsOverride = Omit<FullLyricsMetadata, 'lyrics'> & { id: string };
|
export type LyricsOverride = Omit<FullLyricsMetadata, 'lyrics'> & { id: string };
|
||||||
|
|
||||||
export type LyricsQuery = {
|
export type LyricsQuery = {
|
||||||
songId: string;
|
songId: string;
|
||||||
};
|
};
|
||||||
@@ -58,7 +64,6 @@ export type StructuredSyncedLyric = Omit<FullLyricsMetadata, 'lyrics'> & {
|
|||||||
lyrics: SynchronizedLyricsArray;
|
lyrics: SynchronizedLyricsArray;
|
||||||
synced: true;
|
synced: true;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type StructuredUnsyncedLyric = Omit<FullLyricsMetadata, 'lyrics'> & {
|
export type StructuredUnsyncedLyric = Omit<FullLyricsMetadata, 'lyrics'> & {
|
||||||
lyrics: string;
|
lyrics: string;
|
||||||
synced: false;
|
synced: false;
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import { BaseEndpointArgs } from '/@/shared/types/domain/api-domain-types';
|
||||||
|
import { Song } from '/@/shared/types/domain/song-domain-types';
|
||||||
|
import { PlayerStatus } from '/@/shared/types/types';
|
||||||
|
|
||||||
|
export enum Played {
|
||||||
|
All = 'all',
|
||||||
|
Never = 'never',
|
||||||
|
Played = 'played',
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PlayerData {
|
||||||
|
current: {
|
||||||
|
index: number;
|
||||||
|
nextIndex?: number;
|
||||||
|
player: 1 | 2;
|
||||||
|
previousIndex?: number;
|
||||||
|
shuffledIndex: number;
|
||||||
|
song?: QueueSong;
|
||||||
|
status: PlayerStatus;
|
||||||
|
};
|
||||||
|
player1?: QueueSong;
|
||||||
|
player2?: QueueSong;
|
||||||
|
queue: QueueData;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface QueueData {
|
||||||
|
current?: QueueSong;
|
||||||
|
length: number;
|
||||||
|
next?: QueueSong;
|
||||||
|
previous?: QueueSong;
|
||||||
|
}
|
||||||
|
export type QueueSong = Song & {
|
||||||
|
uniqueId: string;
|
||||||
|
};
|
||||||
|
export type TranscodingArgs = BaseEndpointArgs & {
|
||||||
|
query: TranscodingQuery;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TranscodingQuery = {
|
||||||
|
base: string;
|
||||||
|
bitrate?: number;
|
||||||
|
format?: string;
|
||||||
|
};
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
import i18n from 'src/i18n/i18n';
|
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { Genre } from './genre-domain-types';
|
import i18n from '/@/i18n/i18n';
|
||||||
|
|
||||||
import { JFPlaylistListSort } from '/@/shared/api/jellyfin.types';
|
import { JFPlaylistListSort } from '/@/shared/api/jellyfin.types';
|
||||||
import { jfType } from '/@/shared/api/jellyfin/jellyfin-types';
|
import { jfType } from '/@/shared/api/jellyfin/jellyfin-types';
|
||||||
import { NDPlaylistListSort } from '/@/shared/api/navidrome.types';
|
import { NDPlaylistListSort } from '/@/shared/api/navidrome.types';
|
||||||
@@ -11,10 +9,10 @@ import {
|
|||||||
BaseEndpointArgs,
|
BaseEndpointArgs,
|
||||||
BasePaginatedResponse,
|
BasePaginatedResponse,
|
||||||
BaseQuery,
|
BaseQuery,
|
||||||
LibraryItem,
|
} from '/@/shared/types/domain/api-domain-types';
|
||||||
} from '/@/shared/types/domain-types';
|
import { Genre } from '/@/shared/types/domain/genre-domain-types';
|
||||||
import { ServerType } from '/@/shared/types/domain/server-domain-types';
|
import { ServerType } from '/@/shared/types/domain/server-domain-types';
|
||||||
import { ListSortOrder } from '/@/shared/types/domain/shared-domain-types';
|
import { LibraryItem, ListSortOrder } from '/@/shared/types/domain/shared-domain-types';
|
||||||
import { Song, SongListSort } from '/@/shared/types/domain/song-domain-types';
|
import { Song, SongListSort } from '/@/shared/types/domain/song-domain-types';
|
||||||
|
|
||||||
export enum PlaylistListSortOptions {
|
export enum PlaylistListSortOptions {
|
||||||
@@ -191,6 +189,17 @@ export const playlistListSortMap: PlaylistListSortMap = {
|
|||||||
updatedAt: undefined,
|
updatedAt: undefined,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
export type MoveItemArgs = BaseEndpointArgs & {
|
||||||
|
query: MoveItemQuery;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type MoveItemQuery = {
|
||||||
|
endingIndex: number;
|
||||||
|
playlistId: string;
|
||||||
|
startingIndex: number;
|
||||||
|
trackId: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type PlaylistDetailArgs = BaseEndpointArgs & { query: PlaylistDetailQuery };
|
export type PlaylistDetailArgs = BaseEndpointArgs & { query: PlaylistDetailQuery };
|
||||||
|
|
||||||
export type PlaylistDetailQuery = {
|
export type PlaylistDetailQuery = {
|
||||||
@@ -200,7 +209,6 @@ export type PlaylistDetailQuery = {
|
|||||||
export type PlaylistDetailResponse = Playlist;
|
export type PlaylistDetailResponse = Playlist;
|
||||||
|
|
||||||
export type PlaylistSongListArgs = BaseEndpointArgs & { query: PlaylistSongListQuery };
|
export type PlaylistSongListArgs = BaseEndpointArgs & { query: PlaylistSongListQuery };
|
||||||
|
|
||||||
export type PlaylistSongListQuery = {
|
export type PlaylistSongListQuery = {
|
||||||
id: string;
|
id: string;
|
||||||
limit?: number;
|
limit?: number;
|
||||||
|
|||||||
@@ -0,0 +1,113 @@
|
|||||||
|
import { QueueSong } from '/@/shared/types/domain/player-domain-types';
|
||||||
|
import { PlayerRepeat, PlayerStatus, SongState } from '/@/shared/types/types';
|
||||||
|
|
||||||
|
export interface ClientAuth {
|
||||||
|
event: 'authenticate';
|
||||||
|
header: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ClientEvent =
|
||||||
|
| ClientAuth
|
||||||
|
| ClientFavorite
|
||||||
|
| ClientPosition
|
||||||
|
| ClientRating
|
||||||
|
| ClientSimpleEvent
|
||||||
|
| ClientVolume;
|
||||||
|
|
||||||
|
export interface ClientFavorite {
|
||||||
|
event: 'favorite';
|
||||||
|
favorite: boolean;
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ClientPosition {
|
||||||
|
event: 'position';
|
||||||
|
position: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ClientRating {
|
||||||
|
event: 'rating';
|
||||||
|
id: string;
|
||||||
|
rating: number;
|
||||||
|
}
|
||||||
|
export interface ClientSimpleEvent {
|
||||||
|
event: 'next' | 'pause' | 'play' | 'previous' | 'proxy' | 'repeat' | 'shuffle';
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ClientVolume {
|
||||||
|
event: 'volume';
|
||||||
|
volume: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ServerError {
|
||||||
|
data: string;
|
||||||
|
event: 'error';
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ServerEvent =
|
||||||
|
| ServerError
|
||||||
|
| ServerFavorite
|
||||||
|
| ServerPlayStatus
|
||||||
|
| ServerPosition
|
||||||
|
| ServerProxy
|
||||||
|
| ServerRating
|
||||||
|
| ServerRepeat
|
||||||
|
| ServerShuffle
|
||||||
|
| ServerSong
|
||||||
|
| ServerState
|
||||||
|
| ServerVolume;
|
||||||
|
|
||||||
|
export interface ServerFavorite {
|
||||||
|
data: { favorite: boolean; id: string };
|
||||||
|
event: 'favorite';
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ServerPlayStatus {
|
||||||
|
data: PlayerStatus;
|
||||||
|
event: 'playback';
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ServerPosition {
|
||||||
|
data: number;
|
||||||
|
event: 'position';
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ServerProxy {
|
||||||
|
data: string;
|
||||||
|
event: 'proxy';
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ServerRating {
|
||||||
|
data: { id: string; rating: number };
|
||||||
|
event: 'rating';
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ServerRepeat {
|
||||||
|
data: PlayerRepeat;
|
||||||
|
event: 'repeat';
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ServerShuffle {
|
||||||
|
data: boolean;
|
||||||
|
event: 'shuffle';
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ServerSong {
|
||||||
|
data: null | QueueSong;
|
||||||
|
event: 'song';
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ServerState {
|
||||||
|
data: SongState;
|
||||||
|
event: 'state';
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ServerVolume {
|
||||||
|
data: number;
|
||||||
|
event: 'volume';
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SongUpdateSocket extends Omit<SongState, 'song'> {
|
||||||
|
position?: number;
|
||||||
|
song?: null | QueueSong;
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { BaseEndpointArgs } from '/@/shared/types/domain-types';
|
|
||||||
import { Album } from '/@/shared/types/domain/album-domain-types';
|
import { Album } from '/@/shared/types/domain/album-domain-types';
|
||||||
|
import { BaseEndpointArgs } from '/@/shared/types/domain/api-domain-types';
|
||||||
import { AlbumArtist } from '/@/shared/types/domain/artist-domain-types';
|
import { AlbumArtist } from '/@/shared/types/domain/artist-domain-types';
|
||||||
import { Song } from '/@/shared/types/domain/song-domain-types';
|
import { Song } from '/@/shared/types/domain/song-domain-types';
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import i18n from 'src/i18n/i18n';
|
import i18n from 'src/i18n/i18n';
|
||||||
|
|
||||||
import { BaseEndpointArgs, BasePaginatedResponse } from '/@/shared/types/domain-types';
|
import { BaseEndpointArgs, BasePaginatedResponse } from '/@/shared/types/domain/api-domain-types';
|
||||||
import { ServerFeatures } from '/@/shared/types/features-types';
|
|
||||||
|
|
||||||
export enum ServerListSortOptions {
|
export enum ServerListSortOptions {
|
||||||
CREATED_AT = 'createdAt',
|
CREATED_AT = 'createdAt',
|
||||||
@@ -17,12 +16,24 @@ export const ServerListSortOptionsLabels = {
|
|||||||
[ServerListSortOptions.UPDATED_AT]: i18n.t('filter.updatedAt'),
|
[ServerListSortOptions.UPDATED_AT]: i18n.t('filter.updatedAt'),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export enum ServerFeature {
|
||||||
|
BFR = 'bfr',
|
||||||
|
LYRICS_MULTIPLE_STRUCTURED = 'lyricsMultipleStructured',
|
||||||
|
LYRICS_SINGLE_STRUCTURED = 'lyricsSingleStructured',
|
||||||
|
PLAYLISTS_SMART = 'playlistsSmart',
|
||||||
|
PUBLIC_PLAYLIST = 'publicPlaylist',
|
||||||
|
SHARING_ALBUM_SONG = 'sharingAlbumSong',
|
||||||
|
TAGS = 'tags',
|
||||||
|
}
|
||||||
|
|
||||||
export enum ServerType {
|
export enum ServerType {
|
||||||
JELLYFIN = 'jellyfin',
|
JELLYFIN = 'jellyfin',
|
||||||
NAVIDROME = 'navidrome',
|
NAVIDROME = 'navidrome',
|
||||||
SUBSONIC = 'subsonic',
|
SUBSONIC = 'subsonic',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ServerFeatures = Partial<Record<ServerFeature, number[]>>;
|
||||||
|
|
||||||
export type ServerInfo = {
|
export type ServerInfo = {
|
||||||
features: ServerFeatures;
|
features: ServerFeatures;
|
||||||
id?: string;
|
id?: string;
|
||||||
@@ -53,8 +64,10 @@ export type ServerMusicFolder = {
|
|||||||
export type ServerMusicFolderListArgs = BaseEndpointArgs;
|
export type ServerMusicFolderListArgs = BaseEndpointArgs;
|
||||||
|
|
||||||
export type ServerMusicFolderListQuery = null;
|
export type ServerMusicFolderListQuery = null;
|
||||||
|
|
||||||
export type ServerMusicFolderListResponse =
|
export type ServerMusicFolderListResponse =
|
||||||
| BasePaginatedResponse<ServerMusicFolder[]>
|
| BasePaginatedResponse<ServerMusicFolder[]>
|
||||||
| null
|
| null
|
||||||
| undefined;
|
| undefined;
|
||||||
|
|
||||||
export type ServerMusicFoldersResponse = ServerMusicFolder[];
|
export type ServerMusicFoldersResponse = ServerMusicFolder[];
|
||||||
|
|||||||
@@ -1,4 +1,58 @@
|
|||||||
|
import { JFSortOrder } from '/@/shared/api/jellyfin.types';
|
||||||
|
import { NDSortOrder } from '/@/shared/api/navidrome.types';
|
||||||
|
import { Album } from '/@/shared/types/domain/album-domain-types';
|
||||||
|
import { AlbumArtist, Artist } from '/@/shared/types/domain/artist-domain-types';
|
||||||
|
import { QueueSong } from '/@/shared/types/domain/player-domain-types';
|
||||||
|
import { Playlist } from '/@/shared/types/domain/playlist-domain-types';
|
||||||
|
import { Song } from '/@/shared/types/domain/song-domain-types';
|
||||||
|
|
||||||
|
export enum LibraryItem {
|
||||||
|
ALBUM = 'album',
|
||||||
|
ALBUM_ARTIST = 'albumArtist',
|
||||||
|
ARTIST = 'artist',
|
||||||
|
GENRE = 'genre',
|
||||||
|
PLAYLIST = 'playlist',
|
||||||
|
SONG = 'song',
|
||||||
|
}
|
||||||
export enum ListSortOrder {
|
export enum ListSortOrder {
|
||||||
ASC = 'ASC',
|
ASC = 'ASC',
|
||||||
DESC = 'DESC',
|
DESC = 'DESC',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type AnyLibraryItem = Album | AlbumArtist | Artist | Playlist | QueueSong | Song;
|
||||||
|
|
||||||
|
export type AnyLibraryItems =
|
||||||
|
| Album[]
|
||||||
|
| AlbumArtist[]
|
||||||
|
| Artist[]
|
||||||
|
| Playlist[]
|
||||||
|
| QueueSong[]
|
||||||
|
| Song[];
|
||||||
|
type SortOrderMap = {
|
||||||
|
jellyfin: Record<ListSortOrder, JFSortOrder>;
|
||||||
|
navidrome: Record<ListSortOrder, NDSortOrder>;
|
||||||
|
subsonic: Record<ListSortOrder, undefined>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const sortOrderMap: SortOrderMap = {
|
||||||
|
jellyfin: {
|
||||||
|
ASC: JFSortOrder.ASC,
|
||||||
|
DESC: JFSortOrder.DESC,
|
||||||
|
},
|
||||||
|
navidrome: {
|
||||||
|
ASC: NDSortOrder.ASC,
|
||||||
|
DESC: NDSortOrder.DESC,
|
||||||
|
},
|
||||||
|
subsonic: {
|
||||||
|
ASC: undefined,
|
||||||
|
DESC: undefined,
|
||||||
|
},
|
||||||
|
}; // This type from https://wicg.github.io/local-font-access/#fontdata
|
||||||
|
// NOTE: it is still experimental, so this should be updates as appropriate
|
||||||
|
|
||||||
|
export type FontData = {
|
||||||
|
family: string;
|
||||||
|
fullName: string;
|
||||||
|
postscriptName: string;
|
||||||
|
style: string;
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import i18n from 'src/i18n/i18n';
|
import { orderBy, reverse, shuffle } from 'lodash';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
import i18n from '/@/i18n/i18n';
|
||||||
import { JFSongListSort } from '/@/shared/api/jellyfin.types';
|
import { JFSongListSort } from '/@/shared/api/jellyfin.types';
|
||||||
import { jfType } from '/@/shared/api/jellyfin/jellyfin-types';
|
import { jfType } from '/@/shared/api/jellyfin/jellyfin-types';
|
||||||
import { NDSongListSort } from '/@/shared/api/navidrome.types';
|
import { NDSongListSort } from '/@/shared/api/navidrome.types';
|
||||||
@@ -9,13 +10,12 @@ import {
|
|||||||
BaseEndpointArgs,
|
BaseEndpointArgs,
|
||||||
BasePaginatedResponse,
|
BasePaginatedResponse,
|
||||||
BaseQuery,
|
BaseQuery,
|
||||||
GainInfo,
|
} from '/@/shared/types/domain/api-domain-types';
|
||||||
LibraryItem,
|
|
||||||
Played,
|
|
||||||
} from '/@/shared/types/domain-types';
|
|
||||||
import { RelatedArtist } from '/@/shared/types/domain/artist-domain-types';
|
import { RelatedArtist } from '/@/shared/types/domain/artist-domain-types';
|
||||||
import { Genre } from '/@/shared/types/domain/genre-domain-types';
|
import { Genre } from '/@/shared/types/domain/genre-domain-types';
|
||||||
|
import { Played, QueueSong } from '/@/shared/types/domain/player-domain-types';
|
||||||
import { ServerType } from '/@/shared/types/domain/server-domain-types';
|
import { ServerType } from '/@/shared/types/domain/server-domain-types';
|
||||||
|
import { LibraryItem, ListSortOrder } from '/@/shared/types/domain/shared-domain-types';
|
||||||
|
|
||||||
export enum SongListSortOptions {
|
export enum SongListSortOptions {
|
||||||
ALBUM = 'album',
|
ALBUM = 'album',
|
||||||
@@ -212,6 +212,11 @@ export const songListSortMap: SongListSortMap = {
|
|||||||
year: undefined,
|
year: undefined,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
export type GainInfo = {
|
||||||
|
album?: number;
|
||||||
|
track?: number;
|
||||||
|
};
|
||||||
|
|
||||||
export type RandomSongListArgs = BaseEndpointArgs & {
|
export type RandomSongListArgs = BaseEndpointArgs & {
|
||||||
query: RandomSongListQuery;
|
query: RandomSongListQuery;
|
||||||
};
|
};
|
||||||
@@ -224,8 +229,8 @@ export type RandomSongListQuery = {
|
|||||||
musicFolderId?: string;
|
musicFolderId?: string;
|
||||||
played: Played;
|
played: Played;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type RandomSongListResponse = SongListResponse;
|
export type RandomSongListResponse = SongListResponse;
|
||||||
|
|
||||||
export type SimilarSongsArgs = BaseEndpointArgs & {
|
export type SimilarSongsArgs = BaseEndpointArgs & {
|
||||||
query: SimilarSongsQuery;
|
query: SimilarSongsQuery;
|
||||||
};
|
};
|
||||||
@@ -235,11 +240,11 @@ export type SimilarSongsQuery = {
|
|||||||
count?: number;
|
count?: number;
|
||||||
songId: string;
|
songId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SongDetailArgs = BaseEndpointArgs & { query: SongDetailQuery };
|
export type SongDetailArgs = BaseEndpointArgs & { query: SongDetailQuery };
|
||||||
export type SongDetailQuery = { id: string };
|
|
||||||
|
|
||||||
|
export type SongDetailQuery = { id: string };
|
||||||
export type SongDetailResponse = null | Song | undefined;
|
export type SongDetailResponse = null | Song | undefined;
|
||||||
|
|
||||||
export type TopSongListArgs = BaseEndpointArgs & { query: TopSongListQuery };
|
export type TopSongListArgs = BaseEndpointArgs & { query: TopSongListQuery };
|
||||||
|
|
||||||
export type TopSongListQuery = {
|
export type TopSongListQuery = {
|
||||||
@@ -247,5 +252,99 @@ export type TopSongListQuery = {
|
|||||||
artistId: string;
|
artistId: string;
|
||||||
limit?: number;
|
limit?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TopSongListResponse = BasePaginatedResponse<Song[]> | null | undefined;
|
export type TopSongListResponse = BasePaginatedResponse<Song[]> | null | undefined;
|
||||||
|
export const sortSongList = (
|
||||||
|
songs: QueueSong[],
|
||||||
|
sortBy: SongListSort,
|
||||||
|
sortOrder: ListSortOrder,
|
||||||
|
) => {
|
||||||
|
let results = songs;
|
||||||
|
|
||||||
|
const order = sortOrder === ListSortOrder.ASC ? 'asc' : 'desc';
|
||||||
|
|
||||||
|
switch (sortBy) {
|
||||||
|
case SongListSort.ALBUM:
|
||||||
|
results = orderBy(
|
||||||
|
results,
|
||||||
|
[(v) => v.album?.toLowerCase(), 'discNumber', 'trackNumber'],
|
||||||
|
[order, 'asc', 'asc'],
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SongListSort.ALBUM_ARTIST:
|
||||||
|
results = orderBy(
|
||||||
|
results,
|
||||||
|
['albumArtist', (v) => v.album?.toLowerCase(), 'discNumber', 'trackNumber'],
|
||||||
|
[order, order, 'asc', 'asc'],
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SongListSort.ARTIST:
|
||||||
|
results = orderBy(
|
||||||
|
results,
|
||||||
|
['artist', (v) => v.album?.toLowerCase(), 'discNumber', 'trackNumber'],
|
||||||
|
[order, order, 'asc', 'asc'],
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SongListSort.DURATION:
|
||||||
|
results = orderBy(results, ['duration'], [order]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SongListSort.FAVORITED:
|
||||||
|
results = orderBy(results, ['userFavorite', (v) => v.name.toLowerCase()], [order]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SongListSort.GENRE:
|
||||||
|
results = orderBy(
|
||||||
|
results,
|
||||||
|
[
|
||||||
|
(v) => v.genres?.[0].name.toLowerCase(),
|
||||||
|
(v) => v.album?.toLowerCase(),
|
||||||
|
'discNumber',
|
||||||
|
'trackNumber',
|
||||||
|
],
|
||||||
|
[order, order, 'asc', 'asc'],
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SongListSort.ID:
|
||||||
|
if (order === 'desc') {
|
||||||
|
results = reverse(results as any);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SongListSort.NAME:
|
||||||
|
results = orderBy(results, [(v) => v.name.toLowerCase()], [order]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SongListSort.PLAY_COUNT:
|
||||||
|
results = orderBy(results, ['playCount'], [order]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SongListSort.RANDOM:
|
||||||
|
results = shuffle(results);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SongListSort.RATING:
|
||||||
|
results = orderBy(results, ['userRating', (v) => v.name.toLowerCase()], [order]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SongListSort.RECENTLY_ADDED:
|
||||||
|
results = orderBy(results, ['created'], [order]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SongListSort.YEAR:
|
||||||
|
results = orderBy(
|
||||||
|
results,
|
||||||
|
['year', (v) => v.album?.toLowerCase(), 'discNumber', 'track'],
|
||||||
|
[order, 'asc', 'asc', 'asc'],
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { BaseEndpointArgs } from '/@/shared/types/domain/api-domain-types';
|
||||||
|
import { LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||||
|
|
||||||
|
export type Tag = {
|
||||||
|
name: string;
|
||||||
|
options: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TagArgs = BaseEndpointArgs & {
|
||||||
|
query: TagQuery;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TagQuery = {
|
||||||
|
folder?: string;
|
||||||
|
type: LibraryItem.ALBUM | LibraryItem.SONG;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TagsResponse = {
|
||||||
|
boolTags?: string[];
|
||||||
|
enumTags?: Tag[];
|
||||||
|
};
|
||||||
@@ -1,13 +1,11 @@
|
|||||||
import i18n from 'src/i18n/i18n';
|
import i18n from '/@/i18n/i18n';
|
||||||
|
import { NDUserListSort } from '/@/shared/api/navidrome.types';
|
||||||
import {
|
import {
|
||||||
AnyLibraryItems,
|
|
||||||
BaseEndpointArgs,
|
BaseEndpointArgs,
|
||||||
BasePaginatedResponse,
|
BasePaginatedResponse,
|
||||||
BaseQuery,
|
BaseQuery,
|
||||||
LibraryItem,
|
} from '/@/shared/types/domain/api-domain-types';
|
||||||
} from '/@/shared/types/domain-types';
|
import { AnyLibraryItems, LibraryItem } from '/@/shared/types/domain/shared-domain-types';
|
||||||
import { RatingQuery } from '/@/shared/types/domain/user-domain-types';
|
|
||||||
import { NDUserListSort } from '/@/shared/api/navidrome.types';
|
|
||||||
|
|
||||||
export enum UserListSortOptions {
|
export enum UserListSortOptions {
|
||||||
CREATED_AT = 'createdAt',
|
CREATED_AT = 'createdAt',
|
||||||
@@ -22,6 +20,7 @@ export const UserListSortOptionsLabels = {
|
|||||||
[UserListSortOptions.NAME]: i18n.t('filter.name'),
|
[UserListSortOptions.NAME]: i18n.t('filter.name'),
|
||||||
[UserListSortOptions.UPDATED_AT]: i18n.t('filter.updatedAt'),
|
[UserListSortOptions.UPDATED_AT]: i18n.t('filter.updatedAt'),
|
||||||
};
|
};
|
||||||
|
|
||||||
export type FavoriteArgs = BaseEndpointArgs & { query: FavoriteQuery; serverId?: string };
|
export type FavoriteArgs = BaseEndpointArgs & { query: FavoriteQuery; serverId?: string };
|
||||||
|
|
||||||
export type FavoriteQuery = {
|
export type FavoriteQuery = {
|
||||||
@@ -36,7 +35,9 @@ export type RatingQuery = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type RatingResponse = null | undefined;
|
export type RatingResponse = null | undefined;
|
||||||
|
|
||||||
export type SetRatingArgs = BaseEndpointArgs & { query: RatingQuery; serverId?: string };
|
export type SetRatingArgs = BaseEndpointArgs & { query: RatingQuery; serverId?: string };
|
||||||
|
|
||||||
export type UserListArgs = BaseEndpointArgs & { query: UserListQuery };
|
export type UserListArgs = BaseEndpointArgs & { query: UserListQuery };
|
||||||
|
|
||||||
export interface UserListQuery extends BaseQuery<UserListSort> {
|
export interface UserListQuery extends BaseQuery<UserListSort> {
|
||||||
@@ -51,6 +52,7 @@ export interface UserListQuery extends BaseQuery<UserListSort> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type UserListResponse = BasePaginatedResponse<User[]> | null | undefined;
|
export type UserListResponse = BasePaginatedResponse<User[]> | null | undefined;
|
||||||
|
|
||||||
type UserListSortMap = {
|
type UserListSortMap = {
|
||||||
jellyfin: Record<UserListSort, undefined>;
|
jellyfin: Record<UserListSort, undefined>;
|
||||||
navidrome: Record<UserListSort, NDUserListSort | undefined>;
|
navidrome: Record<UserListSort, NDUserListSort | undefined>;
|
||||||
@@ -68,6 +70,19 @@ export const userListSortMap: UserListSortMap = {
|
|||||||
name: undefined,
|
name: undefined,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export enum UserListSort {
|
||||||
|
NAME = 'name',
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DownloadArgs = BaseEndpointArgs & {
|
||||||
|
query: DownloadQuery;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DownloadQuery = {
|
||||||
|
id: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type ScrobbleArgs = BaseEndpointArgs & {
|
export type ScrobbleArgs = BaseEndpointArgs & {
|
||||||
query: ScrobbleQuery;
|
query: ScrobbleQuery;
|
||||||
serverId?: string;
|
serverId?: string;
|
||||||
@@ -81,9 +96,19 @@ export type ScrobbleQuery = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type ScrobbleResponse = null | undefined;
|
export type ScrobbleResponse = null | undefined;
|
||||||
export enum UserListSort {
|
|
||||||
NAME = 'name',
|
export type ShareItemArgs = BaseEndpointArgs & { body: ShareItemBody; serverId?: string };
|
||||||
}
|
|
||||||
|
export type ShareItemBody = {
|
||||||
|
description: string;
|
||||||
|
downloadable: boolean;
|
||||||
|
expires: number;
|
||||||
|
resourceIds: string;
|
||||||
|
resourceType: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ShareItemResponse = undefined | { id: string };
|
||||||
|
|
||||||
export type User = {
|
export type User = {
|
||||||
createdAt: null | string;
|
createdAt: null | string;
|
||||||
email: null | string;
|
email: null | string;
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
// Should follow a strict naming convention: "<FEATURE GROUP>_<FEATURE NAME>"
|
|
||||||
// For example: <FEATURE GROUP>: "Playlists", <FEATURE NAME>: "Smart" = "PLAYLISTS_SMART"
|
|
||||||
export enum ServerFeature {
|
|
||||||
BFR = 'bfr',
|
|
||||||
LYRICS_MULTIPLE_STRUCTURED = 'lyricsMultipleStructured',
|
|
||||||
LYRICS_SINGLE_STRUCTURED = 'lyricsSingleStructured',
|
|
||||||
PLAYLISTS_SMART = 'playlistsSmart',
|
|
||||||
PUBLIC_PLAYLIST = 'publicPlaylist',
|
|
||||||
SHARING_ALBUM_SONG = 'sharingAlbumSong',
|
|
||||||
TAGS = 'tags',
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ServerFeatures = Partial<Record<ServerFeature, number[]>>;
|
|
||||||
Reference in New Issue
Block a user