feat(discord): Implement retry for cover art api

This commit is contained in:
FoxxMD
2026-02-25 20:56:19 +00:00
parent 975d9540bc
commit d189084c15
+65 -17
View File
@@ -6,6 +6,8 @@ import { isSuperAgentResponseError } from "../../errors/ErrorUtils.js";
import { UpstreamError } from "../../errors/UpstreamError.js";
import { initMemoryCache } from "../../Cache.js";
import { joinedUrl } from "../../../utils/NetworkUtils.js";
import { hasNodeNetworkException } from "../../errors/NodeErrors.js";
import { sleep } from "../../../utils.js";
export type ThumbSize = 250 | 500 | 1200;
const THUMB_SIZES = [250, 500, 1200];
@@ -13,6 +15,7 @@ const THUMB_SIZES = [250, 500, 1200];
export interface ThumbOptions {
type?: 'front' | 'back'
size?: ThumbSize
retries?: number
}
export interface CoverArtReleaseImage {
@@ -72,30 +75,75 @@ export class CoverArtApiClient extends AbstractApiClient {
}
const thumbParams = `${type}${size !== undefined ? `-${size}` : ''}`;
const cacheKey = `albumart-${mbid}-${thumbParams}`;
const cachedArt = await this.cache.get<string>(cacheKey);
const cachedArt = await this.cache.get<string | false>(cacheKey);
if (cachedArt !== undefined) {
if(cachedArt === false) {
return undefined;
}
return cachedArt;
} else {
try {
// https://musicbrainz.org/doc/Cover_Art_Archive/API#/release/{mbid}/({id}|front|back)-(250|500|1200)
const resp = await request
.get(joinedUrl(this.baseUrl, `/release/${mbid}/${thumbParams}`))
// only follow first redirect so we get the url without actually downloading the image
.redirects(1);
} catch (e) {
if (isSuperAgentResponseError(e)) {
if (e.status === 302) {
await this.cache.set(cacheKey, e.response.header['location'], '1hr');
return e.response.header['location'];
} else if ([404].includes(e.status)) {
this.logger.debug(`No front album art found for release ${mbid}`);
let result = undefined,
retries = 0,
err: Error;
const url = joinedUrl(this.baseUrl, `/release/${mbid}/${thumbParams}`);
while(result === undefined && retries < 2) {
try {
const resp = await this.coverThumbRequest(url.toString());
if(resp === undefined) {
result = false;
} else {
this.logger.warn(new UpstreamError(`Unexpected response when trying to get album art`, { cause: e }));
result = resp;
}
err = undefined;
} catch (e) {
err = e;
if(hasNodeNetworkException(e)) {
this.logger.warn(`Request to ${url.toString()} failed but retries (${retries}) are not greater than max (1), retrying request after a short break... Error Message: ${e.message}`);
retries++;
await sleep(500);
continue;
} else {
break;
}
} else {
this.logger.warn(new Error(`Error occurred when trying to get album art`, { cause: e }));
}
}
if(result === false) {
this.logger.debug(`No front album art found for release ${mbid}`);
await this.cache.set(cacheKey, false, '1hr');
return undefined;
}
if(err !== undefined) {
this.logger.warn(err);
} else {
await this.cache.set(cacheKey, result, '1hr');
}
return result;
}
}
protected coverThumbRequest = async (url: string): Promise<string | undefined> => {
try {
// https://musicbrainz.org/doc/Cover_Art_Archive/API#/release/{mbid}/({id}|front|back)-(250|500|1200)
const resp = await request
.get(url)
// only follow first redirect so we get the url without actually downloading the image
.redirects(1);
throw new Error('Should not be getting this far');
} catch (e) {
if (isSuperAgentResponseError(e)) {
if (e.status === 302) {
return e.response.header['location'];
} else if ([404].includes(e.status)) {
return undefined;
} else {
throw new UpstreamError(`Unexpected response when trying to get album art`, { cause: e });
}
} else {
throw new Error(`Error occurred when trying to get album art`, { cause: e });
}
}
}