private static async Task CleanUpSonarr(StreamingProvider[] providers, JustWatchClient justWatch) { if (string.IsNullOrWhiteSpace(_config?.Sonarr?.Url) || string.IsNullOrWhiteSpace(_config?.Sonarr?.Key)) { Console.WriteLine("Sonarr not configured."); return; } Console.WriteLine("Cleaning up Sonarr..."); var sonarr = new SonarrClient(_config.Sonarr.Url, _config.Sonarr.Key); var shows = await sonarr.GetShows(); foreach (var show in shows) { var jwShow = await SearchForTvShow(providers, justWatch, show); if (jwShow == null) { continue; } // Get show details var details = await justWatch.GetShowDetails(jwShow.Id); var canAllBeStreamed = true; var streamableSeasons = new HashSet <int>(); // Filter monitored seasons (or seasons with downloads) foreach (var season in show.Seasons.Where(s => s.Monitored || s.Statistics.EpisodeFileCount > 0)) { // Ignore if season number = 0; not a real season if (season.SeasonNumber < 1) { continue; } var jwSeasonId = details.Seasons.Where(s => s.SeasonNumber == season.SeasonNumber) .Select(s => (long?)s.Id) .FirstOrDefault(); if (!jwSeasonId.HasValue) { canAllBeStreamed = false; continue; } // Check streaming offers that offer the entire season var seasonDetails = await justWatch.GetSeasonDetails(jwSeasonId.Value); var availableOnProviders = seasonDetails.Offers?.Where(o => o.MonetizationType.Equals("flatrate", StringComparison.InvariantCultureIgnoreCase) && o.ElementCount >= seasonDetails.Episodes.Count) .Select(o => providers.FirstOrDefault(p => p.Id == o.ProviderId)) .Where(p => p != null); if (availableOnProviders?.Any() ?? false) { streamableSeasons.Add(season.SeasonNumber); } else { canAllBeStreamed = false; } } var stuffTitle = $"TV Show: {show.Title}"; if (canAllBeStreamed) { // Clean up all stuffTitle += "(all seasons)"; if (await sonarr.DeleteShow(show.Id, true)) { _deletedStuff.Add(stuffTitle); } else { _failedStuff.Add(stuffTitle); } } else if (streamableSeasons.Any()) { // Clean up only streamable seasons _deletedStuff.Add($"{stuffTitle} ({string.Join(", ", streamableSeasons.Select(s => $"S{s}"))})"); // TODO: Use result of next call? await sonarr.UnmonitorSeasons(show.Id, streamableSeasons); var episodeFiles = await sonarr.GetEpisodeFiles(show.Id); foreach (var file in episodeFiles.Where(f => streamableSeasons.Contains(f.SeasonNumber))) { try { await sonarr.DeleteEpisodeFile(file.Id); } catch { await Console.Error.WriteLineAsync( $"Failed to delete episode file #{file.Id} ({show.Title} S{file.SeasonNumber})"); } } } } }