grab info from your spotify playlists

improve

Changed files
+52 -13
scripts
+52 -13
scripts/albums.ts
··· 22 22 const PLAYLISTS_DIR = 'playlists'; 23 23 const OUTPUT_FILE = 'albums.json'; 24 24 const USER_AGENT = 'SpotifyAlbums/1.0 (https://github.com/yourusername/spotify-albums)'; 25 + const REQUEST_DELAY_MS = 1100; 25 26 26 27 async function readPlaylists(): Promise<Playlist[]> { 27 28 const files = await readdir(PLAYLISTS_DIR); ··· 61 62 const artist = encodeURIComponent(album.artist); 62 63 const release = encodeURIComponent(album.name); 63 64 const url = `https://musicbrainz.org/ws/2/release/?query=artist:${artist}+release:${release}&limit=1&fmt=json`; 64 - console.log(` MusicBrainz URL: ${url}`); 65 65 66 66 const response = await fetch(url, { 67 67 headers: { 68 68 'User-Agent': USER_AGENT 69 69 } 70 70 }); 71 - console.log(` MusicBrainz status: ${response.status}`); 72 71 73 72 if (!response.ok) { 74 - console.log(` MusicBrainz failed: ${response.statusText}`); 73 + console.log(` ✗ ${response.statusText}`); 75 74 return undefined; 76 75 } 77 76 78 77 const data = await response.json(); 79 - console.log(` MusicBrainz results count: ${data.releases?.length || 0}`); 80 78 81 79 if (data.releases && data.releases.length > 0) { 82 80 const result = data.releases[0]; 83 - console.log(` Found: ${result.title} (ID: ${result.id})`); 81 + console.log(` ✓ ${result.id}`); 84 82 return result.id; 83 + } else { 84 + console.log(` ✗ no results`); 85 85 } 86 86 } catch (error) { 87 - console.error(` MusicBrainz search error:`, (error as Error).message); 87 + console.log(` ✗ ${(error as Error).message}`); 88 88 } 89 89 90 90 return undefined; ··· 92 92 93 93 async function enrichAlbums(albums: Album[]): Promise<Album[]> { 94 94 const enriched: Album[] = []; 95 + const startTime = Date.now(); 95 96 96 - for (const album of albums) { 97 - console.log(`Looking up: ${album.artist} - ${album.name}`); 97 + for (let i = 0; i < albums.length; i++) { 98 + const album = albums[i]; 99 + const progress = `[${i + 1}/${albums.length}]`; 98 100 101 + console.log(`${progress} ${album.artist} - ${album.name}`); 99 102 const musicbrainzId = await searchMusicBrainz(album); 100 103 101 104 enriched.push({ ··· 103 106 musicbrainz_id: musicbrainzId 104 107 }); 105 108 106 - await new Promise(resolve => setTimeout(resolve, 1000)); 109 + if (i < albums.length - 1) { 110 + await new Promise(resolve => setTimeout(resolve, REQUEST_DELAY_MS)); 111 + } 112 + 113 + if ((i + 1) % 50 === 0) { 114 + const elapsed = Date.now() - startTime; 115 + const avgTimePerAlbum = elapsed / (i + 1); 116 + const remaining = (albums.length - i - 1) * avgTimePerAlbum; 117 + const eta = Math.round(remaining / 1000 / 60); 118 + console.log(`\nProgress: ${((i + 1) / albums.length * 100).toFixed(1)}% | ETA: ~${eta} minutes\n`); 119 + } 107 120 } 108 121 109 122 return enriched; 110 123 } 111 124 125 + async function loadExistingAlbums(): Promise<Set<string>> { 126 + try { 127 + const content = await readFile(OUTPUT_FILE, 'utf-8'); 128 + const existing = JSON.parse(content) as Album[]; 129 + const keys = new Set(existing.map(a => `${a.artist}:${a.name}`)); 130 + console.log(`Found ${keys.size} previously processed albums`); 131 + return keys; 132 + } catch { 133 + return new Set(); 134 + } 135 + } 136 + 112 137 async function main() { 113 138 try { 114 139 console.log('Reading playlists...'); ··· 122 147 123 148 console.log(`Found ${albums.length} unique albums`); 124 149 125 - console.log('\nEnriching album data...'); 126 - const enrichedAlbums = await enrichAlbums(albums); 150 + const existingKeys = await loadExistingAlbums(); 151 + const albumsToProcess = albums.filter(a => !existingKeys.has(`${a.artist}:${a.name}`)); 127 152 128 - const output = JSON.stringify(enrichedAlbums, null, 2); 153 + if (existingKeys.size > 0) { 154 + console.log(`Skipping ${existingKeys.size} already processed albums`); 155 + console.log(`Processing ${albumsToProcess.length} remaining albums\n`); 156 + } else { 157 + console.log('Processing all albums\n'); 158 + } 159 + 160 + const newAlbums = await enrichAlbums(albumsToProcess); 161 + 162 + const existingAlbums = existingKeys.size > 0 163 + ? JSON.parse(await readFile(OUTPUT_FILE, 'utf-8')) as Album[] 164 + : []; 165 + 166 + const allAlbums = [...existingAlbums, ...newAlbums]; 167 + const output = JSON.stringify(allAlbums, null, 2); 129 168 await writeFile(OUTPUT_FILE, output, 'utf-8'); 130 169 131 - console.log(`\nSaved ${enrichedAlbums.length} albums to ${OUTPUT_FILE}`); 170 + console.log(`\nSaved ${allAlbums.length} total albums to ${OUTPUT_FILE}`); 132 171 } catch (error) { 133 172 console.error('Error:', (error as Error).message); 134 173 }