add releaseType to album header

This commit is contained in:
jeffvli
2025-12-29 21:16:39 -08:00
parent 145dc5c99e
commit 62ab4b7a00
7 changed files with 111 additions and 3 deletions
@@ -91,11 +91,13 @@ export const AlbumDetailHeader = forwardRef<HTMLDivElement>((_props, ref) => {
type: 'header', type: 'header',
}); });
const releaseType = detailQuery?.data?.releaseType || undefined;
return ( return (
<Stack ref={ref}> <Stack ref={ref}>
<LibraryHeader <LibraryHeader
imageUrl={imageUrl} imageUrl={imageUrl}
item={{ route: AppRoute.LIBRARY_ALBUMS, type: LibraryItem.ALBUM }} item={{ releaseType, route: AppRoute.LIBRARY_ALBUMS, type: LibraryItem.ALBUM }}
title={detailQuery?.data?.name || ''} title={detailQuery?.data?.name || ''}
> >
<Stack gap="md" w="100%"> <Stack gap="md" w="100%">
@@ -17,6 +17,7 @@ import { usePlayButtonClick } from '/@/renderer/features/shared/hooks/use-play-b
import { useIsMutatingCreateFavorite } from '/@/renderer/features/shared/mutations/create-favorite-mutation'; import { useIsMutatingCreateFavorite } from '/@/renderer/features/shared/mutations/create-favorite-mutation';
import { useIsMutatingDeleteFavorite } from '/@/renderer/features/shared/mutations/delete-favorite-mutation'; import { useIsMutatingDeleteFavorite } from '/@/renderer/features/shared/mutations/delete-favorite-mutation';
import { useIsMutatingRating } from '/@/renderer/features/shared/mutations/set-rating-mutation'; import { useIsMutatingRating } from '/@/renderer/features/shared/mutations/set-rating-mutation';
import { titleCase } from '/@/renderer/utils';
import { ActionIcon } from '/@/shared/components/action-icon/action-icon'; import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
import { Button } from '/@/shared/components/button/button'; import { Button } from '/@/shared/components/button/button';
import { Center } from '/@/shared/components/center/center'; import { Center } from '/@/shared/components/center/center';
@@ -34,7 +35,7 @@ interface LibraryHeaderProps {
containerClassName?: string; containerClassName?: string;
imagePlaceholderUrl?: null | string; imagePlaceholderUrl?: null | string;
imageUrl?: null | string; imageUrl?: null | string;
item: { route: string; type: LibraryItem }; item: { releaseType?: string; route: string; type?: LibraryItem };
loading?: boolean; loading?: boolean;
title: string; title: string;
} }
@@ -51,7 +52,86 @@ export const LibraryHeader = forwardRef(
setIsImageError(true); setIsImageError(true);
}; };
const itemTypeString = () => { const itemTypeString = (): string => {
if (item.releaseType) {
switch (item.releaseType) {
case 'album':
return t('releaseType.primary.album', {
postProcess: 'sentenceCase',
});
case 'appears-on':
return t('page.albumArtistDetail.appearsOn', {
postProcess: 'sentenceCase',
});
case 'audiobook':
return t('releaseType.secondary.audiobook', {
postProcess: 'sentenceCase',
});
case 'audio drama':
return t('releaseType.secondary.audioDrama', {
postProcess: 'sentenceCase',
});
case 'broadcast':
return t('releaseType.primary.broadcast', {
postProcess: 'sentenceCase',
});
case 'compilation':
return t('releaseType.secondary.compilation', {
postProcess: 'sentenceCase',
});
case 'demo':
return t('releaseType.secondary.demo', {
postProcess: 'sentenceCase',
});
case 'dj-mix':
return t('releaseType.secondary.djMix', {
postProcess: 'sentenceCase',
});
case 'ep':
return t('releaseType.primary.ep', {
postProcess: 'sentenceCase',
});
case 'field recording':
return t('releaseType.secondary.fieldRecording', {
postProcess: 'sentenceCase',
});
case 'interview':
return t('releaseType.secondary.interview', {
postProcess: 'sentenceCase',
});
case 'live':
return t('releaseType.secondary.live', {
postProcess: 'sentenceCase',
});
case 'mixtape/street':
return t('releaseType.secondary.mixtape', {
postProcess: 'sentenceCase',
});
case 'other':
return t('releaseType.primary.other', {
postProcess: 'sentenceCase',
});
case 'remix':
return t('releaseType.secondary.remix', {
postProcess: 'sentenceCase',
});
case 'single':
return t('releaseType.primary.single', {
postProcess: 'sentenceCase',
});
case 'soundtrack':
return t('releaseType.secondary.soundtrack', {
postProcess: 'sentenceCase',
});
case 'spokenword':
return t('releaseType.secondary.spokenWord', {
postProcess: 'sentenceCase',
});
default:
return titleCase(item.releaseType);
}
}
switch (item.type) { switch (item.type) {
case LibraryItem.ALBUM: case LibraryItem.ALBUM:
return t('entity.album', { count: 1 }); return t('entity.album', { count: 1 });
@@ -279,6 +279,7 @@ const normalizeAlbum = (
playCount: item.UserData?.PlayCount || 0, playCount: item.UserData?.PlayCount || 0,
recordLabels: item.Studios?.map((entry) => entry.Name) || [], recordLabels: item.Studios?.map((entry) => entry.Name) || [],
releaseDate: item.PremiereDate || null, releaseDate: item.PremiereDate || null,
releaseType: null,
releaseTypes: [], releaseTypes: [],
releaseYear: item.ProductionYear || null, releaseYear: item.ProductionYear || null,
size: null, size: null,
@@ -304,6 +304,7 @@ const normalizeAlbum = (
originalDate: item.originalDate || null, originalDate: item.originalDate || null,
playCount: item.playCount || 0, playCount: item.playCount || 0,
releaseDate: normalizeReleaseDate(item), releaseDate: normalizeReleaseDate(item),
releaseType: item.mbzAlbumType || null,
releaseYear: item.maxYear || null, releaseYear: item.maxYear || null,
size: item.size, size: item.size,
songCount: item.songCount, songCount: item.songCount,
@@ -440,6 +440,7 @@ const album = z.object({
allArtistIds: z.string(), allArtistIds: z.string(),
artist: z.string(), artist: z.string(),
artistId: z.string(), artistId: z.string(),
catalogNum: z.string().optional(),
comment: z.string().optional(), comment: z.string().optional(),
compilation: z.boolean(), compilation: z.boolean(),
coverArtId: z.string().optional(), // Removed after v0.48.0 coverArtId: z.string().optional(), // Removed after v0.48.0
@@ -447,13 +448,21 @@ const album = z.object({
createdAt: z.string(), createdAt: z.string(),
duration: z.number().optional(), duration: z.number().optional(),
explicitStatus: z.string().optional(), explicitStatus: z.string().optional(),
externalInfoUpdatedAt: z.string().optional(),
externalUrl: z.string().optional(),
fullText: z.string(), fullText: z.string(),
genre: z.string(), genre: z.string(),
genres: z.array(genre).nullable(), genres: z.array(genre).nullable(),
id: z.string(), id: z.string(),
importedAt: z.string().optional(),
libraryId: z.number(),
libraryName: z.string(),
libraryPath: z.string(),
maxYear: z.number(), maxYear: z.number(),
mbzAlbumArtistId: z.string().optional(), mbzAlbumArtistId: z.string().optional(),
mbzAlbumId: z.string().optional(), mbzAlbumId: z.string().optional(),
mbzAlbumType: z.string().optional(),
mbzReleaseGroupId: z.string().optional(),
minYear: z.number(), minYear: z.number(),
name: z.string(), name: z.string(),
orderAlbumArtistName: z.string(), orderAlbumArtistName: z.string(),
@@ -226,6 +226,19 @@ const normalizeAlbumArtist = (
}; };
}; };
const PRIMARY_RELEASE_TYPES = ['album', 'ep', 'single', 'broadcast', 'other'];
const getReleaseType = (
item: z.infer<typeof ssType._response.album> | z.infer<typeof ssType._response.albumListEntry>,
) => {
if (!item.releaseTypes) {
return null;
}
// Return the first primary release type
return item.releaseTypes.find((type) => PRIMARY_RELEASE_TYPES.includes(type)) || null;
};
const normalizeAlbum = ( const normalizeAlbum = (
item: z.infer<typeof ssType._response.album> | z.infer<typeof ssType._response.albumListEntry>, item: z.infer<typeof ssType._response.album> | z.infer<typeof ssType._response.albumListEntry>,
server?: null | ServerListItemWithCredential, server?: null | ServerListItemWithCredential,
@@ -269,6 +282,7 @@ const normalizeAlbum = (
item.releaseDate.day, item.releaseDate.day,
).toISOString() ).toISOString()
: null, : null,
releaseType: getReleaseType(item),
releaseTypes: item.releaseTypes || [], releaseTypes: item.releaseTypes || [],
releaseYear: item.year || null, releaseYear: item.year || null,
size: null, size: null,
+1
View File
@@ -191,6 +191,7 @@ export type Album = {
playCount: null | number; playCount: null | number;
recordLabels: string[]; recordLabels: string[];
releaseDate: null | string; releaseDate: null | string;
releaseType: null | string;
releaseTypes: string[]; releaseTypes: string[];
releaseYear: null | number; releaseYear: null | number;
size: null | number; size: null | number;