// Copyright (c) 2026 Gordon Bolton. MIT License. const express = require('express'); const axios = require('axios'); const router = express.Router(); const requireAuth = require('../middleware/requireAuth'); const sanitizeError = require('../utils/sanitizeError'); const { getWebhookSecret, getSofarrBaseUrl } = require('../utils/config'); router.use(requireAuth); // Get queue router.get('/queue', async (req, res) => { try { const response = await axios.get(`${process.env.RADARR_URL}/api/v3/queue`, { headers: { 'X-Api-Key': process.env.RADARR_API_KEY } }); res.json(response.data); } catch (error) { res.status(500).json({ error: 'Failed to fetch Radarr queue', details: sanitizeError(error) }); } }); // Get history router.get('/history', async (req, res) => { try { const response = await axios.get(`${process.env.RADARR_URL}/api/v3/history`, { headers: { 'X-Api-Key': process.env.RADARR_API_KEY }, params: { pageSize: req.query.pageSize || 50 } }); res.json(response.data); } catch (error) { res.status(500).json({ error: 'Failed to fetch Radarr history', details: sanitizeError(error) }); } }); // Get movie details router.get('/movies/:id', async (req, res) => { try { const response = await axios.get(`${process.env.RADARR_URL}/api/v3/movie/${req.params.id}`, { headers: { 'X-Api-Key': process.env.RADARR_API_KEY } }); res.json(response.data); } catch (error) { res.status(500).json({ error: 'Failed to fetch movie details', details: sanitizeError(error) }); } }); // Get all movies with tags router.get('/movies', async (req, res) => { try { const response = await axios.get(`${process.env.RADARR_URL}/api/v3/movie`, { headers: { 'X-Api-Key': process.env.RADARR_API_KEY } }); res.json(response.data); } catch (error) { res.status(500).json({ error: 'Failed to fetch movies', details: sanitizeError(error) }); } }); // Notification proxy routes (Phase 3) // GET /api/radarr/notifications - list all notifications router.get('/notifications', async (req, res) => { try { const response = await axios.get(`${process.env.RADARR_URL}/api/v3/notification`, { headers: { 'X-Api-Key': process.env.RADARR_API_KEY } }); res.json(response.data); } catch (error) { res.status(500).json({ error: 'Failed to fetch Radarr notifications', details: sanitizeError(error) }); } }); // GET /api/radarr/notifications/:id - get specific notification router.get('/notifications/:id', async (req, res) => { try { const response = await axios.get(`${process.env.RADARR_URL}/api/v3/notification/${req.params.id}`, { headers: { 'X-Api-Key': process.env.RADARR_API_KEY } }); res.json(response.data); } catch (error) { res.status(500).json({ error: 'Failed to fetch Radarr notification', details: sanitizeError(error) }); } }); // POST /api/radarr/notifications - create notification router.post('/notifications', async (req, res) => { try { const response = await axios.post(`${process.env.RADARR_URL}/api/v3/notification`, req.body, { headers: { 'X-Api-Key': process.env.RADARR_API_KEY } }); res.json(response.data); } catch (error) { res.status(500).json({ error: 'Failed to create Radarr notification', details: sanitizeError(error) }); } }); // PUT /api/radarr/notifications/:id - update notification router.put('/notifications/:id', async (req, res) => { try { const response = await axios.put(`${process.env.RADARR_URL}/api/v3/notification/${req.params.id}`, req.body, { headers: { 'X-Api-Key': process.env.RADARR_API_KEY } }); res.json(response.data); } catch (error) { res.status(500).json({ error: 'Failed to update Radarr notification', details: sanitizeError(error) }); } }); // DELETE /api/radarr/notifications/:id - delete notification router.delete('/notifications/:id', async (req, res) => { try { const response = await axios.delete(`${process.env.RADARR_URL}/api/v3/notification/${req.params.id}`, { headers: { 'X-Api-Key': process.env.RADARR_API_KEY } }); res.json(response.data); } catch (error) { res.status(500).json({ error: 'Failed to delete Radarr notification', details: sanitizeError(error) }); } }); // POST /api/radarr/notifications/test - test notification router.post('/notifications/test', async (req, res) => { try { const response = await axios.post(`${process.env.RADARR_URL}/api/v3/notification/test`, req.body, { headers: { 'X-Api-Key': process.env.RADARR_API_KEY } }); res.json(response.data); } catch (error) { res.status(500).json({ error: 'Failed to test Radarr notification', details: sanitizeError(error) }); } }); // GET /api/radarr/notifications/schema - get notification schema router.get('/notifications/schema', async (req, res) => { try { const response = await axios.get(`${process.env.RADARR_URL}/api/v3/notification/schema`, { headers: { 'X-Api-Key': process.env.RADARR_API_KEY } }); res.json(response.data); } catch (error) { res.status(500).json({ error: 'Failed to fetch Radarr notification schema', details: sanitizeError(error) }); } }); // POST /api/radarr/notifications/sofarr-webhook - one-click Sofarr webhook setup router.post('/notifications/sofarr-webhook', async (req, res) => { try { const sofarrBaseUrl = getSofarrBaseUrl(); const webhookSecret = getWebhookSecret(); if (!sofarrBaseUrl) { return res.status(400).json({ error: 'SOFARR_BASE_URL not configured' }); } if (!webhookSecret) { return res.status(400).json({ error: 'SOFARR_WEBHOOK_SECRET not configured' }); } const webhookUrl = `${sofarrBaseUrl}/api/webhook/radarr`; // Check if Sofarr webhook already exists const listResponse = await axios.get(`${process.env.RADARR_URL}/api/v3/notification`, { headers: { 'X-Api-Key': process.env.RADARR_API_KEY } }); const existingNotification = listResponse.data.find(n => n.name === 'Sofarr'); const notificationPayload = { name: 'Sofarr', implementation: 'Webhook', configContract: 'WebhookSettings', fields: [ { name: 'url', value: webhookUrl }, { name: 'method', value: 'POST' }, { name: 'headers', value: [{ key: 'X-Sofarr-Webhook-Secret', value: webhookSecret }] } ], onGrab: true, onDownload: true, onImport: true, onUpgrade: true, onRename: false, onHealthIssue: false, onApplicationUpdate: false }; if (existingNotification) { // Update existing notification const response = await axios.put( `${process.env.RADARR_URL}/api/v3/notification/${existingNotification.id}`, { ...notificationPayload, id: existingNotification.id }, { headers: { 'X-Api-Key': process.env.RADARR_API_KEY } } ); res.json(response.data); } else { // Create new notification const response = await axios.post( `${process.env.RADARR_URL}/api/v3/notification`, notificationPayload, { headers: { 'X-Api-Key': process.env.RADARR_API_KEY } } ); res.json(response.data); } } catch (error) { res.status(500).json({ error: 'Failed to configure Sofarr webhook', details: sanitizeError(error) }); } }); module.exports = router;