From 55134d76c160a5258c52ea33fe8936977eb3c140 Mon Sep 17 00:00:00 2001 From: Qstick Date: Fri, 10 Apr 2020 23:48:23 -0400 Subject: [PATCH] New: Allow Filter by Profile from Radarr Instance List --- .../NetImport/Radarr/RadarrAPIResource.cs | 9 +- .../NetImport/Radarr/RadarrImport.cs | 101 +++++++++++++++--- .../NetImport/Radarr/RadarrParser.cs | 53 --------- .../Radarr/RadarrRequestGenerator.cs | 34 ------ .../NetImport/Radarr/RadarrSettings.cs | 7 +- .../NetImport/Radarr/RadarrV3Proxy.cs | 85 +++++++++++++++ 6 files changed, 188 insertions(+), 101 deletions(-) delete mode 100644 src/NzbDrone.Core/NetImport/Radarr/RadarrParser.cs delete mode 100644 src/NzbDrone.Core/NetImport/Radarr/RadarrRequestGenerator.cs create mode 100644 src/NzbDrone.Core/NetImport/Radarr/RadarrV3Proxy.cs diff --git a/src/NzbDrone.Core/NetImport/Radarr/RadarrAPIResource.cs b/src/NzbDrone.Core/NetImport/Radarr/RadarrAPIResource.cs index 8e88027e4..7778bdb66 100644 --- a/src/NzbDrone.Core/NetImport/Radarr/RadarrAPIResource.cs +++ b/src/NzbDrone.Core/NetImport/Radarr/RadarrAPIResource.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; namespace NzbDrone.Core.NetImport.Radarr @@ -15,5 +15,12 @@ namespace NzbDrone.Core.NetImport.Radarr public DateTime PhysicalRelease { get; set; } public int Year { get; set; } public string TitleSlug { get; set; } + public int QualityProfileId { get; set; } + } + + public class RadarrProfile + { + public string Name { get; set; } + public int Id { get; set; } } } diff --git a/src/NzbDrone.Core/NetImport/Radarr/RadarrImport.cs b/src/NzbDrone.Core/NetImport/Radarr/RadarrImport.cs index 683eb2963..7a4c72cc2 100644 --- a/src/NzbDrone.Core/NetImport/Radarr/RadarrImport.cs +++ b/src/NzbDrone.Core/NetImport/Radarr/RadarrImport.cs @@ -1,39 +1,116 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using FluentValidation.Results; using NLog; -using NzbDrone.Common.Http; +using NzbDrone.Common.Extensions; using NzbDrone.Core.Configuration; +using NzbDrone.Core.Movies; using NzbDrone.Core.Parser; +using NzbDrone.Core.Validation; namespace NzbDrone.Core.NetImport.Radarr { - public class RadarrImport : HttpNetImportBase + public class RadarrImport : NetImportBase { + private readonly IRadarrV3Proxy _radarrV3Proxy; public override string Name => "Radarr"; public override bool Enabled => true; public override bool EnableAuto => false; public override NetImportType ListType => NetImportType.Program; - public RadarrImport(IHttpClient httpClient, + public RadarrImport(IRadarrV3Proxy radarrV3Proxy, IConfigService configService, IParsingService parsingService, Logger logger) - : base(httpClient, configService, parsingService, logger) + : base(configService, parsingService, logger) { + _radarrV3Proxy = radarrV3Proxy; } - public override INetImportRequestGenerator GetRequestGenerator() + public override NetImportFetchResult Fetch() { - return new RadarrRequestGenerator() + var movies = new List(); + var anyFailure = false; + + try { - Settings = Settings, - Logger = _logger, - HttpClient = _httpClient - }; + var remoteMovies = _radarrV3Proxy.GetMovies(Settings); + + foreach (var remoteMovie in remoteMovies) + { + if (!Settings.ProfileIds.Any() || Settings.ProfileIds.Contains(remoteMovie.QualityProfileId)) + { + movies.Add(new Movie + { + TmdbId = remoteMovie.TmdbId, + Title = remoteMovie.Title, + SortTitle = remoteMovie.SortTitle, + TitleSlug = remoteMovie.TitleSlug, + Overview = remoteMovie.Overview, + Images = remoteMovie.Images.Select(x => MapImage(x, Settings.BaseUrl)).ToList(), + Monitored = remoteMovie.Monitored, + PhysicalRelease = remoteMovie.PhysicalRelease, + InCinemas = remoteMovie.InCinemas, + Year = remoteMovie.Year + }); + } + } + } + catch + { + anyFailure = true; + } + + return new NetImportFetchResult { Movies = movies, AnyFailure = anyFailure }; } - public override IParseNetImportResponse GetParser() + public override object RequestAction(string action, IDictionary query) { - return new RadarrParser(Settings); + if (action == "getDevices") + { + // Return early if there is not an API key + if (Settings.ApiKey.IsNullOrWhiteSpace()) + { + return new + { + devices = new List() + }; + } + + Settings.Validate().Filter("ApiKey").ThrowOnError(); + + var devices = _radarrV3Proxy.GetProfiles(Settings); + + return new + { + options = devices.OrderBy(d => d.Name, StringComparer.InvariantCultureIgnoreCase) + .Select(d => new + { + id = d.Id, + name = d.Name + }) + }; + } + + return new { }; + } + + protected override void Test(List failures) + { + failures.AddIfNotNull(_radarrV3Proxy.Test(Settings)); + } + + private static MediaCover.MediaCover MapImage(MediaCover.MediaCover arg, string baseUrl) + { + var newImage = new MediaCover.MediaCover + { + Url = string.Format("{0}{1}", baseUrl, arg.Url), + CoverType = arg.CoverType + }; + + return newImage; } } } diff --git a/src/NzbDrone.Core/NetImport/Radarr/RadarrParser.cs b/src/NzbDrone.Core/NetImport/Radarr/RadarrParser.cs deleted file mode 100644 index 3508f557d..000000000 --- a/src/NzbDrone.Core/NetImport/Radarr/RadarrParser.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using NzbDrone.Common.Serializer; -using NzbDrone.Core.Movies; - -namespace NzbDrone.Core.NetImport.Radarr -{ - public class RadarrParser : IParseNetImportResponse - { - private readonly RadarrSettings _settings; - public RadarrParser(RadarrSettings settings) - { - _settings = settings; - } - - public IList ParseResponse(NetImportResponse netMovieImporterResponse) - { - var remoteMovies = Json.Deserialize>(netMovieImporterResponse.Content); - - var movies = new List(); - - foreach (var remoteMovie in remoteMovies) - { - movies.Add(new Movie - { - TmdbId = remoteMovie.TmdbId, - Title = remoteMovie.Title, - SortTitle = remoteMovie.SortTitle, - TitleSlug = remoteMovie.TitleSlug, - Overview = remoteMovie.Overview, - Images = remoteMovie.Images.Select(x => MapImage(x, _settings.BaseUrl)).ToList(), - Monitored = remoteMovie.Monitored, - PhysicalRelease = remoteMovie.PhysicalRelease, - InCinemas = remoteMovie.InCinemas, - Year = remoteMovie.Year - }); - } - - return movies; - } - - private static MediaCover.MediaCover MapImage(MediaCover.MediaCover arg, string baseUrl) - { - var newImage = new MediaCover.MediaCover - { - Url = string.Format("{0}{1}", baseUrl, arg.Url), - CoverType = arg.CoverType - }; - - return newImage; - } - } -} diff --git a/src/NzbDrone.Core/NetImport/Radarr/RadarrRequestGenerator.cs b/src/NzbDrone.Core/NetImport/Radarr/RadarrRequestGenerator.cs deleted file mode 100644 index 09db9cada..000000000 --- a/src/NzbDrone.Core/NetImport/Radarr/RadarrRequestGenerator.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Collections.Generic; -using NLog; -using NzbDrone.Common.Http; - -namespace NzbDrone.Core.NetImport.Radarr -{ - public class RadarrRequestGenerator : INetImportRequestGenerator - { - public RadarrSettings Settings { get; set; } - public IHttpClient HttpClient { get; set; } - public Logger Logger { get; set; } - - public RadarrRequestGenerator() - { - } - - public virtual NetImportPageableRequestChain GetMovies() - { - var pageableRequests = new NetImportPageableRequestChain(); - - var baseUrl = Settings.BaseUrl.TrimEnd('/'); - - var request = new NetImportRequest($"{baseUrl}/api/v3/movie", HttpAccept.Json); - - request.HttpRequest.Headers["X-Api-Key"] = Settings.ApiKey; - - request.HttpRequest.SuppressHttpError = true; - - pageableRequests.Add(new List { request }); - - return pageableRequests; - } - } -} diff --git a/src/NzbDrone.Core/NetImport/Radarr/RadarrSettings.cs b/src/NzbDrone.Core/NetImport/Radarr/RadarrSettings.cs index fc24e6076..0b5cbdaa0 100644 --- a/src/NzbDrone.Core/NetImport/Radarr/RadarrSettings.cs +++ b/src/NzbDrone.Core/NetImport/Radarr/RadarrSettings.cs @@ -1,4 +1,5 @@ -using FluentValidation; +using System.Collections.Generic; +using FluentValidation; using NzbDrone.Core.Annotations; using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; @@ -22,6 +23,7 @@ namespace NzbDrone.Core.NetImport.Radarr { BaseUrl = ""; ApiKey = ""; + ProfileIds = new int[] { }; } [FieldDefinition(0, Label = "Full URL", HelpText = "URL, including port, of the Radarr V3 instance to import from")] @@ -30,6 +32,9 @@ namespace NzbDrone.Core.NetImport.Radarr [FieldDefinition(1, Label = "API Key", HelpText = "Apikey of the Radarr V3 instance to import from")] public string ApiKey { get; set; } + [FieldDefinition(2, Type = FieldType.Device, Label = "Profiles", HelpText = "Profiles from the source instance to import from")] + public IEnumerable ProfileIds { get; set; } + public NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this)); diff --git a/src/NzbDrone.Core/NetImport/Radarr/RadarrV3Proxy.cs b/src/NzbDrone.Core/NetImport/Radarr/RadarrV3Proxy.cs new file mode 100644 index 000000000..79e152c5f --- /dev/null +++ b/src/NzbDrone.Core/NetImport/Radarr/RadarrV3Proxy.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using System.Net; +using FluentValidation.Results; +using Newtonsoft.Json; +using NLog; +using NzbDrone.Common.Extensions; +using NzbDrone.Common.Http; + +namespace NzbDrone.Core.NetImport.Radarr +{ + public interface IRadarrV3Proxy + { + List GetMovies(RadarrSettings settings); + List GetProfiles(RadarrSettings settings); + ValidationFailure Test(RadarrSettings settings); + } + + public class RadarrV3Proxy : IRadarrV3Proxy + { + private readonly IHttpClient _httpClient; + private readonly Logger _logger; + + public RadarrV3Proxy(IHttpClient httpClient, Logger logger) + { + _httpClient = httpClient; + _logger = logger; + } + + public List GetMovies(RadarrSettings settings) + { + return Execute("/api/v3/movie", settings); + } + + public List GetProfiles(RadarrSettings settings) + { + return Execute("/api/v3/qualityprofile", settings); + } + + public ValidationFailure Test(RadarrSettings settings) + { + try + { + GetMovies(settings); + } + catch (HttpException ex) + { + if (ex.Response.StatusCode == HttpStatusCode.Unauthorized) + { + _logger.Error(ex, "API Key is invalid"); + return new ValidationFailure("ApiKey", "API Key is invalid"); + } + + _logger.Error(ex, "Unable to send test message"); + return new ValidationFailure("ApiKey", "Unable to send test message"); + } + catch (Exception ex) + { + _logger.Error(ex, "Unable to send test message"); + return new ValidationFailure("", "Unable to send test message"); + } + + return null; + } + + private List Execute(string resource, RadarrSettings settings) + { + if (settings.BaseUrl.IsNullOrWhiteSpace() || settings.ApiKey.IsNullOrWhiteSpace()) + { + return new List(); + } + + var baseUrl = settings.BaseUrl.TrimEnd('/'); + + var request = new HttpRequestBuilder(baseUrl).Resource(resource).Accept(HttpAccept.Json) + .SetHeader("X-Api-Key", settings.ApiKey).Build(); + + var response = _httpClient.Get(request); + + var results = JsonConvert.DeserializeObject>(response.Content); + + return results; + } + } +}