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.

This commit is contained in:
Jamie 2017-11-27 14:43:09 +00:00
parent 62a3ed924b
commit a1ee52daef
26 changed files with 731 additions and 430 deletions

View file

@ -6,12 +6,14 @@ namespace Ombi.Api.SickRage
public interface ISickRageApi public interface ISickRageApi
{ {
Task<SickRageTvAdd> AddSeason(int tvdbId, int season, string apiKey, string baseUrl); Task<SickRageTvAdd> AddSeason(int tvdbId, int season, string apiKey, string baseUrl);
Task<SickRageTvAdd> AddSeries(int tvdbId, int seasonCount, int[] seasons, string quality, string apiKey, string baseUrl); Task<SickRageTvAdd> AddSeries(int tvdbId, string quality, string status, string apiKey, string baseUrl);
Task<SickRageShows> GetShows(string apiKey, string baseUrl); Task<SickRageShows> GetShows(string apiKey, string baseUrl);
Task<SickRagePing> Ping(string apiKey, string baseUrl); Task<SickRagePing> Ping(string apiKey, string baseUrl);
Task<SickRageSeasonList> VerifyShowHasLoaded(int tvdbId, string apiKey, string baseUrl); Task<SickRageSeasonList> VerifyShowHasLoaded(int tvdbId, string apiKey, string baseUrl);
Task<SickRageShowInformation> GetShow(int tvdbid, string apikey, string baseUrl);
Task<SickRageEpisodeStatus> SetEpisodeStatus(string apiKey, string baseUrl, int tvdbid, string status, Task<SickRageEpisodeStatus> SetEpisodeStatus(string apiKey, string baseUrl, int tvdbid, string status,
int season, int episode = -1); int season, int episode = -1);
Task<SickRageEpisodes> GetEpisodesForSeason(int tvdbid, int season, string apikey, string baseUrl);
Task<SeasonList> GetSeasonList(int tvdbId, string apikey, string baseurl);
} }
} }

View file

@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace Ombi.Api.SickRage.Models
{
public class SeasonList : SickRageBase<List<int>>
{
}
}

View file

@ -0,0 +1,18 @@
using System.Collections.Generic;
namespace Ombi.Api.SickRage.Models
{
public class SickRageEpisodes : SickRageBase<Dictionary<int, SickRageEpisodesData>>
{
}
public class SickRageEpisodesData
{
public string airdate { get; set; }
public string name { get; set; }
public string quality { get; set; }
public string status { get; set; }
}
}

View file

@ -0,0 +1,41 @@
namespace Ombi.Api.SickRage.Models
{
public class SickRageShowInformation : SickRageBase<SickRageShowInformationData>
{
}
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; }
}
}

View file

@ -1,6 +1,4 @@
using System; using System;
using System.Diagnostics;
using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@ -27,15 +25,12 @@ namespace Ombi.Api.SickRage
return await _api.Request<SickRageSeasonList>(request); return await _api.Request<SickRageSeasonList>(request);
} }
public async Task<SickRageTvAdd> AddSeries(int tvdbId, int seasonCount, int[] seasons, string quality, string apiKey, string baseUrl) public async Task<SickRageTvAdd> 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); var request = new Request($"/api/{apiKey}/?cmd=show.addnew", baseUrl, HttpMethod.Get);
request.AddQueryString("tvdbid", tvdbId.ToString()); request.AddQueryString("tvdbid", tvdbId.ToString());
request.AddQueryString("status", status); request.AddQueryString("status", status);
request.AddQueryString("future_status", futureStatus);
if (!quality.Equals("default", StringComparison.CurrentCultureIgnoreCase)) if (!quality.Equals("default", StringComparison.CurrentCultureIgnoreCase))
{ {
@ -44,55 +39,6 @@ namespace Ombi.Api.SickRage
var obj = await _api.Request<SickRageTvAdd>(request); var obj = await _api.Request<SickRageTvAdd>(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; return obj;
} }
@ -113,6 +59,23 @@ namespace Ombi.Api.SickRage
return await _api.Request<SickRageShows>(request); return await _api.Request<SickRageShows>(request);
} }
public async Task<SickRageShowInformation> 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<SickRageShowInformation>(request);
}
public async Task<SickRageEpisodes> 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<SickRageEpisodes>(request);
}
public async Task<SickRagePing> Ping(string apiKey, string baseUrl) public async Task<SickRagePing> Ping(string apiKey, string baseUrl)
{ {
var request = new Request($"/api/{apiKey}/?cmd=sb.ping", baseUrl, HttpMethod.Get); var request = new Request($"/api/{apiKey}/?cmd=sb.ping", baseUrl, HttpMethod.Get);
@ -139,5 +102,13 @@ namespace Ombi.Api.SickRage
return await _api.Request<SickRageEpisodeStatus>(request); return await _api.Request<SickRageEpisodeStatus>(request);
} }
public async Task<SeasonList> 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<SeasonList>(request);
}
} }
} }

View file

@ -1,308 +1,363 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Ombi.Api.DogNzb; using Ombi.Api.DogNzb;
using Ombi.Api.DogNzb.Models; using Ombi.Api.DogNzb.Models;
using Ombi.Api.SickRage; using Ombi.Api.SickRage;
using Ombi.Api.Sonarr; using Ombi.Api.SickRage.Models;
using Ombi.Api.Sonarr.Models; using Ombi.Api.Sonarr;
using Ombi.Core.Settings; using Ombi.Api.Sonarr.Models;
using Ombi.Helpers; using Ombi.Core.Settings;
using Ombi.Settings.Settings.Models.External; using Ombi.Helpers;
using Ombi.Store.Entities.Requests; using Ombi.Settings.Settings.Models.External;
using Ombi.Store.Entities.Requests;
namespace Ombi.Core.Senders
{ namespace Ombi.Core.Senders
public class TvSender : ITvSender {
{ public class TvSender : ITvSender
public TvSender(ISonarrApi sonarrApi, ILogger<TvSender> log, ISettingsService<SonarrSettings> sonarrSettings, {
ISettingsService<DogNzbSettings> dog, IDogNzbApi dogApi, ISettingsService<SickRageSettings> srSettings, public TvSender(ISonarrApi sonarrApi, ILogger<TvSender> log, ISettingsService<SonarrSettings> sonarrSettings,
ISickRageApi srApi) ISettingsService<DogNzbSettings> dog, IDogNzbApi dogApi, ISettingsService<SickRageSettings> srSettings,
{ ISickRageApi srApi)
SonarrApi = sonarrApi; {
Logger = log; SonarrApi = sonarrApi;
SonarrSettings = sonarrSettings; Logger = log;
DogNzbSettings = dog; SonarrSettings = sonarrSettings;
DogNzbApi = dogApi; DogNzbSettings = dog;
SickRageSettings = srSettings; DogNzbApi = dogApi;
SickRageApi = srApi; SickRageSettings = srSettings;
} SickRageApi = srApi;
}
private ISonarrApi SonarrApi { get; }
private IDogNzbApi DogNzbApi { get; } private ISonarrApi SonarrApi { get; }
private ISickRageApi SickRageApi { get; } private IDogNzbApi DogNzbApi { get; }
private ILogger<TvSender> Logger { get; } private ISickRageApi SickRageApi { get; }
private ISettingsService<SonarrSettings> SonarrSettings { get; } private ILogger<TvSender> Logger { get; }
private ISettingsService<DogNzbSettings> DogNzbSettings { get; } private ISettingsService<SonarrSettings> SonarrSettings { get; }
private ISettingsService<SickRageSettings> SickRageSettings { get; } private ISettingsService<DogNzbSettings> DogNzbSettings { get; }
private ISettingsService<SickRageSettings> SickRageSettings { get; }
public async Task<SenderResult> Send(ChildRequests model)
{ public async Task<SenderResult> Send(ChildRequests model)
var sonarr = await SonarrSettings.GetSettingsAsync(); {
if (sonarr.Enabled) var sonarr = await SonarrSettings.GetSettingsAsync();
{ if (sonarr.Enabled)
var result = await SendToSonarr(model); {
if (result != null) var result = await SendToSonarr(model);
{ if (result != null)
return new SenderResult {
{ return new SenderResult
Sent = true, {
Success = true Sent = true,
}; Success = true
} };
} }
var dog = await DogNzbSettings.GetSettingsAsync(); }
if (dog.Enabled) var dog = await DogNzbSettings.GetSettingsAsync();
{ if (dog.Enabled)
var result = await SendToDogNzb(model, dog); {
if (!result.Failure) var result = await SendToDogNzb(model, dog);
{ if (!result.Failure)
return new SenderResult {
{ return new SenderResult
Sent = true, {
Success = true Sent = true,
}; Success = true
} };
return new SenderResult }
{ return new SenderResult
Message = result.ErrorMessage {
}; Message = result.ErrorMessage
} };
return new SenderResult }
{ var sr = await SickRageSettings.GetSettingsAsync();
Success = true if (sr.Enabled)
}; {
} var result = await SendToSickRage(model, sr);
if (result)
private async Task<DogNzbAddResult> SendToDogNzb(ChildRequests model, DogNzbSettings settings) {
{ return new SenderResult
var id = model.ParentRequest.TvDbId; {
return await DogNzbApi.AddTvShow(settings.ApiKey, id.ToString()); Sent = true,
} Success = true
};
/// <summary> }
/// Send the request to Sonarr to process return new SenderResult();
/// </summary> }
/// <param name="s"></param> return new SenderResult
/// <param name="model"></param> {
/// <param name="qualityId">This is for any qualities overriden from the UI</param> Success = true
/// <returns></returns> };
public async Task<NewSeries> SendToSonarr(ChildRequests model, string qualityId = null) }
{
var s = await SonarrSettings.GetSettingsAsync(); private async Task<DogNzbAddResult> SendToDogNzb(ChildRequests model, DogNzbSettings settings)
if (!s.Enabled) {
{ var id = model.ParentRequest.TvDbId;
return null; return await DogNzbApi.AddTvShow(settings.ApiKey, id.ToString());
} }
if(string.IsNullOrEmpty(s.ApiKey))
{ /// <summary>
return null; /// Send the request to Sonarr to process
} /// </summary>
var qualityProfile = 0; /// <param name="s"></param>
if (!string.IsNullOrEmpty(qualityId)) // try to parse the passed in quality, otherwise use the settings default quality /// <param name="model"></param>
{ /// <param name="qualityId">This is for any qualities overriden from the UI</param>
int.TryParse(qualityId, out qualityProfile); /// <returns></returns>
} public async Task<NewSeries> SendToSonarr(ChildRequests model, string qualityId = null)
{
if (qualityProfile <= 0) var s = await SonarrSettings.GetSettingsAsync();
{ if (!s.Enabled)
int.TryParse(s.QualityProfile, out qualityProfile); {
} return null;
}
// Get the root path from the rootfolder selected. if(string.IsNullOrEmpty(s.ApiKey))
// For some reason, if we haven't got one use the first root folder in Sonarr {
// TODO make this overrideable via the UI return null;
var rootFolderPath = await GetSonarrRootPath(model.ParentRequest.RootFolder ?? int.Parse(s.RootPath), s); }
try var qualityProfile = 0;
{ if (!string.IsNullOrEmpty(qualityId)) // try to parse the passed in quality, otherwise use the settings default quality
// Does the series actually exist? {
var allSeries = await SonarrApi.GetSeries(s.ApiKey, s.FullUri); int.TryParse(qualityId, out qualityProfile);
var existingSeries = allSeries.FirstOrDefault(x => x.tvdbId == model.ParentRequest.TvDbId); }
if (existingSeries == null) if (qualityProfile <= 0)
{ {
// Time to add a new one int.TryParse(s.QualityProfile, out qualityProfile);
var newSeries = new NewSeries }
{
title = model.ParentRequest.Title, // Get the root path from the rootfolder selected.
imdbId = model.ParentRequest.ImdbId, // For some reason, if we haven't got one use the first root folder in Sonarr
tvdbId = model.ParentRequest.TvDbId, // TODO make this overrideable via the UI
cleanTitle = model.ParentRequest.Title, var rootFolderPath = await GetSonarrRootPath(model.ParentRequest.RootFolder ?? int.Parse(s.RootPath), s);
monitored = true, try
seasonFolder = s.SeasonFolders, {
rootFolderPath = rootFolderPath, // Does the series actually exist?
qualityProfileId = qualityProfile, var allSeries = await SonarrApi.GetSeries(s.ApiKey, s.FullUri);
titleSlug = model.ParentRequest.Title, var existingSeries = allSeries.FirstOrDefault(x => x.tvdbId == model.ParentRequest.TvDbId);
addOptions = new AddOptions
{ if (existingSeries == null)
ignoreEpisodesWithFiles = true, // There shouldn't be any episodes with files, this is a new season {
ignoreEpisodesWithoutFiles = true, // We want all missing // Time to add a new one
searchForMissingEpisodes = false // we want dont want to search yet. We want to make sure everything is unmonitored/monitored correctly. var newSeries = new NewSeries
} {
}; title = model.ParentRequest.Title,
imdbId = model.ParentRequest.ImdbId,
// Montitor the correct seasons, tvdbId = model.ParentRequest.TvDbId,
// If we have that season in the model then it's monitored! cleanTitle = model.ParentRequest.Title,
var seasonsToAdd = new List<Season>(); monitored = true,
for (var i = 1; i < model.ParentRequest.TotalSeasons + 1; i++) seasonFolder = s.SeasonFolders,
{ rootFolderPath = rootFolderPath,
var index = i; qualityProfileId = qualityProfile,
var season = new Season titleSlug = model.ParentRequest.Title,
{ addOptions = new AddOptions
seasonNumber = i, {
monitored = model.SeasonRequests.Any(x => x.SeasonNumber == index) ignoreEpisodesWithFiles = true, // There shouldn't be any episodes with files, this is a new season
}; ignoreEpisodesWithoutFiles = true, // We want all missing
seasonsToAdd.Add(season); searchForMissingEpisodes = false // we want dont want to search yet. We want to make sure everything is unmonitored/monitored correctly.
} }
newSeries.seasons = seasonsToAdd; };
var result = await SonarrApi.AddSeries(newSeries, s.ApiKey, s.FullUri);
existingSeries = await SonarrApi.GetSeriesById(result.id, s.ApiKey, s.FullUri); // Montitor the correct seasons,
await SendToSonarr(model, existingSeries, s); // If we have that season in the model then it's monitored!
} var seasonsToAdd = new List<Season>();
else for (var i = 1; i < model.ParentRequest.TotalSeasons + 1; i++)
{ {
await SendToSonarr(model, existingSeries, s); var index = i;
} var season = new Season
{
return new NewSeries seasonNumber = i,
{ monitored = model.SeasonRequests.Any(x => x.SeasonNumber == index)
id = existingSeries.id, };
seasons = existingSeries.seasons.ToList(), seasonsToAdd.Add(season);
cleanTitle = existingSeries.cleanTitle, }
title = existingSeries.title, newSeries.seasons = seasonsToAdd;
tvdbId = existingSeries.tvdbId 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);
catch (Exception e) }
{ else
Logger.LogError(LoggingEvents.SonarrSender, e, "Exception thrown when attempting to send series over to Sonarr"); {
throw; await SendToSonarr(model, existingSeries, s);
} }
}
return new NewSeries
private async Task SendToSonarr(ChildRequests model, SonarrSeries result, SonarrSettings s) {
{ id = existingSeries.id,
var episodesToUpdate = new List<Episode>(); seasons = existingSeries.seasons.ToList(),
// Ok, now let's sort out the episodes. cleanTitle = existingSeries.cleanTitle,
title = existingSeries.title,
var sonarrEpisodes = await SonarrApi.GetEpisodes(result.id, s.ApiKey, s.FullUri); tvdbId = existingSeries.tvdbId
var sonarrEpList = sonarrEpisodes.ToList() ?? new List<Episode>(); };
while (!sonarrEpList.Any()) }
{ catch (Exception e)
// It could be that the series metadata is not ready yet. So wait {
sonarrEpList = (await SonarrApi.GetEpisodes(result.id, s.ApiKey, s.FullUri)).ToList(); Logger.LogError(LoggingEvents.SonarrSender, e, "Exception thrown when attempting to send series over to Sonarr");
await Task.Delay(500); throw;
} }
}
foreach (var req in model.SeasonRequests) private async Task SendToSonarr(ChildRequests model, SonarrSeries result, SonarrSettings s)
{ {
foreach (var ep in req.Episodes) var episodesToUpdate = new List<Episode>();
{ // Ok, now let's sort out the episodes.
var sonarrEp = sonarrEpList.FirstOrDefault(x =>
x.episodeNumber == ep.EpisodeNumber && x.seasonNumber == req.SeasonNumber); var sonarrEpisodes = await SonarrApi.GetEpisodes(result.id, s.ApiKey, s.FullUri);
if (sonarrEp != null) var sonarrEpList = sonarrEpisodes.ToList() ?? new List<Episode>();
{ while (!sonarrEpList.Any())
sonarrEp.monitored = true; {
episodesToUpdate.Add(sonarrEp); // 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);
} }
var seriesChanges = false;
foreach (var season in model.SeasonRequests)
{ foreach (var req in model.SeasonRequests)
var sonarrSeason = sonarrEpList.Where(x => x.seasonNumber == season.SeasonNumber); {
var sonarrEpCount = sonarrSeason.Count(); foreach (var ep in req.Episodes)
var ourRequestCount = season.Episodes.Count; {
var sonarrEp = sonarrEpList.FirstOrDefault(x =>
if (sonarrEpCount == ourRequestCount) x.episodeNumber == ep.EpisodeNumber && x.seasonNumber == req.SeasonNumber);
{ if (sonarrEp != null)
// We have the same amount of requests as all of the episodes in the season. {
var existingSeason = sonarrEp.monitored = true;
result.seasons.First(x => x.seasonNumber == season.SeasonNumber); episodesToUpdate.Add(sonarrEp);
existingSeason.monitored = true; }
seriesChanges = true; }
} }
else var seriesChanges = false;
{ foreach (var season in model.SeasonRequests)
// Now update the episodes that need updating {
foreach (var epToUpdate in episodesToUpdate.Where(x => x.seasonNumber == season.SeasonNumber)) var sonarrSeason = sonarrEpList.Where(x => x.seasonNumber == season.SeasonNumber);
{ var sonarrEpCount = sonarrSeason.Count();
await SonarrApi.UpdateEpisode(epToUpdate, s.ApiKey, s.FullUri); var ourRequestCount = season.Episodes.Count;
}
} if (sonarrEpCount == ourRequestCount)
} {
if (seriesChanges) // We have the same amount of requests as all of the episodes in the season.
{ var existingSeason =
await SonarrApi.SeasonPass(s.ApiKey, s.FullUri, result); result.seasons.First(x => x.seasonNumber == season.SeasonNumber);
} existingSeason.monitored = true;
seriesChanges = true;
}
if (!s.AddOnly) else
{ {
await SearchForRequest(model, sonarrEpList, result, s, episodesToUpdate); // 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);
public async Task SendToSickRage(ChildRequests model, string qualityId = null) }
{ }
var settings = await SickRageSettings.GetSettingsAsync(); }
if (qualityId.HasValue()) if (seriesChanges)
{ {
if (settings.Qualities.All(x => x.Key != qualityId)) await SonarrApi.SeasonPass(s.ApiKey, s.FullUri, result);
{ }
qualityId = settings.QualityProfile;
}
} if (!s.AddOnly)
{
//var apiResult = SickRageApi.AddSeries(model.ParentRequest.TvDbId, model.SeasonCount, model.SeasonList, qualityId, await SearchForRequest(model, sonarrEpList, result, s, episodesToUpdate);
// sickRageSettings.ApiKey, sickRageSettings.FullUri); }
}
//var result = apiResult.Result;
private async Task<bool> SendToSickRage(ChildRequests model, SickRageSettings settings, string qualityId = null)
{
//return result; 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
private async Task SearchForRequest(ChildRequests model, IEnumerable<Episode> sonarrEpList, SonarrSeries existingSeries, SonarrSettings s, var existingShow = await SickRageApi.GetShow(tvdbid, settings.ApiKey, settings.FullUri);
IReadOnlyCollection<Episode> episodesToUpdate)
{ if (existingShow == null)
foreach (var season in model.SeasonRequests) {
{ var addResult = await SickRageApi.AddSeries(model.ParentRequest.TvDbId, SickRageStatus.Wanted,
var sonarrSeason = sonarrEpList.Where(x => x.seasonNumber == season.SeasonNumber); qualityId,
var sonarrEpCount = sonarrSeason.Count(); settings.ApiKey, settings.FullUri);
var ourRequestCount = season.Episodes.Count;
Logger.LogDebug("Added the show (tvdbid) {0}. The result is '{2}' : '{3}'", tvdbid, addResult.result, addResult.message);
if (sonarrEpCount == ourRequestCount) if (addResult.result.Equals("failure"))
{ {
// We have the same amount of requests as all of the episodes in the season. // Do something
// Do a season search return false;
await SonarrApi.SeasonSearch(existingSeries.id, season.SeasonNumber, s.ApiKey, s.FullUri); }
} }
else
{ foreach (var seasonRequests in model.SeasonRequests)
// There is a miss-match, let's search the episodes indiviaully {
await SonarrApi.EpisodeSearch(episodesToUpdate.Select(x => x.id).ToArray(), s.ApiKey, s.FullUri); var srEpisodes = await SickRageApi.GetEpisodesForSeason(tvdbid, seasonRequests.SeasonNumber, settings.ApiKey, settings.FullUri);
} var totalSrEpisodes = srEpisodes.data.Count;
}
} if (totalSrEpisodes == seasonRequests.Episodes.Count)
{
private async Task<string> GetSonarrRootPath(int pathId, SonarrSettings sonarrSettings) // This is a request for the whole season
{ var wholeSeasonResult = await SickRageApi.SetEpisodeStatus(settings.ApiKey, settings.FullUri, tvdbid, SickRageStatus.Wanted,
var rootFoldersResult = await SonarrApi.GetRootFolders(sonarrSettings.ApiKey, sonarrSettings.FullUri); seasonRequests.SeasonNumber);
if (pathId == 0) Logger.LogDebug("Set the status to Wanted for season {0}. The result is '{1}' : '{2}'", seasonRequests.SeasonNumber, wholeSeasonResult.result, wholeSeasonResult.message);
{ continue;
return rootFoldersResult.FirstOrDefault().path; }
}
foreach (var srEp in srEpisodes.data)
foreach (var r in rootFoldersResult.Where(r => r.id == pathId)) {
{ var epNumber = srEp.Key;
return r.path; var epData = srEp.Value;
}
return string.Empty; 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<Episode> sonarrEpList, SonarrSeries existingSeries, SonarrSettings s,
IReadOnlyCollection<Episode> 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<string> 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;
}
}
} }

View file

@ -19,6 +19,7 @@ namespace Ombi.Helpers
public static EventId SonarrCacher => new EventId(2006); public static EventId SonarrCacher => new EventId(2006);
public static EventId CouchPotatoCacher => new EventId(2007); public static EventId CouchPotatoCacher => new EventId(2007);
public static EventId PlexContentCacher => new EventId(2008); public static EventId PlexContentCacher => new EventId(2008);
public static EventId SickRageCacher => new EventId(2009);
public static EventId MovieSender => new EventId(3000); public static EventId MovieSender => new EventId(3000);

View file

@ -6,6 +6,7 @@ using Ombi.Schedule.Jobs.Emby;
using Ombi.Schedule.Jobs.Ombi; using Ombi.Schedule.Jobs.Ombi;
using Ombi.Schedule.Jobs.Plex; using Ombi.Schedule.Jobs.Plex;
using Ombi.Schedule.Jobs.Radarr; using Ombi.Schedule.Jobs.Radarr;
using Ombi.Schedule.Jobs.SickRage;
using Ombi.Schedule.Jobs.Sonarr; using Ombi.Schedule.Jobs.Sonarr;
using Ombi.Settings.Settings.Models; using Ombi.Settings.Settings.Models;
@ -16,7 +17,7 @@ namespace Ombi.Schedule
public JobSetup(IPlexContentSync plexContentSync, IRadarrSync radarrSync, public JobSetup(IPlexContentSync plexContentSync, IRadarrSync radarrSync,
IOmbiAutomaticUpdater updater, IEmbyContentSync embySync, IPlexUserImporter userImporter, IOmbiAutomaticUpdater updater, IEmbyContentSync embySync, IPlexUserImporter userImporter,
IEmbyUserImporter embyUserImporter, ISonarrSync cache, ICouchPotatoSync cpCache, IEmbyUserImporter embyUserImporter, ISonarrSync cache, ICouchPotatoSync cpCache,
ISettingsService<JobSettings> jobsettings) ISettingsService<JobSettings> jobsettings, ISickRageSync srSync)
{ {
PlexContentSync = plexContentSync; PlexContentSync = plexContentSync;
RadarrSync = radarrSync; RadarrSync = radarrSync;
@ -37,6 +38,7 @@ namespace Ombi.Schedule
private IEmbyUserImporter EmbyUserImporter { get; } private IEmbyUserImporter EmbyUserImporter { get; }
private ISonarrSync SonarrSync { get; } private ISonarrSync SonarrSync { get; }
private ICouchPotatoSync CpCache { get; } private ICouchPotatoSync CpCache { get; }
private ISickRageSync SrSync { get; }
private ISettingsService<JobSettings> JobSettings { get; set; } private ISettingsService<JobSettings> JobSettings { get; set; }
public void Setup() public void Setup()
@ -48,6 +50,7 @@ namespace Ombi.Schedule
RecurringJob.AddOrUpdate(() => RadarrSync.CacheContent(), JobSettingsHelper.Radarr(s)); RecurringJob.AddOrUpdate(() => RadarrSync.CacheContent(), JobSettingsHelper.Radarr(s));
RecurringJob.AddOrUpdate(() => PlexContentSync.CacheContent(), JobSettingsHelper.PlexContent(s)); RecurringJob.AddOrUpdate(() => PlexContentSync.CacheContent(), JobSettingsHelper.PlexContent(s));
RecurringJob.AddOrUpdate(() => CpCache.Start(), JobSettingsHelper.CouchPotato(s)); RecurringJob.AddOrUpdate(() => CpCache.Start(), JobSettingsHelper.CouchPotato(s));
RecurringJob.AddOrUpdate(() => SrSync.Start(), JobSettingsHelper.SickRageSync(s));
RecurringJob.AddOrUpdate(() => Updater.Update(null), JobSettingsHelper.Updater(s)); RecurringJob.AddOrUpdate(() => Updater.Update(null), JobSettingsHelper.Updater(s));

View file

@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace Ombi.Schedule.Jobs.SickRage
{
public interface ISickRageSync
{
Task Start();
}
}

View file

@ -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<SickRageSettings> s, ISickRageApi api, ILogger<SickRageSync> l, IOmbiContext ctx)
{
_settings = s;
_api = api;
_log = l;
_ctx = ctx;
_settings.ClearCache();
}
private readonly ISettingsService<SickRageSettings> _settings;
private readonly ISickRageApi _api;
private readonly ILogger<SickRageSync> _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<SickRageEpisodeCache>();
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();
}
}
}
}

View file

@ -27,6 +27,7 @@
<ProjectReference Include="..\Ombi.Api.Plex\Ombi.Api.Plex.csproj" /> <ProjectReference Include="..\Ombi.Api.Plex\Ombi.Api.Plex.csproj" />
<ProjectReference Include="..\Ombi.Api.Radarr\Ombi.Api.Radarr.csproj" /> <ProjectReference Include="..\Ombi.Api.Radarr\Ombi.Api.Radarr.csproj" />
<ProjectReference Include="..\Ombi.Api.Service\Ombi.Api.Service.csproj" /> <ProjectReference Include="..\Ombi.Api.Service\Ombi.Api.Service.csproj" />
<ProjectReference Include="..\Ombi.Api.SickRage\Ombi.Api.SickRage.csproj" />
<ProjectReference Include="..\Ombi.Api.Sonarr\Ombi.Api.Sonarr.csproj" /> <ProjectReference Include="..\Ombi.Api.Sonarr\Ombi.Api.Sonarr.csproj" />
<ProjectReference Include="..\Ombi.Notifications\Ombi.Notifications.csproj" /> <ProjectReference Include="..\Ombi.Notifications\Ombi.Notifications.csproj" />
<ProjectReference Include="..\Ombi.Settings\Ombi.Settings.csproj" /> <ProjectReference Include="..\Ombi.Settings\Ombi.Settings.csproj" />

View file

@ -1,5 +1,4 @@
using System.Collections.Generic; using System.Collections.Generic;
using Newtonsoft.Json;
namespace Ombi.Settings.Settings.Models.External namespace Ombi.Settings.Settings.Models.External
{ {
@ -8,19 +7,34 @@ namespace Ombi.Settings.Settings.Models.External
public bool Enabled { get; set; } public bool Enabled { get; set; }
public string ApiKey { get; set; } public string ApiKey { get; set; }
public string QualityProfile { get; set; } public string QualityProfile { get; set; }
[JsonIgnore] public List<DropDownModel> Qualities => new List<DropDownModel>
public Dictionary<string, string> Qualities => new Dictionary<string, string>
{ {
{ "default", "Use Default" }, new DropDownModel("default", "Use Default"),
{ "sdtv", "SD TV" }, new DropDownModel("sdtv", "SD TV"),
{ "sddvd", "SD DVD" }, new DropDownModel("sddvd", "SD DVD"),
{ "hdtv", "HD TV" }, new DropDownModel("hdtv", "HD TV"),
{ "rawhdtv", "Raw HD TV" }, new DropDownModel("rawhdtv", "Raw HD TV"),
{ "hdwebdl", "HD Web DL" }, new DropDownModel("hdwebdl", "HD Web DL"),
{ "fullhdwebdl", "Full HD Web DL" }, new DropDownModel("fullhdwebdl", "Full HD Web DL"),
{ "hdbluray", "HD Bluray" }, new DropDownModel("hdbluray", "HD Bluray"),
{ "fullhdbluray", "Full 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; }
}
} }

View file

@ -9,5 +9,6 @@
public string CouchPotatoSync { get; set; } public string CouchPotatoSync { get; set; }
public string AutomaticUpdater { get; set; } public string AutomaticUpdater { get; set; }
public string UserImporter { get; set; } public string UserImporter { get; set; }
public string SickRageSync { get; set; }
} }
} }

View file

@ -35,6 +35,10 @@ namespace Ombi.Settings.Settings.Models
{ {
return Get(s.UserImporter, Cron.Daily()); 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) private static string Get(string settings, string defaultCron)

View file

@ -38,5 +38,7 @@ namespace Ombi.Store.Context
EntityEntry Update(object entity); EntityEntry Update(object entity);
EntityEntry<TEntity> Update<TEntity>(TEntity entity) where TEntity : class; EntityEntry<TEntity> Update<TEntity>(TEntity entity) where TEntity : class;
DbSet<CouchPotatoCache> CouchPotatoCache { get; set; } DbSet<CouchPotatoCache> CouchPotatoCache { get; set; }
DbSet<SickRageCache> SickRageCache { get; set; }
DbSet<SickRageEpisodeCache> SickRageEpisodeCache { get; set; }
} }
} }

View file

@ -40,6 +40,8 @@ namespace Ombi.Store.Context
public DbSet<Tokens> Tokens { get; set; } public DbSet<Tokens> Tokens { get; set; }
public DbSet<SonarrCache> SonarrCache { get; set; } public DbSet<SonarrCache> SonarrCache { get; set; }
public DbSet<SonarrEpisodeCache> SonarrEpisodeCache { get; set; } public DbSet<SonarrEpisodeCache> SonarrEpisodeCache { get; set; }
public DbSet<SickRageCache> SickRageCache { get; set; }
public DbSet<SickRageEpisodeCache> SickRageEpisodeCache { get; set; }
public DbSet<ApplicationConfiguration> ApplicationConfigurations { get; set; } public DbSet<ApplicationConfiguration> ApplicationConfigurations { get; set; }

View file

@ -0,0 +1,10 @@
using System.ComponentModel.DataAnnotations.Schema;
namespace Ombi.Store.Entities
{
[Table("SickRageCache")]
public class SickRageCache : Entity
{
public int TvDbId { get; set; }
}
}

View file

@ -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; }
}
}

View file

@ -26,7 +26,3 @@ export interface IUsersModel {
id: string; id: string;
username: string; username: string;
} }
export interface IDictionary<T> {
[Key: string]: T;
}

View file

@ -1,4 +1,4 @@
import { IDictionary, ISettings } from "./ICommon"; import { ISettings } from "./ICommon";
export interface IExternalSettings extends ISettings { export interface IExternalSettings extends ISettings {
ssl: boolean; ssl: boolean;
@ -115,6 +115,7 @@ export interface IJobSettings {
couchPotatoSync: string; couchPotatoSync: string;
automaticUpdater: string; automaticUpdater: string;
userImporter: string; userImporter: string;
sickRageSync: string;
} }
export interface IAuthenticationSettings extends ISettings { export interface IAuthenticationSettings extends ISettings {
@ -158,7 +159,12 @@ export interface ISickRageSettings extends IExternalSettings {
enabled: boolean; enabled: boolean;
apiKey: string; apiKey: string;
qualityProfile: string; qualityProfile: string;
qualities: IDictionary<string>; qualities: IDropDownModel[];
}
export interface IDropDownModel {
value: string;
display: string;
} }
export interface IDogNzbSettings extends ISettings { export interface IDogNzbSettings extends ISettings {

View file

@ -13,6 +13,11 @@
<input type="text" class="form-control form-control-custom" [ngClass]="{'form-error': form.get('sonarrSync').hasError('required')}" id="sonarrSync" name="sonarrSync" formControlName="sonarrSync"> <input type="text" class="form-control form-control-custom" [ngClass]="{'form-error': form.get('sonarrSync').hasError('required')}" id="sonarrSync" name="sonarrSync" formControlName="sonarrSync">
<small *ngIf="form.get('sonarrSync').hasError('required')" class="error-text">The Sonarr Sync is required</small> <small *ngIf="form.get('sonarrSync').hasError('required')" class="error-text">The Sonarr Sync is required</small>
</div> </div>
<div class="form-group">
<label for="sickRageSync" class="control-label">SickRage Sync</label>
<input type="text" class="form-control form-control-custom" [ngClass]="{'form-error': form.get('sonarrSync').hasError('required')}" id="sickRageSync" name="sickRageSync" formControlName="sickRageSync">
<small *ngIf="form.get('sickRageSync').hasError('required')" class="error-text">The SickRage Sync is required</small>
</div>
<div class="form-group"> <div class="form-group">
<label for="radarrSync" class="control-label">Radarr Sync</label> <label for="radarrSync" class="control-label">Radarr Sync</label>

View file

@ -23,8 +23,9 @@ export class JobsComponent implements OnInit {
embyContentSync: [x.embyContentSync, Validators.required], embyContentSync: [x.embyContentSync, Validators.required],
plexContentSync: [x.plexContentSync, Validators.required], plexContentSync: [x.plexContentSync, Validators.required],
userImporter: [x.userImporter, Validators.required], userImporter: [x.userImporter, Validators.required],
sonarrSync: [x.radarrSync, Validators.required], sonarrSync: [x.radarrSync, Validators.required],
radarrSync: [x.sonarrSync, Validators.required], radarrSync: [x.sonarrSync, Validators.required],
sickRageSync: [x.sickRageSync, Validators.required],
}); });
}); });
} }

View file

@ -30,8 +30,7 @@
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/Sonarr']">Sonarr</a></li> <li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/Sonarr']">Sonarr</a></li>
<li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/DogNzb']">DogNzb</a></li> <li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/DogNzb']">DogNzb</a></li>
<li [routerLinkActive]="['active']"><a>More Coming Soon...</a></li> <li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/SickRage']">SickRage</a></li>
<!--<li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/SickRage']">SickRage</a></li>-->
</ul> </ul>
</li> </li>
@ -44,7 +43,6 @@
<li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/DogNzb']">DogNzb</a></li> <li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/DogNzb']">DogNzb</a></li>
<li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/Radarr']">Radarr</a></li> <li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/Radarr']">Radarr</a></li>
<!--<li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/Watcher']">Watcher</a></li>--> <!--<li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/Watcher']">Watcher</a></li>-->
<li [routerLinkActive]="['active']"><a>More Coming Soon...</a></li>
</ul> </ul>
</li> </li>

View file

@ -53,7 +53,7 @@
<label for="select" class="control-label">Quality Profiles</label> <label for="select" class="control-label">Quality Profiles</label>
<div id="profiles"> <div id="profiles">
<select class="form-control form-control-custom" [ngClass]="{'form-error': form.get('qualityProfile').hasError('required')}" id="select" formControlName="qualityProfile"> <select class="form-control form-control-custom" [ngClass]="{'form-error': form.get('qualityProfile').hasError('required')}" id="select" formControlName="qualityProfile">
<option *ngFor="let quality of qualities" value="{{quality.id}}" >{{quality.name}}</option> <option *ngFor="let quality of qualities" value="{{quality.value}}" >{{quality.display}}</option>
</select> </select>
</div> </div>
<small *ngIf="form.get('qualityProfile').hasError('required')" class="error-text">A Default Quality Profile is required</small> <small *ngIf="form.get('qualityProfile').hasError('required')" class="error-text">A Default Quality Profile is required</small>

View file

@ -1,9 +1,7 @@
import { Component, OnInit } from "@angular/core"; import { Component, OnInit } from "@angular/core";
import { FormBuilder, FormGroup, Validators } from "@angular/forms"; import { FormBuilder, FormGroup, Validators } from "@angular/forms";
import { ISonarrProfile, ISonarrRootFolder } from "../../interfaces"; import { IDropDownModel, ISickRageSettings } from "../../interfaces";
import { ISickRageSettings } from "../../interfaces";
import { TesterService } from "../../services"; import { TesterService } from "../../services";
import { NotificationService } from "../../services"; import { NotificationService } from "../../services";
import { SettingsService } from "../../services"; import { SettingsService } from "../../services";
@ -13,14 +11,8 @@ import { SettingsService } from "../../services";
}) })
export class SickRageComponent implements OnInit { export class SickRageComponent implements OnInit {
public qualities: ISonarrProfile[]; public qualities: IDropDownModel[];
public rootFolders: ISonarrRootFolder[];
public selectedRootFolder: ISonarrRootFolder;
public selectedQuality: ISonarrProfile;
public profilesRunning: boolean;
public rootFoldersRunning: boolean;
public form: FormGroup; public form: FormGroup;
public advanced = false;
constructor(private settingsService: SettingsService, constructor(private settingsService: SettingsService,
private notificationService: NotificationService, private notificationService: NotificationService,
@ -34,13 +26,12 @@ export class SickRageComponent implements OnInit {
enabled: [x.enabled], enabled: [x.enabled],
apiKey: [x.apiKey, [Validators.required]], apiKey: [x.apiKey, [Validators.required]],
qualityProfile: [x.qualityProfile, [Validators.required]], qualityProfile: [x.qualityProfile, [Validators.required]],
qualities: [x.qualities],
ssl: [x.ssl], ssl: [x.ssl],
subDir: [x.subDir], subDir: [x.subDir],
ip: [x.ip, [Validators.required]], ip: [x.ip, [Validators.required]],
port: [x.port, [Validators.required]], port: [x.port, [Validators.required]],
}); });
this.qualities = x.qualities;
}); });
} }

View file

@ -1,7 +1,6 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Hangfire;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Ombi.Api.CouchPotato; using Ombi.Api.CouchPotato;
@ -10,7 +9,6 @@ using Ombi.Api.Plex;
using Ombi.Api.Radarr; using Ombi.Api.Radarr;
using Ombi.Api.SickRage; using Ombi.Api.SickRage;
using Ombi.Api.Sonarr; using Ombi.Api.Sonarr;
using Ombi.Api.Telegram;
using Ombi.Attributes; using Ombi.Attributes;
using Ombi.Core.Notifications; using Ombi.Core.Notifications;
using Ombi.Core.Settings.Models.External; using Ombi.Core.Settings.Models.External;
@ -18,7 +16,6 @@ using Ombi.Helpers;
using Ombi.Notifications; using Ombi.Notifications;
using Ombi.Notifications.Agents; using Ombi.Notifications.Agents;
using Ombi.Notifications.Models; using Ombi.Notifications.Models;
using Ombi.Notifications.Templates;
using Ombi.Settings.Settings.Models.External; using Ombi.Settings.Settings.Models.External;
using Ombi.Settings.Settings.Models.Notifications; using Ombi.Settings.Settings.Models.Notifications;
@ -84,11 +81,19 @@ namespace Ombi.Controllers.External
[HttpPost("discord")] [HttpPost("discord")]
public bool Discord([FromBody] DiscordNotificationSettings settings) public bool Discord([FromBody] DiscordNotificationSettings settings)
{ {
settings.Enabled = true; try
DiscordNotification.NotifyAsync( {
new NotificationOptions { NotificationType = NotificationType.Test, RequestId = -1 }, settings); 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;
}
} }
/// <summary> /// <summary>
@ -99,11 +104,20 @@ namespace Ombi.Controllers.External
[HttpPost("pushbullet")] [HttpPost("pushbullet")]
public bool Pushbullet([FromBody] PushbulletSettings settings) public bool Pushbullet([FromBody] PushbulletSettings settings)
{ {
settings.Enabled = true; try
PushbulletNotification.NotifyAsync( {
new NotificationOptions { NotificationType = NotificationType.Test, RequestId = -1 }, settings);
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;
}
} }
/// <summary> /// <summary>
@ -114,11 +128,20 @@ namespace Ombi.Controllers.External
[HttpPost("pushover")] [HttpPost("pushover")]
public bool Pushover([FromBody] PushoverSettings settings) public bool Pushover([FromBody] PushoverSettings settings)
{ {
settings.Enabled = true; try
PushoverNotification.NotifyAsync( {
new NotificationOptions { NotificationType = NotificationType.Test, RequestId = -1 }, settings); 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;
} }
/// <summary> /// <summary>
@ -129,11 +152,21 @@ namespace Ombi.Controllers.External
[HttpPost("mattermost")] [HttpPost("mattermost")]
public bool Mattermost([FromBody] MattermostNotificationSettings settings) public bool Mattermost([FromBody] MattermostNotificationSettings settings)
{ {
settings.Enabled = true; try
MattermostNotification.NotifyAsync( {
new NotificationOptions { NotificationType = NotificationType.Test, RequestId = -1 }, settings); 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")] [HttpPost("slack")]
public bool Slack([FromBody] SlackNotificationSettings settings) public bool Slack([FromBody] SlackNotificationSettings settings)
{ {
settings.Enabled = true; try
SlackNotification.NotifyAsync( {
new NotificationOptions { NotificationType = NotificationType.Test, RequestId = -1 }, settings); 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;
}
} }
/// <summary> /// <summary>
@ -293,10 +334,18 @@ namespace Ombi.Controllers.External
[HttpPost("telegram")] [HttpPost("telegram")]
public async Task<bool> Telegram([FromBody] TelegramSettings settings) public async Task<bool> Telegram([FromBody] TelegramSettings settings)
{ {
settings.Enabled = true; try
await TelegramNotification.NotifyAsync(new NotificationOptions { NotificationType = NotificationType.Test, RequestId = -1 }, settings); {
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;
}
} }
/// <summary> /// <summary>
@ -307,9 +356,17 @@ namespace Ombi.Controllers.External
[HttpPost("sickrage")] [HttpPost("sickrage")]
public async Task<bool> SickRage([FromBody] SickRageSettings settings) public async Task<bool> SickRage([FromBody] SickRageSettings settings)
{ {
settings.Enabled = true; try
var result = await SickRageApi.Ping(settings.ApiKey, settings.FullUri); {
return result?.data?.pid != null; 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;
}
} }
} }
} }