Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add retry method for iTunes API requests #102

Closed
wants to merge 13 commits into from
96 changes: 58 additions & 38 deletions music-rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,9 @@ async function getTrackExtras(props: iTunesProps): Promise<TrackExtras> {
async function _getTrackExtras(
song: string,
artist: string,
album: string
): Promise<TrackExtras> {
album: string,
retryCount: number = 3
): Promise<TrackExtras | undefined> {
// Asterisks tend to result in no songs found, and songs are usually able to be found without it
const query = `${song} ${artist} ${album}`.replace("*", "");
const params = new URLSearchParams({
Expand All @@ -109,47 +110,66 @@ async function _getTrackExtras(
term: query,
});
const url = `https://itunes.apple.com/search?${params}`;
const resp = await fetch(url);

if (!resp.ok) {
console.error("iTunes API error:", resp.statusText, url);
let attempts = 0;

return {
artworkUrl: (await _getMBArtwork(artist, song, album)) ?? null,
iTunesUrl: null,
};
}

const json: iTunesSearchResponse = await resp.json();

let result: iTunesSearchResult | undefined;
if (json.resultCount === 1) {
result = json.results[0];
} else if (json.resultCount > 1) {
// If there are multiple results, find the right album
// Use includes as imported songs may format it differently
// Also put them all to lowercase in case of differing capitalisation
result = json.results.find(
(r) =>
r.collectionName.toLowerCase().includes(album.toLowerCase()) &&
r.trackName.toLowerCase().includes(song.toLowerCase())
);
} else if (album.match(/\(.*\)$/)) {
// If there are no results, try to remove the part
// of the album name in parentheses (e.g. "Album (Deluxe Edition)")
return await _getTrackExtras(
song,
artist,
album.replace(/\(.*\)$/, "").trim()
);
}
while (attempts < retryCount) {
try {
const resp = await fetch(url);

const artworkUrl =
result?.artworkUrl100 ?? (await _getMBArtwork(artist, song, album)) ?? null;
if (!resp.ok) {
console.error(
`Failed to fetch from iTunes API: ${resp.statusText}`,
url,
`Attempt ${attempts + 1}/${retryCount}`
);
}

const iTunesUrl = result?.trackViewUrl ?? null;
const json: iTunesSearchResponse = await resp.json();

let result: iTunesSearchResult | undefined;
if (json.resultCount === 1) {
result = json.results[0];
} else if (json.resultCount > 1) {
// If there are multiple results, find the right album
// Use includes as imported songs may format it differently
// Also put them all to lowercase in case of differing capitalization
result = json.results.find(
(r) =>
r.collectionName.toLowerCase().includes(album.toLowerCase()) &&
r.trackName.toLowerCase().includes(song.toLowerCase())
);
} else if (album.match(/\(.*\)$/)) {
// If there are no results, try to remove the part
// of the album name in parentheses (e.g. "Album (Deluxe Edition)")
return await _getTrackExtras(
song,
artist,
album.replace(/\(.*\)$/, "").trim(),
retryCount
);
}

return { artworkUrl, iTunesUrl };
const artworkUrl =
result?.artworkUrl100 ??
(await _getMBArtwork(artist, song, album)) ??
null;

const iTunesUrl = result?.trackViewUrl ?? null;

return { artworkUrl, iTunesUrl };
} catch (error) {
console.error(error);
attempts += 1;
if (attempts >= retryCount) {
// Fall back after exhausting retries
return {
artworkUrl: (await _getMBArtwork(artist, song, album)) ?? null,
iTunesUrl: null,
};
}
}
}
}
//#endregion

Expand Down
Loading