From 4c797733caea44286357ee314e16bf661743f8b7 Mon Sep 17 00:00:00 2001 From: "Jamie.Rees" Date: Wed, 7 Jun 2017 15:07:41 +0100 Subject: [PATCH] Added the Movie Sender, Movies will be sent to Radarr now #865 --- src/Ombi.Api.Radarr/IRadarrApi.cs | 1 + src/Ombi.Api.Radarr/Models/RadarrAddMovie.cs | 27 ++++++++ .../Models/RadarrAddOptions.cs | 9 +++ src/Ombi.Api.Radarr/Models/RadarrError.cs | 21 +++++++ src/Ombi.Api.Radarr/Ombi.Api.Radarr.csproj | 1 + src/Ombi.Api.Radarr/RadarrApi.cs | 53 ++++++++++++++++ src/Ombi.Api/Api.cs | 36 ++++++++++- src/Ombi.Core/Engine/MovieRequestEngine.cs | 53 +++++++--------- src/Ombi.Core/IMovieSender.cs | 10 +++ src/Ombi.Core/MovieSender.cs | 63 +++++++++++-------- src/Ombi.DependencyInjection/IocExtensions.cs | 1 + src/Ombi.Helpers/LoggingEvents.cs | 2 + src/Ombi/Startup.cs | 5 +- 13 files changed, 223 insertions(+), 59 deletions(-) create mode 100644 src/Ombi.Api.Radarr/Models/RadarrAddMovie.cs create mode 100644 src/Ombi.Api.Radarr/Models/RadarrAddOptions.cs create mode 100644 src/Ombi.Api.Radarr/Models/RadarrError.cs create mode 100644 src/Ombi.Core/IMovieSender.cs diff --git a/src/Ombi.Api.Radarr/IRadarrApi.cs b/src/Ombi.Api.Radarr/IRadarrApi.cs index 557aaf613..da2c4f3e2 100644 --- a/src/Ombi.Api.Radarr/IRadarrApi.cs +++ b/src/Ombi.Api.Radarr/IRadarrApi.cs @@ -10,5 +10,6 @@ namespace Ombi.Api.Radarr Task> GetProfiles(string apiKey, string baseUrl); Task> GetRootFolders(string apiKey, string baseUrl); Task SystemStatus(string apiKey, string baseUrl); + Task AddMovie(int tmdbId, string title, int year, int qualityId, string rootPath,string apiKey, string baseUrl, bool searchNow = false); } } \ No newline at end of file diff --git a/src/Ombi.Api.Radarr/Models/RadarrAddMovie.cs b/src/Ombi.Api.Radarr/Models/RadarrAddMovie.cs new file mode 100644 index 000000000..cd685c720 --- /dev/null +++ b/src/Ombi.Api.Radarr/Models/RadarrAddMovie.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; + +namespace Ombi.Api.Radarr.Models +{ + public class RadarrAddMovieResponse + { + + public RadarrAddMovieResponse() + { + images = new List(); + } + public RadarrError Error { get; set; } + public RadarrAddOptions addOptions { get; set; } + public string title { get; set; } + public string rootFolderPath { get; set; } + public int qualityProfileId { get; set; } + public bool monitored { get; set; } + public int tmdbId { get; set; } + public List images { get; set; } + public string cleanTitle { get; set; } + public string imdbId { get; set; } + public string titleSlug { get; set; } + public int id { get; set; } + public int year { get; set; } + + } +} \ No newline at end of file diff --git a/src/Ombi.Api.Radarr/Models/RadarrAddOptions.cs b/src/Ombi.Api.Radarr/Models/RadarrAddOptions.cs new file mode 100644 index 000000000..eb7b9cb35 --- /dev/null +++ b/src/Ombi.Api.Radarr/Models/RadarrAddOptions.cs @@ -0,0 +1,9 @@ +namespace Ombi.Api.Radarr.Models +{ + public class RadarrAddOptions + { + public bool ignoreEpisodesWithFiles { get; set; } + public bool ignoreEpisodesWithoutFiles { get; set; } + public bool searchForMovie { get; set; } + } +} \ No newline at end of file diff --git a/src/Ombi.Api.Radarr/Models/RadarrError.cs b/src/Ombi.Api.Radarr/Models/RadarrError.cs new file mode 100644 index 000000000..a42c2ca52 --- /dev/null +++ b/src/Ombi.Api.Radarr/Models/RadarrError.cs @@ -0,0 +1,21 @@ +namespace Ombi.Api.Radarr.Models +{ + public class RadarrError + { + public string message { get; set; } + public string description { get; set; } + } + + public class RadarrErrorResponse + { + public string propertyName { get; set; } + public string errorMessage { get; set; } + public object attemptedValue { get; set; } + public FormattedMessagePlaceholderValues formattedMessagePlaceholderValues { get; set; } + } + public class FormattedMessagePlaceholderValues + { + public string propertyName { get; set; } + public object propertyValue { get; set; } + } +} \ No newline at end of file diff --git a/src/Ombi.Api.Radarr/Ombi.Api.Radarr.csproj b/src/Ombi.Api.Radarr/Ombi.Api.Radarr.csproj index 028b0e203..41975a213 100644 --- a/src/Ombi.Api.Radarr/Ombi.Api.Radarr.csproj +++ b/src/Ombi.Api.Radarr/Ombi.Api.Radarr.csproj @@ -10,6 +10,7 @@ + \ No newline at end of file diff --git a/src/Ombi.Api.Radarr/RadarrApi.cs b/src/Ombi.Api.Radarr/RadarrApi.cs index 006dce00f..e04c7c8bb 100644 --- a/src/Ombi.Api.Radarr/RadarrApi.cs +++ b/src/Ombi.Api.Radarr/RadarrApi.cs @@ -1,9 +1,12 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Net.Http; using System.Threading.Tasks; using Microsoft.Extensions.Logging; +using Newtonsoft.Json; using Ombi.Api.Radarr.Models; +using Ombi.Helpers; namespace Ombi.Api.Radarr { @@ -50,6 +53,56 @@ namespace Ombi.Api.Radarr return await Api.Request>(request); } + public async Task AddMovie(int tmdbId, string title, int year, int qualityId, string rootPath, string apiKey, string baseUrl, bool searchNow = false) + { + var request = new Request(baseUrl, "/api/movie", HttpMethod.Post); + + var options = new RadarrAddMovieResponse + { + title = title, + tmdbId = tmdbId, + qualityProfileId = qualityId, + rootFolderPath = rootPath, + titleSlug = title, + monitored = true, + year = year + }; + + if (searchNow) + { + options.addOptions = new RadarrAddOptions + { + searchForMovie = true + }; + } + + + request.AddHeader("X-Api-Key", apiKey); + request.AddJsonBody(options); + + try + { + var response = await Api.Request(request); + if (response.Contains("\"message\":")) + { + var error = JsonConvert.DeserializeObject(response); + return new RadarrAddMovieResponse { Error = error }; + } + if (response.Contains("\"errorMessage\":")) + { + var error = JsonConvert.DeserializeObject>(response).FirstOrDefault(); + return new RadarrAddMovieResponse { Error = new RadarrError { message = error?.errorMessage } }; + } + return JsonConvert.DeserializeObject(response); + } + catch (JsonSerializationException jse) + { + Logger.LogError(LoggingEvents.RadarrApiException,jse, "Error When adding movie to Radarr"); + } + return null; + } + + /// /// Adds the required headers and also the authorization header /// diff --git a/src/Ombi.Api/Api.cs b/src/Ombi.Api/Api.cs index 2b885ce0b..248257468 100644 --- a/src/Ombi.Api/Api.cs +++ b/src/Ombi.Api/Api.cs @@ -13,7 +13,7 @@ namespace Ombi.Api { NullValueHandling = NullValueHandling.Ignore }; - + public async Task Request(Request request) { using (var httpClient = new HttpClient()) @@ -30,7 +30,7 @@ namespace Ombi.Api foreach (var header in request.Headers) { httpRequestMessage.Headers.Add(header.Key, header.Value); - + } using (var httpResponseMessage = await httpClient.SendAsync(httpRequestMessage)) { @@ -60,6 +60,38 @@ namespace Ombi.Api } } + public async Task Request(Request request) + { + using (var httpClient = new HttpClient()) + { + using (var httpRequestMessage = new HttpRequestMessage(request.HttpMethod, request.FullUri)) + { + // Add the Json Body + if (request.JsonBody != null) + { + httpRequestMessage.Content = new JsonContent(request.JsonBody); + } + + // Add headers + foreach (var header in request.Headers) + { + httpRequestMessage.Headers.Add(header.Key, header.Value); + + } + using (var httpResponseMessage = await httpClient.SendAsync(httpRequestMessage)) + { + if (!httpResponseMessage.IsSuccessStatusCode) + { + // Logging + } + // do something with the response + var data = httpResponseMessage.Content; + + return await data.ReadAsStringAsync(); + } + } + } + } } } diff --git a/src/Ombi.Core/Engine/MovieRequestEngine.cs b/src/Ombi.Core/Engine/MovieRequestEngine.cs index e369f48c2..61358cecf 100644 --- a/src/Ombi.Core/Engine/MovieRequestEngine.cs +++ b/src/Ombi.Core/Engine/MovieRequestEngine.cs @@ -14,6 +14,7 @@ using System.Globalization; using System.Linq; using System.Security.Principal; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; using Ombi.Core.Engine.Interfaces; namespace Ombi.Core.Engine @@ -21,14 +22,18 @@ namespace Ombi.Core.Engine public class MovieRequestEngine : BaseMediaEngine, IMovieRequestEngine { public MovieRequestEngine(IMovieDbApi movieApi, IRequestServiceMain requestService, IPrincipal user, - INotificationService notificationService, IRuleEvaluator r) : base(user, requestService, r) + INotificationService notificationService, IRuleEvaluator r, IMovieSender sender, ILogger log) : base(user, requestService, r) { MovieApi = movieApi; NotificationService = notificationService; + Sender = sender; + Logger = log; } private IMovieDbApi MovieApi { get; } private INotificationService NotificationService { get; } + private IMovieSender Sender { get; } + private ILogger Logger { get; } public async Task RequestMovie(SearchMovieViewModel model) { @@ -91,7 +96,7 @@ namespace Ombi.Core.Engine Status = movieInfo.Status, RequestedDate = DateTime.UtcNow, Approved = false, - RequestedUsers = new List {Username}, + RequestedUsers = new List { Username }, Issues = IssueState.None }; @@ -106,32 +111,22 @@ namespace Ombi.Core.Engine if (requestModel.Approved) // The rules have auto approved this { - // var result = await MovieSender.Send(model); - // if (result.Result) - // { - // return await AddRequest(model, settings, - // $"{fullMovieName} {Resources.UI.Search_SuccessfullyAdded}"); - // } - // if (result.Error) - - // { - // return - // Response.AsJson(new JsonResponseModel - // { - // Message = "Could not add movie, please contact your administrator", - // Result = false - // }); - // } - // if (!result.MovieSendingEnabled) - // { - // return await AddRequest(model, settings, $"{fullMovieName} {Resources.UI.Search_SuccessfullyAdded}"); - // } - - // return Response.AsJson(new JsonResponseModel - // { - // Result = false, - // Message = Resources.UI.Search_CouchPotatoError - // }); + var result = await Sender.Send(requestModel); + if (result.Success && result.MovieSent) + { + return await AddMovieRequest(requestModel, /*settings,*/ + $"{fullMovieName} has been successfully added!"); + } + if (!result.Success) + { + Logger.LogWarning("Tried auto sending movie but failed. Message: {0}", result.Message); + return new RequestEngineResult + { + Message = result.Message, + ErrorMessage = result.Message, + RequestAdded = false + }; + } } return await AddMovieRequest(requestModel, /*settings,*/ @@ -261,7 +256,7 @@ namespace Ombi.Core.Engine // await RequestLimitRepo.UpdateAsync(usersLimit); //} - return new RequestEngineResult {RequestAdded = true}; + return new RequestEngineResult { RequestAdded = true, Message = message }; } public async Task> GetApprovedRequests() diff --git a/src/Ombi.Core/IMovieSender.cs b/src/Ombi.Core/IMovieSender.cs new file mode 100644 index 000000000..7baf773d0 --- /dev/null +++ b/src/Ombi.Core/IMovieSender.cs @@ -0,0 +1,10 @@ +using System.Threading.Tasks; +using Ombi.Core.Models.Requests.Movie; + +namespace Ombi.Core +{ + public interface IMovieSender + { + Task Send(MovieRequestModel model, string qualityId = ""); + } +} \ No newline at end of file diff --git a/src/Ombi.Core/MovieSender.cs b/src/Ombi.Core/MovieSender.cs index 059c01066..2b8974cbd 100644 --- a/src/Ombi.Core/MovieSender.cs +++ b/src/Ombi.Core/MovieSender.cs @@ -2,17 +2,25 @@ using Ombi.Core.Settings; using Ombi.Settings.Settings.Models.External; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Ombi.Api.Radarr; +using Ombi.Core.Models.Requests; +using Ombi.Helpers; namespace Ombi.Core { - public class MovieSender + public class MovieSender : IMovieSender { - public MovieSender(ISettingsService radarrSettings) + public MovieSender(ISettingsService radarrSettings, IRadarrApi api, ILogger log) { RadarrSettings = radarrSettings; + RadarrApi = api; + Log = log; } private ISettingsService RadarrSettings { get; } + private IRadarrApi RadarrApi { get; } + private ILogger Log { get; } public async Task Send(MovieRequestModel model, string qualityId = "") { @@ -32,7 +40,7 @@ namespace Ombi.Core if (radarrSettings.Enabled) { - //return SendToRadarr(model, radarrSettings, qualityId); + return await SendToRadarr(model, radarrSettings, qualityId); } return new MovieSenderResult @@ -43,32 +51,33 @@ namespace Ombi.Core }; } - // var qualityProfile = 0; - //{ - //private MovieSenderResult SendToRadarr(MovieRequestModel model, RadarrSettings settings, string qualityId) - // if (!string.IsNullOrEmpty(qualityId)) // try to parse the passed in quality, otherwise use the settings default quality - // { - // int.TryParse(qualityId, out qualityProfile); - // } + private async Task SendToRadarr(BaseRequestModel model, RadarrSettings settings, 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(settings.QualityProfile, out qualityProfile); - // } + if (qualityProfile <= 0) + { + int.TryParse(settings.DefaultQualityProfile, out qualityProfile); + } - // var rootFolderPath = model.RootFolderSelected <= 0 ? settings.FullRootPath : GetRootPath(model.RootFolderSelected, settings); - // var result = RadarrApi.AddMovie(model.ProviderId, model.Title, model.ReleaseDate.Year, qualityProfile, rootFolderPath, settings.ApiKey, settings.FullUri, true); + //var rootFolderPath = model.RootFolderSelected <= 0 ? settings.FullRootPath : GetRootPath(model.RootFolderSelected, settings); + var rootFolderPath = settings.DefaultRootPath; // TODO Allow changing in the UI + var result = await RadarrApi.AddMovie(model.ProviderId, model.Title, model.ReleaseDate.Year, qualityProfile, rootFolderPath, settings.ApiKey, settings.FullUri, true); - // if (!string.IsNullOrEmpty(result.Error?.message)) - // { - // Log.Error(result.Error.message); - // return new MovieSenderResult { Result = false, Error = true, MovieSendingEnabled = true }; - // } - // if (!string.IsNullOrEmpty(result.title)) - // { - // return new MovieSenderResult { Result = true, MovieSendingEnabled = true }; - // } - // return new MovieSenderResult { Result = false, MovieSendingEnabled = true }; - //} + if (!string.IsNullOrEmpty(result.Error?.message)) + { + Log.LogError(LoggingEvents.RadarrCacherException,result.Error.message); + return new MovieSenderResult { Success = false, Message = result.Error.message, MovieSent = false }; + } + if (!string.IsNullOrEmpty(result.title)) + { + return new MovieSenderResult { Success = true, MovieSent = false }; + } + return new MovieSenderResult { Success = true, MovieSent = false }; + } } } \ No newline at end of file diff --git a/src/Ombi.DependencyInjection/IocExtensions.cs b/src/Ombi.DependencyInjection/IocExtensions.cs index f45d47b1e..15dc99cd2 100644 --- a/src/Ombi.DependencyInjection/IocExtensions.cs +++ b/src/Ombi.DependencyInjection/IocExtensions.cs @@ -48,6 +48,7 @@ namespace Ombi.DependencyInjection services.AddTransient(); services.AddTransient(); services.AddSingleton(); + services.AddSingleton(); } public static void RegisterApi(this IServiceCollection services) diff --git a/src/Ombi.Helpers/LoggingEvents.cs b/src/Ombi.Helpers/LoggingEvents.cs index d3e03b7d8..acab47918 100644 --- a/src/Ombi.Helpers/LoggingEvents.cs +++ b/src/Ombi.Helpers/LoggingEvents.cs @@ -5,7 +5,9 @@ namespace Ombi.Helpers public class LoggingEvents { public static EventId ApiException => new EventId(1000); + public static EventId RadarrApiException => new EventId(1001); public static EventId CacherException => new EventId(2000); public static EventId RadarrCacherException => new EventId(2001); + public static EventId MovieSender => new EventId(3000); } } \ No newline at end of file diff --git a/src/Ombi/Startup.cs b/src/Ombi/Startup.cs index 6b6407b10..bfbe339f4 100644 --- a/src/Ombi/Startup.cs +++ b/src/Ombi/Startup.cs @@ -78,8 +78,11 @@ namespace Ombi services.AddHangfire(x => { +#if DEBUG + x.UseMemoryStorage(new MemoryStorageOptions()); +#else x.UseSQLiteStorage("Data Source=Ombi.db;"); - //x.UseMemoryStorage(new MemoryStorageOptions()); +#endif x.UseActivator(new IoCJobActivator(services.BuildServiceProvider())); });