diff --git a/src/NzbDrone.Core/ImportLists/Custom/CustomAPIResource.cs b/src/NzbDrone.Core/ImportLists/Custom/CustomAPIResource.cs new file mode 100644 index 000000000..8acb687ad --- /dev/null +++ b/src/NzbDrone.Core/ImportLists/Custom/CustomAPIResource.cs @@ -0,0 +1,7 @@ +namespace NzbDrone.Core.ImportLists.Custom +{ + public class CustomArtist + { + public string MusicBrainzId { get; set; } + } +} diff --git a/src/NzbDrone.Core/ImportLists/Custom/CustomImport.cs b/src/NzbDrone.Core/ImportLists/Custom/CustomImport.cs new file mode 100644 index 000000000..53996101a --- /dev/null +++ b/src/NzbDrone.Core/ImportLists/Custom/CustomImport.cs @@ -0,0 +1,64 @@ +using System.Collections.Generic; +using FluentValidation.Results; +using NLog; +using NzbDrone.Common.Extensions; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; + +namespace NzbDrone.Core.ImportLists.Custom +{ + public class CustomImport : ImportListBase + { + private readonly ICustomImportProxy _customProxy; + public override string Name => "Custom List"; + + public override ImportListType ListType => ImportListType.Advanced; + + public CustomImport(ICustomImportProxy customProxy, + IImportListStatusService importListStatusService, + IConfigService configService, + IParsingService parsingService, + Logger logger) + : base(importListStatusService, configService, parsingService, logger) + { + _customProxy = customProxy; + } + + public override IList Fetch() + { + var artists = new List(); + + try + { + var remoteSeries = _customProxy.GetArtists(Settings); + + foreach (var item in remoteSeries) + { + artists.Add(new ImportListItemInfo + { + ArtistMusicBrainzId = item.MusicBrainzId + }); + } + + _importListStatusService.RecordSuccess(Definition.Id); + } + catch + { + _importListStatusService.RecordFailure(Definition.Id); + } + + return CleanupListItems(artists); + } + + public override object RequestAction(string action, IDictionary query) + { + return new { }; + } + + protected override void Test(List failures) + { + failures.AddIfNotNull(_customProxy.Test(Settings)); + } + } +} diff --git a/src/NzbDrone.Core/ImportLists/Custom/CustomImportProxy.cs b/src/NzbDrone.Core/ImportLists/Custom/CustomImportProxy.cs new file mode 100644 index 000000000..46bf70cc2 --- /dev/null +++ b/src/NzbDrone.Core/ImportLists/Custom/CustomImportProxy.cs @@ -0,0 +1,75 @@ +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.ImportLists.Custom +{ + public interface ICustomImportProxy + { + List GetArtists(CustomSettings settings); + ValidationFailure Test(CustomSettings settings); + } + + public class CustomImportProxy : ICustomImportProxy + { + private readonly IHttpClient _httpClient; + private readonly Logger _logger; + + public CustomImportProxy(IHttpClient httpClient, Logger logger) + { + _httpClient = httpClient; + _logger = logger; + } + + public List GetArtists(CustomSettings settings) + { + return Execute(settings); + } + + public ValidationFailure Test(CustomSettings settings) + { + try + { + GetArtists(settings); + } + catch (HttpException ex) + { + if (ex.Response.StatusCode == HttpStatusCode.Unauthorized) + { + _logger.Error(ex, "There was an authorization issue. We cannot get the list from the provider."); + return new ValidationFailure("BaseUrl", "It seems we are unauthorized to make this request."); + } + + _logger.Error(ex, "Unable to send test message"); + return new ValidationFailure("BaseUrl", $"We are unable to make the request to that URL. StatusCode: {ex.Response.StatusCode}"); + } + catch (Exception ex) + { + _logger.Error(ex, "Unable to send test message"); + return new ValidationFailure("", "Unable to send test message"); + } + + return null; + } + + private List Execute(CustomSettings settings) + { + if (settings.BaseUrl.IsNullOrWhiteSpace()) + { + return new List(); + } + + var baseUrl = settings.BaseUrl.TrimEnd('/'); + var request = new HttpRequestBuilder(baseUrl).Accept(HttpAccept.Json).Build(); + var response = _httpClient.Get(request); + var results = JsonConvert.DeserializeObject>(response.Content); + + return results; + } + } +} diff --git a/src/NzbDrone.Core/ImportLists/Custom/CustomSettings.cs b/src/NzbDrone.Core/ImportLists/Custom/CustomSettings.cs new file mode 100644 index 000000000..91dd359f5 --- /dev/null +++ b/src/NzbDrone.Core/ImportLists/Custom/CustomSettings.cs @@ -0,0 +1,33 @@ +using FluentValidation; + +using NzbDrone.Core.Annotations; +using NzbDrone.Core.Validation; + +namespace NzbDrone.Core.ImportLists.Custom +{ + public class CustomSettingsValidator : AbstractValidator + { + public CustomSettingsValidator() + { + RuleFor(c => c.BaseUrl).ValidRootUrl(); + } + } + + public class CustomSettings : IImportListSettings + { + private static readonly CustomSettingsValidator Validator = new CustomSettingsValidator(); + + public CustomSettings() + { + BaseUrl = ""; + } + + [FieldDefinition(0, Label = "List URL", HelpText = "The URL for the artist list")] + public string BaseUrl { get; set; } + + public NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(Validator.Validate(this)); + } + } +} diff --git a/src/NzbDrone.Core/ImportLists/ImportListType.cs b/src/NzbDrone.Core/ImportLists/ImportListType.cs index ee9097aae..6dd76ef31 100644 --- a/src/NzbDrone.Core/ImportLists/ImportListType.cs +++ b/src/NzbDrone.Core/ImportLists/ImportListType.cs @@ -5,6 +5,7 @@ namespace NzbDrone.Core.ImportLists Program, Spotify, LastFm, - Other + Other, + Advanced } }