Started on sonarr #865

pull/1488/head
tidusjar 7 years ago
parent 3ee65f4f0c
commit 2c945ebb9b

@ -8,5 +8,9 @@ namespace Ombi.Api.Sonarr
{
Task<IEnumerable<SonarrProfile>> GetProfiles(string apiKey, string baseUrl);
Task<IEnumerable<SonarrRootFolder>> GetRootFolders(string apiKey, string baseUrl);
Task<IEnumerable<SonarrSeries>> GetSeries(string apiKey, string baseUrl);
Task<SonarrSeries> GetSeriesById(int id, string apiKey, string baseUrl);
Task<SonarrSeries> UpdateSeries(SonarrSeries updated, string apiKey, string baseUrl);
Task<NewSeries> AddSeries(NewSeries seriesToAdd, string apiKey, string baseUrl);
}
}

@ -0,0 +1,75 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Text;
namespace Ombi.Api.Sonarr.Models
{
public class NewSeries
{
public NewSeries()
{
images = new List<SonarrImage>();
}
public AddOptions addOptions { get; set; }
public string title { get; set; }
public List<Season> seasons { get; set; }
public string rootFolderPath { get; set; }
public int qualityProfileId { get; set; }
public bool seasonFolder { get; set; }
public bool monitored { get; set; }
public int tvdbId { get; set; }
public int tvRageId { get; set; }
public string cleanTitle { get; set; }
public string imdbId { get; set; }
public string titleSlug { get; set; }
public int id { get; set; }
public List<SonarrImage> images { get; set; }
/// <summary>
/// This is for us
/// </summary>
[JsonIgnore]
public List<string> ErrorMessages { get; set; }
public string Validate()
{
var errors = new List<string>();
var sb = new StringBuilder();
if(this.tvdbId == 0)
{
sb.AppendLine("TVDBID is missing");
}
if(string.IsNullOrEmpty(title))
{
sb.AppendLine("Title is missing");
}
if(qualityProfileId == 0)
{
sb.AppendLine("Quality ID is missing");
}
return sb.ToString();
}
}
public class AddOptions
{
public bool ignoreEpisodesWithFiles { get; set; }
public bool ignoreEpisodesWithoutFiles { get; set; }
public bool searchForMissingEpisodes { get; set; }
}
public class SonarrImage
{
public string coverType { get; set; }
public string url { get; set; }
}
public class SonarrError
{
public string propertyName { get; set; }
public string errorMessage { get; set; }
public object attemptedValue { get; set; }
}
}

@ -0,0 +1,88 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Ombi.Api.Sonarr.Models
{
public class SonarrSeries
{
public string title { get; set; }
public Alternatetitle[] alternateTitles { get; set; }
public string sortTitle { get; set; }
public int seasonCount { get; set; }
public int totalEpisodeCount { get; set; }
public int episodeCount { get; set; }
public int episodeFileCount { get; set; }
public long sizeOnDisk { get; set; }
public string status { get; set; }
public string overview { get; set; }
public DateTime previousAiring { get; set; }
public string network { get; set; }
public string airTime { get; set; }
public Image[] images { get; set; }
public Season[] seasons { get; set; }
public int year { get; set; }
public string path { get; set; }
public int profileId { get; set; }
public bool seasonFolder { get; set; }
public bool monitored { get; set; }
public bool useSceneNumbering { get; set; }
public int runtime { get; set; }
public int tvdbId { get; set; }
public int tvRageId { get; set; }
public int tvMazeId { get; set; }
public DateTime firstAired { get; set; }
public DateTime lastInfoSync { get; set; }
public string seriesType { get; set; }
public string cleanTitle { get; set; }
public string imdbId { get; set; }
public string titleSlug { get; set; }
public string certification { get; set; }
public string[] genres { get; set; }
public object[] tags { get; set; }
public DateTime added { get; set; }
public Ratings ratings { get; set; }
public int qualityProfileId { get; set; }
public int id { get; set; }
public DateTime nextAiring { get; set; }
}
public class Ratings
{
public int votes { get; set; }
public float value { get; set; }
}
public class Alternatetitle
{
public string title { get; set; }
public int sceneSeasonNumber { get; set; }
public int seasonNumber { get; set; }
}
public class Image
{
public string coverType { get; set; }
public string url { get; set; }
}
public class Season
{
public int seasonNumber { get; set; }
public bool monitored { get; set; }
public Statistics statistics { get; set; }
}
public class Statistics
{
public int episodeFileCount { get; set; }
public int episodeCount { get; set; }
public int totalEpisodeCount { get; set; }
public long sizeOnDisk { get; set; }
public int percentOfEpisodes { get; set; }
public DateTime previousAiring { get; set; }
public DateTime nextAiring { get; set; }
}
}

@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using Ombi.Api.Sonarr.Models;
using Newtonsoft.Json;
using System.Linq;
namespace Ombi.Api.Sonarr
{
@ -33,5 +35,77 @@ namespace Ombi.Api.Sonarr
return await Api.Request<List<SonarrRootFolder>>(request);
}
/// <summary>
/// Returns all the series in Sonarr
/// </summary>
/// <param name="apiKey"></param>
/// <param name="baseUrl"></param>
/// <returns></returns>
public async Task<IEnumerable<SonarrSeries>> GetSeries(string apiKey, string baseUrl)
{
var request = new Request("/api/series", baseUrl, HttpMethod.Get);
request.AddHeader("X-Api-Key", apiKey);
return await Api.Request<List<SonarrSeries>>(request);
}
/// <summary>
/// Returns the series by the Sonarr ID
/// </summary>
/// <param name="id">Sonarr ID for the series</param>
/// <param name="apiKey"></param>
/// <param name="baseUrl"></param>
/// <returns></returns>
public async Task<SonarrSeries> GetSeriesById(int id, string apiKey, string baseUrl)
{
var request = new Request($"/api/series/{id}", baseUrl, HttpMethod.Get);
request.AddHeader("X-Api-Key", apiKey);
return await Api.Request<SonarrSeries>(request);
}
/// <summary>
/// Update the following series
/// </summary>
/// <param name="updated">The series to update</param>
/// <param name="apiKey"></param>
/// <param name="baseUrl"></param>
/// <returns></returns>
public async Task<SonarrSeries> UpdateSeries(SonarrSeries updated, string apiKey, string baseUrl)
{
var request = new Request("/api/series/", baseUrl, HttpMethod.Put);
request.AddHeader("X-Api-Key", apiKey);
request.AddJsonBody(updated);
return await Api.Request<SonarrSeries>(request);
}
public async Task<NewSeries> AddSeries(NewSeries seriesToAdd, string apiKey, string baseUrl)
{
if(!string.IsNullOrEmpty(seriesToAdd.Validate()))
{
return new NewSeries { ErrorMessages = new List<string> { seriesToAdd.Validate() } };
}
var request = new Request("/api/series/", baseUrl, HttpMethod.Post);
request.AddHeader("X-Api-Key", apiKey);
try
{
return await Api.Request<NewSeries>(request);
}
catch (JsonSerializationException e)
{
var error = await Api.Request<List<SonarrError>>(request);
var messages = error?.Select(x => x.errorMessage).ToList();
messages?.ForEach(x => Log.Error(x));
return new NewSeries { ErrorMessages = messages };
}
}
}
}

@ -24,18 +24,21 @@ namespace Ombi.Core.Engine
{
public TvRequestEngine(ITvMazeApi tvApi, IRequestServiceMain requestService, IPrincipal user,
INotificationHelper helper, IMapper map,
IRuleEvaluator rule, IUserIdentityManager manager) : base(user, requestService, rule)
IRuleEvaluator rule, IUserIdentityManager manager,
ITvSender sender) : base(user, requestService, rule)
{
TvApi = tvApi;
NotificationHelper = helper;
Mapper = map;
UserManager = manager;
TvSender = sender;
}
private INotificationHelper NotificationHelper { get; }
private ITvMazeApi TvApi { get; }
private IMapper Mapper { get; }
private IUserIdentityManager UserManager { get; }
private ITvSender TvSender {get;}
public async Task<RequestEngineResult> RequestTvShow(SearchTvShowViewModel tv)
{
@ -223,7 +226,8 @@ namespace Ombi.Core.Engine
Status = showInfo.status,
ImdbId = showInfo.externals?.imdb ?? string.Empty,
TvDbId = tv.Id,
ChildRequests = new List<ChildRequests>()
ChildRequests = new List<ChildRequests>(),
TotalSeasons = tv.SeasonRequests.Count()
};
model.ChildRequests.Add(childRequest);
return await AddRequest(model);
@ -294,6 +298,12 @@ namespace Ombi.Core.Engine
//NotificationHelper.NewRequest(model.ParentRequest);
}
if(model.Approved)
{
// Autosend
TvSender.SendToSonarr(model,model.ParentRequest.TotalSeasons);
}
//var limit = await RequestLimitRepo.GetAllAsync();
//var usersLimit = limit.FirstOrDefault(x => x.Username == Username && x.RequestType == model.Type);
//if (usersLimit == null)

@ -0,0 +1,12 @@
using System.Threading.Tasks;
using Ombi.Api.Sonarr.Models;
using Ombi.Core.Settings.Models.External;
using Ombi.Store.Entities.Requests;
namespace Ombi.Core
{
public interface ITvSender
{
Task<NewSeries> SendToSonarr(ChildRequests model, int totalSeasons, string qualityId = null);
}
}

@ -1,77 +1,121 @@
using Microsoft.Extensions.Logging;
using Ombi.Api.Sonarr;
using Ombi.Api.Sonarr.Models;
using Ombi.Core.Settings;
using Ombi.Core.Settings.Models.External;
using Ombi.Store.Entities.Requests;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Ombi.Core
{
public class TvSender
public class TvSender : ITvSender
{
public TvSender(ISonarrApi sonarrApi, ILogger<TvSender> log)
public TvSender(ISonarrApi sonarrApi, ILogger<TvSender> log, ISettingsService<SonarrSettings> settings)
{
SonarrApi = sonarrApi;
Logger = log;
Settings = settings;
}
private ISonarrApi SonarrApi { get; }
private ILogger<TvSender> Logger { get; }
private ISettingsService<SonarrSettings> Settings { get; }
//public async Task<SonarrAddSeries> SendToSonarr(SonarrSettings sonarrSettings, TvRequestModel model,
// string qualityId)
//{
// 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(sonarrSettings.QualityProfile, out qualityProfile);
// }
// var rootFolderPath = model.RootFolderSelected <= 0 ? sonarrSettings.FullRootPath : await GetSonarrRootPath(model.RootFolderSelected, sonarrSettings);
// //var episodeRequest = model.Episodes.Any();
// //var requestAll = model.SeasonsRequested?.Equals("All", StringComparison.CurrentCultureIgnoreCase);
// //var first = model.SeasonsRequested?.Equals("First", StringComparison.CurrentCultureIgnoreCase);
// //var latest = model.SeasonsRequested?.Equals("Latest", StringComparison.CurrentCultureIgnoreCase);
// //var specificSeasonRequest = model.SeasonList?.Any();
// //if (episodeRequest)
// //{
// // return await ProcessSonarrEpisodeRequest(sonarrSettings, model, qualityProfile, rootFolderPath);
// //}
// //if (requestAll ?? false)
// //{
// // return await ProcessSonarrRequestSeason(sonarrSettings, model, qualityProfile, rootFolderPath);
// //}
// //if (first ?? false)
// //{
// // return await ProcessSonarrRequestSeason(sonarrSettings, model, qualityProfile, rootFolderPath);
// //}
// //if (latest ?? false)
// //{
// // return await ProcessSonarrRequestSeason(sonarrSettings, model, qualityProfile, rootFolderPath);
// //}
// //if (specificSeasonRequest ?? false)
// //{
// // return await ProcessSonarrRequestSeason(sonarrSettings, model, qualityProfile, rootFolderPath);
// //}
// return null;
//}
/// <summary>
/// Send the request to Sonarr to process
/// </summary>
/// <param name="s"></param>
/// <param name="model"></param>
/// <param name="qualityId">This is for any qualities overriden from the UI</param>
/// <returns></returns>
public async Task<NewSeries> SendToSonarr(ChildRequests model, int totalSeasons, string qualityId = null)
{
var s = await Settings.GetSettingsAsync();
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 ?? 0, s);
// 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 = false, // We want all missing
searchForMissingEpisodes = true // we want to search for missing TODO pass this in
}
};
// Montitor the correct seasons,
// If we have that season in the model then it's monitored!
var seasonsToAdd = new List<Season>();
for (int i = 1; i < totalSeasons; i++)
{
var season = new Season
{
seasonNumber = i,
monitored = model.SeasonRequests.Any(x => x.SeasonNumber == i)
};
seasonsToAdd.Add(season);
}
var result = SonarrApi.AddSeries(newSeries, s.ApiKey, s.FullUri);
return result;
}
else
{
// Let's update the existing
}
return null;
}
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;
}
}

@ -54,6 +54,7 @@ namespace Ombi.DependencyInjection
services.AddTransient<ITvSearchEngine, TvSearchEngine>();
services.AddSingleton<IRuleEvaluator, RuleEvaluator>();
services.AddTransient<IMovieSender, MovieSender>();
services.AddTransient<ITvSender, TvSender>();
}
public static void RegisterApi(this IServiceCollection services)

@ -11,6 +11,8 @@ namespace Ombi.Store.Entities.Requests
public TvRequests ParentRequest { get; set; }
public int ParentRequestId { get; set; }
public int? IssueId { get; set; }
[ForeignKey(nameof(IssueId))]
public List<TvIssues> Issues { get; set; }

@ -13,6 +13,10 @@ namespace Ombi.Store.Entities.Requests
public string PosterPath { get; set; }
public DateTime ReleaseDate { get; set; }
public string Status { get; set; }
/// <summary>
/// This is so we can correctly send the right amount of seasons to Sonarr
/// </summary>
public int TotalSeasons { get; set; }
public List<ChildRequests> ChildRequests { get; set; }
}

Loading…
Cancel
Save