From a282b37d883d973992b9c467d67b72188d58dab1 Mon Sep 17 00:00:00 2001 From: Daniel <790119+DanTheMan827@users.noreply.github.com> Date: Fri, 27 Mar 2026 10:15:47 -0500 Subject: [PATCH] refactor(hifi): add getArtistBiography --- js/HiFi.ts | 43 +++++++++++++++++++++++++++++++++++++------ js/api.js | 9 ++------- js/global.d.ts | 4 ++++ 3 files changed, 43 insertions(+), 13 deletions(-) diff --git a/js/HiFi.ts b/js/HiFi.ts index 1bddd11..e903a58 100644 --- a/js/HiFi.ts +++ b/js/HiFi.ts @@ -57,6 +57,7 @@ class HiFiClient { readonly #albumTracksMax = 20; readonly #albumTracksQueue: Array<() => void> = []; readonly #countryCode: string; + readonly #locale: string; readonly #clientId: string; readonly #clientSecret: string; readonly #emitter = new EventEmitter(); @@ -216,16 +217,27 @@ class HiFiClient { } static #getOptions({ + locale = 'en_US', countryCode = 'US', baseUrl = null, clientId = HiFiClient.BROWSER_CLIENT_ID, clientSecret = HiFiClient.BROWSER_CLIENT_SECRET, token, tokenExpiry, - refreshToken: tokenRefresh, + refreshToken, storage = [], - }: HiFiClient.ConstructorOptions = {}) { - return { countryCode, baseUrl, clientId, clientSecret, token, tokenExpiry, tokenRefresh, storage }; + }: HiFiClient.ConstructorOptions = {}): WithRequiredKeys { + return { + locale, + countryCode, + baseUrl, + clientId, + clientSecret, + token, + tokenExpiry, + refreshToken, + storage, + }; } async fetchToken(force: boolean = false, signal: AbortSignal | undefined = undefined) { @@ -289,15 +301,16 @@ class HiFiClient { } constructor(options: HiFiClient.ConstructorOptions = {}) { - const { countryCode, baseUrl, clientId, clientSecret, token, tokenExpiry, tokenRefresh, storage } = + const { locale, countryCode, baseUrl, clientId, clientSecret, token, tokenExpiry, refreshToken, storage } = HiFiClient.#getOptions(options); + this.#locale = locale; this.#countryCode = countryCode; this.#baseUrl = baseUrl; this.#clientId = clientId; this.#clientSecret = clientSecret; this.token = token; this.appTokenExpiry = tokenExpiry; - this.refreshToken = tokenRefresh; + this.refreshToken = refreshToken; for (const store of !Array.isArray(storage) ? [storage] : storage) { this.#useStorage(store); @@ -633,6 +646,17 @@ class HiFiClient { return HiFiClient.#jsonResponse({ version: HiFiClient.API_VERSION, albums: page_data, tracks }); } + async getArtistBiography(artistId: number, signal?: AbortSignal) { + const url = `https://api.tidal.com/v1/artists/${artistId}/bio`; + const params = { + locale: this.#locale, + countryCode: this.#countryCode, + }; + const data = await this.#fetchJson(url, params, signal); + + return HiFiClient.#jsonResponse({ version: API_VERSION, data: data }); + } + #buildCoverEntry(cover_slug: string, name?: string | null, track_id?: number | null) { const slug = cover_slug.replace(/-/g, '/'); return { @@ -922,6 +946,8 @@ class HiFiClient { return new TidalResponse( await this.getSimilarAlbums(Number(qp.id), qp.cursor ?? undefined, signal) ); + case '/artist/bio': + return new TidalResponse(await this.getArtistBiography(Number(qp.id), signal)); case '/artist': return new TidalResponse( await this.getArtist( @@ -1027,8 +1053,13 @@ namespace HiFiClient { clientSecret?: string; } - export interface ConstructorOptions extends ClientOptions, TokenOptions, RefreshTokenOptions { + export interface LocaleOptions { + locale?: string; countryCode?: string; + } + + export interface ConstructorOptions + extends LocaleOptions, RefreshTokenOptions, ClientOptions, TokenOptions, RefreshTokenOptions { baseUrl?: string; storage?: Pick[] | Pick; } diff --git a/js/api.js b/js/api.js index eafcb65..c8ed8a3 100644 --- a/js/api.js +++ b/js/api.js @@ -1240,15 +1240,10 @@ export class LosslessAPI { if (cached) return cached; try { - const url = `https://api.tidal.com/v1/artists/${artistId}/bio?locale=en_US&countryCode=GB`; - const response = await fetch(url, { - headers: { - 'X-Tidal-Token': TIDAL_V2_TOKEN, - }, - }); + const response = await HiFiClient.instance.query(`/artist/bio/?id=${artistId}`); if (response.ok) { - const data = await response.json(); + const { data } = await response.json(); if (data && data.text) { const bio = { text: data.text, diff --git a/js/global.d.ts b/js/global.d.ts index c8dbc54..838a09d 100644 --- a/js/global.d.ts +++ b/js/global.d.ts @@ -27,3 +27,7 @@ declare module 'https://cdn.jsdelivr.net/npm/client-zip@2.4.5/+esm' { /** Creates a ZIP stream from an async iterable of file entries. */ export function downloadZip(files: AsyncIterable): Response; } + +type WithRequiredKeys = { + [K in keyof T]-?: T[K] | undefined; +};