fix(hifi): use Tidal v2 API for artist biography

The v1 endpoint (api.tidal.com/v1/artists/{id}/bio) returns 404.
Switch getArtistBiography to the v2 OpenAPI endpoint with
include=biography, extracting the biography from the included
resources in the JSON:API response.

Also restore text and source on JsonApiIncludeAttributes, which
were dropped when the v2 artist fix was reverted in b528720.
This commit is contained in:
p1nkhamster 2026-04-24 11:51:27 +02:00
parent 2515242fd7
commit 977c7d0483

View file

@ -1026,6 +1026,8 @@ interface JsonApiIncludeAttributes {
albumType?: string; albumType?: string;
createdAt?: string; createdAt?: string;
type?: string; type?: string;
text?: string;
source?: string;
} }
/** An included resource node from a TIDAL OpenAPI JSON:API response. */ /** An included resource node from a TIDAL OpenAPI JSON:API response. */
@ -1933,14 +1935,34 @@ class HiFiClient {
return HiFiClient.#jsonResponse({ version: HiFiClient.API_VERSION, albums: page_data, tracks }); return HiFiClient.#jsonResponse({ version: HiFiClient.API_VERSION, albums: page_data, tracks });
} }
async getArtistBiography(artistId: number, signal?: AbortSignal): Promise<TidalResponse<ArtistBioResponse>> { async getArtistBiography(artistId: number, signal?: AbortSignal): Promise<TidalResponse<ArtistBioResponse>> {
const url = `https://api.tidal.com/v1/artists/${artistId}/bio`; const url = `https://openapi.tidal.com/v2/artists/${artistId}`;
const params = { const payload = await this.#fetchJson<{ data?: JsonApiInclude; included?: JsonApiInclude[] }>(
locale: this.#locale, url,
countryCode: this.#countryCode, { countryCode: this.#countryCode, include: 'biography' },
}; signal
const data = await this.#fetchJson<ArtistBiography>(url, params, signal); );
return HiFiClient.#jsonResponse({ version: HiFiClient.API_VERSION, data: data }); const includedMap = new Map<string, JsonApiInclude>();
for (const item of payload?.included ?? []) {
includedMap.set(`${item.type}:${item.id}`, item);
}
const bioRelData = payload?.data?.relationships?.biography?.data;
const bioRef = (Array.isArray(bioRelData) ? bioRelData[0] : bioRelData) as JsonApiRef | undefined;
const bioItem = bioRef
? (includedMap.get(`${bioRef.type}:${bioRef.id}`) ??
includedMap.get(`biographies:${bioRef.id}`) ??
includedMap.get(`biography:${bioRef.id}`))
: undefined;
const data: ArtistBiography = {
text: bioItem?.attributes?.text ?? '',
source: bioItem?.attributes?.source ?? 'Tidal',
lastUpdated: '',
summary: '',
};
return HiFiClient.#jsonResponse({ version: HiFiClient.API_VERSION, data });
} }
#buildCoverEntry(cover_slug: string, name?: string | null, track_id?: number | null): CoverEntry { #buildCoverEntry(cover_slug: string, name?: string | null, track_id?: number | null): CoverEntry {