import { Router } from 'express'; import { requireUser } from '../auth.js'; import { getDb } from '../db/index.js'; import { getStatsMap } from '../stats.js'; export const router = Router(); router.use(requireUser); router.get('/favorites', (req, res) => { const rows = getDb().prepare(` SELECT s.*, f.position FROM favorites f JOIN stations s ON s.id = f.station_id WHERE f.user_id = ? AND s.enabled = 1 ORDER BY f.position ASC, f.created_at ASC `).all(req.user.id); const stats = getStatsMap(req.user.id); res.json(rows.map((r) => { const st = stats.get(r.id) || { up: 0, down: 0, plays: 0, myVote: 0, score: 0 }; return { id: r.id, uuid: r.uuid, name: r.name, slug: r.slug, homepage: r.homepage, country: r.country, genres: r.genres ? JSON.parse(r.genres) : [], image_url: r.image_url, category: r.category, position: r.position, up: st.up, down: st.down, plays: st.plays, my_vote: st.myVote, score: st.score }; })); }); // Pick one random favorite. Returns 404 if the user has none. router.get('/favorites/random', (req, res) => { const rows = getDb().prepare(` SELECT s.* FROM favorites f JOIN stations s ON s.id = f.station_id WHERE f.user_id = ? AND s.enabled = 1 `).all(req.user.id); if (!rows.length) return res.status(404).json({ error: 'no favorites' }); const r = rows[Math.floor(Math.random() * rows.length)]; const stats = getStatsMap(req.user.id).get(r.id) || { up: 0, down: 0, plays: 0, myVote: 0, score: 0 }; res.set('Cache-Control', 'no-store'); res.json({ id: r.id, uuid: r.uuid, name: r.name, slug: r.slug, homepage: r.homepage, country: r.country, genres: r.genres ? JSON.parse(r.genres) : [], image_url: r.image_url, category: r.category, up: stats.up, down: stats.down, plays: stats.plays, my_vote: stats.myVote, score: stats.score }); }); router.put('/favorites/:stationId', (req, res) => { const stationId = Number(req.params.stationId); const position = Number(req.body?.position ?? 0); getDb().prepare(` INSERT INTO favorites (user_id, station_id, position) VALUES (?, ?, ?) ON CONFLICT(user_id, station_id) DO UPDATE SET position = excluded.position `).run(req.user.id, stationId, position); res.json({ ok: true }); }); router.delete('/favorites/:stationId', (req, res) => { getDb().prepare('DELETE FROM favorites WHERE user_id = ? AND station_id = ?') .run(req.user.id, Number(req.params.stationId)); res.json({ ok: true }); }); router.get('/profile', (req, res) => { const row = getDb().prepare('SELECT * FROM profiles WHERE user_id = ?').get(req.user.id); res.json(row || { user_id: req.user.id, display_name: req.user.username, theme: 'dark', default_volume: 0.7 }); }); router.patch('/profile', (req, res) => { const { display_name, theme, default_volume } = req.body || {}; getDb().prepare(` INSERT INTO profiles (user_id, display_name, theme, default_volume) VALUES (?, ?, ?, ?) ON CONFLICT(user_id) DO UPDATE SET display_name = COALESCE(excluded.display_name, profiles.display_name), theme = COALESCE(excluded.theme, profiles.theme), default_volume = COALESCE(excluded.default_volume, profiles.default_volume) `).run(req.user.id, display_name ?? null, theme ?? null, default_volume ?? null); res.json({ ok: true }); }); router.get('/history', (req, res) => { const rows = getDb().prepare(` SELECT h.*, s.name AS station_name, s.slug AS station_slug FROM play_history h JOIN stations s ON s.id = h.station_id WHERE h.user_id = ? ORDER BY h.started_at DESC LIMIT 50 `).all(req.user.id); res.json(rows); });