mirror of
https://github.com/Readarr/Readarr
synced 2026-05-08 21:13:58 +02:00
New: Closes Readarr/Readarr#370, adding NYTimes import list
This commit is contained in:
parent
f8cffbb4cf
commit
56ea38f061
4 changed files with 293 additions and 0 deletions
31
src/NzbDrone.Core/ImportLists/NYTimes/NYTimesException.cs
Normal file
31
src/NzbDrone.Core/ImportLists/NYTimes/NYTimesException.cs
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
using System;
|
||||||
|
using NzbDrone.Common.Exceptions;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.ImportLists.NYTimes
|
||||||
|
{
|
||||||
|
public class NYTimesException : NzbDroneException
|
||||||
|
{
|
||||||
|
public NYTimesException(string message)
|
||||||
|
: base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public NYTimesException(string message, params object[] args)
|
||||||
|
: base(message, args)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public NYTimesException(string message, Exception innerException)
|
||||||
|
: base(message, innerException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class NYTimesAuthorizationException : NYTimesException
|
||||||
|
{
|
||||||
|
public NYTimesAuthorizationException(string message)
|
||||||
|
: base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
147
src/NzbDrone.Core/ImportLists/NYTimes/NYTimesImport.cs
Normal file
147
src/NzbDrone.Core/ImportLists/NYTimes/NYTimesImport.cs
Normal file
|
|
@ -0,0 +1,147 @@
|
||||||
|
using FluentValidation.Results;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Common.Extensions;
|
||||||
|
using NzbDrone.Common.Http;
|
||||||
|
using NzbDrone.Core.Configuration;
|
||||||
|
using NzbDrone.Core.Parser;
|
||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.ImportLists.NYTimes
|
||||||
|
{
|
||||||
|
public class NYTimesImport : ImportListBase<NYTimesSettings>
|
||||||
|
{
|
||||||
|
protected readonly IHttpClient _httpClient;
|
||||||
|
|
||||||
|
public override string Name => "New York Times";
|
||||||
|
|
||||||
|
public override ImportListType ListType => ImportListType.Other;
|
||||||
|
public override TimeSpan MinRefreshInterval => TimeSpan.FromHours(12);
|
||||||
|
|
||||||
|
public NYTimesImport(IImportListStatusService importListStatusService,
|
||||||
|
IConfigService configService,
|
||||||
|
IParsingService parsingService,
|
||||||
|
IHttpClient httpClient,
|
||||||
|
Logger logger)
|
||||||
|
: base(importListStatusService, configService, parsingService, logger)
|
||||||
|
{
|
||||||
|
_httpClient = httpClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<NYTimesName> GetNames(NYTimesSettings settings)
|
||||||
|
{
|
||||||
|
if (settings.ApiKey.IsNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
return new List<NYTimesName>();
|
||||||
|
}
|
||||||
|
|
||||||
|
var request = new HttpRequestBuilder(settings.BaseUrl)
|
||||||
|
.Resource("/lists/names.json")
|
||||||
|
.AddQueryParam("api-key", settings.ApiKey)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var response = _httpClient.Get(request);
|
||||||
|
|
||||||
|
var content = JsonConvert.DeserializeObject<NYTimesResponse<List<NYTimesName>>>(response.Content);
|
||||||
|
|
||||||
|
return content.Results;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<NYTimesList> GetList(NYTimesSettings settings)
|
||||||
|
{
|
||||||
|
if (settings.ApiKey.IsNullOrWhiteSpace() || settings.ListName.IsNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
return new List<NYTimesList>();
|
||||||
|
}
|
||||||
|
|
||||||
|
var request = new HttpRequestBuilder(settings.BaseUrl)
|
||||||
|
.Resource("/lists.json")
|
||||||
|
.AddQueryParam("api-key", settings.ApiKey)
|
||||||
|
.AddQueryParam("list", settings.ListName)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var response = _httpClient.Get(request);
|
||||||
|
|
||||||
|
var content = JsonConvert.DeserializeObject<NYTimesResponse<List<NYTimesList>>>(response.Content);
|
||||||
|
|
||||||
|
return content.Results;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IList<ImportListItemInfo> Fetch()
|
||||||
|
{
|
||||||
|
var books = new List<ImportListItemInfo>();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var lists = GetList(Settings);
|
||||||
|
|
||||||
|
foreach (var list in lists)
|
||||||
|
{
|
||||||
|
var book = list.BookDetails.FirstOrDefault();
|
||||||
|
|
||||||
|
books.Add(new ImportListItemInfo
|
||||||
|
{
|
||||||
|
Author = book.Author,
|
||||||
|
Book = book.Title
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_importListStatusService.RecordSuccess(Definition.Id);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
_logger.Warn("List Import Sync Task Failed for List [{0}]", Definition.Name);
|
||||||
|
_importListStatusService.RecordFailure(Definition.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return CleanupListItems(books);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Test(List<ValidationFailure> failures)
|
||||||
|
{
|
||||||
|
failures.AddIfNotNull(TestConnection());
|
||||||
|
}
|
||||||
|
|
||||||
|
private ValidationFailure TestConnection()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
GetNames(Settings);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
catch (HttpException ex)
|
||||||
|
{
|
||||||
|
_logger.Warn(ex, "New York Times Authentication Error");
|
||||||
|
return new ValidationFailure(string.Empty, $"NYTimes authentication error: {ex.Message}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Warn(ex, "Unable to connect to NYTimes");
|
||||||
|
|
||||||
|
return new ValidationFailure(string.Empty, "Unable to connect to import list, check the log for more details");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object RequestAction(string action, IDictionary<string, string> query)
|
||||||
|
{
|
||||||
|
if (action == "getNames")
|
||||||
|
{
|
||||||
|
var names = GetNames(Settings);
|
||||||
|
|
||||||
|
return new
|
||||||
|
{
|
||||||
|
options = names.Select(name => new
|
||||||
|
{
|
||||||
|
Value = name.ListNameEncoded,
|
||||||
|
Name = name.DisplayName
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return new { };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
78
src/NzbDrone.Core/ImportLists/NYTimes/NYTimesImportApi.cs
Normal file
78
src/NzbDrone.Core/ImportLists/NYTimes/NYTimesImportApi.cs
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.ImportLists.NYTimes
|
||||||
|
{
|
||||||
|
public class NYTimesResponse<T>
|
||||||
|
{
|
||||||
|
public string Status { get; set; }
|
||||||
|
public string Copyright { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "num_results")]
|
||||||
|
public int NumResults { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "last_modified")]
|
||||||
|
public string LastModified { get; set; }
|
||||||
|
public T Results { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class NYTimesName
|
||||||
|
{
|
||||||
|
[JsonProperty(PropertyName = "list_name")]
|
||||||
|
public string ListName { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "display_name")]
|
||||||
|
public string DisplayName { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "list_name_encoded")]
|
||||||
|
public string ListNameEncoded { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "oldest_published_date")]
|
||||||
|
public string OldestPublishedDate { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "newest_published_date")]
|
||||||
|
public string NewestPublishedDate { get; set; }
|
||||||
|
public string Updated { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class NYTimesList
|
||||||
|
{
|
||||||
|
[JsonProperty(PropertyName = "list_name")]
|
||||||
|
public string ListName { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "display_name")]
|
||||||
|
public string DisplayName { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "bestsellers_date")]
|
||||||
|
public string BestsellersDate { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "published_date")]
|
||||||
|
public string PublishedDate { get; set; }
|
||||||
|
public int Rank { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "rank_last_week")]
|
||||||
|
public int RankLastWeek { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "weeks_on_list")]
|
||||||
|
public int WeeksonList { get; set; }
|
||||||
|
public int Asterisk { get; set; }
|
||||||
|
public int Dagger { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "amazon_product_url")]
|
||||||
|
public string AmazonProductUrl { get; set; }
|
||||||
|
public object[] Isbns { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "book_details")]
|
||||||
|
public List<NYTimesBook> BookDetails { get; set; }
|
||||||
|
public object[] Reviews { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class NYTimesBook
|
||||||
|
{
|
||||||
|
[JsonProperty(PropertyName = "age_group")]
|
||||||
|
public string AgeGroup { get; set; }
|
||||||
|
public string Author { get; set; }
|
||||||
|
public string Contributor { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "contributor_note")]
|
||||||
|
public string ContributorNote { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "created_date")]
|
||||||
|
public string CreatedDate { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
public string Price { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "primary_isbn13")]
|
||||||
|
public string PrimaryIsbn13 { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "primary_isbn10")]
|
||||||
|
public string PrimaryIsbn10 { get; set; }
|
||||||
|
public string Publisher { get; set; }
|
||||||
|
public int Rank { get; set; }
|
||||||
|
public string Title { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "updated_date")]
|
||||||
|
public string UpdatedDate { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
37
src/NzbDrone.Core/ImportLists/NYTimes/NYTimesSettings.cs
Normal file
37
src/NzbDrone.Core/ImportLists/NYTimes/NYTimesSettings.cs
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
using FluentValidation;
|
||||||
|
using NzbDrone.Core.Annotations;
|
||||||
|
using NzbDrone.Core.Validation;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.ImportLists.NYTimes
|
||||||
|
{
|
||||||
|
public class NYTimesSettingsValidator : AbstractValidator<NYTimesSettings>
|
||||||
|
{
|
||||||
|
public NYTimesSettingsValidator()
|
||||||
|
{
|
||||||
|
RuleFor(c => c.ApiKey).NotEmpty();
|
||||||
|
RuleFor(c => c.ListName).NotEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class NYTimesSettings : IImportListSettings
|
||||||
|
{
|
||||||
|
private static readonly NYTimesSettingsValidator Validator = new ();
|
||||||
|
public NYTimesSettings()
|
||||||
|
{
|
||||||
|
BaseUrl = "https://api.nytimes.com/svc/books/v3";
|
||||||
|
}
|
||||||
|
|
||||||
|
public string BaseUrl { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(0, Label = "API Key")]
|
||||||
|
public string ApiKey { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(1, Type = FieldType.Select, SelectOptionsProviderAction = "getNames", Label = "List Type", HelpText = "The name of the Times best sellers list")]
|
||||||
|
public string ListName { get; set; }
|
||||||
|
|
||||||
|
public NzbDroneValidationResult Validate()
|
||||||
|
{
|
||||||
|
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue