fix: 429 retry, safety counter, local file filter in Spotify pagination

This commit is contained in:
Honey committed 2026-05-09 20:58:16 +02:00
1 parent b7f09058a9
commit 7c1c444bf2
2 files changed
+28 -12

No files matched your search

+27 -12
View File
@@ -94,33 +94,47 @@ async function fetchSpotifyToken() {
async function _spApi(path, token) {
const url = path.startsWith('http') ? path : `https://api.spotify.com/v1${path}`;
const r = await fetch(url, {
headers: { Authorization: `Bearer ${token}` },
signal: AbortSignal.timeout(10000),
});
if (!r.ok) throw new Error(`Spotify API Fehler ${r.status}: ${path}`);
return r.json();
for (let attempt = 0; attempt < 4; attempt++) {
const r = await fetch(url, {
headers: { Authorization: `Bearer ${token}` },
signal: AbortSignal.timeout(10000),
});
if (r.status === 429) {
const wait = (parseInt(r.headers.get('Retry-After') || '5', 10) + 1) * 1000;
await new Promise(res => setTimeout(res, wait));
continue;
}
if (!r.ok) throw new Error(`Spotify API Fehler ${r.status}: ${path}`);
return r.json();
}
throw new Error('Spotify API rate-limited — bitte kurz warten und erneut versuchen');
}
async function _spAllPlaylistTracks(id, token) {
const tracks = [];
let skippedLocal = 0;
let path = `/playlists/${id}/tracks?limit=100`;
while (path) {
let pages = 0;
while (path && pages++ < 100) {
const page = await _spApi(path, token);
for (const item of page.items || []) {
if (item.track?.name) tracks.push(item.track);
const t = item.track;
if (!t || !t.id) continue;
if (t.is_local) { skippedLocal++; continue; }
tracks.push(t);
}
path = page.next || null;
}
return tracks;
return { tracks, skippedLocal };
}
async function _spAllAlbumTracks(id, token) {
const tracks = [];
let path = `/albums/${id}/tracks?limit=50`;
while (path) {
let pages = 0;
while (path && pages++ < 100) {
const page = await _spApi(path, token);
tracks.push(...(page.items || []));
tracks.push(...(page.items || []).filter(t => t?.id));
path = page.next || null;
}
return tracks;
@@ -232,13 +246,14 @@ app.post('/api/spotify/resolve', async (req, res) => {
const pl = await _spApi(`/playlists/${id}?fields=name,description,owner,images`, token);
const owner = pl.owner?.display_name || '';
const artUrl = _spArtwork(pl);
const trackItems = await _spAllPlaylistTracks(id, token);
const { tracks: trackItems, skippedLocal } = await _spAllPlaylistTracks(id, token);
return res.json({
type: 'playlist',
name: pl.name || '',
artist: owner,
artworkUrl: artUrl,
description: pl.description || '',
skippedLocal,
tracks: trackItems.map(t => _spTrackItem(t, null, null, null)),
});
}
+1
View File
@@ -51,6 +51,7 @@ export async function resolveSpotifyLink() {
}
const data = await res.json();
window._spotifyResolved = data;
if (data.skippedLocal > 0) toast(`${data.skippedLocal} lokale Datei(en) übersprungen (kein Stream verfügbar)`);
_renderSpotifyPreview(data);
} catch(e) {
inner.innerHTML = `<div style="color:var(--danger);padding:16px;background:var(--surface);border-radius:10px">${esc(e.message)}</div>`;