add remixer to song artist (#1400)

This commit is contained in:
jeffvli
2026-01-03 03:03:10 -08:00
parent 261c5541cd
commit 186811156e
4 changed files with 147 additions and 57 deletions
@@ -96,24 +96,38 @@ export const JoinedArtists = ({
const hasArtistMatches = parts.some((part) => typeof part !== 'string'); const hasArtistMatches = parts.some((part) => typeof part !== 'string');
// Find artists that were matched
const matchedArtistIds = new Set(nonOverlappingMatches.map((match) => match.artist.id));
// Find artists that are not present in the artist name
const unmatchedArtists = artists.filter(
(artist) => artist.name && !matchedArtistIds.has(artist.id),
);
// If no matches found and there are album artists, return the album artists // If no matches found and there are album artists, return the album artists
if (!hasArtistMatches && artists.length > 0) { if (!hasArtistMatches && artists.length > 0) {
return ( return (
<Text component="span" {...rootTextProps}> <Text component="span" {...rootTextProps}>
{artists.map((artist, index) => ( {artists.map((artist, index) => (
<Fragment key={artist.id}> <Fragment key={artist.id || `artist-${index}`}>
{index > 0 && ', '} {index > 0 && ', '}
<Text {artist.id ? (
component={Link} <Text
fw={600} component={Link}
isLink fw={600}
to={generatePath(AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL, { isLink
albumArtistId: artist.id, to={generatePath(AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL, {
})} albumArtistId: artist.id,
{...linkProps} })}
> {...linkProps}
{artist.name} >
</Text> {artist.name}
</Text>
) : (
<Text fw={600} {...linkProps}>
{artist.name}
</Text>
)}
</Fragment> </Fragment>
))} ))}
</Text> </Text>
@@ -137,21 +151,56 @@ export const JoinedArtists = ({
} }
const { artist, text } = part; const { artist, text } = part;
if (artist.id) {
return (
<Text
component={Link}
fw={600}
isLink
key={`${artist.id}-${index}`}
to={generatePath(AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL, {
albumArtistId: artist.id,
})}
{...linkProps}
>
{text}
</Text>
);
}
return ( return (
<Text <Text fw={600} key={`${artist.name}-${index}`} {...linkProps}>
component={Link}
fw={600}
isLink
key={`${artist.id}-${index}`}
to={generatePath(AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL, {
albumArtistId: artist.id,
})}
{...linkProps}
>
{text} {text}
</Text> </Text>
); );
})} })}
{unmatchedArtists.length > 0 && (
<>
{', '}
{unmatchedArtists.map((artist, index) => (
<Fragment key={artist.id}>
{index > 0 && ', '}
{artist.id ? (
<Text
component={Link}
fw={600}
isLink
to={generatePath(AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL, {
albumArtistId: artist.id,
})}
{...linkProps}
>
{artist.name}
</Text>
) : (
<Text component="span" isMuted>
{artist.name}
</Text>
)}
</Fragment>
))}
</>
)}
</Text> </Text>
); );
}; };
+34 -11
View File
@@ -106,6 +106,33 @@ const getPlaylistImageId = (item: z.infer<typeof jfType._response.playlist>): nu
return null; return null;
}; };
const getArtists = (
item: z.infer<typeof jfType._response.song>,
participants?: null | Record<string, RelatedArtist[]>,
): RelatedArtist[] => {
if (!item?.ArtistItems?.length && !item.AlbumArtists && !participants) {
return [];
}
const result: RelatedArtist[] = [];
(item?.ArtistItems?.length ? item.ArtistItems : item.AlbumArtists)?.forEach((entry) => {
result.push({
id: entry.Id,
imageId: null,
imageUrl: null,
name: entry.Name,
userFavorite: false,
userRating: null,
});
});
if (participants?.['Remixer']) {
result.push(...participants['Remixer']);
}
return result;
};
const normalizeSong = ( const normalizeSong = (
item: z.infer<typeof jfType._response.song>, item: z.infer<typeof jfType._response.song>,
server: null | ServerListItem, server: null | ServerListItem,
@@ -143,6 +170,11 @@ const normalizeSong = (
console.warn('Jellyfin song retrieved with no media sources', item); console.warn('Jellyfin song retrieved with no media sources', item);
} }
const participants = getPeople(item);
const artists = getArtists(item, participants);
console.log('artists', artists);
return { return {
_itemType: LibraryItem.SONG, _itemType: LibraryItem.SONG,
_serverId: server?.id || '', _serverId: server?.id || '',
@@ -159,16 +191,7 @@ const normalizeSong = (
})), })),
albumId: item.AlbumId || `dummy/${item.Id}`, albumId: item.AlbumId || `dummy/${item.Id}`,
artistName: item?.ArtistItems?.map((entry) => entry.Name).join(', ') || '', artistName: item?.ArtistItems?.map((entry) => entry.Name).join(', ') || '',
artists: (item?.ArtistItems?.length ? item.ArtistItems : item.AlbumArtists)?.map( artists,
(entry) => ({
id: entry.Id,
imageId: null,
imageUrl: null,
name: entry.Name,
userFavorite: false,
userRating: null,
}),
),
bitDepth: null, bitDepth: null,
bitRate, bitRate,
bpm: null, bpm: null,
@@ -210,7 +233,7 @@ const normalizeSong = (
mbzRecordingId: null, mbzRecordingId: null,
mbzTrackId: item.ProviderIds?.MusicBrainzTrack || null, mbzTrackId: item.ProviderIds?.MusicBrainzTrack || null,
name: item.Name, name: item.Name,
participants: getPeople(item), participants,
path: replacePathPrefix(path || '', pathReplace, pathReplaceWith), path: replacePathPrefix(path || '', pathReplace, pathReplaceWith),
peak: null, peak: null,
playCount: (item.UserData && item.UserData.PlayCount) || 0, playCount: (item.UserData && item.UserData.PlayCount) || 0,
@@ -57,12 +57,13 @@ const getArtists = (
) => { ) => {
let albumArtists: RelatedArtist[] | undefined; let albumArtists: RelatedArtist[] | undefined;
let artists: RelatedArtist[] | undefined; let artists: RelatedArtist[] | undefined;
let remixers: RelatedArtist[] | undefined;
let participants: null | Record<string, RelatedArtist[]> = null; let participants: null | Record<string, RelatedArtist[]> = null;
if (item.participants) { if (item.participants) {
participants = {}; participants = {};
for (const [role, list] of Object.entries(item.participants)) { for (const [role, list] of Object.entries(item.participants)) {
if (role === 'albumartist' || role === 'artist') { if (role === 'albumartist' || role === 'artist' || role === 'remixer') {
const roleList = list.map((item) => ({ const roleList = list.map((item) => ({
id: item.id, id: item.id,
imageId: null, imageId: null,
@@ -74,6 +75,8 @@ const getArtists = (
if (role === 'albumartist') { if (role === 'albumartist') {
albumArtists = roleList; albumArtists = roleList;
} else if (role === 'remixer') {
remixers = roleList;
} else { } else {
artists = roleList; artists = roleList;
} }
@@ -121,7 +124,7 @@ const getArtists = (
]; ];
} }
if (artists === undefined) { if (artists === undefined && remixers === undefined) {
artists = [ artists = [
{ {
id: item.artistId, id: item.artistId,
@@ -134,7 +137,7 @@ const getArtists = (
]; ];
} }
return { albumArtists, artists, participants }; return { albumArtists, artists: [...(artists || []), ...(remixers || [])], participants };
}; };
const normalizeSong = ( const normalizeSong = (
+36 -21
View File
@@ -21,26 +21,39 @@ const getArtistList = (
artists?: typeof ssType._response.song._type.artists, artists?: typeof ssType._response.song._type.artists,
artistId?: number | string, artistId?: number | string,
artistName?: string, artistName?: string,
participants?: null | Record<string, RelatedArtist[]>,
) => { ) => {
return artists if (!artists && !participants) {
? artists.map((item) => ({ return [
id: item.id.toString(), {
imageId: null, id: artistId?.toString() || '',
imageUrl: null, imageId: null,
name: item.name, imageUrl: null,
userFavorite: false, name: artistName || '',
userRating: null, userFavorite: false,
})) userRating: null,
: [ },
{ ];
id: artistId?.toString() || '', }
imageId: null,
imageUrl: null, const result: RelatedArtist[] = [];
name: artistName || '',
userFavorite: false, artists?.forEach((item) => {
userRating: null, result.push({
}, id: item.id.toString(),
]; imageId: null,
imageUrl: null,
name: item.name,
userFavorite: false,
userRating: null,
});
});
if (participants?.['remixer']) {
result.push(...participants['remixer']);
}
return result;
}; };
const getParticipants = ( const getParticipants = (
@@ -121,6 +134,8 @@ const normalizeSong = (
pathReplace?: string, pathReplace?: string,
pathReplaceWith?: string, pathReplaceWith?: string,
): Song => { ): Song => {
const participants = getParticipants(item);
return { return {
_itemType: LibraryItem.SONG, _itemType: LibraryItem.SONG,
_serverId: server?.id || 'unknown', _serverId: server?.id || 'unknown',
@@ -130,7 +145,7 @@ const normalizeSong = (
albumArtists: getArtistList(item.albumArtists, item.artistId, item.artist), albumArtists: getArtistList(item.albumArtists, item.artistId, item.artist),
albumId: item.albumId?.toString() || '', albumId: item.albumId?.toString() || '',
artistName: item.artist || '', artistName: item.artist || '',
artists: getArtistList(item.artists, item.artistId, item.artist), artists: getArtistList(item.artists, item.artistId, item.artist, participants),
bitDepth: item.bitDepth || null, bitDepth: item.bitDepth || null,
bitRate: item.bitRate || 0, bitRate: item.bitRate || 0,
bpm: item.bpm || null, bpm: item.bpm || null,
@@ -164,7 +179,7 @@ const normalizeSong = (
mbzRecordingId: item.musicBrainzId || null, mbzRecordingId: item.musicBrainzId || null,
mbzTrackId: null, mbzTrackId: null,
name: item.title, name: item.title,
participants: getParticipants(item), participants,
path: replacePathPrefix(item.path || '', pathReplace, pathReplaceWith), path: replacePathPrefix(item.path || '', pathReplace, pathReplaceWith),
peak: peak:
item.replayGain && (item.replayGain.albumPeak || item.replayGain.trackPeak) item.replayGain && (item.replayGain.albumPeak || item.replayGain.trackPeak)