feat(album): plumb featured artists and parental warning
Add Album.parental_warning and Album.artists (with the new AlbumArtist struct) to qbz-models so the /album/get response surfaces both fields. Mirror them in the QobuzAlbum / AlbumDetail TypeScript types and populate featuredArtists (filtered to non-main contributors) and parentalWarning in convertQobuzAlbum. Wire onFeaturedArtistClick from the route so featured artist names route to their discography. cc
This commit is contained in:
4 files changed
+34
No files matched your search
@@ -273,6 +273,23 @@ pub struct Album {
|
|||||||
/// Editorial awards (Qobuzissime, Album of the Week, press accolades).
|
/// Editorial awards (Qobuzissime, Album of the Week, press accolades).
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub awards: Option<Vec<AlbumAward>>,
|
pub awards: Option<Vec<AlbumAward>>,
|
||||||
|
/// Parental advisory / explicit content marker.
|
||||||
|
#[serde(default)]
|
||||||
|
pub parental_warning: Option<bool>,
|
||||||
|
/// Full artist contributor list including roles. The primary artist is
|
||||||
|
/// duplicated here as `roles: ["main-artist"]`; non-main entries are
|
||||||
|
/// the album's featured artists.
|
||||||
|
#[serde(default)]
|
||||||
|
pub artists: Option<Vec<AlbumArtist>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Album artist contributor entry (main artist + featured artists).
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct AlbumArtist {
|
||||||
|
pub id: u64,
|
||||||
|
pub name: String,
|
||||||
|
#[serde(default)]
|
||||||
|
pub roles: Option<Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A downloadable extra bundled with an album (e.g. PDF booklet)
|
/// A downloadable extra bundled with an album (e.g. PDF booklet)
|
||||||
|
|||||||
@@ -358,12 +358,23 @@ export function convertQobuzAlbum(album: QobuzAlbum): AlbumDetail {
|
|||||||
album.maximum_sampling_rate
|
album.maximum_sampling_rate
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const mainArtistId = album.artist?.id;
|
||||||
|
const featuredArtists = (album.artists ?? [])
|
||||||
|
.filter((entry) => {
|
||||||
|
const isMain = entry.roles?.some((role) => role === 'main-artist');
|
||||||
|
const isMainById = mainArtistId !== undefined && entry.id === mainArtistId;
|
||||||
|
return !isMain && !isMainById;
|
||||||
|
})
|
||||||
|
.map((entry) => ({ id: entry.id, name: entry.name }));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: album.id,
|
id: album.id,
|
||||||
artwork,
|
artwork,
|
||||||
title: album.title,
|
title: album.title,
|
||||||
artist: album.artist?.name || 'Unknown Artist',
|
artist: album.artist?.name || 'Unknown Artist',
|
||||||
artistId: album.artist?.id,
|
artistId: album.artist?.id,
|
||||||
|
featuredArtists: featuredArtists.length > 0 ? featuredArtists : undefined,
|
||||||
|
parentalWarning: album.parental_warning ?? false,
|
||||||
year: album.release_date_original?.split('-')[0] || '',
|
year: album.release_date_original?.split('-')[0] || '',
|
||||||
releaseDate: album.release_date_original,
|
releaseDate: album.release_date_original,
|
||||||
label: album.label?.name || '',
|
label: album.label?.name || '',
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ export interface QobuzAlbum {
|
|||||||
title: string;
|
title: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
artist: { id?: number; name: string };
|
artist: { id?: number; name: string };
|
||||||
|
artists?: { id: number; name: string; roles?: string[] }[];
|
||||||
image: QobuzImage;
|
image: QobuzImage;
|
||||||
release_date_original?: string;
|
release_date_original?: string;
|
||||||
hires_streamable?: boolean;
|
hires_streamable?: boolean;
|
||||||
@@ -202,6 +203,10 @@ export interface AlbumDetail {
|
|||||||
title: string;
|
title: string;
|
||||||
artist: string;
|
artist: string;
|
||||||
artistId?: number;
|
artistId?: number;
|
||||||
|
/** Featured artists (excluding the main artist), in API order. */
|
||||||
|
featuredArtists?: { id: number; name: string }[];
|
||||||
|
/** Parental advisory marker — show explicit badge next to artist line. */
|
||||||
|
parentalWarning?: boolean;
|
||||||
year: string;
|
year: string;
|
||||||
releaseDate?: string; // Full date in YYYY-MM-DD format
|
releaseDate?: string; // Full date in YYYY-MM-DD format
|
||||||
label: string;
|
label: string;
|
||||||
|
|||||||
@@ -5922,6 +5922,7 @@
|
|||||||
isPlaybackActive={isPlaying}
|
isPlaybackActive={isPlaying}
|
||||||
onBack={navGoBack}
|
onBack={navGoBack}
|
||||||
onArtistClick={() => selectedAlbum?.artistId && handleArtistClick(selectedAlbum.artistId)}
|
onArtistClick={() => selectedAlbum?.artistId && handleArtistClick(selectedAlbum.artistId)}
|
||||||
|
onFeaturedArtistClick={(artistId) => handleArtistClick(artistId)}
|
||||||
onLabelClick={handleLabelClick}
|
onLabelClick={handleLabelClick}
|
||||||
onAwardClick={handleAwardClick}
|
onAwardClick={handleAwardClick}
|
||||||
onTrackPlay={handleAlbumTrackPlay}
|
onTrackPlay={handleAlbumTrackPlay}
|
||||||
|
|||||||
Reference in new issue
Block a user