From 31ff973effd719747689ce13bcc055b308bd6e82 Mon Sep 17 00:00:00 2001 From: Gronod Date: Sat, 16 May 2026 00:16:31 +0100 Subject: [PATCH] perf: drop includeSeries/includeMovie from history fetches Sonarr/Radarr history with include* params forces expensive DB joins (~2s each). History records still have seriesId/movieId for matching; the series/movie objects come from the queue-built maps instead. Trade-off: completed downloads only show if the series/movie is also currently in the queue. Active downloads unaffected. --- server/routes/dashboard.js | 5 +++-- server/utils/poller.js | 22 ++++------------------ 2 files changed, 7 insertions(+), 20 deletions(-) diff --git a/server/routes/dashboard.js b/server/routes/dashboard.js index bd6538f..d537adc 100644 --- a/server/routes/dashboard.js +++ b/server/routes/dashboard.js @@ -157,8 +157,9 @@ router.get('/user-downloads', async (req, res) => { const radarrHistory = { data: radarrHistoryData }; const radarrTags = { data: radarrTagsData }; - // Build series/movie maps from embedded objects in queue + history records - // (no need to fetch the full library — queue/history include the full object) + // Build series/movie maps from embedded objects in queue records + // (history is fetched without includeSeries/includeMovie for speed; + // history matches fall back to the queue-built map via seriesId/movieId) const seriesMap = new Map(); for (const r of sonarrQueue.data.records) { if (r.series && r.seriesId) seriesMap.set(r.seriesId, r.series); diff --git a/server/utils/poller.js b/server/utils/poller.js index ac5d849..4f3cac0 100644 --- a/server/utils/poller.js +++ b/server/utils/poller.js @@ -74,7 +74,7 @@ async function pollAllServices() { timed('Sonarr History', () => Promise.all(sonarrInstances.map(inst => axios.get(`${inst.url}/api/v3/history`, { headers: { 'X-Api-Key': inst.apiKey }, - params: { pageSize: 10, includeSeries: true } + params: { pageSize: 10 } }).then(res => ({ instance: inst.id, data: res.data })).catch(err => { console.error(`[Poller] Sonarr ${inst.id} history error:`, err.message); return { instance: inst.id, data: { records: [] } }; @@ -92,7 +92,7 @@ async function pollAllServices() { timed('Radarr History', () => Promise.all(radarrInstances.map(inst => axios.get(`${inst.url}/api/v3/history`, { headers: { 'X-Api-Key': inst.apiKey }, - params: { pageSize: 10, includeMovie: true } + params: { pageSize: 10 } }).then(res => ({ instance: inst.id, data: res.data })).catch(err => { console.error(`[Poller] Radarr ${inst.id} history error:`, err.message); return { instance: inst.id, data: { records: [] } }; @@ -160,14 +160,7 @@ async function pollAllServices() { }) }, cacheTTL); cache.set('poll:sonarr-history', { - records: sonarrHistories.flatMap(h => { - const inst = sonarrInstances.find(i => i.id === h.instance); - const url = inst ? inst.url : null; - return (h.data.records || []).map(r => { - if (r.series) r.series._instanceUrl = url; - return r; - }); - }) + records: sonarrHistories.flatMap(h => h.data.records || []) }, cacheTTL); // Radarr @@ -182,14 +175,7 @@ async function pollAllServices() { }) }, cacheTTL); cache.set('poll:radarr-history', { - records: radarrHistories.flatMap(h => { - const inst = radarrInstances.find(i => i.id === h.instance); - const url = inst ? inst.url : null; - return (h.data.records || []).map(r => { - if (r.movie) r.movie._instanceUrl = url; - return r; - }); - }) + records: radarrHistories.flatMap(h => h.data.records || []) }, cacheTTL); cache.set('poll:radarr-tags', radarrTagsResults.flatMap(t => t.data || []), cacheTTL);