From ac5e2ba6c15235d30c7f31c2beeac708e748f489 Mon Sep 17 00:00:00 2001 From: Fallenbagel <98979876+Fallenbagel@users.noreply.github.com> Date: Mon, 19 Jan 2026 01:33:38 +0500 Subject: [PATCH] fix(sonarr): re-monitor episodes when re-requesting deleted but monitored seasons When Sonarr's "Unmonitor Deleted Episodes" is enabled, deleted files cause episodes to be unmonitored while the season stays monitored. Re-requesting sets season.monitored = true, but Sonarr only cascades to episodes on state change. Since the season is already monitored, episodes stay unmonitored and searches find nothing. Now explicitly re-monitors episodes for requested seasons before triggering a search. fix #2309 --- server/api/servarr/sonarr.ts | 60 ++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/server/api/servarr/sonarr.ts b/server/api/servarr/sonarr.ts index 9dec8ebf..01b429ba 100644 --- a/server/api/servarr/sonarr.ts +++ b/server/api/servarr/sonarr.ts @@ -209,6 +209,34 @@ class SonarrAPI extends ServarrBase<{ series: newSeriesResponse.data, }); + try { + const episodes = await this.getEpisodes(newSeriesResponse.data.id); + const episodeIdsToMonitor = episodes + .filter( + (ep) => + options.seasons.includes(ep.seasonNumber) && !ep.monitored + ) + .map((ep) => ep.id); + + if (episodeIdsToMonitor.length > 0) { + logger.debug( + 'Re-monitoring unmonitored episodes for requested seasons.', + { + label: 'Sonarr', + seriesId: newSeriesResponse.data.id, + episodeCount: episodeIdsToMonitor.length, + } + ); + await this.monitorEpisodes(episodeIdsToMonitor); + } + } catch (e) { + logger.warn('Failed to re-monitor episodes', { + label: 'Sonarr', + errorMessage: e.message, + seriesId: newSeriesResponse.data.id, + }); + } + if (options.searchNow) { this.searchSeries(newSeriesResponse.data.id); } @@ -318,6 +346,38 @@ class SonarrAPI extends ServarrBase<{ } } + public async getEpisodes(seriesId: number): Promise { + try { + const response = await this.axios.get('/episode', { + params: { seriesId }, + }); + return response.data; + } catch (e) { + logger.error('Failed to retrieve episodes', { + label: 'Sonarr API', + errorMessage: e.message, + seriesId, + }); + throw new Error('Failed to get episodes'); + } + } + + public async monitorEpisodes(episodeIds: number[]): Promise { + try { + await this.axios.put('/episode/monitor', { + episodeIds, + monitored: true, + }); + } catch (e) { + logger.error('Failed to monitor episodes', { + label: 'Sonarr API', + errorMessage: e.message, + episodeIds, + }); + throw new Error('Failed to monitor episodes'); + } + } + private buildSeasonList( seasons: number[], existingSeasons?: SonarrSeason[]