From b223306ee8bef64d553b8e84871f8b4ccd4a4d46 Mon Sep 17 00:00:00 2001 From: TidusJar Date: Wed, 7 Feb 2018 20:27:36 +0000 Subject: [PATCH] fixed build and added logging --- src/Ombi.Core/Senders/TvSender.cs | 774 +++++++++--------- .../Agents/DiscordNotification.cs | 5 +- .../Agents/EmailNotification.cs | 2 +- .../Agents/MattermostNotification.cs | 2 +- .../Agents/MobileNotification.cs | 2 +- .../Agents/PushbulletNotification.cs | 2 +- .../Agents/PushoverNotification.cs | 6 +- .../Agents/SlackNotification.cs | 2 +- .../Agents/TelegramNotification.cs | 4 +- .../Interfaces/BaseNotification.cs | 8 +- .../NotificationMessageCurlys.cs | 11 +- .../Jobs/Plex/PlexAvailabilityChecker.cs | 332 ++++---- 12 files changed, 576 insertions(+), 574 deletions(-) diff --git a/src/Ombi.Core/Senders/TvSender.cs b/src/Ombi.Core/Senders/TvSender.cs index a4ff311a8..303cc9ee1 100644 --- a/src/Ombi.Core/Senders/TvSender.cs +++ b/src/Ombi.Core/Senders/TvSender.cs @@ -1,388 +1,388 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.Extensions.Logging; -using Ombi.Api.DogNzb; -using Ombi.Api.DogNzb.Models; -using Ombi.Api.SickRage; -using Ombi.Api.SickRage.Models; -using Ombi.Api.Sonarr; -using Ombi.Api.Sonarr.Models; -using Ombi.Core.Settings; -using Ombi.Helpers; -using Ombi.Settings.Settings.Models.External; -using Ombi.Store.Entities.Requests; - -namespace Ombi.Core.Senders -{ - public class TvSender : ITvSender - { - public TvSender(ISonarrApi sonarrApi, ILogger log, ISettingsService sonarrSettings, - ISettingsService dog, IDogNzbApi dogApi, ISettingsService srSettings, - ISickRageApi srApi) - { - SonarrApi = sonarrApi; - Logger = log; - SonarrSettings = sonarrSettings; - DogNzbSettings = dog; - DogNzbApi = dogApi; - SickRageSettings = srSettings; - SickRageApi = srApi; - } - - private ISonarrApi SonarrApi { get; } - private IDogNzbApi DogNzbApi { get; } - private ISickRageApi SickRageApi { get; } - private ILogger Logger { get; } - private ISettingsService SonarrSettings { get; } - private ISettingsService DogNzbSettings { get; } - private ISettingsService SickRageSettings { get; } - - public async Task Send(ChildRequests model) - { - var sonarr = await SonarrSettings.GetSettingsAsync(); - if (sonarr.Enabled) - { - var result = await SendToSonarr(model); - if (result != null) - { - return new SenderResult - { - Sent = true, - Success = true - }; - } - } - var dog = await DogNzbSettings.GetSettingsAsync(); - if (dog.Enabled) - { - var result = await SendToDogNzb(model, dog); - if (!result.Failure) - { - return new SenderResult - { - Sent = true, - Success = true - }; - } - return new SenderResult - { - Message = result.ErrorMessage - }; - } - var sr = await SickRageSettings.GetSettingsAsync(); - if (sr.Enabled) - { - var result = await SendToSickRage(model, sr); - if (result) - { - return new SenderResult - { - Sent = true, - Success = true - }; - } - return new SenderResult - { - Message = "Could not send to SickRage!" - }; - } - return new SenderResult - { - Success = true - }; - } - - private async Task SendToDogNzb(ChildRequests model, DogNzbSettings settings) - { - var id = model.ParentRequest.TvDbId; - return await DogNzbApi.AddTvShow(settings.ApiKey, id.ToString()); - } - - /// - /// Send the request to Sonarr to process - /// - /// - /// - /// This is for any qualities overriden from the UI - /// - public async Task SendToSonarr(ChildRequests model, string qualityId = null) - { - var s = await SonarrSettings.GetSettingsAsync(); - if (!s.Enabled) - { - return null; - } - if (string.IsNullOrEmpty(s.ApiKey)) - { - return null; - } - var qualityProfile = 0; - if (!string.IsNullOrEmpty(qualityId)) // try to parse the passed in quality, otherwise use the settings default quality - { - int.TryParse(qualityId, out qualityProfile); - } - - if (qualityProfile <= 0) - { - int.TryParse(s.QualityProfile, out qualityProfile); - } - - // Get the root path from the rootfolder selected. - // For some reason, if we haven't got one use the first root folder in Sonarr - // TODO make this overrideable via the UI - var rootFolderPath = await GetSonarrRootPath(model.ParentRequest.RootFolder ?? int.Parse(s.RootPath), s); - try - { - // Does the series actually exist? - var allSeries = await SonarrApi.GetSeries(s.ApiKey, s.FullUri); - var existingSeries = allSeries.FirstOrDefault(x => x.tvdbId == model.ParentRequest.TvDbId); - - if (existingSeries == null) - { - // Time to add a new one - var newSeries = new NewSeries - { - title = model.ParentRequest.Title, - imdbId = model.ParentRequest.ImdbId, - tvdbId = model.ParentRequest.TvDbId, - cleanTitle = model.ParentRequest.Title, - monitored = true, - seasonFolder = s.SeasonFolders, - rootFolderPath = rootFolderPath, - qualityProfileId = qualityProfile, - titleSlug = model.ParentRequest.Title, - addOptions = new AddOptions - { - ignoreEpisodesWithFiles = true, // There shouldn't be any episodes with files, this is a new season - ignoreEpisodesWithoutFiles = true, // We want all missing - searchForMissingEpisodes = false // we want dont want to search yet. We want to make sure everything is unmonitored/monitored correctly. - } - }; - - // Montitor the correct seasons, - // If we have that season in the model then it's monitored! - var seasonsToAdd = new List(); - for (var i = 1; i < model.ParentRequest.TotalSeasons + 1; i++) - { - var index = i; - var season = new Season - { - seasonNumber = i, - monitored = model.SeasonRequests.Any(x => x.SeasonNumber == index) - }; - seasonsToAdd.Add(season); - } - newSeries.seasons = seasonsToAdd; - var result = await SonarrApi.AddSeries(newSeries, s.ApiKey, s.FullUri); - existingSeries = await SonarrApi.GetSeriesById(result.id, s.ApiKey, s.FullUri); - await SendToSonarr(model, existingSeries, s); - } - else - { - await SendToSonarr(model, existingSeries, s); - } - - return new NewSeries - { - id = existingSeries.id, - seasons = existingSeries.seasons.ToList(), - cleanTitle = existingSeries.cleanTitle, - title = existingSeries.title, - tvdbId = existingSeries.tvdbId - }; - } - catch (Exception e) - { - Logger.LogError(LoggingEvents.SonarrSender, e, "Exception thrown when attempting to send series over to Sonarr"); - throw; - } - } - - private async Task SendToSonarr(ChildRequests model, SonarrSeries result, SonarrSettings s) - { - var episodesToUpdate = new List(); - // Ok, now let's sort out the episodes. - - if (model.SeriesType == SeriesType.Anime) - { - result.seriesType = "anime"; - await SonarrApi.UpdateSeries(result, s.ApiKey, s.FullUri); - } - - var sonarrEpisodes = await SonarrApi.GetEpisodes(result.id, s.ApiKey, s.FullUri); - var sonarrEpList = sonarrEpisodes.ToList() ?? new List(); - while (!sonarrEpList.Any()) - { - // It could be that the series metadata is not ready yet. So wait - sonarrEpList = (await SonarrApi.GetEpisodes(result.id, s.ApiKey, s.FullUri)).ToList(); - await Task.Delay(500); - } - - - foreach (var req in model.SeasonRequests) - { - foreach (var ep in req.Episodes) - { - var sonarrEp = sonarrEpList.FirstOrDefault(x => - x.episodeNumber == ep.EpisodeNumber && x.seasonNumber == req.SeasonNumber); - if (sonarrEp != null) - { - sonarrEp.monitored = true; - episodesToUpdate.Add(sonarrEp); - } - } - } - var seriesChanges = false; - foreach (var season in model.SeasonRequests) - { - var sonarrSeason = sonarrEpList.Where(x => x.seasonNumber == season.SeasonNumber); - var sonarrEpCount = sonarrSeason.Count(); - var ourRequestCount = season.Episodes.Count; - - if (sonarrEpCount == ourRequestCount) - { - // We have the same amount of requests as all of the episodes in the season. - var existingSeason = - result.seasons.First(x => x.seasonNumber == season.SeasonNumber); - existingSeason.monitored = true; - seriesChanges = true; - } - else - { - // Now update the episodes that need updating - foreach (var epToUpdate in episodesToUpdate.Where(x => x.seasonNumber == season.SeasonNumber)) - { - await SonarrApi.UpdateEpisode(epToUpdate, s.ApiKey, s.FullUri); - } - } - } - if (seriesChanges) - { - await SonarrApi.SeasonPass(s.ApiKey, s.FullUri, result); - } - - - if (!s.AddOnly) - { - await SearchForRequest(model, sonarrEpList, result, s, episodesToUpdate); - } - } - - private async Task SendToSickRage(ChildRequests model, SickRageSettings settings, string qualityId = null) - { - var tvdbid = model.ParentRequest.TvDbId; - if (qualityId.HasValue()) - { - var id = qualityId; - if (settings.Qualities.All(x => x.Value != id)) - { - qualityId = settings.QualityProfile; - } - } - else - { - qualityId = settings.QualityProfile; - } - // Check if the show exists - var existingShow = await SickRageApi.GetShow(tvdbid, settings.ApiKey, settings.FullUri); - - if (existingShow.message.Equals("Show not found", StringComparison.CurrentCultureIgnoreCase)) - { - var addResult = await SickRageApi.AddSeries(model.ParentRequest.TvDbId, qualityId, SickRageStatus.Ignored, - settings.ApiKey, settings.FullUri); - - Logger.LogDebug("Added the show (tvdbid) {0}. The result is '{2}' : '{3}'", tvdbid, addResult.result, addResult.message); - if (addResult.result.Equals("failure") || addResult.result.Equals("fatal")) - { - // Do something - return false; - } - } - - foreach (var seasonRequests in model.SeasonRequests) - { - var srEpisodes = await SickRageApi.GetEpisodesForSeason(tvdbid, seasonRequests.SeasonNumber, settings.ApiKey, settings.FullUri); - while (srEpisodes.message.Equals("Show not found", StringComparison.CurrentCultureIgnoreCase) && srEpisodes.data.Count <= 0) - { - await Task.Delay(TimeSpan.FromSeconds(1)); - srEpisodes = await SickRageApi.GetEpisodesForSeason(tvdbid, seasonRequests.SeasonNumber, settings.ApiKey, settings.FullUri); - } - - var totalSrEpisodes = srEpisodes.data.Count; - - if (totalSrEpisodes == seasonRequests.Episodes.Count) - { - // This is a request for the whole season - var wholeSeasonResult = await SickRageApi.SetEpisodeStatus(settings.ApiKey, settings.FullUri, tvdbid, SickRageStatus.Wanted, - seasonRequests.SeasonNumber); - - Logger.LogDebug("Set the status to Wanted for season {0}. The result is '{1}' : '{2}'", seasonRequests.SeasonNumber, wholeSeasonResult.result, wholeSeasonResult.message); - continue; - } - - foreach (var srEp in srEpisodes.data) - { - var epNumber = srEp.Key; - var epData = srEp.Value; - - var epRequest = seasonRequests.Episodes.FirstOrDefault(x => x.EpisodeNumber == epNumber); - if (epRequest != null) - { - // We want to monior this episode since we have a request for it - // Let's check to see if it's wanted first, save an api call - if (epData.status.Equals(SickRageStatus.Wanted, StringComparison.CurrentCultureIgnoreCase)) - { - continue; - } - var epResult = await SickRageApi.SetEpisodeStatus(settings.ApiKey, settings.FullUri, tvdbid, - SickRageStatus.Wanted, seasonRequests.SeasonNumber, epNumber); - - Logger.LogDebug("Set the status to Wanted for Episode {0} in season {1}. The result is '{2}' : '{3}'", seasonRequests.SeasonNumber, epNumber, epResult.result, epResult.message); - } - } - } - return true; - } - - private async Task SearchForRequest(ChildRequests model, IEnumerable sonarrEpList, SonarrSeries existingSeries, SonarrSettings s, - IReadOnlyCollection episodesToUpdate) - { - foreach (var season in model.SeasonRequests) - { - var sonarrSeason = sonarrEpList.Where(x => x.seasonNumber == season.SeasonNumber); - var sonarrEpCount = sonarrSeason.Count(); - var ourRequestCount = season.Episodes.Count; - - if (sonarrEpCount == ourRequestCount) - { - // We have the same amount of requests as all of the episodes in the season. - // Do a season search - await SonarrApi.SeasonSearch(existingSeries.id, season.SeasonNumber, s.ApiKey, s.FullUri); - } - else - { - // There is a miss-match, let's search the episodes indiviaully - await SonarrApi.EpisodeSearch(episodesToUpdate.Select(x => x.id).ToArray(), s.ApiKey, s.FullUri); - } - } - } - - private async Task GetSonarrRootPath(int pathId, SonarrSettings sonarrSettings) - { - var rootFoldersResult = await SonarrApi.GetRootFolders(sonarrSettings.ApiKey, sonarrSettings.FullUri); - - if (pathId == 0) - { - return rootFoldersResult.FirstOrDefault().path; - } - - foreach (var r in rootFoldersResult.Where(r => r.id == pathId)) - { - return r.path; - } - return string.Empty; - } - } +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Ombi.Api.DogNzb; +using Ombi.Api.DogNzb.Models; +using Ombi.Api.SickRage; +using Ombi.Api.SickRage.Models; +using Ombi.Api.Sonarr; +using Ombi.Api.Sonarr.Models; +using Ombi.Core.Settings; +using Ombi.Helpers; +using Ombi.Settings.Settings.Models.External; +using Ombi.Store.Entities.Requests; + +namespace Ombi.Core.Senders +{ + public class TvSender : ITvSender + { + public TvSender(ISonarrApi sonarrApi, ILogger log, ISettingsService sonarrSettings, + ISettingsService dog, IDogNzbApi dogApi, ISettingsService srSettings, + ISickRageApi srApi) + { + SonarrApi = sonarrApi; + Logger = log; + SonarrSettings = sonarrSettings; + DogNzbSettings = dog; + DogNzbApi = dogApi; + SickRageSettings = srSettings; + SickRageApi = srApi; + } + + private ISonarrApi SonarrApi { get; } + private IDogNzbApi DogNzbApi { get; } + private ISickRageApi SickRageApi { get; } + private ILogger Logger { get; } + private ISettingsService SonarrSettings { get; } + private ISettingsService DogNzbSettings { get; } + private ISettingsService SickRageSettings { get; } + + public async Task Send(ChildRequests model) + { + var sonarr = await SonarrSettings.GetSettingsAsync(); + if (sonarr.Enabled) + { + var result = await SendToSonarr(model); + if (result != null) + { + return new SenderResult + { + Sent = true, + Success = true + }; + } + } + var dog = await DogNzbSettings.GetSettingsAsync(); + if (dog.Enabled) + { + var result = await SendToDogNzb(model, dog); + if (!result.Failure) + { + return new SenderResult + { + Sent = true, + Success = true + }; + } + return new SenderResult + { + Message = result.ErrorMessage + }; + } + var sr = await SickRageSettings.GetSettingsAsync(); + if (sr.Enabled) + { + var result = await SendToSickRage(model, sr); + if (result) + { + return new SenderResult + { + Sent = true, + Success = true + }; + } + return new SenderResult + { + Message = "Could not send to SickRage!" + }; + } + return new SenderResult + { + Success = true + }; + } + + private async Task SendToDogNzb(ChildRequests model, DogNzbSettings settings) + { + var id = model.ParentRequest.TvDbId; + return await DogNzbApi.AddTvShow(settings.ApiKey, id.ToString()); + } + + /// + /// Send the request to Sonarr to process + /// + /// + /// + /// This is for any qualities overriden from the UI + /// + public async Task SendToSonarr(ChildRequests model, string qualityId = null) + { + var s = await SonarrSettings.GetSettingsAsync(); + if (!s.Enabled) + { + return null; + } + if (string.IsNullOrEmpty(s.ApiKey)) + { + return null; + } + var qualityProfile = 0; + if (!string.IsNullOrEmpty(qualityId)) // try to parse the passed in quality, otherwise use the settings default quality + { + int.TryParse(qualityId, out qualityProfile); + } + + if (qualityProfile <= 0) + { + int.TryParse(s.QualityProfile, out qualityProfile); + } + + // Get the root path from the rootfolder selected. + // For some reason, if we haven't got one use the first root folder in Sonarr + // TODO make this overrideable via the UI + var rootFolderPath = await GetSonarrRootPath(model.ParentRequest.RootFolder ?? int.Parse(s.RootPath), s); + try + { + // Does the series actually exist? + var allSeries = await SonarrApi.GetSeries(s.ApiKey, s.FullUri); + var existingSeries = allSeries.FirstOrDefault(x => x.tvdbId == model.ParentRequest.TvDbId); + + if (existingSeries == null) + { + // Time to add a new one + var newSeries = new NewSeries + { + title = model.ParentRequest.Title, + imdbId = model.ParentRequest.ImdbId, + tvdbId = model.ParentRequest.TvDbId, + cleanTitle = model.ParentRequest.Title, + monitored = true, + seasonFolder = s.SeasonFolders, + rootFolderPath = rootFolderPath, + qualityProfileId = qualityProfile, + titleSlug = model.ParentRequest.Title, + addOptions = new AddOptions + { + ignoreEpisodesWithFiles = true, // There shouldn't be any episodes with files, this is a new season + ignoreEpisodesWithoutFiles = true, // We want all missing + searchForMissingEpisodes = false // we want dont want to search yet. We want to make sure everything is unmonitored/monitored correctly. + } + }; + + // Montitor the correct seasons, + // If we have that season in the model then it's monitored! + var seasonsToAdd = new List(); + for (var i = 1; i < model.ParentRequest.TotalSeasons + 1; i++) + { + var index = i; + var season = new Season + { + seasonNumber = i, + monitored = model.SeasonRequests.Any(x => x.SeasonNumber == index) + }; + seasonsToAdd.Add(season); + } + newSeries.seasons = seasonsToAdd; + var result = await SonarrApi.AddSeries(newSeries, s.ApiKey, s.FullUri); + existingSeries = await SonarrApi.GetSeriesById(result.id, s.ApiKey, s.FullUri); + await SendToSonarr(model, existingSeries, s); + } + else + { + await SendToSonarr(model, existingSeries, s); + } + + return new NewSeries + { + id = existingSeries.id, + seasons = existingSeries.seasons.ToList(), + cleanTitle = existingSeries.cleanTitle, + title = existingSeries.title, + tvdbId = existingSeries.tvdbId + }; + } + catch (Exception e) + { + Logger.LogError(LoggingEvents.SonarrSender, e, "Exception thrown when attempting to send series over to Sonarr"); + throw; + } + } + + private async Task SendToSonarr(ChildRequests model, SonarrSeries result, SonarrSettings s) + { + var episodesToUpdate = new List(); + // Ok, now let's sort out the episodes. + + if (model.SeriesType == SeriesType.Anime) + { + result.seriesType = "anime"; + await SonarrApi.UpdateSeries(result, s.ApiKey, s.FullUri); + } + + var sonarrEpisodes = await SonarrApi.GetEpisodes(result.id, s.ApiKey, s.FullUri); + var sonarrEpList = sonarrEpisodes.ToList() ?? new List(); + while (!sonarrEpList.Any()) + { + // It could be that the series metadata is not ready yet. So wait + sonarrEpList = (await SonarrApi.GetEpisodes(result.id, s.ApiKey, s.FullUri)).ToList(); + await Task.Delay(500); + } + + + foreach (var req in model.SeasonRequests) + { + foreach (var ep in req.Episodes) + { + var sonarrEp = sonarrEpList.FirstOrDefault(x => + x.episodeNumber == ep.EpisodeNumber && x.seasonNumber == req.SeasonNumber); + if (sonarrEp != null) + { + sonarrEp.monitored = true; + episodesToUpdate.Add(sonarrEp); + } + } + } + var seriesChanges = false; + foreach (var season in model.SeasonRequests) + { + var sonarrSeason = sonarrEpList.Where(x => x.seasonNumber == season.SeasonNumber); + var sonarrEpCount = sonarrSeason.Count(); + var ourRequestCount = season.Episodes.Count; + + if (sonarrEpCount == ourRequestCount) + { + // We have the same amount of requests as all of the episodes in the season. + var existingSeason = + result.seasons.First(x => x.seasonNumber == season.SeasonNumber); + existingSeason.monitored = true; + seriesChanges = true; + } + else + { + // Now update the episodes that need updating + foreach (var epToUpdate in episodesToUpdate.Where(x => x.seasonNumber == season.SeasonNumber)) + { + await SonarrApi.UpdateEpisode(epToUpdate, s.ApiKey, s.FullUri); + } + } + } + if (seriesChanges) + { + await SonarrApi.SeasonPass(s.ApiKey, s.FullUri, result); + } + + + if (!s.AddOnly) + { + await SearchForRequest(model, sonarrEpList, result, s, episodesToUpdate); + } + } + + private async Task SendToSickRage(ChildRequests model, SickRageSettings settings, string qualityId = null) + { + var tvdbid = model.ParentRequest.TvDbId; + if (qualityId.HasValue()) + { + var id = qualityId; + if (settings.Qualities.All(x => x.Value != id)) + { + qualityId = settings.QualityProfile; + } + } + else + { + qualityId = settings.QualityProfile; + } + // Check if the show exists + var existingShow = await SickRageApi.GetShow(tvdbid, settings.ApiKey, settings.FullUri); + + if (existingShow.message.Equals("Show not found", StringComparison.CurrentCultureIgnoreCase)) + { + var addResult = await SickRageApi.AddSeries(model.ParentRequest.TvDbId, qualityId, SickRageStatus.Ignored, + settings.ApiKey, settings.FullUri); + + Logger.LogDebug("Added the show (tvdbid) {0}. The result is '{2}' : '{3}'", tvdbid, addResult.result, addResult.message); + if (addResult.result.Equals("failure") || addResult.result.Equals("fatal")) + { + // Do something + return false; + } + } + + foreach (var seasonRequests in model.SeasonRequests) + { + var srEpisodes = await SickRageApi.GetEpisodesForSeason(tvdbid, seasonRequests.SeasonNumber, settings.ApiKey, settings.FullUri); + while (srEpisodes.message.Equals("Show not found", StringComparison.CurrentCultureIgnoreCase) && srEpisodes.data.Count <= 0) + { + await Task.Delay(TimeSpan.FromSeconds(1)); + srEpisodes = await SickRageApi.GetEpisodesForSeason(tvdbid, seasonRequests.SeasonNumber, settings.ApiKey, settings.FullUri); + } + + var totalSrEpisodes = srEpisodes.data.Count; + + if (totalSrEpisodes == seasonRequests.Episodes.Count) + { + // This is a request for the whole season + var wholeSeasonResult = await SickRageApi.SetEpisodeStatus(settings.ApiKey, settings.FullUri, tvdbid, SickRageStatus.Wanted, + seasonRequests.SeasonNumber); + + Logger.LogDebug("Set the status to Wanted for season {0}. The result is '{1}' : '{2}'", seasonRequests.SeasonNumber, wholeSeasonResult.result, wholeSeasonResult.message); + continue; + } + + foreach (var srEp in srEpisodes.data) + { + var epNumber = srEp.Key; + var epData = srEp.Value; + + var epRequest = seasonRequests.Episodes.FirstOrDefault(x => x.EpisodeNumber == epNumber); + if (epRequest != null) + { + // We want to monior this episode since we have a request for it + // Let's check to see if it's wanted first, save an api call + if (epData.status.Equals(SickRageStatus.Wanted, StringComparison.CurrentCultureIgnoreCase)) + { + continue; + } + var epResult = await SickRageApi.SetEpisodeStatus(settings.ApiKey, settings.FullUri, tvdbid, + SickRageStatus.Wanted, seasonRequests.SeasonNumber, epNumber); + + Logger.LogDebug("Set the status to Wanted for Episode {0} in season {1}. The result is '{2}' : '{3}'", seasonRequests.SeasonNumber, epNumber, epResult.result, epResult.message); + } + } + } + return true; + } + + private async Task SearchForRequest(ChildRequests model, IEnumerable sonarrEpList, SonarrSeries existingSeries, SonarrSettings s, + IReadOnlyCollection episodesToUpdate) + { + foreach (var season in model.SeasonRequests) + { + var sonarrSeason = sonarrEpList.Where(x => x.seasonNumber == season.SeasonNumber); + var sonarrEpCount = sonarrSeason.Count(); + var ourRequestCount = season.Episodes.Count; + + if (sonarrEpCount == ourRequestCount) + { + // We have the same amount of requests as all of the episodes in the season. + // Do a season search + await SonarrApi.SeasonSearch(existingSeries.id, season.SeasonNumber, s.ApiKey, s.FullUri); + } + else + { + // There is a miss-match, let's search the episodes indiviaully + await SonarrApi.EpisodeSearch(episodesToUpdate.Select(x => x.id).ToArray(), s.ApiKey, s.FullUri); + } + } + } + + private async Task GetSonarrRootPath(int pathId, SonarrSettings sonarrSettings) + { + var rootFoldersResult = await SonarrApi.GetRootFolders(sonarrSettings.ApiKey, sonarrSettings.FullUri); + + if (pathId == 0) + { + return rootFoldersResult.FirstOrDefault().path; + } + + foreach (var r in rootFoldersResult.Where(r => r.id == pathId)) + { + return r.path; + } + return string.Empty; + } + } } \ No newline at end of file diff --git a/src/Ombi.Notifications/Agents/DiscordNotification.cs b/src/Ombi.Notifications/Agents/DiscordNotification.cs index 8d0f70630..918c49940 100644 --- a/src/Ombi.Notifications/Agents/DiscordNotification.cs +++ b/src/Ombi.Notifications/Agents/DiscordNotification.cs @@ -18,7 +18,10 @@ namespace Ombi.Notifications.Agents { public class DiscordNotification : BaseNotification, IDiscordNotification { - public DiscordNotification(IDiscordApi api, ISettingsService sn, ILogger log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t, ISettingsService s) : base(sn, r, m, t,s) + public DiscordNotification(IDiscordApi api, ISettingsService sn, + ILogger log, INotificationTemplatesRepository r, + IMovieRequestRepository m, ITvRequestRepository t, ISettingsService s) + : base(sn, r, m, t,s,log) { Api = api; Logger = log; diff --git a/src/Ombi.Notifications/Agents/EmailNotification.cs b/src/Ombi.Notifications/Agents/EmailNotification.cs index 52dfb47ac..9ca2f3470 100644 --- a/src/Ombi.Notifications/Agents/EmailNotification.cs +++ b/src/Ombi.Notifications/Agents/EmailNotification.cs @@ -19,7 +19,7 @@ namespace Ombi.Notifications.Agents public class EmailNotification : BaseNotification, IEmailNotification { public EmailNotification(ISettingsService settings, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t, IEmailProvider prov, ISettingsService c, - ILogger log) : base(settings, r, m, t, c) + ILogger log) : base(settings, r, m, t, c,log) { EmailProvider = prov; Logger = log; diff --git a/src/Ombi.Notifications/Agents/MattermostNotification.cs b/src/Ombi.Notifications/Agents/MattermostNotification.cs index 850c78ae7..5b55c95d5 100644 --- a/src/Ombi.Notifications/Agents/MattermostNotification.cs +++ b/src/Ombi.Notifications/Agents/MattermostNotification.cs @@ -21,7 +21,7 @@ namespace Ombi.Notifications.Agents public class MattermostNotification : BaseNotification, IMattermostNotification { public MattermostNotification(IMattermostApi api, ISettingsService sn, ILogger log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t, - ISettingsService s) : base(sn, r, m, t,s) + ISettingsService s) : base(sn, r, m, t,s,log) { Api = api; Logger = log; diff --git a/src/Ombi.Notifications/Agents/MobileNotification.cs b/src/Ombi.Notifications/Agents/MobileNotification.cs index 79272c1aa..fb84fe57f 100644 --- a/src/Ombi.Notifications/Agents/MobileNotification.cs +++ b/src/Ombi.Notifications/Agents/MobileNotification.cs @@ -22,7 +22,7 @@ namespace Ombi.Notifications.Agents { public MobileNotification(IOneSignalApi api, ISettingsService sn, ILogger log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t, ISettingsService s, IRepository notification, - UserManager um) : base(sn, r, m, t, s) + UserManager um) : base(sn, r, m, t, s,log) { _api = api; _logger = log; diff --git a/src/Ombi.Notifications/Agents/PushbulletNotification.cs b/src/Ombi.Notifications/Agents/PushbulletNotification.cs index d6f99a8de..11e69563a 100644 --- a/src/Ombi.Notifications/Agents/PushbulletNotification.cs +++ b/src/Ombi.Notifications/Agents/PushbulletNotification.cs @@ -17,7 +17,7 @@ namespace Ombi.Notifications.Agents public class PushbulletNotification : BaseNotification, IPushbulletNotification { public PushbulletNotification(IPushbulletApi api, ISettingsService sn, ILogger log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t, - ISettingsService s) : base(sn, r, m, t,s) + ISettingsService s) : base(sn, r, m, t,s,log) { Api = api; Logger = log; diff --git a/src/Ombi.Notifications/Agents/PushoverNotification.cs b/src/Ombi.Notifications/Agents/PushoverNotification.cs index eb3134817..ae1a860a9 100644 --- a/src/Ombi.Notifications/Agents/PushoverNotification.cs +++ b/src/Ombi.Notifications/Agents/PushoverNotification.cs @@ -17,8 +17,8 @@ namespace Ombi.Notifications.Agents { public class PushoverNotification : BaseNotification, IPushoverNotification { - public PushoverNotification(IPushoverApi api, ISettingsService sn, ILogger log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t, - ISettingsService s) : base(sn, r, m, t, s) + public PushoverNotification(IPushoverApi api, ISettingsService sn, ILogger log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t, + ISettingsService s) : base(sn, r, m, t, s, log) { Api = api; Logger = log; @@ -27,7 +27,7 @@ namespace Ombi.Notifications.Agents public override string NotificationName => "PushoverNotification"; private IPushoverApi Api { get; } - private ILogger Logger { get; } + private ILogger Logger { get; } protected override bool ValidateConfiguration(PushoverSettings settings) { diff --git a/src/Ombi.Notifications/Agents/SlackNotification.cs b/src/Ombi.Notifications/Agents/SlackNotification.cs index 66705dc97..1cb41e1a4 100644 --- a/src/Ombi.Notifications/Agents/SlackNotification.cs +++ b/src/Ombi.Notifications/Agents/SlackNotification.cs @@ -18,7 +18,7 @@ namespace Ombi.Notifications.Agents public class SlackNotification : BaseNotification, ISlackNotification { public SlackNotification(ISlackApi api, ISettingsService sn, ILogger log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t, - ISettingsService s) : base(sn, r, m, t, s) + ISettingsService s) : base(sn, r, m, t, s, log) { Api = api; Logger = log; diff --git a/src/Ombi.Notifications/Agents/TelegramNotification.cs b/src/Ombi.Notifications/Agents/TelegramNotification.cs index 6f4207296..1ccc0f0eb 100644 --- a/src/Ombi.Notifications/Agents/TelegramNotification.cs +++ b/src/Ombi.Notifications/Agents/TelegramNotification.cs @@ -16,7 +16,9 @@ namespace Ombi.Notifications.Agents { public class TelegramNotification : BaseNotification, ITelegramNotification { - public TelegramNotification(ITelegramApi api, ISettingsService sn, ILogger log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t, ISettingsService s) : base(sn, r, m, t,s) + public TelegramNotification(ITelegramApi api, ISettingsService sn, ILogger log, + INotificationTemplatesRepository r, IMovieRequestRepository m, + ITvRequestRepository t, ISettingsService s) : base(sn, r, m, t,s,log) { Api = api; Logger = log; diff --git a/src/Ombi.Notifications/Interfaces/BaseNotification.cs b/src/Ombi.Notifications/Interfaces/BaseNotification.cs index 411936f72..be07e36c5 100644 --- a/src/Ombi.Notifications/Interfaces/BaseNotification.cs +++ b/src/Ombi.Notifications/Interfaces/BaseNotification.cs @@ -1,6 +1,7 @@ using System; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; using Ombi.Core.Settings; using Ombi.Helpers; using Ombi.Notifications.Exceptions; @@ -16,7 +17,7 @@ namespace Ombi.Notifications.Interfaces public abstract class BaseNotification : INotification where T : Settings.Settings.Models.Settings, new() { protected BaseNotification(ISettingsService settings, INotificationTemplatesRepository templateRepo, IMovieRequestRepository movie, ITvRequestRepository tv, - ISettingsService customization) + ISettingsService customization, ILogger> log) { Settings = settings; TemplateRepository = templateRepo; @@ -25,6 +26,7 @@ namespace Ombi.Notifications.Interfaces CustomizationSettings = customization; Settings.ClearCache(); CustomizationSettings.ClearCache(); + _log = log; } protected ISettingsService Settings { get; } @@ -33,6 +35,7 @@ namespace Ombi.Notifications.Interfaces protected ITvRequestRepository TvRepository { get; } protected CustomizationSettings Customization { get; set; } private ISettingsService CustomizationSettings { get; } + private readonly ILogger> _log; protected ChildRequests TvRequest { get; set; } @@ -159,10 +162,13 @@ namespace Ombi.Notifications.Interfaces var curlys = new NotificationMessageCurlys(); if (model.RequestType == RequestType.Movie) { + _log.LogDebug("Notification options: {@model}, Req: {@MovieRequest}, Settings: {@Customization}", model, MovieRequest, Customization); + curlys.Setup(model, MovieRequest, Customization); } else { + _log.LogDebug("Notification options: {@model}, Req: {@TvRequest}, Settings: {@Customization}", model, TvRequest, Customization); curlys.Setup(model, TvRequest, Customization); } var parsed = resolver.ParseMessage(template, curlys); diff --git a/src/Ombi.Notifications/NotificationMessageCurlys.cs b/src/Ombi.Notifications/NotificationMessageCurlys.cs index 251f7162d..94a345261 100644 --- a/src/Ombi.Notifications/NotificationMessageCurlys.cs +++ b/src/Ombi.Notifications/NotificationMessageCurlys.cs @@ -11,16 +11,8 @@ namespace Ombi.Notifications { public class NotificationMessageCurlys { - public NotificationMessageCurlys(ILogger log) - { - _log = log; - } - - private readonly ILogger _log; - public void Setup(NotificationOptions opts, FullBaseRequest req, CustomizationSettings s) { - _log.LogDebug("Notification options: {@Opts}, Req: {@Req}, Settings: {@S}", opts, req, s); ApplicationUrl = (s?.ApplicationUrl.HasValue() ?? false) ? s.ApplicationUrl : string.Empty; ApplicationName = string.IsNullOrEmpty(s?.ApplicationName) ? "Ombi" : s?.ApplicationName; RequestedUser = string.IsNullOrEmpty(req.RequestedUser.Alias) @@ -39,8 +31,7 @@ namespace Ombi.Notifications public void Setup(NotificationOptions opts, ChildRequests req, CustomizationSettings s) { - _log.LogDebug("Notification options: {@Opts}, Req: {@Req}, Settings: {@S}", opts, req, s); - ApplicationUrl = (s?.ApplicationUrl.HasValue() ?? false) ? s.ApplicationUrl : string.Empty; + ApplicationUrl = (s?.ApplicationUrl.HasValue() ?? false) ? s.ApplicationUrl : string.Empty; ApplicationName = string.IsNullOrEmpty(s?.ApplicationName) ? "Ombi" : s?.ApplicationName; RequestedUser = string.IsNullOrEmpty(req.RequestedUser.Alias) ? req.RequestedUser.UserName diff --git a/src/Ombi.Schedule/Jobs/Plex/PlexAvailabilityChecker.cs b/src/Ombi.Schedule/Jobs/Plex/PlexAvailabilityChecker.cs index 7a58345f1..c6b876c21 100644 --- a/src/Ombi.Schedule/Jobs/Plex/PlexAvailabilityChecker.cs +++ b/src/Ombi.Schedule/Jobs/Plex/PlexAvailabilityChecker.cs @@ -1,167 +1,167 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Hangfire; -using Microsoft.EntityFrameworkCore; -using Ombi.Core.Notifications; -using Ombi.Helpers; -using Ombi.Notifications.Models; -using Ombi.Store.Entities; -using Ombi.Store.Repository; -using Ombi.Store.Repository.Requests; - -namespace Ombi.Schedule.Jobs.Plex -{ - public class PlexAvailabilityChecker : IPlexAvailabilityChecker - { - public PlexAvailabilityChecker(IPlexContentRepository repo, ITvRequestRepository tvRequest, IMovieRequestRepository movies, - INotificationService notification, IBackgroundJobClient background) - { - _tvRepo = tvRequest; - _repo = repo; - _movieRepo = movies; - _notificationService = notification; - _backgroundJobClient = background; - } - - private readonly ITvRequestRepository _tvRepo; - private readonly IMovieRequestRepository _movieRepo; - private readonly IPlexContentRepository _repo; - private readonly INotificationService _notificationService; - private readonly IBackgroundJobClient _backgroundJobClient; - - public async Task Start() - { - await ProcessMovies(); - await ProcessTv(); - } - - private async Task ProcessTv() - { - var tv = _tvRepo.GetChild().Where(x => !x.Available); - var plexEpisodes = _repo.GetAllEpisodes().Include(x => x.Series); - - foreach (var child in tv) - { - var useImdb = false; - var useTvDb = false; - if (child.ParentRequest.ImdbId.HasValue()) - { - useImdb = true; - } - - if (child.ParentRequest.TvDbId.ToString().HasValue()) - { - useTvDb = true; - } - - var tvDbId = child.ParentRequest.TvDbId; - var imdbId = child.ParentRequest.ImdbId; - IQueryable seriesEpisodes = null; - if (useImdb) - { - seriesEpisodes = plexEpisodes.Where(x => x.Series.ImdbId == imdbId.ToString()); - } - if (useTvDb) - { - seriesEpisodes = plexEpisodes.Where(x => x.Series.TvDbId == tvDbId.ToString()); - } - foreach (var season in child.SeasonRequests) - { - foreach (var episode in season.Episodes) - { - var foundEp = await seriesEpisodes.FirstOrDefaultAsync( - x => x.EpisodeNumber == episode.EpisodeNumber && - x.SeasonNumber == episode.Season.SeasonNumber); - - if (foundEp != null) - { - episode.Available = true; - } - } - } - - // Check to see if all of the episodes in all seasons are available for this request - var allAvailable = child.SeasonRequests.All(x => x.Episodes.All(c => c.Available)); - if (allAvailable) - { - // We have fulfulled this request! - child.Available = true; - _backgroundJobClient.Enqueue(() => _notificationService.Publish(new NotificationOptions - { - DateTime = DateTime.Now, - NotificationType = NotificationType.RequestAvailable, - RequestId = child.ParentRequestId, - RequestType = RequestType.TvShow, - Recipient = child.RequestedUser.Email - })); - } - } - - await _tvRepo.Save(); - } - - private async Task ProcessMovies() - { - // Get all non available - var movies = _movieRepo.GetAll().Include(x => x.RequestedUser).Where(x => !x.Available); - - foreach (var movie in movies) - { - PlexServerContent item = null; - if (movie.ImdbId.HasValue()) - { - item = await _repo.Get(movie.ImdbId); - } - if (item == null) - { - if (movie.TheMovieDbId.ToString().HasValue()) - { - item = await _repo.Get(movie.TheMovieDbId.ToString()); - } - } - if (item == null) - { - // We don't yet have this - continue; - } - - movie.Available = true; - if (movie.Available) - { - _backgroundJobClient.Enqueue(() => _notificationService.Publish(new NotificationOptions - { - DateTime = DateTime.Now, - NotificationType = NotificationType.RequestAvailable, - RequestId = movie.Id, - RequestType = RequestType.Movie, - Recipient = movie.RequestedUser != null ? movie.RequestedUser.Email : string.Empty - })); - } - } - - await _movieRepo.Save(); - } - - private bool _disposed; - protected virtual void Dispose(bool disposing) - { - if (_disposed) - return; - - if (disposing) - { - _movieRepo?.Dispose(); - _repo?.Dispose(); - } - _disposed = true; - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - } +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Hangfire; +using Microsoft.EntityFrameworkCore; +using Ombi.Core.Notifications; +using Ombi.Helpers; +using Ombi.Notifications.Models; +using Ombi.Store.Entities; +using Ombi.Store.Repository; +using Ombi.Store.Repository.Requests; + +namespace Ombi.Schedule.Jobs.Plex +{ + public class PlexAvailabilityChecker : IPlexAvailabilityChecker + { + public PlexAvailabilityChecker(IPlexContentRepository repo, ITvRequestRepository tvRequest, IMovieRequestRepository movies, + INotificationService notification, IBackgroundJobClient background) + { + _tvRepo = tvRequest; + _repo = repo; + _movieRepo = movies; + _notificationService = notification; + _backgroundJobClient = background; + } + + private readonly ITvRequestRepository _tvRepo; + private readonly IMovieRequestRepository _movieRepo; + private readonly IPlexContentRepository _repo; + private readonly INotificationService _notificationService; + private readonly IBackgroundJobClient _backgroundJobClient; + + public async Task Start() + { + await ProcessMovies(); + await ProcessTv(); + } + + private async Task ProcessTv() + { + var tv = _tvRepo.GetChild().Where(x => !x.Available); + var plexEpisodes = _repo.GetAllEpisodes().Include(x => x.Series); + + foreach (var child in tv) + { + var useImdb = false; + var useTvDb = false; + if (child.ParentRequest.ImdbId.HasValue()) + { + useImdb = true; + } + + if (child.ParentRequest.TvDbId.ToString().HasValue()) + { + useTvDb = true; + } + + var tvDbId = child.ParentRequest.TvDbId; + var imdbId = child.ParentRequest.ImdbId; + IQueryable seriesEpisodes = null; + if (useImdb) + { + seriesEpisodes = plexEpisodes.Where(x => x.Series.ImdbId == imdbId.ToString()); + } + if (useTvDb) + { + seriesEpisodes = plexEpisodes.Where(x => x.Series.TvDbId == tvDbId.ToString()); + } + foreach (var season in child.SeasonRequests) + { + foreach (var episode in season.Episodes) + { + var foundEp = await seriesEpisodes.FirstOrDefaultAsync( + x => x.EpisodeNumber == episode.EpisodeNumber && + x.SeasonNumber == episode.Season.SeasonNumber); + + if (foundEp != null) + { + episode.Available = true; + } + } + } + + // Check to see if all of the episodes in all seasons are available for this request + var allAvailable = child.SeasonRequests.All(x => x.Episodes.All(c => c.Available)); + if (allAvailable) + { + // We have fulfulled this request! + child.Available = true; + _backgroundJobClient.Enqueue(() => _notificationService.Publish(new NotificationOptions + { + DateTime = DateTime.Now, + NotificationType = NotificationType.RequestAvailable, + RequestId = child.ParentRequestId, + RequestType = RequestType.TvShow, + Recipient = child.RequestedUser.Email + })); + } + } + + await _tvRepo.Save(); + } + + private async Task ProcessMovies() + { + // Get all non available + var movies = _movieRepo.GetAll().Include(x => x.RequestedUser).Where(x => !x.Available); + + foreach (var movie in movies) + { + PlexServerContent item = null; + if (movie.ImdbId.HasValue()) + { + item = await _repo.Get(movie.ImdbId); + } + if (item == null) + { + if (movie.TheMovieDbId.ToString().HasValue()) + { + item = await _repo.Get(movie.TheMovieDbId.ToString()); + } + } + if (item == null) + { + // We don't yet have this + continue; + } + + movie.Available = true; + if (movie.Available) + { + _backgroundJobClient.Enqueue(() => _notificationService.Publish(new NotificationOptions + { + DateTime = DateTime.Now, + NotificationType = NotificationType.RequestAvailable, + RequestId = movie.Id, + RequestType = RequestType.Movie, + Recipient = movie.RequestedUser != null ? movie.RequestedUser.Email : string.Empty + })); + } + } + + await _movieRepo.Save(); + } + + private bool _disposed; + protected virtual void Dispose(bool disposing) + { + if (_disposed) + return; + + if (disposing) + { + _movieRepo?.Dispose(); + _repo?.Dispose(); + } + _disposed = true; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + } } \ No newline at end of file