refactor(hifi): add getArtistBiography

This commit is contained in:
Daniel 2026-03-27 10:15:47 -05:00 committed by edideaur
parent e154215fc5
commit a282b37d88
3 changed files with 43 additions and 13 deletions

View file

@ -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<HiFiClient.ConstructorOptions> {
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<Storage, 'setItem' | 'removeItem'>[] | Pick<Storage, 'setItem' | 'removeItem'>;
}

View file

@ -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,

4
js/global.d.ts vendored
View file

@ -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<object>): Response;
}
type WithRequiredKeys<T> = {
[K in keyof T]-?: T[K] | undefined;
};