Add additional information to album: record label, release type, version (#1242)

* Add additional information to album

* add mbz release types and normalization

* update Pill styling

---------

Co-authored-by: jeffvli <jeffvictorli@gmail.com>
This commit is contained in:
Kendall Garner
2025-11-03 08:34:42 +00:00
committed by GitHub
parent 3fe6ccf300
commit e26ffaac53
12 changed files with 223 additions and 40 deletions
@@ -340,7 +340,9 @@ const normalizeAlbum = (
originalDate: null,
participants: getPeople(item),
playCount: item.UserData?.PlayCount || 0,
recordLabels: [],
releaseDate: item.PremiereDate?.split('T')[0] || null,
releaseTypes: [],
releaseYear: item.ProductionYear || null,
serverId: server?.id || '',
serverType: ServerType.JELLYFIN,
@@ -352,6 +354,7 @@ const normalizeAlbum = (
updatedAt: item?.DateLastMediaAdded || item.DateCreated,
userFavorite: item.UserData?.IsFavorite || false,
userRating: null,
version: null,
};
};
@@ -218,6 +218,47 @@ const normalizeSong = (
};
};
const parseAlbumTags = (
item: z.infer<typeof ndType._response.album>,
): Pick<Album, 'recordLabels' | 'releaseTypes' | 'tags' | 'version'> => {
if (!item.tags) {
return {
recordLabels: [],
releaseTypes: [],
tags: null,
version: null,
};
}
// We get the genre from elsewhere. We don't need genre twice
delete item.tags['genre'];
let recordLabels: string[] = [];
if (item.tags['recordlabel']) {
recordLabels = item.tags['recordlabel'];
delete item.tags['recordlabel'];
}
let releaseTypes: string[] = [];
if (item.tags['releasetype']) {
releaseTypes = item.tags['releasetype'];
delete item.tags['releasetype'];
}
let version: null | string = null;
if (item.tags['albumversion']) {
version = item.tags['albumversion'].join(' · ');
delete item.tags['albumversion'];
}
return {
recordLabels,
releaseTypes,
tags: item.tags,
version,
};
};
const normalizeAlbum = (
item: z.infer<typeof ndType._response.album> & {
songs?: z.infer<typeof ndType._response.songList>;
@@ -238,8 +279,9 @@ const normalizeAlbum = (
const imageBackdropUrl = imageUrl?.replace(/size=\d+/, 'size=1000') || null;
return {
albumArtist: item.albumArtist,
...parseAlbumTags(item),
...getArtists(item),
albumArtist: item.albumArtist,
backdropImageUrl: imageBackdropUrl,
comment: item.comment || null,
createdAt: item.createdAt.split('T')[0],
@@ -281,7 +323,6 @@ const normalizeAlbum = (
size: item.size,
songCount: item.songCount,
songs: item.songs ? item.songs.map((song) => normalizeSong(song, server)) : undefined,
tags: item.tags || null,
uniqueId: nanoid(),
updatedAt: item.updatedAt,
userFavorite: item.starred,
@@ -272,7 +272,9 @@ const normalizeAlbum = (
originalDate: null,
participants: getParticipants(item),
playCount: null,
recordLabels: item.recordLabels?.map((item) => item.name) || [],
releaseDate: item.year ? new Date(Date.UTC(item.year, 0, 1)).toISOString() : null,
releaseTypes: item.releaseTypes || [],
releaseYear: item.year ? Number(item.year) : null,
serverId: server?.id || 'unknown',
serverType: ServerType.SUBSONIC,
@@ -287,6 +289,7 @@ const normalizeAlbum = (
updatedAt: item.created,
userFavorite: item.starred || false,
userRating: item.userRating || null,
version: item.version || null,
};
};
@@ -117,6 +117,10 @@ const song = z.object({
year: z.number().optional(),
});
const recordLabel = z.object({
name: z.string(),
});
const album = z.object({
album: z.string(),
artist: z.string(),
@@ -135,11 +139,14 @@ const album = z.object({
isVideo: z.boolean(),
name: z.string(),
parent: z.string(),
recordLabels: z.array(recordLabel).optional(),
releaseTypes: z.array(z.string()).optional(),
song: z.array(song),
songCount: z.number(),
starred: z.boolean().optional(),
title: z.string(),
userRating: z.number().optional(),
version: z.string().optional(),
year: z.number().optional(),
});
+18 -7
View File
@@ -1,28 +1,39 @@
.root {
box-sizing: border-box;
user-select: auto;
background: alpha(var(--theme-colors-background), 0.5);
border: 1px solid var(--theme-colors-border);
&[data-variant='outline'] {
background: transparent;
border: 1px solid var(--theme-colors-border);
}
}
.label {
font-family: var(--theme-content-font-family);
font-family: var(--theme-content-font-family);
}
.label.sm {
font-size: var(--theme-font-size-sm);
font-size: var(--theme-font-size-sm);
}
.label.md {
font-size: var(--theme-font-size-md);
font-size: var(--theme-font-size-md);
}
.label.lg {
font-size: var(--theme-font-size-lg);
font-size: var(--theme-font-size-lg);
}
.label.xl {
font-size: var(--theme-font-size-xl);
font-size: var(--theme-font-size-xl);
}
.label.xs {
font-size: var(--theme-font-size-xs);
font-size: var(--theme-font-size-xs);
}
.remove {
transition: color 0.1s ease-in-out;
+6 -2
View File
@@ -3,7 +3,9 @@ import clsx from 'clsx';
import styles from './pill.module.css';
export const Pill = ({ children, size = 'md', ...props }: MantinePillProps) => {
interface PillProps extends MantinePillProps {}
export const Pill = ({ children, classNames, radius = 'md', size = 'md', ...props }: PillProps) => {
return (
<MantinePill
classNames={{
@@ -17,8 +19,10 @@ export const Pill = ({ children, size = 'md', ...props }: MantinePillProps) => {
}),
remove: styles.remove,
root: styles.root,
...classNames,
}}
size="md"
radius={radius}
size={size}
{...props}
>
{children}
+3
View File
@@ -182,7 +182,9 @@ export type Album = {
originalDate: null | string;
participants: null | Record<string, RelatedArtist[]>;
playCount: null | number;
recordLabels: string[];
releaseDate: null | string;
releaseTypes: string[];
releaseYear: null | number;
serverId: string;
serverType: ServerType;
@@ -194,6 +196,7 @@ export type Album = {
updatedAt: string;
userFavorite: boolean;
userRating: null | number;
version: null | string;
} & { songs?: Song[] };
export type AlbumArtist = {