fix: add User-Agent, dual timeout, done-guard, and response logging to _fetchTimeout

- User-Agent header (Spotify may throttle anonymous requests)
- req.setTimeout + socket.setTimeout for belt-and-suspenders
- done() guard prevents double-resolve/reject
- [sp-http] log shows status code of each Spotify response
  so logs reveal whether the hang is before or after HTTP headers arrive

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
HoneyandClaude Sonnet 4.6 committed 2026-05-10 17:50:18 +02:00
1 parent f4766acc74
commit d2cb1bed68
1 file changed
+16 -7
+16 -7
View File
@@ -72,28 +72,37 @@ function parseSpotifyUrl(url) {
function _fetchTimeout(url, opts = {}, ms = 10000) {
return new Promise((resolve, reject) => {
const u = new URL(url);
const label = u.hostname + u.pathname.slice(0, 40);
const done = (fn) => { if (!done.called) { done.called = true; fn(); } };
const req = https.request({
hostname: u.hostname, port: 443,
path: u.pathname + u.search,
method: opts.method || 'GET',
headers: opts.headers || {},
headers: {
'User-Agent': 'NovaSonic/1.0',
'Accept': 'application/json',
...opts.headers,
},
}, res => {
console.log(`[sp-http] ${res.statusCode} ${label}`);
const chunks = [];
res.on('data', c => chunks.push(c));
res.on('end', () => {
const body = Buffer.concat(chunks).toString();
resolve({
const body = Buffer.concat(chunks).toString('utf8');
done(() => resolve({
ok: res.statusCode >= 200 && res.statusCode < 300,
status: res.statusCode,
headers: { get: h => res.headers[h.toLowerCase()] ?? null },
json: () => { try { return Promise.resolve(JSON.parse(body)); } catch(e) { return Promise.reject(e); } },
text: () => Promise.resolve(body),
}));
});
res.on('error', e => done(() => reject(e)));
});
res.on('error', reject);
});
req.on('socket', s => s.setTimeout(ms, () => req.destroy(new Error(`Spotify nicht erreichbar (Timeout ${ms}ms) — api.spotify.com blockiert?`))));
req.on('error', reject);
// Two-layer timeout: req-level (fires after ms of total inactivity) + socket-level
req.setTimeout(ms, () => req.destroy(new Error(`Spotify timeout ${ms}ms: ${label}`)));
req.on('socket', s => s.setTimeout(ms, () => req.destroy(new Error(`Spotify socket timeout ${ms}ms: ${label}`))));
req.on('error', e => done(() => reject(e)));
if (opts.body) req.write(opts.body);
req.end();
});