handle favorite/update in similarArtists

This commit is contained in:
jeffvli
2025-12-28 03:43:59 -08:00
parent 66699b9572
commit 1a930021b6
9 changed files with 124 additions and 15 deletions
@@ -279,11 +279,11 @@ export const SubsonicController: InternalControllerEndpoint = {
} }
return { return {
...ssNormalize.albumArtist(artist, apiClientProps.server, 300), ...ssNormalize.albumArtist(artist, apiClientProps.server),
albums: artist.album?.map((album) => ssNormalize.album(album, apiClientProps.server)), albums: artist.album?.map((album) => ssNormalize.album(album, apiClientProps.server)),
similarArtists: similarArtists:
artistInfo?.similarArtist?.map((artist) => artistInfo?.similarArtist?.map((artist) =>
ssNormalize.albumArtist(artist, apiClientProps.server, 300), ssNormalize.albumArtist(artist, apiClientProps.server),
) || null, ) || null,
}; };
}, },
@@ -303,7 +303,7 @@ export const SubsonicController: InternalControllerEndpoint = {
const artists = (res.body.artists?.index || []).flatMap((index) => index.artist); const artists = (res.body.artists?.index || []).flatMap((index) => index.artist);
let results = artists.map((artist) => let results = artists.map((artist) =>
ssNormalize.albumArtist(artist, apiClientProps.server, 300), ssNormalize.albumArtist(artist, apiClientProps.server),
); );
if (query.searchTerm) { if (query.searchTerm) {
@@ -488,7 +488,7 @@ export const SubsonicController: InternalControllerEndpoint = {
return { return {
items: items:
res.body.albumList2.album?.map((album) => res.body.albumList2.album?.map((album) =>
ssNormalize.album(album, apiClientProps.server, 300), ssNormalize.album(album, apiClientProps.server),
) || [], ) || [],
startIndex: query.startIndex, startIndex: query.startIndex,
totalRecordCount: null, totalRecordCount: null,
@@ -658,7 +658,7 @@ export const SubsonicController: InternalControllerEndpoint = {
} }
let results = artists.map((artist) => let results = artists.map((artist) =>
ssNormalize.albumArtist(artist, apiClientProps.server, 300), ssNormalize.albumArtist(artist, apiClientProps.server),
); );
if (query.searchTerm) { if (query.searchTerm) {
@@ -506,8 +506,8 @@ const AlbumArtistMetadataSimilarArtists = ({
playCount: null, playCount: null,
similarArtists: null, similarArtists: null,
songCount: null, songCount: null,
userFavorite: false, userFavorite: relatedArtist.userFavorite,
userRating: null, userRating: relatedArtist.userRating,
}), }),
); );
}, [detailQuery.data?.similarArtists, server?.type, serverId]); }, [detailQuery.data?.similarArtists, server?.type, serverId]);
@@ -215,13 +215,36 @@ export const applyFavoriteOptimisticUpdates = (
queryClient.setQueryData( queryClient.setQueryData(
queryKey, queryKey,
(prev: AlbumArtistDetailResponse | undefined) => { (prev: AlbumArtistDetailResponse | undefined) => {
if (prev && itemIdSet.has(prev.id)) { if (!prev) {
return prev;
}
// Update the main artist if it matches
if (itemIdSet.has(prev.id)) {
return { return {
...prev, ...prev,
userFavorite: isFavorite, userFavorite: isFavorite,
}; };
} }
// Update similar artists if any match
if (prev.similarArtists && prev.similarArtists.length > 0) {
const hasMatchingSimilarArtist = prev.similarArtists.some(
(artist) => itemIdSet.has(artist.id),
);
if (hasMatchingSimilarArtist) {
return {
...prev,
similarArtists: prev.similarArtists.map((artist) =>
itemIdSet.has(artist.id)
? { ...artist, userFavorite: isFavorite }
: artist,
),
};
}
}
return prev; return prev;
}, },
); );
@@ -184,9 +184,33 @@ export const applyRatingOptimisticUpdates = (
queryClient.setQueryData( queryClient.setQueryData(
queryKey, queryKey,
(prev: AlbumArtistDetailResponse | undefined) => { (prev: AlbumArtistDetailResponse | undefined) => {
if (prev && itemIdSet.has(prev.id)) { if (!prev) {
return prev;
}
// Update the main artist if it matches
if (itemIdSet.has(prev.id)) {
return { ...prev, userRating: rating }; return { ...prev, userRating: rating };
} }
// Update similar artists if any match
if (prev.similarArtists && prev.similarArtists.length > 0) {
const hasMatchingSimilarArtist = prev.similarArtists.some(
(artist) => itemIdSet.has(artist.id),
);
if (hasMatchingSimilarArtist) {
return {
...prev,
similarArtists: prev.similarArtists.map((artist) =>
itemIdSet.has(artist.id)
? { ...artist, userRating: rating }
: artist,
),
};
}
}
return prev; return prev;
}, },
); );
@@ -37,6 +37,8 @@ const getPeople = (item: AlbumOrSong): null | Record<string, RelatedArtist[]> =>
imageId: null, imageId: null,
imageUrl: null, imageUrl: null,
name: person.Name, name: person.Name,
userFavorite: false,
userRating: null,
}; };
if (key in participants) { if (key in participants) {
@@ -148,6 +150,8 @@ const normalizeSong = (
imageId: entry.Id, imageId: entry.Id,
imageUrl: null, imageUrl: null,
name: entry.Name, name: entry.Name,
userFavorite: false,
userRating: null,
})), })),
albumId: item.AlbumId || `dummy/${item.Id}`, albumId: item.AlbumId || `dummy/${item.Id}`,
artistName: item?.ArtistItems?.[0]?.Name || item?.AlbumArtists?.[0]?.Name, artistName: item?.ArtistItems?.[0]?.Name || item?.AlbumArtists?.[0]?.Name,
@@ -157,6 +161,8 @@ const normalizeSong = (
imageId: null, imageId: null,
imageUrl: null, imageUrl: null,
name: entry.Name, name: entry.Name,
userFavorite: false,
userRating: null,
}), }),
), ),
bitDepth: null, bitDepth: null,
@@ -232,6 +238,8 @@ const normalizeAlbum = (
imageId: entry.Id, imageId: entry.Id,
imageUrl: null, imageUrl: null,
name: entry.Name, name: entry.Name,
userFavorite: false,
userRating: null,
})) || [], })) || [],
artists: (item.ArtistItems?.length ? item.ArtistItems : item.AlbumArtists)?.map( artists: (item.ArtistItems?.length ? item.ArtistItems : item.AlbumArtists)?.map(
(entry) => ({ (entry) => ({
@@ -239,6 +247,8 @@ const normalizeAlbum = (
imageId: entry.Id, imageId: entry.Id,
imageUrl: null, imageUrl: null,
name: entry.Name, name: entry.Name,
userFavorite: false,
userRating: null,
}), }),
), ),
comment: null, comment: null,
@@ -295,6 +305,8 @@ const normalizeAlbumArtist = (
imageId: getAlbumArtistImageId(entry), imageId: getAlbumArtistImageId(entry),
imageUrl: null, imageUrl: null,
name: entry.Name, name: entry.Name,
userFavorite: entry.UserData?.IsFavorite || false,
userRating: null,
}), }),
) || []; ) || [];
@@ -51,6 +51,8 @@ const getArtists = (
imageId: null, imageId: null,
imageUrl: null, imageUrl: null,
name: item.name, name: item.name,
userFavorite: false,
userRating: null,
})); }));
if (role === 'albumartist') { if (role === 'albumartist') {
@@ -67,6 +69,8 @@ const getArtists = (
imageId: null, imageId: null,
imageUrl: null, imageUrl: null,
name: artist.name, name: artist.name,
userFavorite: false,
userRating: null,
}; };
if (subRoles.has(artist.subRole)) { if (subRoles.has(artist.subRole)) {
@@ -89,12 +93,28 @@ const getArtists = (
if (albumArtists === undefined) { if (albumArtists === undefined) {
albumArtists = [ albumArtists = [
{ id: item.albumArtistId, imageId: null, imageUrl: null, name: item.albumArtist }, {
id: item.albumArtistId,
imageId: null,
imageUrl: null,
name: item.albumArtist,
userFavorite: false,
userRating: null,
},
]; ];
} }
if (artists === undefined) { if (artists === undefined) {
artists = [{ id: item.artistId, imageId: null, imageUrl: null, name: item.artist }]; artists = [
{
id: item.artistId,
imageId: null,
imageUrl: null,
name: item.artist,
userFavorite: false,
userRating: null,
},
];
} }
return { albumArtists, artists, participants }; return { albumArtists, artists, participants };
@@ -304,6 +324,8 @@ const normalizeAlbumArtist = (
songCount = item.songCount; songCount = item.songCount;
} }
console.log('similarArtists', item.similarArtists);
return { return {
_itemType: LibraryItem.ALBUM_ARTIST, _itemType: LibraryItem.ALBUM_ARTIST,
_serverId: server?.id || 'unknown', _serverId: server?.id || 'unknown',
@@ -335,7 +357,9 @@ const normalizeAlbumArtist = (
imageId: null, imageId: null,
imageUrl: artist?.artistImageUrl?.replace(/\?size=\d+/, '') || null, imageUrl: artist?.artistImageUrl?.replace(/\?size=\d+/, '') || null,
name: artist.name, name: artist.name,
})) || null, userFavorite: Boolean(artist.starred) || false,
userRating: artist.userRating || null,
})) || [],
songCount, songCount,
userFavorite: item.starred || false, userFavorite: item.starred || false,
userRating: item.rating || null, userRating: item.rating || null,
+25 -3
View File
@@ -27,6 +27,8 @@ const getArtistList = (
imageId: null, imageId: null,
imageUrl: null, imageUrl: null,
name: item.name, name: item.name,
userFavorite: false,
userRating: null,
})) }))
: [ : [
{ {
@@ -34,6 +36,8 @@ const getArtistList = (
imageId: null, imageId: null,
imageUrl: null, imageUrl: null,
name: artistName || '', name: artistName || '',
userFavorite: false,
userRating: null,
}, },
]; ];
}; };
@@ -55,6 +59,8 @@ const getParticipants = (
imageId: null, imageId: null,
imageUrl: null, imageUrl: null,
name: contributor.artist.name || '', name: contributor.artist.name || '',
userFavorite: false,
userRating: null,
}; };
const role = contributor.subRole const role = contributor.subRole
@@ -178,8 +184,16 @@ const normalizeSong = (
const normalizeAlbumArtist = ( const normalizeAlbumArtist = (
item: item:
| z.infer<typeof ssType._response.albumArtist> | (z.infer<typeof ssType._response.albumArtist> & {
| z.infer<typeof ssType._response.artistListEntry>, similarArtists?: z.infer<
typeof ssType._response.artistInfo
>['artistInfo']['similarArtist'];
})
| (z.infer<typeof ssType._response.artistListEntry> & {
similarArtists?: z.infer<
typeof ssType._response.artistInfo
>['artistInfo']['similarArtist'];
}),
server?: null | ServerListItemWithCredential, server?: null | ServerListItemWithCredential,
): AlbumArtist => { ): AlbumArtist => {
return { return {
@@ -197,7 +211,15 @@ const normalizeAlbumArtist = (
mbz: null, mbz: null,
name: item.name, name: item.name,
playCount: null, playCount: null,
similarArtists: [], similarArtists:
item.similarArtists?.map((artist) => ({
id: artist.id,
imageId: null,
imageUrl: null,
name: artist.name,
userFavorite: Boolean(artist.starred) || false,
userRating: artist.userRating || null,
})) || [],
songCount: null, songCount: null,
userFavorite: Boolean(item.starred) || false, userFavorite: Boolean(item.starred) || false,
userRating: null, userRating: null,
@@ -236,6 +236,8 @@ const artistInfo = z.object({
coverArt: z.string().optional(), coverArt: z.string().optional(),
id: z.string(), id: z.string(),
name: z.string(), name: z.string(),
starred: z.string().optional(),
userRating: z.number().optional(),
}), }),
), ),
smallImageUrl: z.string().optional(), smallImageUrl: z.string().optional(),
+2
View File
@@ -356,6 +356,8 @@ export type RelatedArtist = {
imageId: null | string; imageId: null | string;
imageUrl: null | string; imageUrl: null | string;
name: string; name: string;
userFavorite: boolean;
userRating: null | number;
}; };
export type Song = { export type Song = {