diff --git a/src/shared/types/domain-types.ts b/src/shared/types/domain-types.ts deleted file mode 100644 index aa1c884a3..000000000 --- a/src/shared/types/domain-types.ts +++ /dev/null @@ -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; - navidrome: Record; - subsonic: Record; -}; - -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 { - error?: any | string; - items: T; - startIndex: number; - totalRecordCount: null | number; -} - -export interface BaseQuery { - 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; - authenticate: ( - url: string, - body: { legacy?: boolean; password: string; username: string }, - ) => Promise; - createFavorite: (args: FavoriteArgs) => Promise; - createPlaylist: (args: CreatePlaylistArgs) => Promise; - deleteFavorite: (args: FavoriteArgs) => Promise; - deletePlaylist: (args: DeletePlaylistArgs) => Promise; - getAlbumArtistDetail: (args: AlbumArtistDetailArgs) => Promise; - getAlbumArtistList: (args: AlbumArtistListArgs) => Promise; - getAlbumArtistListCount: (args: AlbumArtistListArgs) => Promise; - getAlbumDetail: (args: AlbumDetailArgs) => Promise; - getAlbumInfo?: (args: AlbumDetailArgs) => Promise; - getAlbumList: (args: AlbumListArgs) => Promise; - getAlbumListCount: (args: AlbumListArgs) => Promise; - // getArtistInfo?: (args: any) => void; - getArtistList: (args: ArtistListArgs) => Promise; - getArtistListCount: (args: ArtistListArgs) => Promise; - getDownloadUrl: (args: DownloadArgs) => string; - getGenreList: (args: GenreListArgs) => Promise; - getLyrics?: (args: LyricsArgs) => Promise; - getMusicFolderList: (args: ServerMusicFolderListArgs) => Promise; - getPlaylistDetail: (args: PlaylistDetailArgs) => Promise; - getPlaylistList: (args: PlaylistListArgs) => Promise; - getPlaylistListCount: (args: PlaylistListArgs) => Promise; - getPlaylistSongList: (args: PlaylistSongListArgs) => Promise; - getRandomSongList: (args: RandomSongListArgs) => Promise; - getRoles: (args: BaseEndpointArgs) => Promise>; - getServerInfo: (args: ServerInfoArgs) => Promise; - getSimilarSongs: (args: SimilarSongsArgs) => Promise; - getSongDetail: (args: SongDetailArgs) => Promise; - getSongList: (args: SongListArgs) => Promise; - getSongListCount: (args: SongListArgs) => Promise; - getStructuredLyrics?: (args: StructuredLyricsArgs) => Promise; - getTags?: (args: TagArgs) => Promise; - getTopSongs: (args: TopSongListArgs) => Promise; - getTranscodingUrl: (args: TranscodingArgs) => string; - getUserList?: (args: UserListArgs) => Promise; - movePlaylistItem?: (args: MoveItemArgs) => Promise; - removeFromPlaylist: (args: RemoveFromPlaylistArgs) => Promise; - scrobble: (args: ScrobbleArgs) => Promise; - search: (args: SearchArgs) => Promise; - setRating?: (args: SetRatingArgs) => Promise; - shareItem?: (args: ShareItemArgs) => Promise; - updatePlaylist: (args: UpdatePlaylistArgs) => Promise; -}; - -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; -}; diff --git a/src/shared/types/domain/album-domain-types.ts b/src/shared/types/domain/album-domain-types.ts index f05034fb0..8f852db83 100644 --- a/src/shared/types/domain/album-domain-types.ts +++ b/src/shared/types/domain/album-domain-types.ts @@ -1,6 +1,7 @@ -import i18n from 'src/i18n/i18n'; +import { orderBy, shuffle } from 'lodash'; import { z } from 'zod'; +import i18n from '/@/i18n/i18n'; import { JFAlbumListSort } from '/@/shared/api/jellyfin.types'; import { jfType } from '/@/shared/api/jellyfin/jellyfin-types'; import { NDAlbumListSort } from '/@/shared/api/navidrome.types'; @@ -9,11 +10,11 @@ import { BaseEndpointArgs, BasePaginatedResponse, BaseQuery, - LibraryItem, -} from '/@/shared/types/domain-types'; +} from '/@/shared/types/domain/api-domain-types'; import { RelatedArtist } from '/@/shared/types/domain/artist-domain-types'; import { Genre } from '/@/shared/types/domain/genre-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'; export enum AlbumListSortOptions { @@ -51,6 +52,7 @@ export const AlbumListSortOptionsLabels = { [AlbumListSortOptions.TRACK_COUNT]: i18n.t('filter.trackCount'), [AlbumListSortOptions.YEAR]: i18n.t('filter.year'), }; + export enum AlbumListSort { ALBUM_ARTIST = 'albumArtist', ARTIST = 'artist', @@ -87,7 +89,6 @@ export interface AlbumListQuery extends BaseQuery { searchTerm?: string; startIndex: number; } -// Album List export type AlbumListResponse = BasePaginatedResponse | null | undefined; type AlbumListSortMap = { @@ -150,13 +151,20 @@ export const albumListSortMap: AlbumListSortMap = { year: undefined, }, }; + export type Album = { albumArtist: string; albumArtists: RelatedArtist[]; artists: RelatedArtist[]; backdropImageUrl: null | string; comment: null | string; - createdAt: string; + createdDate: string; + description: null | string; + discTitles: { + disc: number; + title: string; + }[]; + displayArtist: null | string; duration: null | number; genres: Genre[]; id: string; @@ -164,33 +172,91 @@ export type Album = { imageUrl: null | string; isCompilation: boolean | null; itemType: LibraryItem.ALBUM; - lastPlayedAt: null | string; - mbzId: null | string; + mbzAlbumId: null | string; + mbzReleaseGroupId: null | string; + missing: boolean; name: string; - originalDate: null | string; + originalReleaseDate: null | string; participants: null | Record; - playCount: null | number; releaseDate: null | string; + releaseTypes: { + id: string; + name: string; + }[]; releaseYear: null | number; serverId: string; serverType: ServerType; size: null | number; songCount: null | number; songs?: Song[]; - tags: null | Record; + sortName: string; + tags: Record; uniqueId: string; - updatedAt: string; + updatedDate: string; userFavorite: boolean; + userFavoriteDate: null | string; + userLastPlayedDate: null | string; + userPlayCount: null | number; userRating: null | number; } & { songs?: Song[] }; export type AlbumDetailArgs = BaseEndpointArgs & { query: AlbumDetailQuery }; -// Album Detail export type AlbumDetailQuery = { id: string }; export type AlbumDetailResponse = Album | null | undefined; + export type AlbumInfo = { imageUrl: 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; +}; diff --git a/src/shared/types/domain/api-domain-types.ts b/src/shared/types/domain/api-domain-types.ts new file mode 100644 index 000000000..d2d8053b5 --- /dev/null +++ b/src/shared/types/domain/api-domain-types.ts @@ -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 { + error?: any | string; + items: T; + startIndex: number; + totalRecordCount: null | number; +} + +export interface BaseQuery { + 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; + authenticate: ( + url: string, + body: { legacy?: boolean; password: string; username: string }, + ) => Promise; + createFavorite: (args: FavoriteArgs) => Promise; + createPlaylist: (args: CreatePlaylistArgs) => Promise; + deleteFavorite: (args: FavoriteArgs) => Promise; + deletePlaylist: (args: DeletePlaylistArgs) => Promise; + getAlbumArtistDetail: (args: AlbumArtistDetailArgs) => Promise; + getAlbumArtistList: (args: AlbumArtistListArgs) => Promise; + getAlbumArtistListCount: (args: AlbumArtistListArgs) => Promise; + getAlbumDetail: (args: AlbumDetailArgs) => Promise; + getAlbumInfo?: (args: AlbumDetailArgs) => Promise; + getAlbumList: (args: AlbumListArgs) => Promise; + getAlbumListCount: (args: AlbumListArgs) => Promise; + getArtistList: (args: ArtistListArgs) => Promise; + getArtistListCount: (args: ArtistListArgs) => Promise; + getDownloadUrl: (args: DownloadArgs) => string; + getGenreList: (args: GenreListArgs) => Promise; + getLyrics?: (args: LyricsArgs) => Promise; + getMusicFolderList: (args: ServerMusicFolderListArgs) => Promise; + getPlaylistDetail: (args: PlaylistDetailArgs) => Promise; + getPlaylistList: (args: PlaylistListArgs) => Promise; + getPlaylistListCount: (args: PlaylistListArgs) => Promise; + getPlaylistSongList: (args: PlaylistSongListArgs) => Promise; + getRandomSongList: (args: RandomSongListArgs) => Promise; + getRoles: (args: BaseEndpointArgs) => Promise>; + getServerInfo: (args: ServerInfoArgs) => Promise; + getSimilarSongs: (args: SimilarSongsArgs) => Promise; + getSongDetail: (args: SongDetailArgs) => Promise; + getSongList: (args: SongListArgs) => Promise; + getSongListCount: (args: SongListArgs) => Promise; + getStructuredLyrics?: (args: StructuredLyricsArgs) => Promise; + getTags?: (args: TagArgs) => Promise; + getTopSongs: (args: TopSongListArgs) => Promise; + getTranscodingUrl: (args: TranscodingArgs) => string; + getUserList?: (args: UserListArgs) => Promise; + movePlaylistItem?: (args: MoveItemArgs) => Promise; + removeFromPlaylist: (args: RemoveFromPlaylistArgs) => Promise; + scrobble: (args: ScrobbleArgs) => Promise; + search: (args: SearchArgs) => Promise; + setRating?: (args: SetRatingArgs) => Promise; + shareItem?: (args: ShareItemArgs) => Promise; + updatePlaylist: (args: UpdatePlaylistArgs) => Promise; +}; diff --git a/src/shared/types/domain/artist-domain-types.ts b/src/shared/types/domain/artist-domain-types.ts index eda4eec67..9d04b836e 100644 --- a/src/shared/types/domain/artist-domain-types.ts +++ b/src/shared/types/domain/artist-domain-types.ts @@ -1,6 +1,7 @@ -import i18n from 'src/i18n/i18n'; +import { orderBy } from 'lodash'; import { z } from 'zod'; +import i18n from '/@/i18n/i18n'; import { JFAlbumArtistListSort, JFArtistListSort } from '/@/shared/api/jellyfin.types'; import { jfType } from '/@/shared/api/jellyfin/jellyfin-types'; import { NDAlbumArtistListSort } from '/@/shared/api/navidrome.types'; @@ -9,10 +10,10 @@ import { BaseEndpointArgs, BasePaginatedResponse, BaseQuery, - LibraryItem, -} from '/@/shared/types/domain-types'; +} from '/@/shared/types/domain/api-domain-types'; import { Genre } from '/@/shared/types/domain/genre-domain-types'; import { ServerType } from '/@/shared/types/domain/server-domain-types'; +import { LibraryItem, ListSortOrder } from '/@/shared/types/domain/shared-domain-types'; export enum ArtistListSortOptions { ALBUM_COUNT = 'albumCount', @@ -243,3 +244,35 @@ export type ArtistInfoQuery = { limit: number; 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; +}; diff --git a/src/shared/types/domain/auth-domain-types.ts b/src/shared/types/domain/auth-domain-types.ts new file mode 100644 index 000000000..bc44fb149 --- /dev/null +++ b/src/shared/types/domain/auth-domain-types.ts @@ -0,0 +1,6 @@ +export type AuthenticationResponse = { + credential: string; + ndCredential?: string; + userId: null | string; + username: string; +}; diff --git a/src/shared/types/domain/external-domain-types.ts b/src/shared/types/domain/external-domain-types.ts new file mode 100644 index 000000000..bc6d30088 --- /dev/null +++ b/src/shared/types/domain/external-domain-types.ts @@ -0,0 +1,11 @@ +export enum ExternalSource { + LASTFM = 'LASTFM', + MUSICBRAINZ = 'MUSICBRAINZ', + SPOTIFY = 'SPOTIFY', + THEAUDIODB = 'THEAUDIODB', +} + +export enum ExternalType { + ID = 'ID', + LINK = 'LINK', +} diff --git a/src/shared/types/domain/genre-domain-types.ts b/src/shared/types/domain/genre-domain-types.ts index a43e35ec2..7cf94310d 100644 --- a/src/shared/types/domain/genre-domain-types.ts +++ b/src/shared/types/domain/genre-domain-types.ts @@ -1,15 +1,13 @@ -import i18n from 'src/i18n/i18n'; - -import { UserListSort } from './user-domain-types'; - +import i18n from '/@/i18n/i18n'; import { JFGenreListSort } from '/@/shared/api/jellyfin.types'; import { NDGenreListSort } from '/@/shared/api/navidrome.types'; import { BaseEndpointArgs, BasePaginatedResponse, BaseQuery, - LibraryItem, -} from '/@/shared/types/domain-types'; +} from '/@/shared/types/domain/api-domain-types'; +import { LibraryItem } from '/@/shared/types/domain/shared-domain-types'; +import { UserListSort } from '/@/shared/types/domain/user-domain-types'; export enum GenreListSortOptions { ALBUM_COUNT = 'albumCount', @@ -22,6 +20,7 @@ export const GenreListSortOptionsLabels = { [GenreListSortOptions.NAME]: i18n.t('filter.name'), [GenreListSortOptions.TRACK_COUNT]: i18n.t('filter.trackCount'), }; + export type Genre = { albumCount?: number; id: string; @@ -43,7 +42,6 @@ export interface GenreListQuery extends BaseQuery { searchTerm?: string; startIndex: number; } -// Genre List export type GenreListResponse = BasePaginatedResponse | null | undefined; diff --git a/src/shared/types/domain/image-domain-types.ts b/src/shared/types/domain/image-domain-types.ts new file mode 100644 index 000000000..618bd13e4 --- /dev/null +++ b/src/shared/types/domain/image-domain-types.ts @@ -0,0 +1,6 @@ +export enum ImageType { + BACKDROP = 'BACKDROP', + LOGO = 'LOGO', + PRIMARY = 'PRIMARY', + SCREENSHOT = 'SCREENSHOT', +} diff --git a/src/shared/types/domain/lyric-domain-types.ts b/src/shared/types/domain/lyric-domain-types.ts index 33424dce1..7f3ed3f54 100644 --- a/src/shared/types/domain/lyric-domain-types.ts +++ b/src/shared/types/domain/lyric-domain-types.ts @@ -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'; +export enum LyricSource { + GENIUS = 'Genius', + LRCLIB = 'lrclib.net', + NETEASE = 'NetEase', +} + export type FullLyricsMetadata = Omit & { lyrics: LyricsResponse; remote: boolean; source: string; }; - export type InternetProviderLyricResponse = { artist: string; id: string; @@ -21,6 +26,7 @@ export type InternetProviderLyricSearchResponse = { score?: number; source: LyricSource; }; + export type LyricGetQuery = { remoteSongId: string; remoteSource: LyricSource; @@ -32,7 +38,6 @@ export type LyricOverride = Omit; export type LyricsArgs = BaseEndpointArgs & { query: LyricsQuery; }; - export type LyricSearchQuery = { album?: string; artist?: string; @@ -40,6 +45,7 @@ export type LyricSearchQuery = { name?: string; }; export type LyricsOverride = Omit & { id: string }; + export type LyricsQuery = { songId: string; }; @@ -58,7 +64,6 @@ export type StructuredSyncedLyric = Omit & { lyrics: SynchronizedLyricsArray; synced: true; }; - export type StructuredUnsyncedLyric = Omit & { lyrics: string; synced: false; diff --git a/src/shared/types/domain/player-domain-types.ts b/src/shared/types/domain/player-domain-types.ts new file mode 100644 index 000000000..01c708c54 --- /dev/null +++ b/src/shared/types/domain/player-domain-types.ts @@ -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; +}; diff --git a/src/shared/types/domain/playlist-domain-types.ts b/src/shared/types/domain/playlist-domain-types.ts index 01b3b4e74..a95ce53d0 100644 --- a/src/shared/types/domain/playlist-domain-types.ts +++ b/src/shared/types/domain/playlist-domain-types.ts @@ -1,8 +1,6 @@ -import i18n from 'src/i18n/i18n'; import { z } from 'zod'; -import { Genre } from './genre-domain-types'; - +import i18n from '/@/i18n/i18n'; import { JFPlaylistListSort } from '/@/shared/api/jellyfin.types'; import { jfType } from '/@/shared/api/jellyfin/jellyfin-types'; import { NDPlaylistListSort } from '/@/shared/api/navidrome.types'; @@ -11,10 +9,10 @@ import { BaseEndpointArgs, BasePaginatedResponse, BaseQuery, - LibraryItem, -} from '/@/shared/types/domain-types'; +} from '/@/shared/types/domain/api-domain-types'; +import { Genre } from '/@/shared/types/domain/genre-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'; export enum PlaylistListSortOptions { @@ -191,6 +189,17 @@ export const playlistListSortMap: PlaylistListSortMap = { 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 PlaylistDetailQuery = { @@ -200,7 +209,6 @@ export type PlaylistDetailQuery = { export type PlaylistDetailResponse = Playlist; export type PlaylistSongListArgs = BaseEndpointArgs & { query: PlaylistSongListQuery }; - export type PlaylistSongListQuery = { id: string; limit?: number; diff --git a/src/shared/types/domain/remote-types.ts b/src/shared/types/domain/remote-types.ts new file mode 100644 index 000000000..7e2fb5208 --- /dev/null +++ b/src/shared/types/domain/remote-types.ts @@ -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 { + position?: number; + song?: null | QueueSong; +} diff --git a/src/shared/types/domain/search-domain-types.ts b/src/shared/types/domain/search-domain-types.ts index bd73b0d18..4f666751a 100644 --- a/src/shared/types/domain/search-domain-types.ts +++ b/src/shared/types/domain/search-domain-types.ts @@ -1,5 +1,5 @@ -import { BaseEndpointArgs } from '/@/shared/types/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 { Song } from '/@/shared/types/domain/song-domain-types'; diff --git a/src/shared/types/domain/server-domain-types.ts b/src/shared/types/domain/server-domain-types.ts index 49e44fc6b..b6d82d4c6 100644 --- a/src/shared/types/domain/server-domain-types.ts +++ b/src/shared/types/domain/server-domain-types.ts @@ -1,7 +1,6 @@ import i18n from 'src/i18n/i18n'; -import { BaseEndpointArgs, BasePaginatedResponse } from '/@/shared/types/domain-types'; -import { ServerFeatures } from '/@/shared/types/features-types'; +import { BaseEndpointArgs, BasePaginatedResponse } from '/@/shared/types/domain/api-domain-types'; export enum ServerListSortOptions { CREATED_AT = 'createdAt', @@ -17,12 +16,24 @@ export const ServerListSortOptionsLabels = { [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 { JELLYFIN = 'jellyfin', NAVIDROME = 'navidrome', SUBSONIC = 'subsonic', } +export type ServerFeatures = Partial>; + export type ServerInfo = { features: ServerFeatures; id?: string; @@ -53,8 +64,10 @@ export type ServerMusicFolder = { export type ServerMusicFolderListArgs = BaseEndpointArgs; export type ServerMusicFolderListQuery = null; + export type ServerMusicFolderListResponse = | BasePaginatedResponse | null | undefined; + export type ServerMusicFoldersResponse = ServerMusicFolder[]; diff --git a/src/shared/types/domain/shared-domain-types.ts b/src/shared/types/domain/shared-domain-types.ts index 9d167ec09..739878c9b 100644 --- a/src/shared/types/domain/shared-domain-types.ts +++ b/src/shared/types/domain/shared-domain-types.ts @@ -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 { ASC = 'ASC', DESC = 'DESC', } + +export type AnyLibraryItem = Album | AlbumArtist | Artist | Playlist | QueueSong | Song; + +export type AnyLibraryItems = + | Album[] + | AlbumArtist[] + | Artist[] + | Playlist[] + | QueueSong[] + | Song[]; +type SortOrderMap = { + jellyfin: Record; + navidrome: Record; + subsonic: Record; +}; + +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; +}; diff --git a/src/shared/types/domain/song-domain-types.ts b/src/shared/types/domain/song-domain-types.ts index 180bc402e..d364e9eba 100644 --- a/src/shared/types/domain/song-domain-types.ts +++ b/src/shared/types/domain/song-domain-types.ts @@ -1,6 +1,7 @@ -import i18n from 'src/i18n/i18n'; +import { orderBy, reverse, shuffle } from 'lodash'; import { z } from 'zod'; +import i18n from '/@/i18n/i18n'; import { JFSongListSort } from '/@/shared/api/jellyfin.types'; import { jfType } from '/@/shared/api/jellyfin/jellyfin-types'; import { NDSongListSort } from '/@/shared/api/navidrome.types'; @@ -9,13 +10,12 @@ import { BaseEndpointArgs, BasePaginatedResponse, BaseQuery, - GainInfo, - LibraryItem, - Played, -} from '/@/shared/types/domain-types'; +} from '/@/shared/types/domain/api-domain-types'; import { RelatedArtist } from '/@/shared/types/domain/artist-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 { LibraryItem, ListSortOrder } from '/@/shared/types/domain/shared-domain-types'; export enum SongListSortOptions { ALBUM = 'album', @@ -212,6 +212,11 @@ export const songListSortMap: SongListSortMap = { year: undefined, }, }; +export type GainInfo = { + album?: number; + track?: number; +}; + export type RandomSongListArgs = BaseEndpointArgs & { query: RandomSongListQuery; }; @@ -224,8 +229,8 @@ export type RandomSongListQuery = { musicFolderId?: string; played: Played; }; - export type RandomSongListResponse = SongListResponse; + export type SimilarSongsArgs = BaseEndpointArgs & { query: SimilarSongsQuery; }; @@ -235,11 +240,11 @@ export type SimilarSongsQuery = { count?: number; songId: string; }; - export type SongDetailArgs = BaseEndpointArgs & { query: SongDetailQuery }; -export type SongDetailQuery = { id: string }; +export type SongDetailQuery = { id: string }; export type SongDetailResponse = null | Song | undefined; + export type TopSongListArgs = BaseEndpointArgs & { query: TopSongListQuery }; export type TopSongListQuery = { @@ -247,5 +252,99 @@ export type TopSongListQuery = { artistId: string; limit?: number; }; - export type TopSongListResponse = BasePaginatedResponse | 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; +}; diff --git a/src/shared/types/domain/tag-domain-types.ts b/src/shared/types/domain/tag-domain-types.ts new file mode 100644 index 000000000..5e121cc8e --- /dev/null +++ b/src/shared/types/domain/tag-domain-types.ts @@ -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[]; +}; diff --git a/src/shared/types/domain/user-domain-types.ts b/src/shared/types/domain/user-domain-types.ts index 14e28bfbd..55b1725d5 100644 --- a/src/shared/types/domain/user-domain-types.ts +++ b/src/shared/types/domain/user-domain-types.ts @@ -1,13 +1,11 @@ -import i18n from 'src/i18n/i18n'; +import i18n from '/@/i18n/i18n'; +import { NDUserListSort } from '/@/shared/api/navidrome.types'; import { - AnyLibraryItems, BaseEndpointArgs, BasePaginatedResponse, BaseQuery, - LibraryItem, -} from '/@/shared/types/domain-types'; -import { RatingQuery } from '/@/shared/types/domain/user-domain-types'; -import { NDUserListSort } from '/@/shared/api/navidrome.types'; +} from '/@/shared/types/domain/api-domain-types'; +import { AnyLibraryItems, LibraryItem } from '/@/shared/types/domain/shared-domain-types'; export enum UserListSortOptions { CREATED_AT = 'createdAt', @@ -22,6 +20,7 @@ export const UserListSortOptionsLabels = { [UserListSortOptions.NAME]: i18n.t('filter.name'), [UserListSortOptions.UPDATED_AT]: i18n.t('filter.updatedAt'), }; + export type FavoriteArgs = BaseEndpointArgs & { query: FavoriteQuery; serverId?: string }; export type FavoriteQuery = { @@ -36,7 +35,9 @@ export type RatingQuery = { }; export type RatingResponse = null | undefined; + export type SetRatingArgs = BaseEndpointArgs & { query: RatingQuery; serverId?: string }; + export type UserListArgs = BaseEndpointArgs & { query: UserListQuery }; export interface UserListQuery extends BaseQuery { @@ -51,6 +52,7 @@ export interface UserListQuery extends BaseQuery { } export type UserListResponse = BasePaginatedResponse | null | undefined; + type UserListSortMap = { jellyfin: Record; navidrome: Record; @@ -68,6 +70,19 @@ export const userListSortMap: UserListSortMap = { name: undefined, }, }; + +export enum UserListSort { + NAME = 'name', +} + +export type DownloadArgs = BaseEndpointArgs & { + query: DownloadQuery; +}; + +export type DownloadQuery = { + id: string; +}; + export type ScrobbleArgs = BaseEndpointArgs & { query: ScrobbleQuery; serverId?: string; @@ -81,9 +96,19 @@ export type ScrobbleQuery = { }; 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 = { createdAt: null | string; email: null | string; diff --git a/src/shared/types/features-types.ts b/src/shared/types/features-types.ts deleted file mode 100644 index 872deafca..000000000 --- a/src/shared/types/features-types.ts +++ /dev/null @@ -1,13 +0,0 @@ -// Should follow a strict naming convention: "_" -// For example: : "Playlists", : "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>;