feat: remove MusicBrainz integration and exclusively use iTunes for song release years
This commit is contained in:
@@ -1,121 +0,0 @@
|
||||
/**
|
||||
* MusicBrainz API integration for fetching release years
|
||||
* API Documentation: https://musicbrainz.org/doc/MusicBrainz_API
|
||||
* Rate Limiting: 50 requests per second for meaningful User-Agent strings
|
||||
*/
|
||||
|
||||
const MUSICBRAINZ_API_BASE = 'https://musicbrainz.org/ws/2';
|
||||
const USER_AGENT = 'hoerdle/0.1.0 ( elpatron@mailbox.org )';
|
||||
const RATE_LIMIT_DELAY = 25; // 25ms between requests = ~40 req/s (safe margin)
|
||||
|
||||
/**
|
||||
* Sleep utility for rate limiting
|
||||
*/
|
||||
function sleep(ms: number): Promise<void> {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch with retry logic for HTTP 503 (rate limit exceeded)
|
||||
*/
|
||||
async function fetchWithRetry(url: string, maxRetries = 5): Promise<Response> {
|
||||
let lastError: Error | null = null;
|
||||
|
||||
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
headers: {
|
||||
'User-Agent': USER_AGENT,
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
// If rate limited (503), wait with exponential backoff
|
||||
if (response.status === 503) {
|
||||
const waitTime = Math.pow(2, attempt) * 1000; // 1s, 2s, 4s, 8s, 16s
|
||||
console.log(`Rate limited (503), waiting ${waitTime}ms before retry ${attempt + 1}/${maxRetries}...`);
|
||||
await sleep(waitTime);
|
||||
continue;
|
||||
}
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
lastError = error as Error;
|
||||
if (attempt < maxRetries - 1) {
|
||||
const waitTime = Math.pow(2, attempt) * 1000;
|
||||
console.log(`Network error, waiting ${waitTime}ms before retry ${attempt + 1}/${maxRetries}...`);
|
||||
await sleep(waitTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw lastError || new Error('Max retries exceeded');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the earliest release year for a song from MusicBrainz
|
||||
* @param artist Artist name
|
||||
* @param title Song title
|
||||
* @returns Release year or null if not found
|
||||
*/
|
||||
export async function getReleaseYear(artist: string, title: string): Promise<number | null> {
|
||||
try {
|
||||
// Build search query using Lucene syntax
|
||||
const query = `artist:"${artist}" AND recording:"${title}"`;
|
||||
const url = `${MUSICBRAINZ_API_BASE}/recording?query=${encodeURIComponent(query)}&fmt=json&limit=10`;
|
||||
|
||||
// Add rate limiting delay
|
||||
await sleep(RATE_LIMIT_DELAY);
|
||||
|
||||
const response = await fetchWithRetry(url);
|
||||
|
||||
if (!response.ok) {
|
||||
console.error(`MusicBrainz API error: ${response.status} ${response.statusText}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!data.recordings || data.recordings.length === 0) {
|
||||
console.log(`No recordings found for "${title}" by "${artist}"`);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Find the earliest release year from all recordings
|
||||
let earliestYear: number | null = null;
|
||||
|
||||
for (const recording of data.recordings) {
|
||||
// Check if recording has releases
|
||||
if (recording.releases && recording.releases.length > 0) {
|
||||
for (const release of recording.releases) {
|
||||
if (release.date) {
|
||||
// Extract year from date (format: YYYY-MM-DD or YYYY)
|
||||
const year = parseInt(release.date.split('-')[0]);
|
||||
if (!isNaN(year) && (earliestYear === null || year < earliestYear)) {
|
||||
earliestYear = year;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Also check first-release-date on the recording itself
|
||||
if (recording['first-release-date']) {
|
||||
const year = parseInt(recording['first-release-date'].split('-')[0]);
|
||||
if (!isNaN(year) && (earliestYear === null || year < earliestYear)) {
|
||||
earliestYear = year;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (earliestYear) {
|
||||
console.log(`Found release year ${earliestYear} for "${title}" by "${artist}"`);
|
||||
} else {
|
||||
console.log(`No release year found for "${title}" by "${artist}"`);
|
||||
}
|
||||
|
||||
return earliestYear;
|
||||
} catch (error) {
|
||||
console.error(`Error fetching release year for "${title}" by "${artist}":`, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user