mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-07 04:20:12 +02:00
begin reorganizing domain types
This commit is contained in:
@@ -227,7 +227,11 @@
|
||||
"songCount": "song count",
|
||||
"title": "title",
|
||||
"toYear": "to year",
|
||||
"trackNumber": "track"
|
||||
"trackNumber": "track",
|
||||
"createdAt": "created at",
|
||||
"updatedAt": "updated at",
|
||||
"type": "type",
|
||||
"email": "email"
|
||||
},
|
||||
"form": {
|
||||
"addServer": {
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
getSearchResults as searchNetease,
|
||||
} from './netease';
|
||||
|
||||
import { Song } from '/@/shared/types/domain-types';
|
||||
import { Song } from '/@/shared/types/domain/song-domain-types';
|
||||
|
||||
export enum LyricSource {
|
||||
GENIUS = 'Genius',
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import Fuse from 'fuse.js';
|
||||
|
||||
import {
|
||||
InternetProviderLyricSearchResponse,
|
||||
LyricSearchQuery,
|
||||
} from '/@/shared/types/domain-types';
|
||||
import { InternetProviderLyricSearchResponse } from '/@/shared/types/domain/lyric-domain-types';
|
||||
import { LyricSearchQuery } from '/@/shared/types/domain/lyric-domain-types';
|
||||
|
||||
export const orderSearchResults = (args: {
|
||||
params: LyricSearchQuery;
|
||||
|
||||
@@ -3,17 +3,17 @@ import { z } from 'zod';
|
||||
|
||||
import { JFAlbum, JFGenre, JFMusicFolder, JFPlaylist } from '/@/shared/api/jellyfin.types';
|
||||
import { jfType } from '/@/shared/api/jellyfin/jellyfin-types';
|
||||
import { LibraryItem } from '/@/shared/types/domain-types';
|
||||
import { Album } from '/@/shared/types/domain/album-domain-types';
|
||||
import { AlbumArtist, RelatedArtist } from '/@/shared/types/domain/artist-domain-types';
|
||||
import { Genre } from '/@/shared/types/domain/genre-domain-types';
|
||||
import { Playlist } from '/@/shared/types/domain/playlist-domain-types';
|
||||
import {
|
||||
Album,
|
||||
AlbumArtist,
|
||||
Genre,
|
||||
LibraryItem,
|
||||
MusicFolder,
|
||||
Playlist,
|
||||
RelatedArtist,
|
||||
Song,
|
||||
} from '/@/shared/types/domain-types';
|
||||
import { ServerListItem, ServerType } from '/@/shared/types/types';
|
||||
ServerListItem,
|
||||
ServerMusicFolder,
|
||||
ServerType,
|
||||
} from '/@/shared/types/domain/server-domain-types';
|
||||
import { Song } from '/@/shared/types/domain/song-domain-types';
|
||||
|
||||
const getStreamUrl = (args: {
|
||||
container?: string;
|
||||
@@ -432,7 +432,7 @@ const normalizePlaylist = (
|
||||
};
|
||||
};
|
||||
|
||||
const normalizeMusicFolder = (item: JFMusicFolder): MusicFolder => {
|
||||
const normalizeMusicFolder = (item: JFMusicFolder): ServerMusicFolder => {
|
||||
return {
|
||||
id: item.Id,
|
||||
name: item.Name,
|
||||
|
||||
@@ -4,17 +4,14 @@ import z from 'zod';
|
||||
import { NDGenre } from '/@/shared/api/navidrome.types';
|
||||
import { ndType } from '/@/shared/api/navidrome/navidrome-types';
|
||||
import { ssType } from '/@/shared/api/subsonic/subsonic-types';
|
||||
import {
|
||||
Album,
|
||||
AlbumArtist,
|
||||
Genre,
|
||||
LibraryItem,
|
||||
Playlist,
|
||||
RelatedArtist,
|
||||
Song,
|
||||
User,
|
||||
} from '/@/shared/types/domain-types';
|
||||
import { ServerListItem, ServerType } from '/@/shared/types/types';
|
||||
import { LibraryItem } from '/@/shared/types/domain-types';
|
||||
import { Album } from '/@/shared/types/domain/album-domain-types';
|
||||
import { AlbumArtist, RelatedArtist } from '/@/shared/types/domain/artist-domain-types';
|
||||
import { Genre } from '/@/shared/types/domain/genre-domain-types';
|
||||
import { Playlist } from '/@/shared/types/domain/playlist-domain-types';
|
||||
import { ServerListItem, ServerType } from '/@/shared/types/domain/server-domain-types';
|
||||
import { Song } from '/@/shared/types/domain/song-domain-types';
|
||||
import { User } from '/@/shared/types/domain/user-domain-types';
|
||||
|
||||
const getImageUrl = (args: { url: null | string }) => {
|
||||
const { url } = args;
|
||||
|
||||
@@ -2,17 +2,12 @@ import { nanoid } from 'nanoid';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { ssType } from '/@/shared/api/subsonic/subsonic-types';
|
||||
import {
|
||||
Album,
|
||||
AlbumArtist,
|
||||
Genre,
|
||||
LibraryItem,
|
||||
Playlist,
|
||||
QueueSong,
|
||||
RelatedArtist,
|
||||
ServerListItem,
|
||||
ServerType,
|
||||
} from '/@/shared/types/domain-types';
|
||||
import { LibraryItem, QueueSong } from '/@/shared/types/domain-types';
|
||||
import { Album } from '/@/shared/types/domain/album-domain-types';
|
||||
import { AlbumArtist, RelatedArtist } from '/@/shared/types/domain/artist-domain-types';
|
||||
import { Genre } from '/@/shared/types/domain/genre-domain-types';
|
||||
import { Playlist } from '/@/shared/types/domain/playlist-domain-types';
|
||||
import { ServerListItem, ServerType } from '/@/shared/types/domain/server-domain-types';
|
||||
|
||||
const getCoverArtUrl = (args: {
|
||||
baseUrl: string | undefined;
|
||||
|
||||
@@ -4,7 +4,7 @@ import semverCoerce from 'semver/functions/coerce';
|
||||
import semverGte from 'semver/functions/gte';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { ServerListItem } from '/@/shared/types/domain-types';
|
||||
import { ServerListItem } from '/@/shared/types/domain/server-domain-types';
|
||||
import { ServerFeature } from '/@/shared/types/features-types';
|
||||
|
||||
// Since ts-rest client returns a strict response type, we need to add the headers to the body object
|
||||
|
||||
+104
-1096
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,196 @@
|
||||
import i18n from 'src/i18n/i18n';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { JFAlbumListSort } from '/@/shared/api/jellyfin.types';
|
||||
import { jfType } from '/@/shared/api/jellyfin/jellyfin-types';
|
||||
import { NDAlbumListSort } from '/@/shared/api/navidrome.types';
|
||||
import { ndType } from '/@/shared/api/navidrome/navidrome-types';
|
||||
import {
|
||||
BaseEndpointArgs,
|
||||
BasePaginatedResponse,
|
||||
BaseQuery,
|
||||
LibraryItem,
|
||||
} from '/@/shared/types/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 { Song } from '/@/shared/types/domain/song-domain-types';
|
||||
|
||||
export enum AlbumListSortOptions {
|
||||
ALBUM_ARTIST = 'albumArtist',
|
||||
ARTIST = 'artist',
|
||||
COMMUNITY_RATING = 'communityRating',
|
||||
CRITIC_RATING = 'criticRating',
|
||||
DATE_ADDED = 'dateAdded',
|
||||
DATE_PLAYED = 'datePlayed',
|
||||
DURATION = 'duration',
|
||||
IS_FAVORITE = 'isFavorite',
|
||||
NAME = 'name',
|
||||
PLAY_COUNT = 'playCount',
|
||||
RANDOM = 'random',
|
||||
RATING = 'rating',
|
||||
RELEASE_DATE = 'releaseDate',
|
||||
TRACK_COUNT = 'trackCount',
|
||||
YEAR = 'year',
|
||||
}
|
||||
|
||||
export const AlbumListSortOptionsLabels = {
|
||||
[AlbumListSortOptions.ALBUM_ARTIST]: i18n.t('filter.albumArtist'),
|
||||
[AlbumListSortOptions.ARTIST]: i18n.t('filter.artist'),
|
||||
[AlbumListSortOptions.COMMUNITY_RATING]: i18n.t('filter.communityRating'),
|
||||
[AlbumListSortOptions.CRITIC_RATING]: i18n.t('filter.criticRating'),
|
||||
[AlbumListSortOptions.DATE_ADDED]: i18n.t('filter.dateAdded'),
|
||||
[AlbumListSortOptions.DATE_PLAYED]: i18n.t('filter.datePlayed'),
|
||||
[AlbumListSortOptions.DURATION]: i18n.t('filter.duration'),
|
||||
[AlbumListSortOptions.IS_FAVORITE]: i18n.t('filter.isFavorite'),
|
||||
[AlbumListSortOptions.NAME]: i18n.t('filter.name'),
|
||||
[AlbumListSortOptions.PLAY_COUNT]: i18n.t('filter.playCount'),
|
||||
[AlbumListSortOptions.RANDOM]: i18n.t('filter.random'),
|
||||
[AlbumListSortOptions.RATING]: i18n.t('filter.rating'),
|
||||
[AlbumListSortOptions.RELEASE_DATE]: i18n.t('filter.releaseDate'),
|
||||
[AlbumListSortOptions.TRACK_COUNT]: i18n.t('filter.trackCount'),
|
||||
[AlbumListSortOptions.YEAR]: i18n.t('filter.year'),
|
||||
};
|
||||
export enum AlbumListSort {
|
||||
ALBUM_ARTIST = 'albumArtist',
|
||||
ARTIST = 'artist',
|
||||
COMMUNITY_RATING = 'communityRating',
|
||||
CRITIC_RATING = 'criticRating',
|
||||
DURATION = 'duration',
|
||||
FAVORITED = 'favorited',
|
||||
NAME = 'name',
|
||||
PLAY_COUNT = 'playCount',
|
||||
RANDOM = 'random',
|
||||
RATING = 'rating',
|
||||
RECENTLY_ADDED = 'recentlyAdded',
|
||||
RECENTLY_PLAYED = 'recentlyPlayed',
|
||||
RELEASE_DATE = 'releaseDate',
|
||||
SONG_COUNT = 'songCount',
|
||||
YEAR = 'year',
|
||||
}
|
||||
|
||||
export type AlbumListArgs = BaseEndpointArgs & { query: AlbumListQuery };
|
||||
|
||||
export interface AlbumListQuery extends BaseQuery<AlbumListSort> {
|
||||
_custom?: {
|
||||
jellyfin?: Partial<z.infer<typeof jfType._parameters.albumList>>;
|
||||
navidrome?: Partial<z.infer<typeof ndType._parameters.albumList>>;
|
||||
};
|
||||
artistIds?: string[];
|
||||
compilation?: boolean;
|
||||
favorite?: boolean;
|
||||
genres?: string[];
|
||||
limit?: number;
|
||||
maxYear?: number;
|
||||
minYear?: number;
|
||||
musicFolderId?: string;
|
||||
searchTerm?: string;
|
||||
startIndex: number;
|
||||
}
|
||||
// Album List
|
||||
|
||||
export type AlbumListResponse = BasePaginatedResponse<Album[]> | null | undefined;
|
||||
type AlbumListSortMap = {
|
||||
jellyfin: Record<AlbumListSort, JFAlbumListSort | undefined>;
|
||||
navidrome: Record<AlbumListSort, NDAlbumListSort | undefined>;
|
||||
subsonic: Record<AlbumListSort, undefined>;
|
||||
};
|
||||
|
||||
export const albumListSortMap: AlbumListSortMap = {
|
||||
jellyfin: {
|
||||
albumArtist: JFAlbumListSort.ALBUM_ARTIST,
|
||||
artist: undefined,
|
||||
communityRating: JFAlbumListSort.COMMUNITY_RATING,
|
||||
criticRating: JFAlbumListSort.CRITIC_RATING,
|
||||
duration: undefined,
|
||||
favorited: undefined,
|
||||
name: JFAlbumListSort.NAME,
|
||||
playCount: JFAlbumListSort.PLAY_COUNT,
|
||||
random: JFAlbumListSort.RANDOM,
|
||||
rating: undefined,
|
||||
recentlyAdded: JFAlbumListSort.RECENTLY_ADDED,
|
||||
recentlyPlayed: undefined,
|
||||
releaseDate: JFAlbumListSort.RELEASE_DATE,
|
||||
songCount: undefined,
|
||||
year: undefined,
|
||||
},
|
||||
navidrome: {
|
||||
albumArtist: NDAlbumListSort.ALBUM_ARTIST,
|
||||
artist: NDAlbumListSort.ARTIST,
|
||||
communityRating: undefined,
|
||||
criticRating: undefined,
|
||||
duration: NDAlbumListSort.DURATION,
|
||||
favorited: NDAlbumListSort.STARRED,
|
||||
name: NDAlbumListSort.NAME,
|
||||
playCount: NDAlbumListSort.PLAY_COUNT,
|
||||
random: NDAlbumListSort.RANDOM,
|
||||
rating: NDAlbumListSort.RATING,
|
||||
recentlyAdded: NDAlbumListSort.RECENTLY_ADDED,
|
||||
recentlyPlayed: NDAlbumListSort.PLAY_DATE,
|
||||
// Recent versions of Navidrome support release date, but fallback to year for now
|
||||
releaseDate: NDAlbumListSort.YEAR,
|
||||
songCount: NDAlbumListSort.SONG_COUNT,
|
||||
year: NDAlbumListSort.YEAR,
|
||||
},
|
||||
subsonic: {
|
||||
albumArtist: undefined,
|
||||
artist: undefined,
|
||||
communityRating: undefined,
|
||||
criticRating: undefined,
|
||||
duration: undefined,
|
||||
favorited: undefined,
|
||||
name: undefined,
|
||||
playCount: undefined,
|
||||
random: undefined,
|
||||
rating: undefined,
|
||||
recentlyAdded: undefined,
|
||||
recentlyPlayed: undefined,
|
||||
releaseDate: undefined,
|
||||
songCount: undefined,
|
||||
year: undefined,
|
||||
},
|
||||
};
|
||||
export type Album = {
|
||||
albumArtist: string;
|
||||
albumArtists: RelatedArtist[];
|
||||
artists: RelatedArtist[];
|
||||
backdropImageUrl: null | string;
|
||||
comment: null | string;
|
||||
createdAt: string;
|
||||
duration: null | number;
|
||||
genres: Genre[];
|
||||
id: string;
|
||||
imagePlaceholderUrl: null | string;
|
||||
imageUrl: null | string;
|
||||
isCompilation: boolean | null;
|
||||
itemType: LibraryItem.ALBUM;
|
||||
lastPlayedAt: null | string;
|
||||
mbzId: null | string;
|
||||
name: string;
|
||||
originalDate: null | string;
|
||||
participants: null | Record<string, RelatedArtist[]>;
|
||||
playCount: null | number;
|
||||
releaseDate: null | string;
|
||||
releaseYear: null | number;
|
||||
serverId: string;
|
||||
serverType: ServerType;
|
||||
size: null | number;
|
||||
songCount: null | number;
|
||||
songs?: Song[];
|
||||
tags: null | Record<string, string[]>;
|
||||
uniqueId: string;
|
||||
updatedAt: string;
|
||||
userFavorite: boolean;
|
||||
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;
|
||||
};
|
||||
@@ -0,0 +1,245 @@
|
||||
import i18n from 'src/i18n/i18n';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { JFAlbumArtistListSort, JFArtistListSort } from '/@/shared/api/jellyfin.types';
|
||||
import { jfType } from '/@/shared/api/jellyfin/jellyfin-types';
|
||||
import { NDAlbumArtistListSort } from '/@/shared/api/navidrome.types';
|
||||
import { ndType } from '/@/shared/api/navidrome/navidrome-types';
|
||||
import {
|
||||
BaseEndpointArgs,
|
||||
BasePaginatedResponse,
|
||||
BaseQuery,
|
||||
LibraryItem,
|
||||
} from '/@/shared/types/domain-types';
|
||||
import { Genre } from '/@/shared/types/domain/genre-domain-types';
|
||||
import { ServerType } from '/@/shared/types/domain/server-domain-types';
|
||||
|
||||
export enum ArtistListSortOptions {
|
||||
ALBUM_COUNT = 'albumCount',
|
||||
DURATION = 'duration',
|
||||
IS_FAVORITE = 'isFavorite',
|
||||
NAME = 'name',
|
||||
RANDOM = 'random',
|
||||
RATING = 'rating',
|
||||
TRACK_COUNT = 'trackCount',
|
||||
}
|
||||
|
||||
export const ArtistListSortOptionsLabels = {
|
||||
[ArtistListSortOptions.ALBUM_COUNT]: i18n.t('filter.albumCount'),
|
||||
[ArtistListSortOptions.DURATION]: i18n.t('filter.duration'),
|
||||
[ArtistListSortOptions.IS_FAVORITE]: i18n.t('filter.isFavorite'),
|
||||
[ArtistListSortOptions.NAME]: i18n.t('filter.name'),
|
||||
[ArtistListSortOptions.RANDOM]: i18n.t('filter.random'),
|
||||
[ArtistListSortOptions.RATING]: i18n.t('filter.rating'),
|
||||
[ArtistListSortOptions.TRACK_COUNT]: i18n.t('filter.trackCount'),
|
||||
};
|
||||
|
||||
export type AlbumArtist = {
|
||||
albumCount: null | number;
|
||||
backgroundImageUrl: null | string;
|
||||
biography: null | string;
|
||||
duration: null | number;
|
||||
genres: Genre[];
|
||||
id: string;
|
||||
imageUrl: null | string;
|
||||
itemType: LibraryItem.ALBUM_ARTIST;
|
||||
lastPlayedAt: null | string;
|
||||
mbz: null | string;
|
||||
name: string;
|
||||
playCount: null | number;
|
||||
serverId: string;
|
||||
serverType: ServerType;
|
||||
similarArtists: null | RelatedArtist[];
|
||||
songCount: null | number;
|
||||
userFavorite: boolean;
|
||||
userRating: null | number;
|
||||
};
|
||||
|
||||
export type Artist = {
|
||||
biography: null | string;
|
||||
createdAt: string;
|
||||
id: string;
|
||||
itemType: LibraryItem.ARTIST;
|
||||
name: string;
|
||||
remoteCreatedAt: null | string;
|
||||
serverFolderId: string;
|
||||
serverId: string;
|
||||
serverType: ServerType;
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
export type RelatedAlbumArtist = {
|
||||
id: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
export type RelatedArtist = {
|
||||
id: string;
|
||||
imageUrl: null | string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
type AlbumArtistListSortMap = {
|
||||
jellyfin: Record<AlbumArtistListSort, JFAlbumArtistListSort | undefined>;
|
||||
navidrome: Record<AlbumArtistListSort, NDAlbumArtistListSort | undefined>;
|
||||
subsonic: Record<AlbumArtistListSort, undefined>;
|
||||
};
|
||||
|
||||
export const albumArtistListSortMap: AlbumArtistListSortMap = {
|
||||
jellyfin: {
|
||||
album: JFAlbumArtistListSort.ALBUM,
|
||||
albumCount: undefined,
|
||||
duration: JFAlbumArtistListSort.DURATION,
|
||||
favorited: undefined,
|
||||
name: JFAlbumArtistListSort.NAME,
|
||||
playCount: undefined,
|
||||
random: JFAlbumArtistListSort.RANDOM,
|
||||
rating: undefined,
|
||||
recentlyAdded: JFAlbumArtistListSort.RECENTLY_ADDED,
|
||||
releaseDate: undefined,
|
||||
songCount: undefined,
|
||||
},
|
||||
navidrome: {
|
||||
album: undefined,
|
||||
albumCount: NDAlbumArtistListSort.ALBUM_COUNT,
|
||||
duration: undefined,
|
||||
favorited: NDAlbumArtistListSort.FAVORITED,
|
||||
name: NDAlbumArtistListSort.NAME,
|
||||
playCount: NDAlbumArtistListSort.PLAY_COUNT,
|
||||
random: undefined,
|
||||
rating: NDAlbumArtistListSort.RATING,
|
||||
recentlyAdded: undefined,
|
||||
releaseDate: undefined,
|
||||
songCount: NDAlbumArtistListSort.SONG_COUNT,
|
||||
},
|
||||
subsonic: {
|
||||
album: undefined,
|
||||
albumCount: undefined,
|
||||
duration: undefined,
|
||||
favorited: undefined,
|
||||
name: undefined,
|
||||
playCount: undefined,
|
||||
random: undefined,
|
||||
rating: undefined,
|
||||
recentlyAdded: undefined,
|
||||
releaseDate: undefined,
|
||||
songCount: undefined,
|
||||
},
|
||||
};
|
||||
|
||||
export enum ArtistListSort {
|
||||
ALBUM = 'album',
|
||||
ALBUM_COUNT = 'albumCount',
|
||||
DURATION = 'duration',
|
||||
FAVORITED = 'favorited',
|
||||
NAME = 'name',
|
||||
PLAY_COUNT = 'playCount',
|
||||
RANDOM = 'random',
|
||||
RATING = 'rating',
|
||||
RECENTLY_ADDED = 'recentlyAdded',
|
||||
RELEASE_DATE = 'releaseDate',
|
||||
SONG_COUNT = 'songCount',
|
||||
}
|
||||
|
||||
export type AlbumArtistDetailArgs = BaseEndpointArgs & { query: AlbumArtistDetailQuery };
|
||||
|
||||
export type AlbumArtistDetailQuery = { id: string };
|
||||
|
||||
export type AlbumArtistDetailResponse = AlbumArtist | null;
|
||||
|
||||
export type ArtistListArgs = BaseEndpointArgs & { query: ArtistListQuery };
|
||||
|
||||
export interface ArtistListQuery extends BaseQuery<ArtistListSort> {
|
||||
_custom?: {
|
||||
jellyfin?: Partial<z.infer<typeof jfType._parameters.albumArtistList>>;
|
||||
navidrome?: Partial<z.infer<typeof ndType._parameters.albumArtistList>>;
|
||||
};
|
||||
limit?: number;
|
||||
musicFolderId?: string;
|
||||
role?: string;
|
||||
searchTerm?: string;
|
||||
startIndex: number;
|
||||
}
|
||||
|
||||
export type ArtistListResponse = BasePaginatedResponse<AlbumArtist[]> | null | undefined;
|
||||
type ArtistListSortMap = {
|
||||
jellyfin: Record<ArtistListSort, JFArtistListSort | undefined>;
|
||||
navidrome: Record<ArtistListSort, undefined>;
|
||||
subsonic: Record<ArtistListSort, undefined>;
|
||||
};
|
||||
|
||||
export const artistListSortMap: ArtistListSortMap = {
|
||||
jellyfin: {
|
||||
album: JFArtistListSort.ALBUM,
|
||||
albumCount: undefined,
|
||||
duration: JFArtistListSort.DURATION,
|
||||
favorited: undefined,
|
||||
name: JFArtistListSort.NAME,
|
||||
playCount: undefined,
|
||||
random: JFArtistListSort.RANDOM,
|
||||
rating: undefined,
|
||||
recentlyAdded: JFArtistListSort.RECENTLY_ADDED,
|
||||
releaseDate: undefined,
|
||||
songCount: undefined,
|
||||
},
|
||||
navidrome: {
|
||||
album: undefined,
|
||||
albumCount: undefined,
|
||||
duration: undefined,
|
||||
favorited: undefined,
|
||||
name: undefined,
|
||||
playCount: undefined,
|
||||
random: undefined,
|
||||
rating: undefined,
|
||||
recentlyAdded: undefined,
|
||||
releaseDate: undefined,
|
||||
songCount: undefined,
|
||||
},
|
||||
subsonic: {
|
||||
album: undefined,
|
||||
albumCount: undefined,
|
||||
duration: undefined,
|
||||
favorited: undefined,
|
||||
name: undefined,
|
||||
playCount: undefined,
|
||||
random: undefined,
|
||||
rating: undefined,
|
||||
recentlyAdded: undefined,
|
||||
releaseDate: undefined,
|
||||
songCount: undefined,
|
||||
},
|
||||
};
|
||||
export enum AlbumArtistListSort {
|
||||
ALBUM = 'album',
|
||||
ALBUM_COUNT = 'albumCount',
|
||||
DURATION = 'duration',
|
||||
FAVORITED = 'favorited',
|
||||
NAME = 'name',
|
||||
PLAY_COUNT = 'playCount',
|
||||
RANDOM = 'random',
|
||||
RATING = 'rating',
|
||||
RECENTLY_ADDED = 'recentlyAdded',
|
||||
RELEASE_DATE = 'releaseDate',
|
||||
SONG_COUNT = 'songCount',
|
||||
}
|
||||
|
||||
export type AlbumArtistListArgs = BaseEndpointArgs & { query: AlbumArtistListQuery };
|
||||
|
||||
export interface AlbumArtistListQuery extends BaseQuery<AlbumArtistListSort> {
|
||||
_custom?: {
|
||||
jellyfin?: Partial<z.infer<typeof jfType._parameters.albumArtistList>>;
|
||||
navidrome?: Partial<z.infer<typeof ndType._parameters.albumArtistList>>;
|
||||
};
|
||||
limit?: number;
|
||||
musicFolderId?: string;
|
||||
searchTerm?: string;
|
||||
startIndex: number;
|
||||
}
|
||||
export type AlbumArtistListResponse = BasePaginatedResponse<AlbumArtist[]> | null | undefined;
|
||||
export type ArtistInfoArgs = BaseEndpointArgs & { query: ArtistInfoQuery };
|
||||
|
||||
export type ArtistInfoQuery = {
|
||||
artistId: string;
|
||||
limit: number;
|
||||
musicFolderId?: string;
|
||||
};
|
||||
@@ -0,0 +1,70 @@
|
||||
import i18n from 'src/i18n/i18n';
|
||||
|
||||
import { UserListSort } from './user-domain-types';
|
||||
|
||||
import { JFGenreListSort } from '/@/shared/api/jellyfin.types';
|
||||
import { NDGenreListSort } from '/@/shared/api/navidrome.types';
|
||||
import {
|
||||
BaseEndpointArgs,
|
||||
BasePaginatedResponse,
|
||||
BaseQuery,
|
||||
LibraryItem,
|
||||
} from '/@/shared/types/domain-types';
|
||||
|
||||
export enum GenreListSortOptions {
|
||||
ALBUM_COUNT = 'albumCount',
|
||||
NAME = 'name',
|
||||
TRACK_COUNT = 'trackCount',
|
||||
}
|
||||
|
||||
export const GenreListSortOptionsLabels = {
|
||||
[GenreListSortOptions.ALBUM_COUNT]: i18n.t('filter.albumCount'),
|
||||
[GenreListSortOptions.NAME]: i18n.t('filter.name'),
|
||||
[GenreListSortOptions.TRACK_COUNT]: i18n.t('filter.trackCount'),
|
||||
};
|
||||
export type Genre = {
|
||||
albumCount?: number;
|
||||
id: string;
|
||||
imageUrl: null | string;
|
||||
itemType: LibraryItem.GENRE;
|
||||
name: string;
|
||||
songCount?: number;
|
||||
};
|
||||
|
||||
export type GenreListArgs = BaseEndpointArgs & { query: GenreListQuery };
|
||||
|
||||
export interface GenreListQuery extends BaseQuery<GenreListSort> {
|
||||
_custom?: {
|
||||
jellyfin?: null;
|
||||
navidrome?: null;
|
||||
};
|
||||
limit?: number;
|
||||
musicFolderId?: string;
|
||||
searchTerm?: string;
|
||||
startIndex: number;
|
||||
}
|
||||
// Genre List
|
||||
|
||||
export type GenreListResponse = BasePaginatedResponse<Genre[]> | null | undefined;
|
||||
|
||||
export type GenresResponse = Genre[];
|
||||
type GenreListSortMap = {
|
||||
jellyfin: Record<GenreListSort, JFGenreListSort | undefined>;
|
||||
navidrome: Record<GenreListSort, NDGenreListSort | undefined>;
|
||||
subsonic: Record<UserListSort, undefined>;
|
||||
};
|
||||
|
||||
export const genreListSortMap: GenreListSortMap = {
|
||||
jellyfin: {
|
||||
name: JFGenreListSort.NAME,
|
||||
},
|
||||
navidrome: {
|
||||
name: NDGenreListSort.NAME,
|
||||
},
|
||||
subsonic: {
|
||||
name: undefined,
|
||||
},
|
||||
};
|
||||
export enum GenreListSort {
|
||||
NAME = 'name',
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
import { BaseEndpointArgs, LyricSource } from '/@/shared/types/domain-types';
|
||||
import { Song } from '/@/shared/types/domain/song-domain-types';
|
||||
|
||||
export type FullLyricsMetadata = Omit<InternetProviderLyricResponse, 'id' | 'lyrics' | 'source'> & {
|
||||
lyrics: LyricsResponse;
|
||||
remote: boolean;
|
||||
source: string;
|
||||
};
|
||||
|
||||
export type InternetProviderLyricResponse = {
|
||||
artist: string;
|
||||
id: string;
|
||||
lyrics: string;
|
||||
name: string;
|
||||
source: LyricSource;
|
||||
};
|
||||
export type InternetProviderLyricSearchResponse = {
|
||||
artist: string;
|
||||
id: string;
|
||||
name: string;
|
||||
score?: number;
|
||||
source: LyricSource;
|
||||
};
|
||||
export type LyricGetQuery = {
|
||||
remoteSongId: string;
|
||||
remoteSource: LyricSource;
|
||||
song: Song;
|
||||
};
|
||||
|
||||
export type LyricOverride = Omit<InternetProviderLyricResponse, 'lyrics'>;
|
||||
|
||||
export type LyricsArgs = BaseEndpointArgs & {
|
||||
query: LyricsQuery;
|
||||
};
|
||||
|
||||
export type LyricSearchQuery = {
|
||||
album?: string;
|
||||
artist?: string;
|
||||
duration?: number;
|
||||
name?: string;
|
||||
};
|
||||
export type LyricsOverride = Omit<FullLyricsMetadata, 'lyrics'> & { id: string };
|
||||
export type LyricsQuery = {
|
||||
songId: string;
|
||||
};
|
||||
|
||||
export type LyricsResponse = string | SynchronizedLyricsArray;
|
||||
|
||||
export type StructuredLyric = (StructuredSyncedLyric | StructuredUnsyncedLyric) & {
|
||||
lang: string;
|
||||
};
|
||||
|
||||
export type StructuredLyricsArgs = BaseEndpointArgs & {
|
||||
query: LyricsQuery;
|
||||
};
|
||||
|
||||
export type StructuredSyncedLyric = Omit<FullLyricsMetadata, 'lyrics'> & {
|
||||
lyrics: SynchronizedLyricsArray;
|
||||
synced: true;
|
||||
};
|
||||
|
||||
export type StructuredUnsyncedLyric = Omit<FullLyricsMetadata, 'lyrics'> & {
|
||||
lyrics: string;
|
||||
synced: false;
|
||||
};
|
||||
export type SynchronizedLyricsArray = Array<[number, string]>;
|
||||
@@ -0,0 +1,12 @@
|
||||
export interface AuthUserPermissions {
|
||||
'jukebox.manage': boolean;
|
||||
'media.download': boolean;
|
||||
'media.share': boolean;
|
||||
'media.stream': boolean;
|
||||
'media.upload': boolean;
|
||||
'playlist.create': boolean;
|
||||
'playlist.delete': boolean;
|
||||
'playlist.edit': boolean;
|
||||
'server.admin': boolean;
|
||||
'user.edit': boolean;
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
import i18n from 'src/i18n/i18n';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { Genre } from './genre-domain-types';
|
||||
|
||||
import { JFPlaylistListSort } from '/@/shared/api/jellyfin.types';
|
||||
import { jfType } from '/@/shared/api/jellyfin/jellyfin-types';
|
||||
import { NDPlaylistListSort } from '/@/shared/api/navidrome.types';
|
||||
import { ndType } from '/@/shared/api/navidrome/navidrome-types';
|
||||
import {
|
||||
BaseEndpointArgs,
|
||||
BasePaginatedResponse,
|
||||
BaseQuery,
|
||||
LibraryItem,
|
||||
} from '/@/shared/types/domain-types';
|
||||
import { ServerType } from '/@/shared/types/domain/server-domain-types';
|
||||
import { ListSortOrder } from '/@/shared/types/domain/shared-domain-types';
|
||||
import { Song, SongListSort } from '/@/shared/types/domain/song-domain-types';
|
||||
|
||||
export enum PlaylistListSortOptions {
|
||||
DURATION = 'duration',
|
||||
NAME = 'name',
|
||||
OWNER = 'owner',
|
||||
PUBLIC = 'public',
|
||||
TRACK_COUNT = 'trackCount',
|
||||
UPDATED_AT = 'updatedAt',
|
||||
}
|
||||
|
||||
export const PlaylistListSortOptionsLabels = {
|
||||
[PlaylistListSortOptions.DURATION]: i18n.t('filter.duration'),
|
||||
[PlaylistListSortOptions.NAME]: i18n.t('filter.name'),
|
||||
[PlaylistListSortOptions.OWNER]: i18n.t('filter.owner'),
|
||||
[PlaylistListSortOptions.PUBLIC]: i18n.t('filter.public'),
|
||||
[PlaylistListSortOptions.TRACK_COUNT]: i18n.t('filter.trackCount'),
|
||||
[PlaylistListSortOptions.UPDATED_AT]: i18n.t('filter.updatedAt'),
|
||||
};
|
||||
|
||||
export enum PlaylistListSort {
|
||||
DURATION = 'duration',
|
||||
NAME = 'name',
|
||||
OWNER = 'owner',
|
||||
PUBLIC = 'public',
|
||||
SONG_COUNT = 'songCount',
|
||||
UPDATED_AT = 'updatedAt',
|
||||
}
|
||||
|
||||
export type AddToPlaylistArgs = BaseEndpointArgs & {
|
||||
body: AddToPlaylistBody;
|
||||
query: AddToPlaylistQuery;
|
||||
serverId?: string;
|
||||
};
|
||||
|
||||
export type AddToPlaylistBody = {
|
||||
songId: string[];
|
||||
};
|
||||
|
||||
export type AddToPlaylistQuery = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
export type AddToPlaylistResponse = null | undefined;
|
||||
|
||||
export type CreatePlaylistArgs = BaseEndpointArgs & { body: CreatePlaylistBody; serverId?: string };
|
||||
|
||||
export type CreatePlaylistBody = {
|
||||
_custom?: {
|
||||
navidrome?: {
|
||||
owner?: string;
|
||||
ownerId?: string;
|
||||
rules?: Record<string, any>;
|
||||
sync?: boolean;
|
||||
};
|
||||
};
|
||||
comment?: string;
|
||||
name: string;
|
||||
public?: boolean;
|
||||
};
|
||||
|
||||
export type CreatePlaylistResponse = undefined | { id: string };
|
||||
|
||||
export type DeletePlaylistArgs = BaseEndpointArgs & {
|
||||
query: DeletePlaylistQuery;
|
||||
serverId?: string;
|
||||
};
|
||||
|
||||
export type DeletePlaylistQuery = { id: string };
|
||||
|
||||
export type DeletePlaylistResponse = null | undefined;
|
||||
|
||||
export type Playlist = {
|
||||
description: null | string;
|
||||
duration: null | number;
|
||||
genres: Genre[];
|
||||
id: string;
|
||||
imagePlaceholderUrl: null | string;
|
||||
imageUrl: null | string;
|
||||
itemType: LibraryItem.PLAYLIST;
|
||||
name: string;
|
||||
owner: null | string;
|
||||
ownerId: null | string;
|
||||
public: boolean | null;
|
||||
rules?: null | Record<string, any>;
|
||||
serverId: string;
|
||||
serverType: ServerType;
|
||||
size: null | number;
|
||||
songCount: null | number;
|
||||
sync?: boolean | null;
|
||||
};
|
||||
export type PlaylistListArgs = BaseEndpointArgs & { query: PlaylistListQuery };
|
||||
|
||||
export interface PlaylistListQuery extends BaseQuery<PlaylistListSort> {
|
||||
_custom?: {
|
||||
jellyfin?: Partial<z.infer<typeof jfType._parameters.playlistList>>;
|
||||
navidrome?: Partial<z.infer<typeof ndType._parameters.playlistList>>;
|
||||
};
|
||||
limit?: number;
|
||||
searchTerm?: string;
|
||||
startIndex: number;
|
||||
}
|
||||
|
||||
export type PlaylistListResponse = BasePaginatedResponse<Playlist[]> | null | undefined;
|
||||
|
||||
export type RemoveFromPlaylistArgs = BaseEndpointArgs & {
|
||||
query: RemoveFromPlaylistQuery;
|
||||
serverId?: string;
|
||||
};
|
||||
|
||||
export type RemoveFromPlaylistQuery = {
|
||||
id: string;
|
||||
songId: string[];
|
||||
};
|
||||
|
||||
export type RemoveFromPlaylistResponse = null | undefined;
|
||||
|
||||
export type UpdatePlaylistArgs = BaseEndpointArgs & {
|
||||
body: UpdatePlaylistBody;
|
||||
query: UpdatePlaylistQuery;
|
||||
serverId?: string;
|
||||
};
|
||||
|
||||
export type UpdatePlaylistBody = {
|
||||
_custom?: {
|
||||
navidrome?: {
|
||||
owner?: string;
|
||||
ownerId?: string;
|
||||
rules?: Record<string, any>;
|
||||
sync?: boolean;
|
||||
};
|
||||
};
|
||||
comment?: string;
|
||||
genres?: Genre[];
|
||||
name: string;
|
||||
public?: boolean;
|
||||
};
|
||||
|
||||
export type UpdatePlaylistQuery = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
export type UpdatePlaylistResponse = null | undefined;
|
||||
|
||||
type PlaylistListSortMap = {
|
||||
jellyfin: Record<PlaylistListSort, JFPlaylistListSort | undefined>;
|
||||
navidrome: Record<PlaylistListSort, NDPlaylistListSort | undefined>;
|
||||
subsonic: Record<PlaylistListSort, undefined>;
|
||||
};
|
||||
|
||||
export const playlistListSortMap: PlaylistListSortMap = {
|
||||
jellyfin: {
|
||||
duration: JFPlaylistListSort.DURATION,
|
||||
name: JFPlaylistListSort.NAME,
|
||||
owner: undefined,
|
||||
public: undefined,
|
||||
songCount: JFPlaylistListSort.SONG_COUNT,
|
||||
updatedAt: undefined,
|
||||
},
|
||||
navidrome: {
|
||||
duration: NDPlaylistListSort.DURATION,
|
||||
name: NDPlaylistListSort.NAME,
|
||||
owner: NDPlaylistListSort.OWNER,
|
||||
public: NDPlaylistListSort.PUBLIC,
|
||||
songCount: NDPlaylistListSort.SONG_COUNT,
|
||||
updatedAt: NDPlaylistListSort.UPDATED_AT,
|
||||
},
|
||||
subsonic: {
|
||||
duration: undefined,
|
||||
name: undefined,
|
||||
owner: undefined,
|
||||
public: undefined,
|
||||
songCount: undefined,
|
||||
updatedAt: undefined,
|
||||
},
|
||||
};
|
||||
export type PlaylistDetailArgs = BaseEndpointArgs & { query: PlaylistDetailQuery };
|
||||
|
||||
export type PlaylistDetailQuery = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
export type PlaylistDetailResponse = Playlist;
|
||||
|
||||
export type PlaylistSongListArgs = BaseEndpointArgs & { query: PlaylistSongListQuery };
|
||||
|
||||
export type PlaylistSongListQuery = {
|
||||
id: string;
|
||||
limit?: number;
|
||||
sortBy?: SongListSort;
|
||||
sortOrder?: ListSortOrder;
|
||||
startIndex: number;
|
||||
};
|
||||
|
||||
export type PlaylistSongListResponse = BasePaginatedResponse<Song[]> | null | undefined;
|
||||
@@ -0,0 +1,46 @@
|
||||
import { BaseEndpointArgs } from '/@/shared/types/domain-types';
|
||||
import { Album } from '/@/shared/types/domain/album-domain-types';
|
||||
import { AlbumArtist } from '/@/shared/types/domain/artist-domain-types';
|
||||
import { Song } from '/@/shared/types/domain/song-domain-types';
|
||||
|
||||
export type SearchAlbumArtistsQuery = {
|
||||
albumArtistLimit?: number;
|
||||
albumArtistStartIndex?: number;
|
||||
musicFolderId?: string;
|
||||
query?: string;
|
||||
};
|
||||
|
||||
export type SearchAlbumsQuery = {
|
||||
albumLimit?: number;
|
||||
albumStartIndex?: number;
|
||||
musicFolderId?: string;
|
||||
query?: string;
|
||||
};
|
||||
|
||||
export type SearchArgs = BaseEndpointArgs & {
|
||||
query: SearchQuery;
|
||||
};
|
||||
|
||||
export type SearchQuery = {
|
||||
albumArtistLimit?: number;
|
||||
albumArtistStartIndex?: number;
|
||||
albumLimit?: number;
|
||||
albumStartIndex?: number;
|
||||
musicFolderId?: string;
|
||||
query?: string;
|
||||
songLimit?: number;
|
||||
songStartIndex?: number;
|
||||
};
|
||||
|
||||
export type SearchResponse = {
|
||||
albumArtists: AlbumArtist[];
|
||||
albums: Album[];
|
||||
songs: Song[];
|
||||
};
|
||||
|
||||
export type SearchSongsQuery = {
|
||||
musicFolderId?: string;
|
||||
query?: string;
|
||||
songLimit?: number;
|
||||
songStartIndex?: number;
|
||||
};
|
||||
@@ -0,0 +1,60 @@
|
||||
import i18n from 'src/i18n/i18n';
|
||||
|
||||
import { BaseEndpointArgs, BasePaginatedResponse } from '/@/shared/types/domain-types';
|
||||
import { ServerFeatures } from '/@/shared/types/features-types';
|
||||
|
||||
export enum ServerListSortOptions {
|
||||
CREATED_AT = 'createdAt',
|
||||
NAME = 'name',
|
||||
TYPE = 'type',
|
||||
UPDATED_AT = 'updatedAt',
|
||||
}
|
||||
|
||||
export const ServerListSortOptionsLabels = {
|
||||
[ServerListSortOptions.CREATED_AT]: i18n.t('filter.createdAt'),
|
||||
[ServerListSortOptions.NAME]: i18n.t('filter.name'),
|
||||
[ServerListSortOptions.TYPE]: i18n.t('filter.type'),
|
||||
[ServerListSortOptions.UPDATED_AT]: i18n.t('filter.updatedAt'),
|
||||
};
|
||||
|
||||
export enum ServerType {
|
||||
JELLYFIN = 'jellyfin',
|
||||
NAVIDROME = 'navidrome',
|
||||
SUBSONIC = 'subsonic',
|
||||
}
|
||||
|
||||
export type ServerInfo = {
|
||||
features: ServerFeatures;
|
||||
id?: string;
|
||||
version: string;
|
||||
};
|
||||
|
||||
export type ServerInfoArgs = BaseEndpointArgs;
|
||||
|
||||
export type ServerListItem = {
|
||||
credential: string;
|
||||
features?: ServerFeatures;
|
||||
id: string;
|
||||
name: string;
|
||||
ndCredential?: string;
|
||||
savePassword?: boolean;
|
||||
type: ServerType;
|
||||
url: string;
|
||||
userId: null | string;
|
||||
username: string;
|
||||
version?: string;
|
||||
};
|
||||
|
||||
export type ServerMusicFolder = {
|
||||
id: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
export type ServerMusicFolderListArgs = BaseEndpointArgs;
|
||||
|
||||
export type ServerMusicFolderListQuery = null;
|
||||
export type ServerMusicFolderListResponse =
|
||||
| BasePaginatedResponse<ServerMusicFolder[]>
|
||||
| null
|
||||
| undefined;
|
||||
export type ServerMusicFoldersResponse = ServerMusicFolder[];
|
||||
@@ -0,0 +1,4 @@
|
||||
export enum ListSortOrder {
|
||||
ASC = 'ASC',
|
||||
DESC = 'DESC',
|
||||
}
|
||||
@@ -0,0 +1,251 @@
|
||||
import i18n from 'src/i18n/i18n';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { JFSongListSort } from '/@/shared/api/jellyfin.types';
|
||||
import { jfType } from '/@/shared/api/jellyfin/jellyfin-types';
|
||||
import { NDSongListSort } from '/@/shared/api/navidrome.types';
|
||||
import { ndType } from '/@/shared/api/navidrome/navidrome-types';
|
||||
import {
|
||||
BaseEndpointArgs,
|
||||
BasePaginatedResponse,
|
||||
BaseQuery,
|
||||
GainInfo,
|
||||
LibraryItem,
|
||||
Played,
|
||||
} from '/@/shared/types/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';
|
||||
|
||||
export enum SongListSortOptions {
|
||||
ALBUM = 'album',
|
||||
ALBUM_ARTIST = 'albumArtist',
|
||||
ARTIST = 'artist',
|
||||
BPM = 'bpm',
|
||||
CHANNELS = 'channels',
|
||||
COMMENT = 'comment',
|
||||
DURATION = 'duration',
|
||||
GENRE = 'genre',
|
||||
ID = 'id',
|
||||
IS_FAVORITE = 'isFavorite',
|
||||
NAME = 'name',
|
||||
PLAY_COUNT = 'playCount',
|
||||
RANDOM = 'random',
|
||||
RATING = 'rating',
|
||||
RECENTLY_ADDED = 'recentlyAdded',
|
||||
RECENTLY_PLAYED = 'recentlyPlayed',
|
||||
RELEASE_DATE = 'releaseDate',
|
||||
YEAR = 'year',
|
||||
}
|
||||
|
||||
export const SongListSortOptionsLabels = {
|
||||
[SongListSortOptions.ALBUM]: i18n.t('filter.album'),
|
||||
[SongListSortOptions.ALBUM_ARTIST]: i18n.t('filter.albumArtist'),
|
||||
[SongListSortOptions.ARTIST]: i18n.t('filter.artist'),
|
||||
[SongListSortOptions.BPM]: i18n.t('filter.bpm'),
|
||||
[SongListSortOptions.CHANNELS]: i18n.t('filter.channels'),
|
||||
[SongListSortOptions.COMMENT]: i18n.t('filter.comment'),
|
||||
[SongListSortOptions.DURATION]: i18n.t('filter.duration'),
|
||||
[SongListSortOptions.GENRE]: i18n.t('filter.genre'),
|
||||
[SongListSortOptions.ID]: i18n.t('filter.id'),
|
||||
[SongListSortOptions.IS_FAVORITE]: i18n.t('filter.isFavorite'),
|
||||
[SongListSortOptions.NAME]: i18n.t('filter.name'),
|
||||
[SongListSortOptions.PLAY_COUNT]: i18n.t('filter.playCount'),
|
||||
[SongListSortOptions.RANDOM]: i18n.t('filter.random'),
|
||||
[SongListSortOptions.RATING]: i18n.t('filter.rating'),
|
||||
[SongListSortOptions.RECENTLY_ADDED]: i18n.t('filter.recentlyAdded'),
|
||||
[SongListSortOptions.RECENTLY_PLAYED]: i18n.t('filter.recentlyPlayed'),
|
||||
[SongListSortOptions.RELEASE_DATE]: i18n.t('filter.releaseDate'),
|
||||
[SongListSortOptions.YEAR]: i18n.t('filter.year'),
|
||||
};
|
||||
export enum SongListSort {
|
||||
ALBUM = 'album',
|
||||
ALBUM_ARTIST = 'albumArtist',
|
||||
ARTIST = 'artist',
|
||||
BPM = 'bpm',
|
||||
CHANNELS = 'channels',
|
||||
COMMENT = 'comment',
|
||||
DURATION = 'duration',
|
||||
FAVORITED = 'favorited',
|
||||
GENRE = 'genre',
|
||||
ID = 'id',
|
||||
NAME = 'name',
|
||||
PLAY_COUNT = 'playCount',
|
||||
RANDOM = 'random',
|
||||
RATING = 'rating',
|
||||
RECENTLY_ADDED = 'recentlyAdded',
|
||||
RECENTLY_PLAYED = 'recentlyPlayed',
|
||||
RELEASE_DATE = 'releaseDate',
|
||||
YEAR = 'year',
|
||||
}
|
||||
export type Song = {
|
||||
album: null | string;
|
||||
albumArtists: RelatedArtist[];
|
||||
albumId: string;
|
||||
artistName: string;
|
||||
artists: RelatedArtist[];
|
||||
bitRate: number;
|
||||
bpm: null | number;
|
||||
channels: null | number;
|
||||
comment: null | string;
|
||||
compilation: boolean | null;
|
||||
container: null | string;
|
||||
createdAt: string;
|
||||
discNumber: number;
|
||||
discSubtitle: null | string;
|
||||
duration: number;
|
||||
gain: GainInfo | null;
|
||||
genres: Genre[];
|
||||
id: string;
|
||||
imagePlaceholderUrl: null | string;
|
||||
imageUrl: null | string;
|
||||
itemType: LibraryItem.SONG;
|
||||
lastPlayedAt: null | string;
|
||||
lyrics: null | string;
|
||||
name: string;
|
||||
participants: null | Record<string, RelatedArtist[]>;
|
||||
path: null | string;
|
||||
peak: GainInfo | null;
|
||||
playCount: number;
|
||||
playlistItemId?: string;
|
||||
releaseDate: null | string;
|
||||
releaseYear: null | string;
|
||||
serverId: string;
|
||||
serverType: ServerType;
|
||||
size: number;
|
||||
streamUrl: string;
|
||||
tags: null | Record<string, string[]>;
|
||||
trackNumber: number;
|
||||
uniqueId: string;
|
||||
updatedAt: string;
|
||||
userFavorite: boolean;
|
||||
userRating: null | number;
|
||||
};
|
||||
export type SongListArgs = BaseEndpointArgs & { query: SongListQuery };
|
||||
|
||||
export interface SongListQuery extends BaseQuery<SongListSort> {
|
||||
_custom?: {
|
||||
jellyfin?: Partial<z.infer<typeof jfType._parameters.songList>>;
|
||||
navidrome?: Partial<z.infer<typeof ndType._parameters.songList>>;
|
||||
};
|
||||
albumArtistIds?: string[];
|
||||
albumIds?: string[];
|
||||
artistIds?: string[];
|
||||
favorite?: boolean;
|
||||
genreIds?: string[];
|
||||
imageSize?: number;
|
||||
limit?: number;
|
||||
maxYear?: number;
|
||||
minYear?: number;
|
||||
musicFolderId?: string;
|
||||
role?: string;
|
||||
searchTerm?: string;
|
||||
startIndex: number;
|
||||
}
|
||||
|
||||
export type SongListResponse = BasePaginatedResponse<Song[]> | null | undefined;
|
||||
type SongListSortMap = {
|
||||
jellyfin: Record<SongListSort, JFSongListSort | undefined>;
|
||||
navidrome: Record<SongListSort, NDSongListSort | undefined>;
|
||||
subsonic: Record<SongListSort, undefined>;
|
||||
};
|
||||
|
||||
export const songListSortMap: SongListSortMap = {
|
||||
jellyfin: {
|
||||
album: JFSongListSort.ALBUM,
|
||||
albumArtist: JFSongListSort.ALBUM_ARTIST,
|
||||
artist: JFSongListSort.ARTIST,
|
||||
bpm: undefined,
|
||||
channels: undefined,
|
||||
comment: undefined,
|
||||
duration: JFSongListSort.DURATION,
|
||||
favorited: undefined,
|
||||
genre: undefined,
|
||||
id: undefined,
|
||||
name: JFSongListSort.NAME,
|
||||
playCount: JFSongListSort.PLAY_COUNT,
|
||||
random: JFSongListSort.RANDOM,
|
||||
rating: undefined,
|
||||
recentlyAdded: JFSongListSort.RECENTLY_ADDED,
|
||||
recentlyPlayed: JFSongListSort.RECENTLY_PLAYED,
|
||||
releaseDate: JFSongListSort.RELEASE_DATE,
|
||||
year: undefined,
|
||||
},
|
||||
navidrome: {
|
||||
album: NDSongListSort.ALBUM_SONGS,
|
||||
albumArtist: NDSongListSort.ALBUM_ARTIST,
|
||||
artist: NDSongListSort.ARTIST,
|
||||
bpm: NDSongListSort.BPM,
|
||||
channels: NDSongListSort.CHANNELS,
|
||||
comment: NDSongListSort.COMMENT,
|
||||
duration: NDSongListSort.DURATION,
|
||||
favorited: NDSongListSort.FAVORITED,
|
||||
genre: NDSongListSort.GENRE,
|
||||
id: NDSongListSort.ID,
|
||||
name: NDSongListSort.TITLE,
|
||||
playCount: NDSongListSort.PLAY_COUNT,
|
||||
random: NDSongListSort.RANDOM,
|
||||
rating: NDSongListSort.RATING,
|
||||
recentlyAdded: NDSongListSort.RECENTLY_ADDED,
|
||||
recentlyPlayed: NDSongListSort.PLAY_DATE,
|
||||
releaseDate: undefined,
|
||||
year: NDSongListSort.YEAR,
|
||||
},
|
||||
subsonic: {
|
||||
album: undefined,
|
||||
albumArtist: undefined,
|
||||
artist: undefined,
|
||||
bpm: undefined,
|
||||
channels: undefined,
|
||||
comment: undefined,
|
||||
duration: undefined,
|
||||
favorited: undefined,
|
||||
genre: undefined,
|
||||
id: undefined,
|
||||
name: undefined,
|
||||
playCount: undefined,
|
||||
random: undefined,
|
||||
rating: undefined,
|
||||
recentlyAdded: undefined,
|
||||
recentlyPlayed: undefined,
|
||||
releaseDate: undefined,
|
||||
year: undefined,
|
||||
},
|
||||
};
|
||||
export type RandomSongListArgs = BaseEndpointArgs & {
|
||||
query: RandomSongListQuery;
|
||||
};
|
||||
|
||||
export type RandomSongListQuery = {
|
||||
genre?: string;
|
||||
limit?: number;
|
||||
maxYear?: number;
|
||||
minYear?: number;
|
||||
musicFolderId?: string;
|
||||
played: Played;
|
||||
};
|
||||
|
||||
export type RandomSongListResponse = SongListResponse;
|
||||
export type SimilarSongsArgs = BaseEndpointArgs & {
|
||||
query: SimilarSongsQuery;
|
||||
};
|
||||
|
||||
export type SimilarSongsQuery = {
|
||||
albumArtistIds: string[];
|
||||
count?: number;
|
||||
songId: string;
|
||||
};
|
||||
|
||||
export type SongDetailArgs = BaseEndpointArgs & { query: SongDetailQuery };
|
||||
export type SongDetailQuery = { id: string };
|
||||
|
||||
export type SongDetailResponse = null | Song | undefined;
|
||||
export type TopSongListArgs = BaseEndpointArgs & { query: TopSongListQuery };
|
||||
|
||||
export type TopSongListQuery = {
|
||||
artist: string;
|
||||
artistId: string;
|
||||
limit?: number;
|
||||
};
|
||||
|
||||
export type TopSongListResponse = BasePaginatedResponse<Song[]> | null | undefined;
|
||||
@@ -0,0 +1,95 @@
|
||||
import i18n from 'src/i18n/i18n';
|
||||
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';
|
||||
|
||||
export enum UserListSortOptions {
|
||||
CREATED_AT = 'createdAt',
|
||||
EMAIL = 'email',
|
||||
NAME = 'name',
|
||||
UPDATED_AT = 'updatedAt',
|
||||
}
|
||||
|
||||
export const UserListSortOptionsLabels = {
|
||||
[UserListSortOptions.CREATED_AT]: i18n.t('filter.createdAt'),
|
||||
[UserListSortOptions.EMAIL]: i18n.t('filter.email'),
|
||||
[UserListSortOptions.NAME]: i18n.t('filter.name'),
|
||||
[UserListSortOptions.UPDATED_AT]: i18n.t('filter.updatedAt'),
|
||||
};
|
||||
export type FavoriteArgs = BaseEndpointArgs & { query: FavoriteQuery; serverId?: string };
|
||||
|
||||
export type FavoriteQuery = {
|
||||
id: string[];
|
||||
type: LibraryItem;
|
||||
};
|
||||
|
||||
export type FavoriteResponse = null | undefined;
|
||||
export type RatingQuery = {
|
||||
item: AnyLibraryItems;
|
||||
rating: number;
|
||||
};
|
||||
|
||||
export type RatingResponse = null | undefined;
|
||||
export type SetRatingArgs = BaseEndpointArgs & { query: RatingQuery; serverId?: string };
|
||||
export type UserListArgs = BaseEndpointArgs & { query: UserListQuery };
|
||||
|
||||
export interface UserListQuery extends BaseQuery<UserListSort> {
|
||||
_custom?: {
|
||||
navidrome?: {
|
||||
owner_id?: string;
|
||||
};
|
||||
};
|
||||
limit?: number;
|
||||
searchTerm?: string;
|
||||
startIndex: number;
|
||||
}
|
||||
|
||||
export type UserListResponse = BasePaginatedResponse<User[]> | null | undefined;
|
||||
type UserListSortMap = {
|
||||
jellyfin: Record<UserListSort, undefined>;
|
||||
navidrome: Record<UserListSort, NDUserListSort | undefined>;
|
||||
subsonic: Record<UserListSort, undefined>;
|
||||
};
|
||||
|
||||
export const userListSortMap: UserListSortMap = {
|
||||
jellyfin: {
|
||||
name: undefined,
|
||||
},
|
||||
navidrome: {
|
||||
name: NDUserListSort.NAME,
|
||||
},
|
||||
subsonic: {
|
||||
name: undefined,
|
||||
},
|
||||
};
|
||||
export type ScrobbleArgs = BaseEndpointArgs & {
|
||||
query: ScrobbleQuery;
|
||||
serverId?: string;
|
||||
};
|
||||
|
||||
export type ScrobbleQuery = {
|
||||
event?: 'pause' | 'start' | 'timeupdate' | 'unpause';
|
||||
id: string;
|
||||
position?: number;
|
||||
submission: boolean;
|
||||
};
|
||||
|
||||
export type ScrobbleResponse = null | undefined;
|
||||
export enum UserListSort {
|
||||
NAME = 'name',
|
||||
}
|
||||
export type User = {
|
||||
createdAt: null | string;
|
||||
email: null | string;
|
||||
id: string;
|
||||
isAdmin: boolean | null;
|
||||
lastLoginAt: null | string;
|
||||
name: string;
|
||||
updatedAt: null | string;
|
||||
};
|
||||
@@ -2,15 +2,11 @@ import { AppRoute } from '@ts-rest/core';
|
||||
import { ReactNode } from 'react';
|
||||
import { Song } from 'src/main/features/core/lyrics/netease';
|
||||
|
||||
import {
|
||||
Album,
|
||||
AlbumArtist,
|
||||
Artist,
|
||||
LibraryItem,
|
||||
Playlist,
|
||||
QueueSong,
|
||||
} from '/@/shared/types/domain-types';
|
||||
import { ServerFeatures } from '/@/shared/types/features-types';
|
||||
import { LibraryItem, QueueSong } from '/@/shared/types/domain-types';
|
||||
import { Album } from '/@/shared/types/domain/album-domain-types';
|
||||
import { AlbumArtist, Artist } from '/@/shared/types/domain/artist-domain-types';
|
||||
import { Playlist } from '/@/shared/types/domain/playlist-domain-types';
|
||||
import { ServerType } from '/@/shared/types/domain/server-domain-types';
|
||||
|
||||
export enum ListDisplayType {
|
||||
CARD = 'card',
|
||||
@@ -27,12 +23,6 @@ export enum Platform {
|
||||
WINDOWS = 'windows',
|
||||
}
|
||||
|
||||
export enum ServerType {
|
||||
JELLYFIN = 'jellyfin',
|
||||
NAVIDROME = 'navidrome',
|
||||
SUBSONIC = 'subsonic',
|
||||
}
|
||||
|
||||
export type CardRoute = {
|
||||
route: AppRoute | string;
|
||||
slugs?: RouteSlug[];
|
||||
@@ -210,20 +200,6 @@ export type QueryBuilderRule = {
|
||||
value?: any | Date | null | number | string | undefined;
|
||||
};
|
||||
|
||||
export type ServerListItem = {
|
||||
credential: string;
|
||||
features?: ServerFeatures;
|
||||
id: string;
|
||||
name: string;
|
||||
ndCredential?: string;
|
||||
savePassword?: boolean;
|
||||
type: ServerType;
|
||||
url: string;
|
||||
userId: null | string;
|
||||
username: string;
|
||||
version?: string;
|
||||
};
|
||||
|
||||
export type SongState = {
|
||||
position?: number;
|
||||
repeat?: PlayerRepeat;
|
||||
|
||||
Reference in New Issue
Block a user