feishin/src/renderer/api/subsonic/subsonic-normalize.ts

275 lines
8 KiB
TypeScript
Raw Normal View History

2023-04-24 01:21:29 -07:00
import { nanoid } from 'nanoid';
import { z } from 'zod';
import { ssType } from '/@/renderer/api/subsonic/subsonic-types';
import {
QueueSong,
LibraryItem,
AlbumArtist,
Album,
ServerListItem,
ServerType,
2024-09-26 04:23:08 +00:00
Playlist,
Genre,
} from '/@/renderer/api/types';
2023-04-24 01:21:29 -07:00
const getCoverArtUrl = (args: {
2023-07-01 19:10:05 -07:00
baseUrl: string | undefined;
coverArtId?: string;
credential: string | undefined;
size: number;
2023-04-24 01:21:29 -07:00
}) => {
2023-07-01 19:10:05 -07:00
const size = args.size ? args.size : 250;
2023-04-24 01:21:29 -07:00
2023-07-01 19:10:05 -07:00
if (!args.coverArtId || args.coverArtId.match('2a96cbd8b46e442fc41c2b86b821562f')) {
return null;
}
2023-04-24 01:21:29 -07:00
2023-07-01 19:10:05 -07:00
return (
`${args.baseUrl}/rest/getCoverArt.view` +
`?id=${args.coverArtId}` +
`&${args.credential}` +
'&v=1.13.0' +
'&c=feishin' +
`&size=${size}`
);
2023-04-24 01:21:29 -07:00
};
const normalizeSong = (
2023-07-01 19:10:05 -07:00
item: z.infer<typeof ssType._response.song>,
server: ServerListItem | null,
deviceId: string,
2024-09-26 04:23:08 +00:00
size?: number,
2023-04-24 01:21:29 -07:00
): QueueSong => {
2023-07-01 19:10:05 -07:00
const imageUrl =
getCoverArtUrl({
baseUrl: server?.url,
coverArtId: item.coverArt?.toString(),
2023-07-01 19:10:05 -07:00
credential: server?.credential,
2024-09-26 04:23:08 +00:00
size: size || 300,
2023-07-01 19:10:05 -07:00
}) || null;
2023-04-24 01:21:29 -07:00
2023-07-01 19:10:05 -07:00
const streamUrl = `${server?.url}/rest/stream.view?id=${item.id}&v=1.13.0&c=feishin_${deviceId}&${server?.credential}`;
2023-04-24 01:21:29 -07:00
2023-07-01 19:10:05 -07:00
return {
album: item.album || '',
albumArtists: [
{
2024-10-01 17:21:28 -07:00
id: item.artistId?.toString() || '',
2023-07-01 19:10:05 -07:00
imageUrl: null,
name: item.artist || '',
},
],
2024-10-01 17:21:28 -07:00
albumId: item.albumId?.toString() || '',
2023-07-01 19:10:05 -07:00
artistName: item.artist || '',
artists: [
{
2024-10-01 17:21:28 -07:00
id: item.artistId?.toString() || '',
2023-07-01 19:10:05 -07:00
imageUrl: null,
name: item.artist || '',
},
],
bitRate: item.bitRate || 0,
2024-09-26 04:23:08 +00:00
bpm: item.bpm || null,
2023-07-01 19:10:05 -07:00
channels: null,
comment: null,
compilation: null,
container: item.contentType,
createdAt: item.created,
discNumber: item.discNumber || 1,
2023-09-22 15:12:23 -07:00
discSubtitle: null,
2023-09-21 17:22:42 -07:00
duration: item.duration ? item.duration * 1000 : 0,
gain:
item.replayGain && (item.replayGain.albumGain || item.replayGain.trackGain)
? {
album: item.replayGain.albumGain,
track: item.replayGain.trackGain,
}
: null,
2023-07-01 19:10:05 -07:00
genres: item.genre
? [
{
id: item.genre,
2023-08-04 10:32:35 -07:00
imageUrl: null,
itemType: LibraryItem.GENRE,
2023-07-01 19:10:05 -07:00
name: item.genre,
},
]
: [],
2024-10-01 17:21:28 -07:00
id: item.id.toString(),
2023-07-01 19:10:05 -07:00
imagePlaceholderUrl: null,
imageUrl,
itemType: LibraryItem.SONG,
lastPlayedAt: null,
lyrics: null,
name: item.title,
path: item.path,
peak:
item.replayGain && (item.replayGain.albumPeak || item.replayGain.trackPeak)
? {
album: item.replayGain.albumPeak,
track: item.replayGain.trackPeak,
}
: null,
2023-07-01 19:10:05 -07:00
playCount: item?.playCount || 0,
releaseDate: null,
releaseYear: item.year ? String(item.year) : null,
serverId: server?.id || 'unknown',
serverType: ServerType.SUBSONIC,
size: item.size,
streamUrl,
trackNumber: item.track || 1,
uniqueId: nanoid(),
updatedAt: '',
userFavorite: item.starred || false,
userRating: item.userRating || null,
};
2023-04-24 01:21:29 -07:00
};
2023-05-19 00:14:41 -07:00
const normalizeAlbumArtist = (
2024-09-26 04:23:08 +00:00
item:
| z.infer<typeof ssType._response.albumArtist>
| z.infer<typeof ssType._response.artistListEntry>,
2023-07-01 19:10:05 -07:00
server: ServerListItem | null,
2024-09-26 04:23:08 +00:00
imageSize?: number,
2023-05-19 00:14:41 -07:00
): AlbumArtist => {
2023-07-01 19:10:05 -07:00
const imageUrl =
getCoverArtUrl({
baseUrl: server?.url,
coverArtId: item.coverArt?.toString(),
2023-07-01 19:10:05 -07:00
credential: server?.credential,
2024-09-26 04:23:08 +00:00
size: imageSize || 100,
2023-07-01 19:10:05 -07:00
}) || null;
2023-05-19 00:14:41 -07:00
2023-07-01 19:10:05 -07:00
return {
albumCount: item.albumCount ? Number(item.albumCount) : 0,
backgroundImageUrl: null,
biography: null,
duration: null,
genres: [],
2024-10-01 17:21:28 -07:00
id: item.id.toString(),
2023-07-01 19:10:05 -07:00
imageUrl,
itemType: LibraryItem.ALBUM_ARTIST,
lastPlayedAt: null,
2024-01-15 22:10:50 -08:00
mbz: null,
2023-07-01 19:10:05 -07:00
name: item.name,
playCount: null,
serverId: server?.id || 'unknown',
serverType: ServerType.SUBSONIC,
similarArtists: [],
songCount: null,
userFavorite: false,
userRating: null,
};
2023-05-19 00:14:41 -07:00
};
const normalizeAlbum = (
2024-09-26 04:23:08 +00:00
item: z.infer<typeof ssType._response.album> | z.infer<typeof ssType._response.albumListEntry>,
2023-07-01 19:10:05 -07:00
server: ServerListItem | null,
2024-09-26 04:23:08 +00:00
imageSize?: number,
2023-05-19 00:14:41 -07:00
): Album => {
2023-07-01 19:10:05 -07:00
const imageUrl =
getCoverArtUrl({
baseUrl: server?.url,
coverArtId: item.coverArt?.toString(),
2023-07-01 19:10:05 -07:00
credential: server?.credential,
2024-09-26 04:23:08 +00:00
size: imageSize || 300,
2023-07-01 19:10:05 -07:00
}) || null;
2023-05-19 00:14:41 -07:00
2023-07-01 19:10:05 -07:00
return {
2024-01-15 22:10:50 -08:00
albumArtist: item.artist,
2023-07-01 19:10:05 -07:00
albumArtists: item.artistId
2024-10-01 17:21:28 -07:00
? [{ id: item.artistId.toString(), imageUrl: null, name: item.artist }]
: [],
artists: item.artistId
? [{ id: item.artistId.toString(), imageUrl: null, name: item.artist }]
2023-07-01 19:10:05 -07:00
: [],
backdropImageUrl: null,
2024-01-15 20:46:06 -08:00
comment: null,
2023-07-01 19:10:05 -07:00
createdAt: item.created,
2024-09-26 04:23:08 +00:00
duration: item.duration * 1000,
2023-08-04 10:32:35 -07:00
genres: item.genre
? [
{
id: item.genre,
imageUrl: null,
itemType: LibraryItem.GENRE,
name: item.genre,
},
]
: [],
2024-10-01 17:21:28 -07:00
id: item.id.toString(),
2023-07-01 19:10:05 -07:00
imagePlaceholderUrl: null,
imageUrl,
isCompilation: null,
itemType: LibraryItem.ALBUM,
lastPlayedAt: null,
2024-01-15 22:10:50 -08:00
mbzId: null,
2023-07-01 19:10:05 -07:00
name: item.name,
2024-08-25 19:52:44 -07:00
originalDate: null,
2023-07-01 19:10:05 -07:00
playCount: null,
releaseDate: item.year ? new Date(Date.UTC(item.year, 0, 1)).toISOString() : null,
2023-07-01 19:10:05 -07:00
releaseYear: item.year ? Number(item.year) : null,
serverId: server?.id || 'unknown',
serverType: ServerType.SUBSONIC,
size: null,
songCount: item.songCount,
2024-09-26 04:23:08 +00:00
songs:
(item as z.infer<typeof ssType._response.album>).song?.map((song) =>
normalizeSong(song, server, ''),
) || [],
2023-07-01 19:10:05 -07:00
uniqueId: nanoid(),
updatedAt: item.created,
userFavorite: item.starred || false,
userRating: item.userRating || null,
};
2023-05-19 00:14:41 -07:00
};
2024-09-26 04:23:08 +00:00
const normalizePlaylist = (
item:
| z.infer<typeof ssType._response.playlist>
| z.infer<typeof ssType._response.playlistListEntry>,
server: ServerListItem | null,
): Playlist => {
return {
description: item.comment || null,
duration: item.duration,
genres: [],
2024-10-01 17:21:28 -07:00
id: item.id.toString(),
2024-09-26 04:23:08 +00:00
imagePlaceholderUrl: null,
imageUrl: getCoverArtUrl({
baseUrl: server?.url,
coverArtId: item.coverArt?.toString(),
2024-09-26 04:23:08 +00:00
credential: server?.credential,
size: 300,
}),
itemType: LibraryItem.PLAYLIST,
name: item.name,
owner: item.owner,
ownerId: item.owner,
public: item.public,
serverId: server?.id || 'unknown',
serverType: ServerType.SUBSONIC,
size: null,
songCount: item.songCount,
};
};
const normalizeGenre = (item: z.infer<typeof ssType._response.genre>): Genre => {
return {
albumCount: item.albumCount,
id: item.value,
imageUrl: null,
itemType: LibraryItem.GENRE,
name: item.value,
songCount: item.songCount,
};
};
2023-04-24 01:21:29 -07:00
export const ssNormalize = {
2023-07-01 19:10:05 -07:00
album: normalizeAlbum,
albumArtist: normalizeAlbumArtist,
2024-09-26 04:23:08 +00:00
genre: normalizeGenre,
playlist: normalizePlaylist,
2023-07-01 19:10:05 -07:00
song: normalizeSong,
2023-04-24 01:21:29 -07:00
};