Revert "fix(backend): cache the iTunes proxy to avoid Apple rate-limiting the search"
This reverts commit a3c8b1afd1.
This commit is contained in:
1 parent
a3c8b1afd1
commit
8cd3e9ac23
1 file changed
+1
-25
@@ -312,38 +312,14 @@ app.get('/api/itunes/lookup', async (req, res, next) => {
|
|||||||
// ─── ITUNES PROXY ─────────────────────────────────────────────────────────────
|
// ─── ITUNES PROXY ─────────────────────────────────────────────────────────────
|
||||||
// Browsers can't call itunes.apple.com directly (no CORS headers). Proxy it here.
|
// Browsers can't call itunes.apple.com directly (no CORS headers). Proxy it here.
|
||||||
// Note: /api/itunes/lookup is handled above — proxy only covers /search and id-based /lookup.
|
// Note: /api/itunes/lookup is handled above — proxy only covers /search and id-based /lookup.
|
||||||
//
|
|
||||||
// Cached (30 min): iTunes' Search API rate-limits ~20 req/min per IP. Without a cache, heavy
|
|
||||||
// download activity (each download does several album/track lookups) plus client searches blow
|
|
||||||
// past that and Apple starts returning empty/throttle responses — so the Apple-Music search "finds
|
|
||||||
// nothing". Serving repeated identical queries from cache keeps us well under the limit.
|
|
||||||
const _itunesCache = new Map(); // target url → { ts, body }
|
|
||||||
const ITUNES_TTL = 30 * 60 * 1000;
|
|
||||||
app.get('/api/itunes/:endpoint', (req, res) => {
|
app.get('/api/itunes/:endpoint', (req, res) => {
|
||||||
const allowed = new Set(['search', 'lookup']);
|
const allowed = new Set(['search', 'lookup']);
|
||||||
if (!allowed.has(req.params.endpoint)) return res.status(404).json({ error: 'not found' });
|
if (!allowed.has(req.params.endpoint)) return res.status(404).json({ error: 'not found' });
|
||||||
const qs = new URLSearchParams(req.query).toString();
|
const qs = new URLSearchParams(req.query).toString();
|
||||||
const target = `https://itunes.apple.com/${req.params.endpoint}${qs ? '?' + qs : ''}`;
|
const target = `https://itunes.apple.com/${req.params.endpoint}${qs ? '?' + qs : ''}`;
|
||||||
|
|
||||||
const cached = _itunesCache.get(target);
|
|
||||||
if (cached && Date.now() - cached.ts < ITUNES_TTL) {
|
|
||||||
res.setHeader('Content-Type', 'application/json');
|
|
||||||
return res.send(cached.body);
|
|
||||||
}
|
|
||||||
|
|
||||||
https.get(target, { headers: { 'User-Agent': 'NovaSonic/1.0' } }, upstream => {
|
https.get(target, { headers: { 'User-Agent': 'NovaSonic/1.0' } }, upstream => {
|
||||||
let body = '';
|
|
||||||
upstream.on('data', d => body += d);
|
|
||||||
upstream.on('end', () => {
|
|
||||||
// Only cache a genuine iTunes response (200 + the resultCount signature) — never a throttle
|
|
||||||
// or error page, or an empty result would get pinned for 30 min.
|
|
||||||
if (upstream.statusCode === 200 && body.includes('"resultCount"')) {
|
|
||||||
if (_itunesCache.size > 500) _itunesCache.clear(); // simple bound
|
|
||||||
_itunesCache.set(target, { ts: Date.now(), body });
|
|
||||||
}
|
|
||||||
res.setHeader('Content-Type', 'application/json');
|
res.setHeader('Content-Type', 'application/json');
|
||||||
res.status(upstream.statusCode || 200).send(body);
|
upstream.pipe(res);
|
||||||
});
|
|
||||||
}).on('error', e => res.status(502).json({ error: e.message }));
|
}).on('error', e => res.status(502).json({ error: e.message }));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user