mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-10 04:30:25 +02:00
add selector to convert musicbrainz releases to Album type
This commit is contained in:
@@ -1,9 +1,17 @@
|
|||||||
import { queryOptions } from '@tanstack/react-query';
|
import { queryOptions } from '@tanstack/react-query';
|
||||||
import { MusicBrainzApi } from 'musicbrainz-api';
|
import memoize from 'lodash/memoize';
|
||||||
|
import { IArtist, IRelease, IReleaseGroup, MusicBrainzApi } from 'musicbrainz-api';
|
||||||
|
|
||||||
import packageJson from '../../../../../package.json';
|
import packageJson from '../../../../../package.json';
|
||||||
|
|
||||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
import { queryKeys } from '/@/renderer/api/query-keys';
|
||||||
|
import {
|
||||||
|
Album,
|
||||||
|
AlbumArtist,
|
||||||
|
LibraryItem,
|
||||||
|
RelatedArtist,
|
||||||
|
ServerType,
|
||||||
|
} from '/@/shared/types/domain-types';
|
||||||
|
|
||||||
export const musicbrainzApi = new MusicBrainzApi({
|
export const musicbrainzApi = new MusicBrainzApi({
|
||||||
appContactInfo: packageJson.homepage,
|
appContactInfo: packageJson.homepage,
|
||||||
@@ -14,20 +22,145 @@ export const musicbrainzApi = new MusicBrainzApi({
|
|||||||
// Cache all musicbrainz api results for 5 minutes
|
// Cache all musicbrainz api results for 5 minutes
|
||||||
const CACHE_TIME = 1000 * 60 * 5;
|
const CACHE_TIME = 1000 * 60 * 5;
|
||||||
|
|
||||||
|
const artistSelect = memoize(
|
||||||
|
({ data, meta }: { data: IArtist; meta: { albumArtist: AlbumArtist } }) => {
|
||||||
|
const releaseGroups =
|
||||||
|
data['release-groups']?.reduce(
|
||||||
|
(
|
||||||
|
acc: Record<
|
||||||
|
string,
|
||||||
|
{
|
||||||
|
originalDate: null | string;
|
||||||
|
primaryReleaseType: null | string;
|
||||||
|
secondaryReleaseTypes: string[];
|
||||||
|
}
|
||||||
|
>,
|
||||||
|
releaseGroup: IReleaseGroup,
|
||||||
|
) => {
|
||||||
|
const primaryReleaseType = releaseGroup['primary-type'].toLowerCase();
|
||||||
|
const secondaryReleaseTypes = releaseGroup['secondary-types'].map((type) =>
|
||||||
|
type.toLowerCase(),
|
||||||
|
);
|
||||||
|
const originalDate = releaseGroup['first-release-date'];
|
||||||
|
|
||||||
|
acc[releaseGroup.title] = {
|
||||||
|
originalDate: originalDate,
|
||||||
|
primaryReleaseType: primaryReleaseType,
|
||||||
|
secondaryReleaseTypes: secondaryReleaseTypes,
|
||||||
|
};
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{} as Record<
|
||||||
|
string,
|
||||||
|
{
|
||||||
|
originalDate: null | string;
|
||||||
|
primaryReleaseType: null | string;
|
||||||
|
secondaryReleaseTypes: string[];
|
||||||
|
}
|
||||||
|
>,
|
||||||
|
) || {};
|
||||||
|
|
||||||
|
const albumArtist: RelatedArtist = {
|
||||||
|
id: meta.albumArtist.id,
|
||||||
|
imageId: meta.albumArtist.imageId,
|
||||||
|
imageUrl: meta.albumArtist.imageUrl,
|
||||||
|
name: meta.albumArtist.name,
|
||||||
|
userFavorite: meta.albumArtist.userFavorite,
|
||||||
|
userRating: meta.albumArtist.userRating,
|
||||||
|
};
|
||||||
|
|
||||||
|
const albumArtistName = meta.albumArtist.name;
|
||||||
|
|
||||||
|
const albums: Album[] = (data['releases'] || [])
|
||||||
|
.map((release: IRelease) => {
|
||||||
|
const releaseGroup = releaseGroups[release.title];
|
||||||
|
|
||||||
|
if (!releaseGroup) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const releaseType = releaseGroup.primaryReleaseType;
|
||||||
|
const secondaryReleaseTypes = releaseGroup.secondaryReleaseTypes || [];
|
||||||
|
const releaseTypes = [releaseType, ...secondaryReleaseTypes].filter(
|
||||||
|
(type) => type !== null,
|
||||||
|
) as string[];
|
||||||
|
const isCompilation = releaseTypes.includes('compilation');
|
||||||
|
const originalDate = releaseGroup.originalDate;
|
||||||
|
const originalYear = originalDate ? Number(originalDate.split('-')[0]) : null;
|
||||||
|
const releaseDate = release.date ? release.date : null;
|
||||||
|
const releaseYear = release.date ? Number(release.date.split('-')[0]) : null;
|
||||||
|
const imageUrl = release.media.length > 0 ? getImageUrl(release.id) : null;
|
||||||
|
|
||||||
|
const album: Album = {
|
||||||
|
_itemType: LibraryItem.ALBUM,
|
||||||
|
_serverId: '',
|
||||||
|
_serverType: ServerType.EXTERNAL,
|
||||||
|
albumArtistName: albumArtistName,
|
||||||
|
albumArtists: [albumArtist],
|
||||||
|
artists: [],
|
||||||
|
comment: null,
|
||||||
|
createdAt: '',
|
||||||
|
duration: null,
|
||||||
|
explicitStatus: null,
|
||||||
|
genres: [],
|
||||||
|
id: `musicbrainz-${release.id}`,
|
||||||
|
imageId: null,
|
||||||
|
imageUrl: imageUrl,
|
||||||
|
isCompilation: isCompilation,
|
||||||
|
lastPlayedAt: null,
|
||||||
|
mbzId: release.id,
|
||||||
|
name: release.title,
|
||||||
|
originalDate: originalDate,
|
||||||
|
originalYear: originalYear,
|
||||||
|
participants: {},
|
||||||
|
playCount: null,
|
||||||
|
recordLabels: [],
|
||||||
|
releaseDate: releaseDate,
|
||||||
|
releaseType: releaseType,
|
||||||
|
releaseTypes: releaseTypes,
|
||||||
|
releaseYear: releaseYear,
|
||||||
|
size: null,
|
||||||
|
songCount: null,
|
||||||
|
tags: {},
|
||||||
|
updatedAt: '',
|
||||||
|
userFavorite: false,
|
||||||
|
userRating: null,
|
||||||
|
version: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
return album;
|
||||||
|
})
|
||||||
|
.filter((album): album is Album => album !== null);
|
||||||
|
|
||||||
|
return albums;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
export const musicbrainzQueries = {
|
export const musicbrainzQueries = {
|
||||||
artist: (args: { mbzArtistId: string }) => {
|
artist: (args: { mbzArtistId: string }) => {
|
||||||
return queryOptions({
|
return queryOptions({
|
||||||
gcTime: CACHE_TIME,
|
gcTime: CACHE_TIME,
|
||||||
queryFn: () =>
|
queryFn: async ({ meta }) => {
|
||||||
musicbrainzApi.lookup('artist', args.mbzArtistId, [
|
const data = await musicbrainzApi.lookup('artist', args.mbzArtistId, [
|
||||||
'releases',
|
'releases',
|
||||||
|
'release-rels',
|
||||||
'recordings',
|
'recordings',
|
||||||
'release-groups',
|
'release-groups',
|
||||||
|
'release-group-rels',
|
||||||
'works',
|
'works',
|
||||||
'media',
|
'media',
|
||||||
]),
|
]);
|
||||||
|
|
||||||
|
return { data, meta: meta as { albumArtist: AlbumArtist } };
|
||||||
|
},
|
||||||
queryKey: queryKeys.musicbrainz.artist(args.mbzArtistId),
|
queryKey: queryKeys.musicbrainz.artist(args.mbzArtistId),
|
||||||
|
select: artistSelect,
|
||||||
staleTime: CACHE_TIME,
|
staleTime: CACHE_TIME,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function getImageUrl(releaseId: string): string {
|
||||||
|
return `https://coverartarchive.org/release/${releaseId}/front-250.jpg`;
|
||||||
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ export enum LibraryItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export enum ServerType {
|
export enum ServerType {
|
||||||
|
EXTERNAL = 'external', // This is not an actual server type. This is used when fetching from external sources (e.g. musicbrainz)
|
||||||
JELLYFIN = 'jellyfin',
|
JELLYFIN = 'jellyfin',
|
||||||
NAVIDROME = 'navidrome',
|
NAVIDROME = 'navidrome',
|
||||||
SUBSONIC = 'subsonic',
|
SUBSONIC = 'subsonic',
|
||||||
|
|||||||
Reference in New Issue
Block a user