From a1ee52daefd973554e8b6a41b6b089e93358ca5f Mon Sep 17 00:00:00 2001 From: Jamie Date: Mon, 27 Nov 2017 14:43:09 +0000 Subject: [PATCH] Sickrage done. Ish... So i've written all the code by looking at the API. the key there is i've looked at the api. I have not tested anything so expect this to fail. --- src/Ombi.Api.SickRage/ISickRageApi.cs | 6 +- src/Ombi.Api.SickRage/Models/SeasonList.cs | 9 + .../Models/SickRageEpisodesData.cs | 18 + .../Models/SickRageShowInformation.cs | 41 ++ src/Ombi.Api.SickRage/SickRageApi.cs | 81 +-- src/Ombi.Core/Senders/TvSender.cs | 669 ++++++++++-------- src/Ombi.Helpers/LoggingEvents.cs | 1 + src/Ombi.Schedule/JobSetup.cs | 5 +- .../Jobs/SickRage/ISickRageSync.cs | 9 + .../Jobs/SickRage/SickRageSync.cs | 92 +++ src/Ombi.Schedule/Ombi.Schedule.csproj | 1 + .../Models/External/SickRageSettings.cs | 40 +- .../Settings/Models/JobSettings.cs | 1 + .../Settings/Models/JobSettingsHelper.cs | 4 + src/Ombi.Store/Context/IOmbiContext.cs | 2 + src/Ombi.Store/Context/OmbiContext.cs | 2 + src/Ombi.Store/Entities/SickRageCache.cs | 10 + .../Entities/SickRageEpisodeCache.cs | 12 + src/Ombi/ClientApp/app/interfaces/ICommon.ts | 4 - .../ClientApp/app/interfaces/ISettings.ts | 10 +- .../app/settings/jobs/jobs.component.html | 5 + .../app/settings/jobs/jobs.component.ts | 3 +- .../app/settings/settingsmenu.component.html | 4 +- .../settings/sickrage/sickrage.component.html | 2 +- .../settings/sickrage/sickrage.component.ts | 15 +- .../Controllers/External/TesterController.cs | 115 ++- 26 files changed, 731 insertions(+), 430 deletions(-) create mode 100644 src/Ombi.Api.SickRage/Models/SeasonList.cs create mode 100644 src/Ombi.Api.SickRage/Models/SickRageEpisodesData.cs create mode 100644 src/Ombi.Api.SickRage/Models/SickRageShowInformation.cs create mode 100644 src/Ombi.Schedule/Jobs/SickRage/ISickRageSync.cs create mode 100644 src/Ombi.Schedule/Jobs/SickRage/SickRageSync.cs create mode 100644 src/Ombi.Store/Entities/SickRageCache.cs create mode 100644 src/Ombi.Store/Entities/SickRageEpisodeCache.cs diff --git a/src/Ombi.Api.SickRage/ISickRageApi.cs b/src/Ombi.Api.SickRage/ISickRageApi.cs index 55bd0222a..1b33344fe 100644 --- a/src/Ombi.Api.SickRage/ISickRageApi.cs +++ b/src/Ombi.Api.SickRage/ISickRageApi.cs @@ -6,12 +6,14 @@ namespace Ombi.Api.SickRage public interface ISickRageApi { Task AddSeason(int tvdbId, int season, string apiKey, string baseUrl); - Task AddSeries(int tvdbId, int seasonCount, int[] seasons, string quality, string apiKey, string baseUrl); + Task AddSeries(int tvdbId, string quality, string status, string apiKey, string baseUrl); Task GetShows(string apiKey, string baseUrl); Task Ping(string apiKey, string baseUrl); Task VerifyShowHasLoaded(int tvdbId, string apiKey, string baseUrl); - + Task GetShow(int tvdbid, string apikey, string baseUrl); Task SetEpisodeStatus(string apiKey, string baseUrl, int tvdbid, string status, int season, int episode = -1); + Task GetEpisodesForSeason(int tvdbid, int season, string apikey, string baseUrl); + Task GetSeasonList(int tvdbId, string apikey, string baseurl); } } \ No newline at end of file diff --git a/src/Ombi.Api.SickRage/Models/SeasonList.cs b/src/Ombi.Api.SickRage/Models/SeasonList.cs new file mode 100644 index 000000000..30e4990b6 --- /dev/null +++ b/src/Ombi.Api.SickRage/Models/SeasonList.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace Ombi.Api.SickRage.Models +{ + public class SeasonList : SickRageBase> + { + + } +} \ No newline at end of file diff --git a/src/Ombi.Api.SickRage/Models/SickRageEpisodesData.cs b/src/Ombi.Api.SickRage/Models/SickRageEpisodesData.cs new file mode 100644 index 000000000..7cb81459e --- /dev/null +++ b/src/Ombi.Api.SickRage/Models/SickRageEpisodesData.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; + +namespace Ombi.Api.SickRage.Models +{ + public class SickRageEpisodes : SickRageBase> + { + + } + + public class SickRageEpisodesData + { + public string airdate { get; set; } + public string name { get; set; } + public string quality { get; set; } + public string status { get; set; } + } + +} \ No newline at end of file diff --git a/src/Ombi.Api.SickRage/Models/SickRageShowInformation.cs b/src/Ombi.Api.SickRage/Models/SickRageShowInformation.cs new file mode 100644 index 000000000..57c4411d1 --- /dev/null +++ b/src/Ombi.Api.SickRage/Models/SickRageShowInformation.cs @@ -0,0 +1,41 @@ +namespace Ombi.Api.SickRage.Models +{ + public class SickRageShowInformation : SickRageBase + { + + } + + public class SickRageShowInformationData + { + public int air_by_date { get; set; } + public string airs { get; set; } + public Cache cache { get; set; } + public int flatten_folders { get; set; } + public string[] genre { get; set; } + public string language { get; set; } + public string location { get; set; } + public string network { get; set; } + public string next_ep_airdate { get; set; } + public int paused { get; set; } + public string quality { get; set; } + public Quality_Details quality_details { get; set; } + public int[] season_list { get; set; } + public string show_name { get; set; } + public string status { get; set; } + public int tvrage_id { get; set; } + public string tvrage_name { get; set; } + } + + public class Cache + { + public int banner { get; set; } + public int poster { get; set; } + } + + public class Quality_Details + { + public object[] archive { get; set; } + public string[] initial { get; set; } + } + +} \ No newline at end of file diff --git a/src/Ombi.Api.SickRage/SickRageApi.cs b/src/Ombi.Api.SickRage/SickRageApi.cs index e178479b8..2bebb4989 100644 --- a/src/Ombi.Api.SickRage/SickRageApi.cs +++ b/src/Ombi.Api.SickRage/SickRageApi.cs @@ -1,6 +1,4 @@ using System; -using System.Diagnostics; -using System.Linq; using System.Net.Http; using System.Threading.Tasks; using Microsoft.Extensions.Logging; @@ -27,15 +25,12 @@ namespace Ombi.Api.SickRage return await _api.Request(request); } - public async Task AddSeries(int tvdbId, int seasonCount, int[] seasons, string quality, string apiKey, string baseUrl) + public async Task AddSeries(int tvdbId, string quality, string status, string apiKey, string baseUrl) { - var futureStatus = seasons.Length > 0 && seasons.All(x => x != seasonCount) ? SickRageStatus.Skipped : SickRageStatus.Wanted; - var status = seasons.Length > 0 ? SickRageStatus.Skipped : SickRageStatus.Wanted; var request = new Request($"/api/{apiKey}/?cmd=show.addnew", baseUrl, HttpMethod.Get); request.AddQueryString("tvdbid", tvdbId.ToString()); request.AddQueryString("status", status); - request.AddQueryString("future_status", futureStatus); if (!quality.Equals("default", StringComparison.CurrentCultureIgnoreCase)) { @@ -44,55 +39,6 @@ namespace Ombi.Api.SickRage var obj = await _api.Request(request); - if (obj.result != "failure") - { - var sw = new Stopwatch(); - sw.Start(); - - var seasonIncrement = 0; - try - { - while (seasonIncrement < seasonCount) - { - var seasonList = await VerifyShowHasLoaded(tvdbId, apiKey, baseUrl); - if (seasonList.result.Equals("failure")) - { - await Task.Delay(3000); - continue; - } - seasonIncrement = seasonList.Data?.Length ?? 0; - - if (sw.ElapsedMilliseconds > 30000) // Break out after 30 seconds, it's not going to get added - { - _log.LogWarning("Couldn't find out if the show had been added after 10 seconds. I doubt we can change the status to wanted."); - break; - } - } - sw.Stop(); - } - catch (Exception e) - { - _log.LogCritical(e, "Exception thrown when getting the seasonList"); - } - } - - try - { - if (seasons.Length > 0) - { - //handle the seasons requested - foreach (var s in seasons) - { - var result = await AddSeason(tvdbId, s, apiKey, baseUrl); - } - } - } - catch (Exception e) - { - _log.LogCritical(e, "Exception when adding seasons:"); - throw; - } - return obj; } @@ -113,6 +59,23 @@ namespace Ombi.Api.SickRage return await _api.Request(request); } + public async Task GetShow(int tvdbid, string apikey, string baseUrl) + { + var request = new Request($"/api/{apikey}/?cmd=show", baseUrl, HttpMethod.Get); + request.AddQueryString("tvdbid", tvdbid.ToString()); + + return await _api.Request(request); + } + + public async Task GetEpisodesForSeason(int tvdbid, int season, string apikey, string baseUrl) + { + var request = new Request($"/api/{apikey}/?cmd=show.seasons", baseUrl, HttpMethod.Get); + request.AddQueryString("tvdbid", tvdbid.ToString()); + request.AddQueryString("season", season.ToString()); + + return await _api.Request(request); + } + public async Task Ping(string apiKey, string baseUrl) { var request = new Request($"/api/{apiKey}/?cmd=sb.ping", baseUrl, HttpMethod.Get); @@ -139,5 +102,13 @@ namespace Ombi.Api.SickRage return await _api.Request(request); } + + public async Task GetSeasonList(int tvdbId, string apikey, string baseurl) + { + var request = new Request($"/api/{apikey}/?cmd=show.seasonlist", baseurl, HttpMethod.Get); + request.AddQueryString("tvdbid", tvdbId.ToString()); + + return await _api.Request(request); + } } } diff --git a/src/Ombi.Core/Senders/TvSender.cs b/src/Ombi.Core/Senders/TvSender.cs index 0275656cf..e839e2a5b 100644 --- a/src/Ombi.Core/Senders/TvSender.cs +++ b/src/Ombi.Core/Senders/TvSender.cs @@ -1,308 +1,363 @@ -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.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 - }; - } - 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. - - 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); - } - } - - public async Task SendToSickRage(ChildRequests model, string qualityId = null) - { - var settings = await SickRageSettings.GetSettingsAsync(); - if (qualityId.HasValue()) - { - if (settings.Qualities.All(x => x.Key != qualityId)) - { - qualityId = settings.QualityProfile; - } - } - - //var apiResult = SickRageApi.AddSeries(model.ParentRequest.TvDbId, model.SeasonCount, model.SeasonList, qualityId, - // sickRageSettings.ApiKey, sickRageSettings.FullUri); - - //var result = apiResult.Result; - - - //return result; - } - - 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(); + } + 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. + + 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; } } + // Check if the show exists + var existingShow = await SickRageApi.GetShow(tvdbid, settings.ApiKey, settings.FullUri); + + if (existingShow == null) + { + var addResult = await SickRageApi.AddSeries(model.ParentRequest.TvDbId, SickRageStatus.Wanted, + qualityId, + 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")) + { + // Do something + return false; + } + } + + foreach (var seasonRequests in model.SeasonRequests) + { + var 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.Helpers/LoggingEvents.cs b/src/Ombi.Helpers/LoggingEvents.cs index 0a2311b80..39c309102 100644 --- a/src/Ombi.Helpers/LoggingEvents.cs +++ b/src/Ombi.Helpers/LoggingEvents.cs @@ -19,6 +19,7 @@ namespace Ombi.Helpers public static EventId SonarrCacher => new EventId(2006); public static EventId CouchPotatoCacher => new EventId(2007); public static EventId PlexContentCacher => new EventId(2008); + public static EventId SickRageCacher => new EventId(2009); public static EventId MovieSender => new EventId(3000); diff --git a/src/Ombi.Schedule/JobSetup.cs b/src/Ombi.Schedule/JobSetup.cs index f9bccc61b..dabe0da9f 100644 --- a/src/Ombi.Schedule/JobSetup.cs +++ b/src/Ombi.Schedule/JobSetup.cs @@ -6,6 +6,7 @@ using Ombi.Schedule.Jobs.Emby; using Ombi.Schedule.Jobs.Ombi; using Ombi.Schedule.Jobs.Plex; using Ombi.Schedule.Jobs.Radarr; +using Ombi.Schedule.Jobs.SickRage; using Ombi.Schedule.Jobs.Sonarr; using Ombi.Settings.Settings.Models; @@ -16,7 +17,7 @@ namespace Ombi.Schedule public JobSetup(IPlexContentSync plexContentSync, IRadarrSync radarrSync, IOmbiAutomaticUpdater updater, IEmbyContentSync embySync, IPlexUserImporter userImporter, IEmbyUserImporter embyUserImporter, ISonarrSync cache, ICouchPotatoSync cpCache, - ISettingsService jobsettings) + ISettingsService jobsettings, ISickRageSync srSync) { PlexContentSync = plexContentSync; RadarrSync = radarrSync; @@ -37,6 +38,7 @@ namespace Ombi.Schedule private IEmbyUserImporter EmbyUserImporter { get; } private ISonarrSync SonarrSync { get; } private ICouchPotatoSync CpCache { get; } + private ISickRageSync SrSync { get; } private ISettingsService JobSettings { get; set; } public void Setup() @@ -48,6 +50,7 @@ namespace Ombi.Schedule RecurringJob.AddOrUpdate(() => RadarrSync.CacheContent(), JobSettingsHelper.Radarr(s)); RecurringJob.AddOrUpdate(() => PlexContentSync.CacheContent(), JobSettingsHelper.PlexContent(s)); RecurringJob.AddOrUpdate(() => CpCache.Start(), JobSettingsHelper.CouchPotato(s)); + RecurringJob.AddOrUpdate(() => SrSync.Start(), JobSettingsHelper.SickRageSync(s)); RecurringJob.AddOrUpdate(() => Updater.Update(null), JobSettingsHelper.Updater(s)); diff --git a/src/Ombi.Schedule/Jobs/SickRage/ISickRageSync.cs b/src/Ombi.Schedule/Jobs/SickRage/ISickRageSync.cs new file mode 100644 index 000000000..2127dca5e --- /dev/null +++ b/src/Ombi.Schedule/Jobs/SickRage/ISickRageSync.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace Ombi.Schedule.Jobs.SickRage +{ + public interface ISickRageSync + { + Task Start(); + } +} \ No newline at end of file diff --git a/src/Ombi.Schedule/Jobs/SickRage/SickRageSync.cs b/src/Ombi.Schedule/Jobs/SickRage/SickRageSync.cs new file mode 100644 index 000000000..6e373ed58 --- /dev/null +++ b/src/Ombi.Schedule/Jobs/SickRage/SickRageSync.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using Ombi.Api.SickRage; +using Ombi.Api.SickRage.Models; +using Ombi.Core.Settings; +using Ombi.Helpers; +using Ombi.Settings.Settings.Models.External; +using Ombi.Store.Context; +using Ombi.Store.Entities; + +namespace Ombi.Schedule.Jobs.SickRage +{ + public class SickRageSync : ISickRageSync + { + public SickRageSync(ISettingsService s, ISickRageApi api, ILogger l, IOmbiContext ctx) + { + _settings = s; + _api = api; + _log = l; + _ctx = ctx; + _settings.ClearCache(); + } + + private readonly ISettingsService _settings; + private readonly ISickRageApi _api; + private readonly ILogger _log; + private readonly IOmbiContext _ctx; + + private static readonly SemaphoreSlim SemaphoreSlim = new SemaphoreSlim(1, 1); + public async Task Start() + { + await SemaphoreSlim.WaitAsync(); + try + { + var settings = await _settings.GetSettingsAsync(); + if (!settings.Enabled) + { + return; + } + var shows = await _api.GetShows(settings.ApiKey, settings.FullUri); + if (shows != null) + { + var srShows = shows.data.Values; + var ids = srShows.Select(x => x.tvdbid); + + await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM SickRageCache"); + var entites = ids.Select(id => new SickRageCache { TvDbId = id }).ToList(); + + await _ctx.SickRageCache.AddRangeAsync(entites); + + var episodesToAdd = new List(); + await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM SickRageEpisodeCache"); + foreach (var s in srShows) + { + var seasons = await _api.GetSeasonList(s.tvdbid, settings.ApiKey, settings.FullUri); + foreach (var season in seasons.data) + { + var episodes = + await _api.GetEpisodesForSeason(s.tvdbid, season, settings.ApiKey, settings.FullUri); + + var monitoredEpisodes = episodes.data.Where(x => x.Value.status.Equals(SickRageStatus.Wanted)); + + episodesToAdd.AddRange(monitoredEpisodes.Select(episode => new SickRageEpisodeCache + { + EpisodeNumber = episode.Key, + SeasonNumber = season, + TvDbId = s.tvdbid + })); + } + + } + + await _ctx.SickRageEpisodeCache.AddRangeAsync(episodesToAdd); + await _ctx.SaveChangesAsync(); + } + } + catch (Exception e) + { + _log.LogError(LoggingEvents.SickRageCacher, e, "Exception when trying to cache SickRage"); + } + finally + { + SemaphoreSlim.Release(); + } + } + } +} \ No newline at end of file diff --git a/src/Ombi.Schedule/Ombi.Schedule.csproj b/src/Ombi.Schedule/Ombi.Schedule.csproj index 3d884cc4a..02dcc9dec 100644 --- a/src/Ombi.Schedule/Ombi.Schedule.csproj +++ b/src/Ombi.Schedule/Ombi.Schedule.csproj @@ -27,6 +27,7 @@ + diff --git a/src/Ombi.Settings/Settings/Models/External/SickRageSettings.cs b/src/Ombi.Settings/Settings/Models/External/SickRageSettings.cs index 1cb49267d..05c7fd992 100644 --- a/src/Ombi.Settings/Settings/Models/External/SickRageSettings.cs +++ b/src/Ombi.Settings/Settings/Models/External/SickRageSettings.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using Newtonsoft.Json; namespace Ombi.Settings.Settings.Models.External { @@ -8,19 +7,34 @@ namespace Ombi.Settings.Settings.Models.External public bool Enabled { get; set; } public string ApiKey { get; set; } public string QualityProfile { get; set; } - - [JsonIgnore] - public Dictionary Qualities => new Dictionary + + public List Qualities => new List { - { "default", "Use Default" }, - { "sdtv", "SD TV" }, - { "sddvd", "SD DVD" }, - { "hdtv", "HD TV" }, - { "rawhdtv", "Raw HD TV" }, - { "hdwebdl", "HD Web DL" }, - { "fullhdwebdl", "Full HD Web DL" }, - { "hdbluray", "HD Bluray" }, - { "fullhdbluray", "Full HD Bluray" } + new DropDownModel("default", "Use Default"), + new DropDownModel("sdtv", "SD TV"), + new DropDownModel("sddvd", "SD DVD"), + new DropDownModel("hdtv", "HD TV"), + new DropDownModel("rawhdtv", "Raw HD TV"), + new DropDownModel("hdwebdl", "HD Web DL"), + new DropDownModel("fullhdwebdl", "Full HD Web DL"), + new DropDownModel("hdbluray", "HD Bluray"), + new DropDownModel("fullhdbluray", "Full HD Bluray"), }; } + + public class DropDownModel + { + public DropDownModel(string val, string display) + { + Value = val; + Display = display; + } + + public DropDownModel() + { + + } + public string Value { get; set; } + public string Display { get; set; } + } } \ No newline at end of file diff --git a/src/Ombi.Settings/Settings/Models/JobSettings.cs b/src/Ombi.Settings/Settings/Models/JobSettings.cs index 780741302..7cf6e7104 100644 --- a/src/Ombi.Settings/Settings/Models/JobSettings.cs +++ b/src/Ombi.Settings/Settings/Models/JobSettings.cs @@ -9,5 +9,6 @@ public string CouchPotatoSync { get; set; } public string AutomaticUpdater { get; set; } public string UserImporter { get; set; } + public string SickRageSync { get; set; } } } \ No newline at end of file diff --git a/src/Ombi.Settings/Settings/Models/JobSettingsHelper.cs b/src/Ombi.Settings/Settings/Models/JobSettingsHelper.cs index 119406baa..69eaf4b33 100644 --- a/src/Ombi.Settings/Settings/Models/JobSettingsHelper.cs +++ b/src/Ombi.Settings/Settings/Models/JobSettingsHelper.cs @@ -35,6 +35,10 @@ namespace Ombi.Settings.Settings.Models { return Get(s.UserImporter, Cron.Daily()); } + public static string SickRageSync(JobSettings s) + { + return Get(s.SickRageSync, Cron.Hourly(35)); + } private static string Get(string settings, string defaultCron) diff --git a/src/Ombi.Store/Context/IOmbiContext.cs b/src/Ombi.Store/Context/IOmbiContext.cs index 6f85a974f..0d3045d2a 100644 --- a/src/Ombi.Store/Context/IOmbiContext.cs +++ b/src/Ombi.Store/Context/IOmbiContext.cs @@ -38,5 +38,7 @@ namespace Ombi.Store.Context EntityEntry Update(object entity); EntityEntry Update(TEntity entity) where TEntity : class; DbSet CouchPotatoCache { get; set; } + DbSet SickRageCache { get; set; } + DbSet SickRageEpisodeCache { get; set; } } } \ No newline at end of file diff --git a/src/Ombi.Store/Context/OmbiContext.cs b/src/Ombi.Store/Context/OmbiContext.cs index fe508e060..8621a2f07 100644 --- a/src/Ombi.Store/Context/OmbiContext.cs +++ b/src/Ombi.Store/Context/OmbiContext.cs @@ -40,6 +40,8 @@ namespace Ombi.Store.Context public DbSet Tokens { get; set; } public DbSet SonarrCache { get; set; } public DbSet SonarrEpisodeCache { get; set; } + public DbSet SickRageCache { get; set; } + public DbSet SickRageEpisodeCache { get; set; } public DbSet ApplicationConfigurations { get; set; } diff --git a/src/Ombi.Store/Entities/SickRageCache.cs b/src/Ombi.Store/Entities/SickRageCache.cs new file mode 100644 index 000000000..ed5a9af17 --- /dev/null +++ b/src/Ombi.Store/Entities/SickRageCache.cs @@ -0,0 +1,10 @@ +using System.ComponentModel.DataAnnotations.Schema; + +namespace Ombi.Store.Entities +{ + [Table("SickRageCache")] + public class SickRageCache : Entity + { + public int TvDbId { get; set; } + } +} \ No newline at end of file diff --git a/src/Ombi.Store/Entities/SickRageEpisodeCache.cs b/src/Ombi.Store/Entities/SickRageEpisodeCache.cs new file mode 100644 index 000000000..5aeb1745a --- /dev/null +++ b/src/Ombi.Store/Entities/SickRageEpisodeCache.cs @@ -0,0 +1,12 @@ +using System.ComponentModel.DataAnnotations.Schema; + +namespace Ombi.Store.Entities +{ + [Table("SickRageEpisodeCache")] + public class SickRageEpisodeCache : Entity + { + public int SeasonNumber { get; set; } + public int EpisodeNumber { get; set; } + public int TvDbId { get; set; } + } +} \ No newline at end of file diff --git a/src/Ombi/ClientApp/app/interfaces/ICommon.ts b/src/Ombi/ClientApp/app/interfaces/ICommon.ts index 649e94e25..c2e1e7e1d 100644 --- a/src/Ombi/ClientApp/app/interfaces/ICommon.ts +++ b/src/Ombi/ClientApp/app/interfaces/ICommon.ts @@ -26,7 +26,3 @@ export interface IUsersModel { id: string; username: string; } - -export interface IDictionary { - [Key: string]: T; -} diff --git a/src/Ombi/ClientApp/app/interfaces/ISettings.ts b/src/Ombi/ClientApp/app/interfaces/ISettings.ts index 36cad977f..63223dcf4 100644 --- a/src/Ombi/ClientApp/app/interfaces/ISettings.ts +++ b/src/Ombi/ClientApp/app/interfaces/ISettings.ts @@ -1,4 +1,4 @@ -import { IDictionary, ISettings } from "./ICommon"; +import { ISettings } from "./ICommon"; export interface IExternalSettings extends ISettings { ssl: boolean; @@ -115,6 +115,7 @@ export interface IJobSettings { couchPotatoSync: string; automaticUpdater: string; userImporter: string; + sickRageSync: string; } export interface IAuthenticationSettings extends ISettings { @@ -158,7 +159,12 @@ export interface ISickRageSettings extends IExternalSettings { enabled: boolean; apiKey: string; qualityProfile: string; - qualities: IDictionary; + qualities: IDropDownModel[]; +} + +export interface IDropDownModel { + value: string; + display: string; } export interface IDogNzbSettings extends ISettings { diff --git a/src/Ombi/ClientApp/app/settings/jobs/jobs.component.html b/src/Ombi/ClientApp/app/settings/jobs/jobs.component.html index db1500b9c..ff5e56ed8 100644 --- a/src/Ombi/ClientApp/app/settings/jobs/jobs.component.html +++ b/src/Ombi/ClientApp/app/settings/jobs/jobs.component.html @@ -13,6 +13,11 @@ The Sonarr Sync is required +
+ + + The SickRage Sync is required +
diff --git a/src/Ombi/ClientApp/app/settings/jobs/jobs.component.ts b/src/Ombi/ClientApp/app/settings/jobs/jobs.component.ts index 524c980cd..f547c5056 100644 --- a/src/Ombi/ClientApp/app/settings/jobs/jobs.component.ts +++ b/src/Ombi/ClientApp/app/settings/jobs/jobs.component.ts @@ -23,8 +23,9 @@ export class JobsComponent implements OnInit { embyContentSync: [x.embyContentSync, Validators.required], plexContentSync: [x.plexContentSync, Validators.required], userImporter: [x.userImporter, Validators.required], - sonarrSync: [x.radarrSync, Validators.required], + sonarrSync: [x.radarrSync, Validators.required], radarrSync: [x.sonarrSync, Validators.required], + sickRageSync: [x.sickRageSync, Validators.required], }); }); } diff --git a/src/Ombi/ClientApp/app/settings/settingsmenu.component.html b/src/Ombi/ClientApp/app/settings/settingsmenu.component.html index 391590abb..029a754a3 100644 --- a/src/Ombi/ClientApp/app/settings/settingsmenu.component.html +++ b/src/Ombi/ClientApp/app/settings/settingsmenu.component.html @@ -30,8 +30,7 @@ @@ -44,7 +43,6 @@
  • DogNzb
  • Radarr
  • -
  • More Coming Soon...
  • diff --git a/src/Ombi/ClientApp/app/settings/sickrage/sickrage.component.html b/src/Ombi/ClientApp/app/settings/sickrage/sickrage.component.html index 94b7e4f91..6307b6332 100644 --- a/src/Ombi/ClientApp/app/settings/sickrage/sickrage.component.html +++ b/src/Ombi/ClientApp/app/settings/sickrage/sickrage.component.html @@ -53,7 +53,7 @@
    A Default Quality Profile is required diff --git a/src/Ombi/ClientApp/app/settings/sickrage/sickrage.component.ts b/src/Ombi/ClientApp/app/settings/sickrage/sickrage.component.ts index 9576fd60b..4db2b904a 100644 --- a/src/Ombi/ClientApp/app/settings/sickrage/sickrage.component.ts +++ b/src/Ombi/ClientApp/app/settings/sickrage/sickrage.component.ts @@ -1,9 +1,7 @@ import { Component, OnInit } from "@angular/core"; import { FormBuilder, FormGroup, Validators } from "@angular/forms"; -import { ISonarrProfile, ISonarrRootFolder } from "../../interfaces"; - -import { ISickRageSettings } from "../../interfaces"; +import { IDropDownModel, ISickRageSettings } from "../../interfaces"; import { TesterService } from "../../services"; import { NotificationService } from "../../services"; import { SettingsService } from "../../services"; @@ -13,14 +11,8 @@ import { SettingsService } from "../../services"; }) export class SickRageComponent implements OnInit { - public qualities: ISonarrProfile[]; - public rootFolders: ISonarrRootFolder[]; - public selectedRootFolder: ISonarrRootFolder; - public selectedQuality: ISonarrProfile; - public profilesRunning: boolean; - public rootFoldersRunning: boolean; + public qualities: IDropDownModel[]; public form: FormGroup; - public advanced = false; constructor(private settingsService: SettingsService, private notificationService: NotificationService, @@ -34,13 +26,12 @@ export class SickRageComponent implements OnInit { enabled: [x.enabled], apiKey: [x.apiKey, [Validators.required]], qualityProfile: [x.qualityProfile, [Validators.required]], - qualities: [x.qualities], ssl: [x.ssl], subDir: [x.subDir], ip: [x.ip, [Validators.required]], port: [x.port, [Validators.required]], }); - + this.qualities = x.qualities; }); } diff --git a/src/Ombi/Controllers/External/TesterController.cs b/src/Ombi/Controllers/External/TesterController.cs index ba62b05c1..013798e13 100644 --- a/src/Ombi/Controllers/External/TesterController.cs +++ b/src/Ombi/Controllers/External/TesterController.cs @@ -1,7 +1,6 @@ using System; using System.Linq; using System.Threading.Tasks; -using Hangfire; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Ombi.Api.CouchPotato; @@ -10,7 +9,6 @@ using Ombi.Api.Plex; using Ombi.Api.Radarr; using Ombi.Api.SickRage; using Ombi.Api.Sonarr; -using Ombi.Api.Telegram; using Ombi.Attributes; using Ombi.Core.Notifications; using Ombi.Core.Settings.Models.External; @@ -18,7 +16,6 @@ using Ombi.Helpers; using Ombi.Notifications; using Ombi.Notifications.Agents; using Ombi.Notifications.Models; -using Ombi.Notifications.Templates; using Ombi.Settings.Settings.Models.External; using Ombi.Settings.Settings.Models.Notifications; @@ -84,11 +81,19 @@ namespace Ombi.Controllers.External [HttpPost("discord")] public bool Discord([FromBody] DiscordNotificationSettings settings) { - settings.Enabled = true; - DiscordNotification.NotifyAsync( - new NotificationOptions { NotificationType = NotificationType.Test, RequestId = -1 }, settings); + try + { + settings.Enabled = true; + DiscordNotification.NotifyAsync( + new NotificationOptions { NotificationType = NotificationType.Test, RequestId = -1 }, settings); - return true; + return true; + } + catch (Exception e) + { + Log.LogError(LoggingEvents.Api, e, "Could not test Discord"); + return false; + } } /// @@ -99,11 +104,20 @@ namespace Ombi.Controllers.External [HttpPost("pushbullet")] public bool Pushbullet([FromBody] PushbulletSettings settings) { - settings.Enabled = true; - PushbulletNotification.NotifyAsync( - new NotificationOptions { NotificationType = NotificationType.Test, RequestId = -1 }, settings); + try + { - return true; + settings.Enabled = true; + PushbulletNotification.NotifyAsync( + new NotificationOptions { NotificationType = NotificationType.Test, RequestId = -1 }, settings); + + return true; + } + catch (Exception e) + { + Log.LogError(LoggingEvents.Api, e, "Could not test Pushbullet"); + return false; + } } /// @@ -114,11 +128,20 @@ namespace Ombi.Controllers.External [HttpPost("pushover")] public bool Pushover([FromBody] PushoverSettings settings) { - settings.Enabled = true; - PushoverNotification.NotifyAsync( - new NotificationOptions { NotificationType = NotificationType.Test, RequestId = -1 }, settings); + try + { + settings.Enabled = true; + PushoverNotification.NotifyAsync( + new NotificationOptions { NotificationType = NotificationType.Test, RequestId = -1 }, settings); + + return true; + } + catch (Exception e) + { + Log.LogError(LoggingEvents.Api, e, "Could not test Pushover"); + return false; + } - return true; } /// @@ -129,11 +152,21 @@ namespace Ombi.Controllers.External [HttpPost("mattermost")] public bool Mattermost([FromBody] MattermostNotificationSettings settings) { - settings.Enabled = true; - MattermostNotification.NotifyAsync( - new NotificationOptions { NotificationType = NotificationType.Test, RequestId = -1 }, settings); + try + { + settings.Enabled = true; + MattermostNotification.NotifyAsync( + new NotificationOptions { NotificationType = NotificationType.Test, RequestId = -1 }, settings); + + return true; + + } + catch (Exception e) + { + Log.LogError(LoggingEvents.Api, e, "Could not test Mattermost"); + return false; + } - return true; } @@ -145,11 +178,19 @@ namespace Ombi.Controllers.External [HttpPost("slack")] public bool Slack([FromBody] SlackNotificationSettings settings) { - settings.Enabled = true; - SlackNotification.NotifyAsync( - new NotificationOptions { NotificationType = NotificationType.Test, RequestId = -1 }, settings); + try + { + settings.Enabled = true; + SlackNotification.NotifyAsync( + new NotificationOptions { NotificationType = NotificationType.Test, RequestId = -1 }, settings); - return true; + return true; + } + catch (Exception e) + { + Log.LogError(LoggingEvents.Api, e, "Could not test Slack"); + return false; + } } /// @@ -293,10 +334,18 @@ namespace Ombi.Controllers.External [HttpPost("telegram")] public async Task Telegram([FromBody] TelegramSettings settings) { - settings.Enabled = true; - await TelegramNotification.NotifyAsync(new NotificationOptions { NotificationType = NotificationType.Test, RequestId = -1 }, settings); + try + { + settings.Enabled = true; + await TelegramNotification.NotifyAsync(new NotificationOptions { NotificationType = NotificationType.Test, RequestId = -1 }, settings); - return true; + return true; + } + catch (Exception e) + { + Log.LogError(LoggingEvents.Api, e, "Could not test Telegram"); + return false; + } } /// @@ -307,9 +356,17 @@ namespace Ombi.Controllers.External [HttpPost("sickrage")] public async Task SickRage([FromBody] SickRageSettings settings) { - settings.Enabled = true; - var result = await SickRageApi.Ping(settings.ApiKey, settings.FullUri); - return result?.data?.pid != null; + try + { + settings.Enabled = true; + var result = await SickRageApi.Ping(settings.ApiKey, settings.FullUri); + return result?.data?.pid != null; + } + catch (Exception e) + { + Log.LogError(LoggingEvents.Api, e, "Could not test SickRage"); + return false; + } } } } \ No newline at end of file