import { Hono } from 'hono'; import { setConfig, getAllConfig, getDb, getEnvLockedKeys } from '../db/index'; import { testConnection as testJellyfin, getUsers } from '../services/jellyfin'; import { testConnection as testRadarr } from '../services/radarr'; import { testConnection as testSonarr } from '../services/sonarr'; const app = new Hono(); app.get('/', (c) => { const config = getAllConfig(); const envLocked = Array.from(getEnvLockedKeys()); return c.json({ config, envLocked }); }); app.post('/jellyfin', async (c) => { const body = await c.req.json<{ url: string; api_key: string }>(); const url = body.url?.replace(/\/$/, ''); const apiKey = body.api_key; if (!url || !apiKey) return c.json({ ok: false, error: 'URL and API key are required' }, 400); const result = await testJellyfin({ url, apiKey }); if (!result.ok) return c.json({ ok: false, error: result.error }); setConfig('jellyfin_url', url); setConfig('jellyfin_api_key', apiKey); setConfig('setup_complete', '1'); try { const users = await getUsers({ url, apiKey }); const admin = users.find((u) => u.Name === 'admin') ?? users[0]; if (admin?.Id) setConfig('jellyfin_user_id', admin.Id); } catch { /* ignore */ } return c.json({ ok: true }); }); app.post('/radarr', async (c) => { const body = await c.req.json<{ url?: string; api_key?: string }>(); const url = body.url?.replace(/\/$/, ''); const apiKey = body.api_key; if (!url || !apiKey) { setConfig('radarr_enabled', '0'); return c.json({ ok: false, error: 'URL and API key are required' }, 400); } const result = await testRadarr({ url, apiKey }); if (!result.ok) return c.json({ ok: false, error: result.error }); setConfig('radarr_url', url); setConfig('radarr_api_key', apiKey); setConfig('radarr_enabled', '1'); return c.json({ ok: true }); }); app.post('/sonarr', async (c) => { const body = await c.req.json<{ url?: string; api_key?: string }>(); const url = body.url?.replace(/\/$/, ''); const apiKey = body.api_key; if (!url || !apiKey) { setConfig('sonarr_enabled', '0'); return c.json({ ok: false, error: 'URL and API key are required' }, 400); } const result = await testSonarr({ url, apiKey }); if (!result.ok) return c.json({ ok: false, error: result.error }); setConfig('sonarr_url', url); setConfig('sonarr_api_key', apiKey); setConfig('sonarr_enabled', '1'); return c.json({ ok: true }); }); app.post('/subtitle-languages', async (c) => { const body = await c.req.json<{ langs: string[] }>(); if (body.langs?.length > 0) { setConfig('subtitle_languages', JSON.stringify(body.langs)); } return c.json({ ok: true }); }); app.post('/audio-languages', async (c) => { const body = await c.req.json<{ langs: string[] }>(); setConfig('audio_languages', JSON.stringify(body.langs ?? [])); return c.json({ ok: true }); }); app.post('/clear-scan', (c) => { const db = getDb(); // Delete children first to avoid slow cascade deletes db.transaction(() => { db.prepare('DELETE FROM stream_decisions').run(); db.prepare('DELETE FROM jobs').run(); db.prepare('DELETE FROM subtitle_files').run(); db.prepare('DELETE FROM review_plans').run(); db.prepare('DELETE FROM media_streams').run(); db.prepare('DELETE FROM media_items').run(); db.prepare("UPDATE config SET value = '0' WHERE key = 'scan_running'").run(); })(); return c.json({ ok: true }); }); export default app;