New: Trakt Auth per List

pull/3950/head
Qstick 5 years ago
parent 5e52a12287
commit 5d7804478b

@ -6,11 +6,8 @@ namespace NzbDrone.Api.Config
public class NetImportConfigResource : RestResource
{
public int NetImportSyncInterval { get; set; }
public string ListSyncLevel { get; set; }
public string ImportExclusions { get; set; }
public string TraktAuthToken { get; set; }
public string TraktRefreshToken { get; set; }
public int TraktTokenExpiry { get; set; }
public string ListSyncLevel { get; set; }
public string ImportExclusions { get; set; }
}
public static class NetImportConfigResourceMapper
@ -20,11 +17,8 @@ namespace NzbDrone.Api.Config
return new NetImportConfigResource
{
NetImportSyncInterval = model.NetImportSyncInterval,
ListSyncLevel = model.ListSyncLevel,
ImportExclusions = model.ImportExclusions,
TraktAuthToken = model.TraktAuthToken,
TraktRefreshToken = model.TraktRefreshToken,
TraktTokenExpiry = model.TraktTokenExpiry,
ListSyncLevel = model.ListSyncLevel,
ImportExclusions = model.ImportExclusions,
};
}
}

@ -119,45 +119,6 @@ namespace NzbDrone.Core.Configuration
set { SetValue("NetImportSyncInterval", value); }
}
public string TraktAuthToken
{
get { return GetValue("TraktAuthToken", string.Empty); }
set { SetValue("TraktAuthToken", value); }
}
public string TraktRefreshToken
{
get { return GetValue("TraktRefreshToken", string.Empty); }
set { SetValue("TraktRefreshToken", value); }
}
public int TraktTokenExpiry
{
get { return GetValueInt("TraktTokenExpiry", 0); }
set { SetValue("TraktTokenExpiry", value); }
}
public string NewTraktAuthToken
{
get { return GetValue("NewTraktAuthToken", string.Empty); }
set { SetValue("NewTraktAuthToken", value); }
}
public string NewTraktRefreshToken
{
get { return GetValue("NewTraktRefreshToken", string.Empty); }
set { SetValue("NewTraktRefreshToken", value); }
}
public int NewTraktTokenExpiry
{
get { return GetValueInt("NewTraktTokenExpiry", 0); }
set { SetValue("NewTraktTokenExpiry", value); }
}
public string ListSyncLevel
{
get { return GetValue("ListSyncLevel", "disabled"); }

@ -66,12 +66,6 @@ namespace NzbDrone.Core.Configuration
int NetImportSyncInterval { get; set; }
string ListSyncLevel { get; set; }
string ImportExclusions { get; set; }
string TraktAuthToken { get; set; }
string TraktRefreshToken { get; set; }
int TraktTokenExpiry { get; set; }
string NewTraktAuthToken { get; set; }
string NewTraktRefreshToken {get; set; }
int NewTraktTokenExpiry { get; set; }
//UI
int FirstDayOfWeek { get; set; }

@ -7,7 +7,7 @@ namespace NzbDrone.Core.NetImport
{
public interface INetImportRepository : IProviderRepository<NetImportDefinition>
{
void UpdateSettings(NetImportDefinition model);
}
public class NetImportRepository : ProviderRepository<NetImportDefinition>, INetImportRepository
@ -16,5 +16,10 @@ namespace NzbDrone.Core.NetImport
: base(database, eventAggregator)
{
}
public void UpdateSettings(NetImportDefinition model)
{
SetFields(model, m => m.Settings);
}
}
}

@ -2,6 +2,9 @@
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Validation;
using System;
using System.Collections.Generic;
namespace NzbDrone.Core.NetImport.Trakt
{
@ -11,13 +14,62 @@ namespace NzbDrone.Core.NetImport.Trakt
public override bool Enabled => true;
public override bool EnableAuto => false;
public TraktImport(IHttpClient httpClient, IConfigService configService, IParsingService parsingService, Logger logger)
private INetImportRepository _netImportRepository;
public TraktImport(INetImportRepository netImportRepository,
IHttpClient httpClient,
IConfigService configService,
IParsingService parsingService,
Logger logger)
: base(httpClient, configService, parsingService, logger)
{
_netImportRepository = netImportRepository;
}
private void RefreshToken()
{
_logger.Trace("Refreshing Token");
Settings.Validate().Filter("RefreshToken").ThrowOnError();
var request = new HttpRequestBuilder(Settings.RenewUri)
.AddQueryParam("refresh", Settings.RefreshToken)
.Build();
try
{
var response = _httpClient.Get<RefreshRequestResponse>(request);
if (response != null && response.Resource != null)
{
var token = response.Resource;
Settings.AccessToken = token.access_token;
Settings.Expires = DateTime.UtcNow.AddSeconds(token.expires_in);
Settings.RefreshToken = token.refresh_token != null ? token.refresh_token : Settings.RefreshToken;
if (Definition.Id > 0)
{
_netImportRepository.UpdateSettings((NetImportDefinition)Definition);
}
}
}
catch (HttpException)
{
_logger.Warn($"Error refreshing trakt access token");
}
}
public override INetImportRequestGenerator GetRequestGenerator()
{
Settings.Validate().Filter("AccessToken", "RefreshToken").ThrowOnError();
_logger.Trace($"Access token expires at {Settings.Expires}");
if (Settings.Expires < DateTime.UtcNow.AddMinutes(5))
{
RefreshToken();
}
return new TraktRequestGenerator() { Settings = Settings, _configService=_configService, HttpClient = _httpClient, };
}
@ -25,5 +77,31 @@ namespace NzbDrone.Core.NetImport.Trakt
{
return new TraktParser(Settings);
}
public override object RequestAction(string action, IDictionary<string, string> query)
{
if (action == "startOAuth")
{
var request = new HttpRequestBuilder(Settings.OAuthUrl)
.AddQueryParam("target", query["callbackUrl"])
.Build();
return new
{
OauthUrl = request.Url.ToString()
};
}
else if (action == "getOAuthToken")
{
return new
{
accessToken = query["access"],
expires = DateTime.UtcNow.AddSeconds(4838400),
refreshToken = query["refresh"],
};
}
return new { };
}
}
}

@ -24,11 +24,8 @@ namespace NzbDrone.Core.NetImport.Trakt
public IHttpClient HttpClient { get; set; }
public TraktSettings Settings { get; set; }
public string RadarrTraktUrl { get; set; }
public TraktRequestGenerator()
{
RadarrTraktUrl = "http://radarr.aeonlucid.com/v1/trakt/refresh?refresh=";
}
public virtual NetImportPageableRequestChain GetMovies()
{
@ -39,52 +36,6 @@ namespace NzbDrone.Core.NetImport.Trakt
return pageableRequests;
}
private void Authenticate()
{
if (_configService.TraktRefreshToken != string.Empty)
{
//tokens were overwritten with something other than nothing
if (_configService.NewTraktTokenExpiry > _configService.TraktTokenExpiry)
{
//but our refreshedTokens are more current
_configService.TraktAuthToken = _configService.NewTraktAuthToken;
_configService.TraktRefreshToken = _configService.NewTraktRefreshToken;
_configService.TraktTokenExpiry = _configService.NewTraktTokenExpiry;
}
var unixTime = (int)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
if (unixTime > _configService.TraktTokenExpiry)
{
var requestBuilder = new HttpRequestBuilder($"{RadarrTraktUrl + _configService.TraktRefreshToken}")
{
LogResponseContent = true
};
requestBuilder.Method = HttpMethod.GET;
var authLoginRequest = requestBuilder
.SetHeader("Content-Type", "application/json")
.Accept(HttpAccept.Json)
.Build();
var response = HttpClient.Execute(authLoginRequest);
var result = Json.Deserialize<RefreshRequestResponse>(response.Content);
_configService.TraktAuthToken = result.access_token;
_configService.TraktRefreshToken = result.refresh_token;
//lets have it expire in 8 weeks (4838400 seconds)
_configService.TraktTokenExpiry = unixTime + 4838400;
//store the refreshed tokens in case they get overwritten by an old set of tokens
_configService.NewTraktAuthToken = _configService.TraktAuthToken;
_configService.NewTraktRefreshToken = _configService.TraktRefreshToken;
_configService.NewTraktTokenExpiry = _configService.TraktTokenExpiry;
}
}
}
private IEnumerable<NetImportRequest> GetMovies(string searchParameters)
{
var link = Settings.Link.Trim();
@ -129,14 +80,14 @@ namespace NzbDrone.Core.NetImport.Trakt
break;
}
Authenticate();
var request = new NetImportRequest($"{link}", HttpAccept.Json);
request.HttpRequest.Headers.Add("trakt-api-version", "2");
request.HttpRequest.Headers.Add("trakt-api-key", "964f67b126ade0112c4ae1f0aea3a8fb03190f71117bd83af6a0560a99bc52e6"); //aeon
if (_configService.TraktAuthToken.IsNotNullOrWhiteSpace())
request.HttpRequest.Headers.Add("trakt-api-key", Settings.ClientId); //aeon
if (Settings.AccessToken.IsNotNullOrWhiteSpace())
{
request.HttpRequest.Headers.Add("Authorization", "Bearer " + _configService.TraktAuthToken);
request.HttpRequest.Headers.Add("Authorization", "Bearer " + Settings.AccessToken);
}
yield return request;

@ -3,6 +3,7 @@ using NzbDrone.Common.Extensions;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation;
using System;
using System.Text.RegularExpressions;
namespace NzbDrone.Core.NetImport.Trakt
@ -13,6 +14,9 @@ namespace NzbDrone.Core.NetImport.Trakt
public TraktSettingsValidator()
{
RuleFor(c => c.Link).ValidRootUrl();
RuleFor(c => c.AccessToken).NotEmpty();
RuleFor(c => c.RefreshToken).NotEmpty();
RuleFor(c => c.Expires).NotEmpty();
// List name required for UserCustomList
RuleFor(c => c.Listname)
@ -59,6 +63,7 @@ namespace NzbDrone.Core.NetImport.Trakt
public TraktSettings()
{
Link = "https://api.trakt.tv";
SignIn = "startOAuth";
ListType = (int)TraktListType.Popular;
Username = "";
Listname = "";
@ -69,6 +74,20 @@ namespace NzbDrone.Core.NetImport.Trakt
Limit = 100;
}
public string OAuthUrl => "http://radarr.aeonlucid.com/v1/trakt/redirect";
public string RenewUri => "http://radarr.aeonlucid.com/v1/trakt/refresh";
public string ClientId => "964f67b126ade0112c4ae1f0aea3a8fb03190f71117bd83af6a0560a99bc52e6";
public virtual string Scope => "";
[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 = "Trakt API URL", HelpText = "Link to to Trakt API URL, do not change unless you know what you are doing.")]
public string Link { get; set; }
@ -99,6 +118,9 @@ namespace NzbDrone.Core.NetImport.Trakt
[FieldDefinition(9, Label = "Additional Parameters", HelpText = "Additional Trakt API parameters", Advanced = true)]
public string TraktAdditionalParameters { get; set; }
[FieldDefinition(99, Label = "Authenticate with Trakt", Type = FieldType.OAuth)]
public string SignIn { get; set; }
public NzbDroneValidationResult Validate()
{

@ -8,9 +8,6 @@ namespace Radarr.Api.V3.Config
public int NetImportSyncInterval { get; set; }
public string ListSyncLevel { get; set; }
public string ImportExclusions { get; set; }
public string TraktAuthToken { get; set; }
public string TraktRefreshToken { get; set; }
public int TraktTokenExpiry { get; set; }
}
public static class NetImportConfigResourceMapper
@ -21,10 +18,7 @@ namespace Radarr.Api.V3.Config
{
NetImportSyncInterval = model.NetImportSyncInterval,
ListSyncLevel = model.ListSyncLevel,
ImportExclusions = model.ImportExclusions,
TraktAuthToken = model.TraktAuthToken,
TraktRefreshToken = model.TraktRefreshToken,
TraktTokenExpiry = model.TraktTokenExpiry,
ImportExclusions = model.ImportExclusions
};
}
}

Loading…
Cancel
Save