New: Simkl List Support (#5313)
* New: Simkl List Support * fixup! smarter sync * fixup! comments * fixup! comments
This commit is contained in:
parent
e07936fb84
commit
4a740acb80
|
@ -49,7 +49,7 @@ namespace NzbDrone.Core.ImportLists
|
||||||
var importListLocal = importList;
|
var importListLocal = importList;
|
||||||
var importListStatus = _importListStatusService.GetLastSyncListInfo(importListLocal.Definition.Id);
|
var importListStatus = _importListStatusService.GetLastSyncListInfo(importListLocal.Definition.Id);
|
||||||
|
|
||||||
if (DateTime.UtcNow < (importListStatus + importListLocal.MinRefreshInterval))
|
if (importListStatus.HasValue && DateTime.UtcNow < (importListStatus + importListLocal.MinRefreshInterval))
|
||||||
{
|
{
|
||||||
_logger.Trace("Skipping refresh of Import List {0} due to minimum refresh inverval", importListLocal.Definition.Name);
|
_logger.Trace("Skipping refresh of Import List {0} due to minimum refresh inverval", importListLocal.Definition.Name);
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -6,6 +6,6 @@ namespace NzbDrone.Core.ImportLists
|
||||||
{
|
{
|
||||||
public class ImportListStatus : ProviderStatusBase
|
public class ImportListStatus : ProviderStatusBase
|
||||||
{
|
{
|
||||||
public DateTime LastInfoSync { get; set; }
|
public DateTime? LastInfoSync { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ namespace NzbDrone.Core.ImportLists
|
||||||
{
|
{
|
||||||
public interface IImportListStatusService : IProviderStatusServiceBase<ImportListStatus>
|
public interface IImportListStatusService : IProviderStatusServiceBase<ImportListStatus>
|
||||||
{
|
{
|
||||||
DateTime GetLastSyncListInfo(int importListId);
|
DateTime? GetLastSyncListInfo(int importListId);
|
||||||
|
|
||||||
void UpdateListSyncStatus(int importListId);
|
void UpdateListSyncStatus(int importListId);
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ namespace NzbDrone.Core.ImportLists
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public DateTime GetLastSyncListInfo(int importListId)
|
public DateTime? GetLastSyncListInfo(int importListId)
|
||||||
{
|
{
|
||||||
return GetProviderStatus(importListId).LastInfoSync;
|
return GetProviderStatus(importListId).LastInfoSync;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ namespace NzbDrone.Core.ImportLists
|
||||||
Program,
|
Program,
|
||||||
Plex,
|
Plex,
|
||||||
Trakt,
|
Trakt,
|
||||||
|
Simkl,
|
||||||
Other,
|
Other,
|
||||||
Advanced
|
Advanced
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.ImportLists.Simkl
|
||||||
|
{
|
||||||
|
public class SimklSeriesIdsResource
|
||||||
|
{
|
||||||
|
public int Simkl { get; set; }
|
||||||
|
public string Slug { get; set; }
|
||||||
|
public string Imdb { get; set; }
|
||||||
|
public string Tmdb { get; set; }
|
||||||
|
public string Tvdb { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SimklSeriesPropsResource
|
||||||
|
{
|
||||||
|
public string Title { get; set; }
|
||||||
|
public int? Year { get; set; }
|
||||||
|
public SimklSeriesIdsResource Ids { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SimklSeriesResource
|
||||||
|
{
|
||||||
|
public SimklSeriesPropsResource Show { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SimklResponse
|
||||||
|
{
|
||||||
|
public List<SimklSeriesResource> Shows { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RefreshRequestResponse
|
||||||
|
{
|
||||||
|
[JsonProperty("access_token")]
|
||||||
|
public string AccessToken { get; set; }
|
||||||
|
[JsonProperty("expires_in")]
|
||||||
|
public int ExpiresIn { get; set; }
|
||||||
|
[JsonProperty("refresh_token")]
|
||||||
|
public string RefreshToken { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UserSettingsResponse
|
||||||
|
{
|
||||||
|
public SimklUserResource User { get; set; }
|
||||||
|
public SimklUserAccountResource Account { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SimklUserResource
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SimklUserAccountResource
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SimklSyncActivityResource
|
||||||
|
{
|
||||||
|
[JsonProperty("tv_shows")]
|
||||||
|
public SimklTvSyncActivityResource TvShows { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SimklTvSyncActivityResource
|
||||||
|
{
|
||||||
|
public DateTime All { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,183 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Common.Extensions;
|
||||||
|
using NzbDrone.Common.Http;
|
||||||
|
using NzbDrone.Core.Configuration;
|
||||||
|
using NzbDrone.Core.Parser;
|
||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
using NzbDrone.Core.Validation;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.ImportLists.Simkl
|
||||||
|
{
|
||||||
|
public abstract class SimklImportBase<TSettings> : HttpImportListBase<TSettings>
|
||||||
|
where TSettings : SimklSettingsBase<TSettings>, new()
|
||||||
|
{
|
||||||
|
public override ImportListType ListType => ImportListType.Simkl;
|
||||||
|
public override TimeSpan MinRefreshInterval => TimeSpan.FromHours(6);
|
||||||
|
|
||||||
|
public const string OAuthUrl = "https://simkl.com/oauth/authorize";
|
||||||
|
public const string RedirectUri = "https://auth.servarr.com/v1/simkl_sonarr/auth";
|
||||||
|
public const string RenewUri = "https://auth.servarr.com/v1/simkl_sonarr/renew";
|
||||||
|
public const string ClientId = "3281c139f576b2f59c1389b22337140b6b087ee17e000e89dbafdcf20af6dac7";
|
||||||
|
|
||||||
|
private IImportListRepository _importListRepository;
|
||||||
|
|
||||||
|
protected SimklImportBase(IImportListRepository netImportRepository,
|
||||||
|
IHttpClient httpClient,
|
||||||
|
IImportListStatusService importListStatusService,
|
||||||
|
IConfigService configService,
|
||||||
|
IParsingService parsingService,
|
||||||
|
Logger logger)
|
||||||
|
: base(httpClient, importListStatusService, configService, parsingService, logger)
|
||||||
|
{
|
||||||
|
_importListRepository = netImportRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IList<ImportListItemInfo> Fetch()
|
||||||
|
{
|
||||||
|
Settings.Validate().Filter("AccessToken", "RefreshToken").ThrowOnError();
|
||||||
|
_logger.Trace($"Access token expires at {Settings.Expires}");
|
||||||
|
|
||||||
|
// Simkl doesn't currently expire access tokens, but if they start lets be prepared
|
||||||
|
if (Settings.RefreshToken.IsNotNullOrWhiteSpace() && Settings.Expires < DateTime.UtcNow.AddMinutes(5))
|
||||||
|
{
|
||||||
|
RefreshToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
var lastFetch = _importListStatusService.GetLastSyncListInfo(Definition.Id);
|
||||||
|
var lastActivity = GetLastActivity();
|
||||||
|
|
||||||
|
// Check to see if user has any activity since last sync, if not return empty to avoid work
|
||||||
|
if (lastFetch.HasValue && lastActivity < lastFetch.Value.AddHours(-2))
|
||||||
|
{
|
||||||
|
return new List<ImportListItemInfo>();
|
||||||
|
}
|
||||||
|
|
||||||
|
var generator = GetRequestGenerator();
|
||||||
|
|
||||||
|
return FetchItems(g => g.GetListItems(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IParseImportListResponse GetParser()
|
||||||
|
{
|
||||||
|
return new SimklParser();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object RequestAction(string action, IDictionary<string, string> query)
|
||||||
|
{
|
||||||
|
if (action == "startOAuth")
|
||||||
|
{
|
||||||
|
var request = new HttpRequestBuilder(OAuthUrl)
|
||||||
|
.AddQueryParam("client_id", ClientId)
|
||||||
|
.AddQueryParam("response_type", "code")
|
||||||
|
.AddQueryParam("redirect_uri", RedirectUri)
|
||||||
|
.AddQueryParam("state", query["callbackUrl"])
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
return new
|
||||||
|
{
|
||||||
|
OauthUrl = request.Url.ToString()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if (action == "getOAuthToken")
|
||||||
|
{
|
||||||
|
return new
|
||||||
|
{
|
||||||
|
accessToken = query["access_token"],
|
||||||
|
expires = DateTime.UtcNow.AddSeconds(int.Parse(query["expires_in"])),
|
||||||
|
refreshToken = query["refresh_token"],
|
||||||
|
authUser = GetUserId(query["access_token"])
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return new { };
|
||||||
|
}
|
||||||
|
|
||||||
|
private DateTime GetLastActivity()
|
||||||
|
{
|
||||||
|
var request = new HttpRequestBuilder(string.Format("{0}/sync/activities", Settings.BaseUrl)).Build();
|
||||||
|
|
||||||
|
request.Headers.Add("simkl-api-key", ClientId);
|
||||||
|
request.Headers.Add("Authorization", "Bearer " + Settings.AccessToken);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var response = _httpClient.Get<SimklSyncActivityResource>(request);
|
||||||
|
|
||||||
|
if (response?.Resource != null)
|
||||||
|
{
|
||||||
|
return response.Resource.TvShows.All;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (HttpException)
|
||||||
|
{
|
||||||
|
_logger.Warn($"Error fetching user activity");
|
||||||
|
}
|
||||||
|
|
||||||
|
return DateTime.UtcNow;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetUserId(string accessToken)
|
||||||
|
{
|
||||||
|
var request = new HttpRequestBuilder(string.Format("{0}/users/settings", Settings.BaseUrl))
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
request.Headers.Add("simkl-api-key", ClientId);
|
||||||
|
|
||||||
|
if (accessToken.IsNotNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
request.Headers.Add("Authorization", "Bearer " + accessToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var response = _httpClient.Get<UserSettingsResponse>(request);
|
||||||
|
|
||||||
|
if (response?.Resource != null)
|
||||||
|
{
|
||||||
|
return response.Resource.Account.Id.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (HttpException)
|
||||||
|
{
|
||||||
|
_logger.Warn($"Error refreshing simkl access token");
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RefreshToken()
|
||||||
|
{
|
||||||
|
_logger.Trace("Refreshing Token");
|
||||||
|
|
||||||
|
Settings.Validate().Filter("RefreshToken").ThrowOnError();
|
||||||
|
|
||||||
|
var request = new HttpRequestBuilder(RenewUri)
|
||||||
|
.AddQueryParam("refresh_token", Settings.RefreshToken)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var response = _httpClient.Get<RefreshRequestResponse>(request);
|
||||||
|
|
||||||
|
if (response?.Resource != null)
|
||||||
|
{
|
||||||
|
var token = response.Resource;
|
||||||
|
Settings.AccessToken = token.AccessToken;
|
||||||
|
Settings.Expires = DateTime.UtcNow.AddSeconds(token.ExpiresIn);
|
||||||
|
Settings.RefreshToken = token.RefreshToken ?? Settings.RefreshToken;
|
||||||
|
|
||||||
|
if (Definition.Id > 0)
|
||||||
|
{
|
||||||
|
_importListRepository.UpdateSettings((ImportListDefinition)Definition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (HttpException)
|
||||||
|
{
|
||||||
|
_logger.Warn($"Error refreshing simkl access token");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Net;
|
||||||
|
using NzbDrone.Common.Extensions;
|
||||||
|
using NzbDrone.Common.Serializer;
|
||||||
|
using NzbDrone.Core.ImportLists.Exceptions;
|
||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.ImportLists.Simkl
|
||||||
|
{
|
||||||
|
public class SimklParser : IParseImportListResponse
|
||||||
|
{
|
||||||
|
private ImportListResponse _importResponse;
|
||||||
|
|
||||||
|
public SimklParser()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual IList<ImportListItemInfo> ParseResponse(ImportListResponse importResponse)
|
||||||
|
{
|
||||||
|
_importResponse = importResponse;
|
||||||
|
|
||||||
|
var series = new List<ImportListItemInfo>();
|
||||||
|
|
||||||
|
if (!PreProcess(_importResponse))
|
||||||
|
{
|
||||||
|
return series;
|
||||||
|
}
|
||||||
|
|
||||||
|
var jsonResponse = STJson.Deserialize<SimklResponse>(_importResponse.Content);
|
||||||
|
|
||||||
|
// no shows were return
|
||||||
|
if (jsonResponse == null)
|
||||||
|
{
|
||||||
|
return series;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var show in jsonResponse.Shows)
|
||||||
|
{
|
||||||
|
series.AddIfNotNull(new ImportListItemInfo()
|
||||||
|
{
|
||||||
|
Title = show.Show.Title,
|
||||||
|
TvdbId = int.TryParse(show.Show.Ids.Tvdb, out var tvdbId) ? tvdbId : 0,
|
||||||
|
ImdbId = show.Show.Ids.Imdb
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return series;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual bool PreProcess(ImportListResponse netImportResponse)
|
||||||
|
{
|
||||||
|
if (netImportResponse.HttpResponse.StatusCode != HttpStatusCode.OK)
|
||||||
|
{
|
||||||
|
throw new ImportListException(netImportResponse, "Simkl API call resulted in an unexpected StatusCode [{0}]", netImportResponse.HttpResponse.StatusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (netImportResponse.HttpResponse.Headers.ContentType != null && netImportResponse.HttpResponse.Headers.ContentType.Contains("text/json") &&
|
||||||
|
netImportResponse.HttpRequest.Headers.Accept != null && !netImportResponse.HttpRequest.Headers.Accept.Contains("text/json"))
|
||||||
|
{
|
||||||
|
throw new ImportListException(netImportResponse, "Simkl API responded with html content. Site is likely blocked or unavailable.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
using System;
|
||||||
|
using FluentValidation;
|
||||||
|
using NzbDrone.Common.Extensions;
|
||||||
|
using NzbDrone.Core.Annotations;
|
||||||
|
using NzbDrone.Core.Validation;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.ImportLists.Simkl
|
||||||
|
{
|
||||||
|
public class SimklSettingsBaseValidator<TSettings> : AbstractValidator<TSettings>
|
||||||
|
where TSettings : SimklSettingsBase<TSettings>
|
||||||
|
{
|
||||||
|
public SimklSettingsBaseValidator()
|
||||||
|
{
|
||||||
|
RuleFor(c => c.BaseUrl).ValidRootUrl();
|
||||||
|
|
||||||
|
RuleFor(c => c.AccessToken).NotEmpty()
|
||||||
|
.OverridePropertyName("SignIn")
|
||||||
|
.WithMessage("Must authenticate with Simkl");
|
||||||
|
|
||||||
|
RuleFor(c => c.Expires).NotEmpty()
|
||||||
|
.OverridePropertyName("SignIn")
|
||||||
|
.WithMessage("Must authenticate with Simkl")
|
||||||
|
.When(c => c.AccessToken.IsNotNullOrWhiteSpace() && c.RefreshToken.IsNotNullOrWhiteSpace());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SimklSettingsBase<TSettings> : IImportListSettings
|
||||||
|
where TSettings : SimklSettingsBase<TSettings>
|
||||||
|
{
|
||||||
|
protected virtual AbstractValidator<TSettings> Validator => new SimklSettingsBaseValidator<TSettings>();
|
||||||
|
|
||||||
|
public SimklSettingsBase()
|
||||||
|
{
|
||||||
|
BaseUrl = "https://api.simkl.com";
|
||||||
|
SignIn = "startOAuth";
|
||||||
|
}
|
||||||
|
|
||||||
|
public string BaseUrl { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(0, Label = "Access Token", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)]
|
||||||
|
public string AccessToken { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(0, Label = "Refresh Token", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)]
|
||||||
|
public string RefreshToken { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(0, Label = "Expires", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)]
|
||||||
|
public DateTime Expires { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(0, Label = "Auth User", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)]
|
||||||
|
public string AuthUser { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(99, Label = "Authenticate with Simkl", Type = FieldType.OAuth)]
|
||||||
|
public string SignIn { get; set; }
|
||||||
|
|
||||||
|
public NzbDroneValidationResult Validate()
|
||||||
|
{
|
||||||
|
return new NzbDroneValidationResult(Validator.Validate((TSettings)this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Common.Http;
|
||||||
|
using NzbDrone.Core.Configuration;
|
||||||
|
using NzbDrone.Core.Parser;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.ImportLists.Simkl.User
|
||||||
|
{
|
||||||
|
public class SimklUserImport : SimklImportBase<SimklUserSettings>
|
||||||
|
{
|
||||||
|
public SimklUserImport(IImportListRepository netImportRepository,
|
||||||
|
IHttpClient httpClient,
|
||||||
|
IImportListStatusService netImportStatusService,
|
||||||
|
IConfigService configService,
|
||||||
|
IParsingService parsingService,
|
||||||
|
Logger logger)
|
||||||
|
: base(netImportRepository, httpClient, netImportStatusService, configService, parsingService, logger)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string Name => "Simkl User Watchlist";
|
||||||
|
|
||||||
|
public override IImportListRequestGenerator GetRequestGenerator()
|
||||||
|
{
|
||||||
|
return new SimklUserRequestGenerator()
|
||||||
|
{
|
||||||
|
Settings = Settings,
|
||||||
|
ClientId = ClientId
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.ImportLists.Simkl.User
|
||||||
|
{
|
||||||
|
public enum SimklUserListType
|
||||||
|
{
|
||||||
|
[EnumMember(Value = "Watching")]
|
||||||
|
Watching = 0,
|
||||||
|
[EnumMember(Value = "Plan To Watch")]
|
||||||
|
PlanToWatch = 1,
|
||||||
|
[EnumMember(Value = "Hold")]
|
||||||
|
Hold = 2,
|
||||||
|
[EnumMember(Value = "Completed")]
|
||||||
|
Completed = 3,
|
||||||
|
[EnumMember(Value = "Dropped")]
|
||||||
|
Dropped = 4
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using NzbDrone.Common.Extensions;
|
||||||
|
using NzbDrone.Common.Http;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.ImportLists.Simkl.User
|
||||||
|
{
|
||||||
|
public class SimklUserRequestGenerator : IImportListRequestGenerator
|
||||||
|
{
|
||||||
|
public SimklUserSettings Settings { get; set; }
|
||||||
|
|
||||||
|
public string ClientId { get; set; }
|
||||||
|
|
||||||
|
public SimklUserRequestGenerator()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual ImportListPageableRequestChain GetListItems()
|
||||||
|
{
|
||||||
|
var pageableRequests = new ImportListPageableRequestChain();
|
||||||
|
|
||||||
|
pageableRequests.Add(GetSeriesRequest());
|
||||||
|
|
||||||
|
return pageableRequests;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<ImportListRequest> GetSeriesRequest()
|
||||||
|
{
|
||||||
|
var link = $"{Settings.BaseUrl.Trim()}/sync/all-items/shows/{((SimklUserListType)Settings.ListType).ToString().ToLowerInvariant()}";
|
||||||
|
|
||||||
|
var request = new ImportListRequest(link, HttpAccept.Json);
|
||||||
|
|
||||||
|
request.HttpRequest.Headers.Add("simkl-api-key", ClientId);
|
||||||
|
|
||||||
|
if (Settings.AccessToken.IsNotNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
request.HttpRequest.Headers.Add("Authorization", "Bearer " + Settings.AccessToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
yield return request;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
using FluentValidation;
|
||||||
|
using NzbDrone.Core.Annotations;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.ImportLists.Simkl.User
|
||||||
|
{
|
||||||
|
public class SimklUserSettingsValidator : SimklSettingsBaseValidator<SimklUserSettings>
|
||||||
|
{
|
||||||
|
public SimklUserSettingsValidator()
|
||||||
|
: base()
|
||||||
|
{
|
||||||
|
RuleFor(c => c.ListType).NotNull();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SimklUserSettings : SimklSettingsBase<SimklUserSettings>
|
||||||
|
{
|
||||||
|
protected override AbstractValidator<SimklUserSettings> Validator => new SimklUserSettingsValidator();
|
||||||
|
|
||||||
|
public SimklUserSettings()
|
||||||
|
{
|
||||||
|
ListType = (int)SimklUserListType.Watching;
|
||||||
|
}
|
||||||
|
|
||||||
|
[FieldDefinition(1, Label = "List Type", Type = FieldType.Select, SelectOptions = typeof(SimklUserListType), HelpText = "Type of list you're seeking to import from")]
|
||||||
|
public int ListType { get; set; }
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue