87 lines
2.4 KiB
TypeScript
87 lines
2.4 KiB
TypeScript
import { SpotifyTrack } from "../types/spotify.ts";
|
|
import { getSpotifyAccessToken } from "../spotify-api.ts";
|
|
import { assert } from "jsr:@std/assert/assert";
|
|
|
|
// Simple in-memory cache for track objects by ID
|
|
const trackCache = new Map<string, SpotifyTrack>();
|
|
|
|
/**
|
|
* Inner function that performs the actual API call without retries.
|
|
*/
|
|
async function fetchSpotifyTrackById(trackId: string): Promise<SpotifyTrack> {
|
|
const accessToken = await getSpotifyAccessToken();
|
|
const url = `https://api.spotify.com/v1/tracks/${trackId}?market=US`;
|
|
|
|
const response = await fetch(url, {
|
|
headers: {
|
|
"Authorization": `Bearer ${accessToken}`,
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(
|
|
`Failed to fetch track: ${response.status} ${await response.text()}`,
|
|
);
|
|
}
|
|
|
|
const track: SpotifyTrack = await response.json();
|
|
|
|
// Cache the result
|
|
trackCache.set(trackId, track);
|
|
|
|
return track;
|
|
}
|
|
|
|
/**
|
|
* Fetches a Spotify track by its ID, with caching.
|
|
* Returns the full SpotifyTrack object.
|
|
*/
|
|
export async function getSpotifyTrackById(
|
|
trackId: string,
|
|
): Promise<SpotifyTrack> {
|
|
// Check cache first
|
|
if (trackCache.has(trackId)) {
|
|
return trackCache.get(trackId)!;
|
|
}
|
|
|
|
const maxRetries = 10;
|
|
let lastError: Error;
|
|
|
|
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
try {
|
|
return await fetchSpotifyTrackById(trackId);
|
|
} catch (error) {
|
|
lastError = error as Error;
|
|
if (attempt === maxRetries) {
|
|
throw Error(`Attempt ${attempt}: ${lastError}`);
|
|
}
|
|
// Optional: add delay between retries
|
|
await new Promise((resolve) => setTimeout(resolve, 1000 * attempt));
|
|
}
|
|
}
|
|
|
|
throw lastError!;
|
|
}
|
|
|
|
Deno.test("getSpotifyTrackById basic", async () => {
|
|
// Example: Blinding Lights by The Weeknd
|
|
const trackId = "2EqlS6tkEnglzr7tkKAAYD";
|
|
|
|
// First call (should fetch from API)
|
|
const track1 = await getSpotifyTrackById(trackId);
|
|
assert(track1.id === trackId);
|
|
assert(typeof track1.name === "string");
|
|
assert(Array.isArray(track1.artists));
|
|
|
|
// Second call (should hit cache)
|
|
const start = performance.now();
|
|
const track2 = await getSpotifyTrackById(trackId);
|
|
const elapsed = performance.now() - start;
|
|
|
|
console.log(track2);
|
|
console.log("Second call elapsed:", elapsed, "ms");
|
|
assert(track2.id === trackId);
|
|
assert(typeof track2.name === "string");
|
|
assert(Array.isArray(track2.artists));
|
|
assert(elapsed < 10, `Second call took too long: ${elapsed}ms`);
|
|
});
|