import { Router } from 'express'; import { spotifyAsHost } from './hostAuth.js'; const router = Router(); // Simple in-memory TTL cache — playlists/tracks don't need to be fresher // than this, and it keeps a session-start from hammering Spotify's API. const CACHE_TTL_MS = 5 * 60 * 1000; const cache = new Map(); function cached(key, fn) { const hit = cache.get(key); if (hit && Date.now() - hit.ts < CACHE_TTL_MS) return Promise.resolve(hit.data); return fn().then(data => { cache.set(key, { data, ts: Date.now() }); return data; }); } function summarizePlaylist(p) { return { id: p.id, name: p.name, trackCount: p.items?.total ?? p.tracks?.total ?? 0, // Spotify's field name for this varies by endpoint/version; checked the real response directly image: p.images?.[0]?.url ?? null, }; } // Both facets of the card, plus cover art — track title, primary artist, // and album art, everything a square could render as. function summarizeTrack(entry) { const t = entry.item; if (!t) return null; return { id: t.id, title: t.name, artist: t.artists?.[0]?.name ?? 'Unknown artist', album: t.album?.name ?? '', image: t.album?.images?.[0]?.url ?? null, uri: t.uri, }; } // GET /api/host/playlists — the host's own playlists as candidate song pools. router.get('/playlists', async (req, res) => { try { const data = await cached('host-playlists', async () => { const out = []; let url = '/me/playlists?limit=50'; while (url) { const page = await spotifyAsHost(url); out.push(...(page.items ?? [])); url = page.next ? page.next.replace('https://api.spotify.com/v1', '') : null; } return out.map(summarizePlaylist); }); res.json(data); } catch (e) { res.status(502).json({ error: e.message }); } }); // GET /api/host/playlist/:id/tracks — full track pool for one playlist. router.get('/playlist/:id/tracks', async (req, res) => { try { const data = await cached(`host-tracks:${req.params.id}`, async () => { const out = []; let url = `/playlists/${req.params.id}/items?limit=100&fields=next,items(item(id,name,uri,artists(name),album(name,images)))`; while (url) { const page = await spotifyAsHost(url); out.push(...(page.items ?? [])); url = page.next ? page.next.replace('https://api.spotify.com/v1', '') : null; } return out.map(summarizeTrack).filter(Boolean); }); res.json(data); } catch (e) { res.status(502).json({ error: e.message }); } }); // GET /api/host/now-playing — thin wrapper for the auto-call poller. router.get('/now-playing', async (req, res) => { try { const data = await spotifyAsHost('/me/player/currently-playing'); res.json(data ?? { playing: false }); } catch (e) { res.status(502).json({ error: e.message }); } }); export default router;