fix: 429 retry, safety counter, local file filter in Spotify pagination
This commit is contained in:
1 parent
b7f09058a9
commit
7c1c444bf2
2 files changed
+22
-6
No files matched your search
@@ -94,33 +94,47 @@ async function fetchSpotifyToken() {
|
||||
|
||||
async function _spApi(path, token) {
|
||||
const url = path.startsWith('http') ? path : `https://api.spotify.com/v1${path}`;
|
||||
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)),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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>`;
|
||||
|
||||
Reference in new issue
Block a user