diff --git a/client/src/ui/statusPanel.js b/client/src/ui/statusPanel.js index 57e58c0..bd81b09 100644 --- a/client/src/ui/statusPanel.js +++ b/client/src/ui/statusPanel.js @@ -118,18 +118,22 @@ export function renderStatusPanel(data, panel) { const wh = data.webhooks; const sonarrEnabled = wh.sonarr?.enabled ? '●' : '○'; const radarrEnabled = wh.radarr?.enabled ? '●' : '○'; + const ombiEnabled = wh.ombi?.enabled ? '●' : '○'; const sonarrEvents = wh.sonarr?.eventsReceived || 0; const radarrEvents = wh.radarr?.eventsReceived || 0; + const ombiEvents = wh.ombi?.eventsReceived || 0; const sonarrPolls = wh.sonarr?.pollsSkipped || 0; const radarrPolls = wh.radarr?.pollsSkipped || 0; + const ombiPolls = wh.ombi?.pollsSkipped || 0; html += `
Webhooks
Sonarr${sonarrEnabled} ${wh.sonarr?.enabled ? 'Enabled' : 'Disabled'}
Radarr${radarrEnabled} ${wh.radarr?.enabled ? 'Enabled' : 'Disabled'}
-
EventsS:${sonarrEvents} R:${radarrEvents}
-
Polls skippedS:${sonarrPolls} R:${radarrPolls}
+
Ombi${ombiEnabled} ${wh.ombi?.enabled ? 'Enabled' : 'Disabled'}
+
EventsS:${sonarrEvents} R:${radarrEvents} O:${ombiEvents}
+
Polls skippedS:${sonarrPolls} R:${radarrPolls} O:${ombiPolls}
`; } diff --git a/server/routes/status.js b/server/routes/status.js index d826ffa..a6fb68f 100644 --- a/server/routes/status.js +++ b/server/routes/status.js @@ -4,9 +4,9 @@ const router = express.Router(); const requireAuth = require('../middleware/requireAuth'); const cache = require('../utils/cache'); const { getLastPollTimings, POLLING_ENABLED } = require('../utils/poller'); -const { getSonarrInstances, getRadarrInstances } = require('../utils/config'); +const { getSonarrInstances, getRadarrInstances, getOmbiInstances } = require('../utils/config'); const { getGlobalWebhookMetrics } = require('../utils/cache'); -const { checkWebhookConfigured, aggregateMetrics } = require('../services/WebhookStatus'); +const { checkWebhookConfigured, checkOmbiWebhookConfigured, aggregateMetrics } = require('../services/WebhookStatus'); /** * @openapi @@ -121,6 +121,7 @@ router.get('/', requireAuth, async (req, res) => { // Check webhook configuration for each service const sonarrInstances = getSonarrInstances(); const radarrInstances = getRadarrInstances(); + const ombiInstances = getOmbiInstances(); const sonarrWebhookConfigured = sonarrInstances.length > 0 ? await checkWebhookConfigured(sonarrInstances[0], 'Sonarr') @@ -128,15 +129,21 @@ router.get('/', requireAuth, async (req, res) => { const radarrWebhookConfigured = radarrInstances.length > 0 ? await checkWebhookConfigured(radarrInstances[0], 'Radarr') : false; + const ombiWebhookConfigured = ombiInstances.length > 0 + ? await checkOmbiWebhookConfigured(ombiInstances[0]) + : false; - // Find Sonarr and Radarr metrics from instances + // Find Sonarr, Radarr, and Ombi metrics from instances const sonarrMetrics = {}; const radarrMetrics = {}; + const ombiMetrics = {}; for (const [url, metrics] of Object.entries(webhookMetrics.instances || {})) { if (url.includes('sonarr')) { sonarrMetrics[url] = metrics; } else if (url.includes('radarr')) { radarrMetrics[url] = metrics; + } else if (url.includes('ombi') || (ombiInstances.length > 0 && url === ombiInstances[0].url)) { + ombiMetrics[url] = metrics; } } @@ -156,7 +163,8 @@ router.get('/', requireAuth, async (req, res) => { cache: cacheStats, webhooks: { sonarr: aggregateMetrics(sonarrMetrics, sonarrWebhookConfigured), - radarr: aggregateMetrics(radarrMetrics, radarrWebhookConfigured) + radarr: aggregateMetrics(radarrMetrics, radarrWebhookConfigured), + ombi: aggregateMetrics(ombiMetrics, ombiWebhookConfigured) } }); } catch (err) { diff --git a/server/routes/webhook.js b/server/routes/webhook.js index bccc8f5..3ceb170 100644 --- a/server/routes/webhook.js +++ b/server/routes/webhook.js @@ -259,6 +259,8 @@ async function processWebhookEvent(serviceType, eventType) { const ombiInstances = getOmbiInstances(); if (affectsOmbi) { + // Add a 2000ms delay to resolve the race condition where Ombi fires the webhook before committing to DB + await new Promise(r => setTimeout(r, 2000)); const ombiRequests = await arrRetrieverRegistry.getOmbiRequests(true); cache.set('poll:ombi-requests', ombiRequests, CACHE_TTL); logToFile(`[Webhook] Refreshed poll:ombi-requests (${ombiRequests.movie?.length || 0} movies, ${ombiRequests.tv?.length || 0} TV shows)`); diff --git a/server/services/WebhookStatus.js b/server/services/WebhookStatus.js index f13f556..3597570 100644 --- a/server/services/WebhookStatus.js +++ b/server/services/WebhookStatus.js @@ -49,7 +49,26 @@ function aggregateMetrics(metricsMap, configured) { }; } +/** + * Check if Sofarr webhook is configured in an Ombi instance. + * @param {Object} instance - The Ombi instance config + * @returns {Promise} true if webhook is configured + */ +async function checkOmbiWebhookConfigured(instance) { + try { + const response = await axios.get(`${instance.url}/api/v1/Settings/notifications/webhook`, { + headers: { 'ApiKey': instance.apiKey }, + timeout: 5000 + }); + return !!(response.data && response.data.enabled); + } catch (err) { + console.log(`[WebhookStatus] Failed to check Ombi webhook config: ${err.message}`); + return false; + } +} + module.exports = { checkWebhookConfigured, + checkOmbiWebhookConfigured, aggregateMetrics };