import { Router } from 'express'; import { requireAdmin } from '../auth.js'; import { runHealthCheck } from '../streams/checker.js'; import { applySeedIfEmpty } from '../sources/seed.js'; import { getDb } from '../db/index.js'; import { scrapeIcon } from '../sources/iconScraper.js'; import { listStations, getStation, updateStation } from '../stations.js'; export const router = Router(); router.use(requireAdmin); router.post('/health-check', async (_req, res) => { const n = await runHealthCheck(); res.json({ checked: n }); }); router.post('/reseed', (_req, res) => { res.json(applySeedIfEmpty()); }); router.get('/system', (_req, res) => { const db = getDb(); res.json({ stations: db.prepare('SELECT COUNT(*) AS n FROM stations').get().n, streams: db.prepare('SELECT COUNT(*) AS n FROM streams').get().n, users: db.prepare('SELECT COUNT(*) AS n FROM users').get().n, favorites: db.prepare('SELECT COUNT(*) AS n FROM favorites').get().n, node: process.version, uptime_s: Math.round(process.uptime()) }); }); // Scrape an icon for a single station. router.post('/stations/:id/scrape-icon', async (req, res) => { const id = Number(req.params.id); const st = getStation(id); if (!st) return res.status(404).json({ error: 'not found' }); const url = await scrapeIcon(st); if (!url) return res.status(404).json({ error: 'no icon found' }); const updated = updateStation(id, { image_url: url }); res.json({ id, image_url: url, station: updated }); }); // Bulk: scrape icons for every station (optionally only those missing one). router.post('/scrape-icons', async (req, res) => { const onlyMissing = req.query.all !== '1'; const stations = listStations({ enabled: null }).filter((s) => !onlyMissing || !s.image_url); const results = { total: stations.length, updated: 0, skipped: 0, failed: 0, items: [] }; // Limit concurrency to avoid hammering hosts. const concurrency = 4; let i = 0; async function worker() { while (i < stations.length) { const s = stations[i++]; try { const url = await scrapeIcon(s); if (url) { updateStation(s.id, { image_url: url }); results.updated++; results.items.push({ id: s.id, name: s.name, image_url: url }); } else { results.failed++; results.items.push({ id: s.id, name: s.name, image_url: null }); } } catch (err) { results.failed++; results.items.push({ id: s.id, name: s.name, error: String(err?.message || err) }); } } } await Promise.all(Array.from({ length: concurrency }, worker)); res.json(results); });