New: Trakt Auth per List

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

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

@ -119,45 +119,6 @@ namespace NzbDrone.Core.Configuration
set { SetValue("NetImportSyncInterval", value); } 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 public string ListSyncLevel
{ {
get { return GetValue("ListSyncLevel", "disabled"); } get { return GetValue("ListSyncLevel", "disabled"); }

@ -66,12 +66,6 @@ namespace NzbDrone.Core.Configuration
int NetImportSyncInterval { get; set; } int NetImportSyncInterval { get; set; }
string ListSyncLevel { get; set; } string ListSyncLevel { get; set; }
string ImportExclusions { 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 //UI
int FirstDayOfWeek { get; set; } int FirstDayOfWeek { get; set; }

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

@ -2,6 +2,9 @@
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Validation;
using System;
using System.Collections.Generic;
namespace NzbDrone.Core.NetImport.Trakt namespace NzbDrone.Core.NetImport.Trakt
{ {
@ -11,13 +14,62 @@ namespace NzbDrone.Core.NetImport.Trakt
public override bool Enabled => true; public override bool Enabled => true;
public override bool EnableAuto => false; 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) : 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() 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, }; return new TraktRequestGenerator() { Settings = Settings, _configService=_configService, HttpClient = _httpClient, };
} }
@ -25,5 +77,31 @@ namespace NzbDrone.Core.NetImport.Trakt
{ {
return new TraktParser(Settings); 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 IHttpClient HttpClient { get; set; }
public TraktSettings Settings { get; set; } public TraktSettings Settings { get; set; }
public string RadarrTraktUrl { get; set; }
public TraktRequestGenerator() public TraktRequestGenerator()
{ {
RadarrTraktUrl = "http://radarr.aeonlucid.com/v1/trakt/refresh?refresh=";
} }
public virtual NetImportPageableRequestChain GetMovies() public virtual NetImportPageableRequestChain GetMovies()
{ {
@ -39,52 +36,6 @@ namespace NzbDrone.Core.NetImport.Trakt
return pageableRequests; 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) private IEnumerable<NetImportRequest> GetMovies(string searchParameters)
{ {
var link = Settings.Link.Trim(); var link = Settings.Link.Trim();
@ -129,14 +80,14 @@ namespace NzbDrone.Core.NetImport.Trakt
break; break;
} }
Authenticate();
var request = new NetImportRequest($"{link}", HttpAccept.Json); var request = new NetImportRequest($"{link}", HttpAccept.Json);
request.HttpRequest.Headers.Add("trakt-api-version", "2"); request.HttpRequest.Headers.Add("trakt-api-version", "2");
request.HttpRequest.Headers.Add("trakt-api-key", "964f67b126ade0112c4ae1f0aea3a8fb03190f71117bd83af6a0560a99bc52e6"); //aeon request.HttpRequest.Headers.Add("trakt-api-key", Settings.ClientId); //aeon
if (_configService.TraktAuthToken.IsNotNullOrWhiteSpace())
if (Settings.AccessToken.IsNotNullOrWhiteSpace())
{ {
request.HttpRequest.Headers.Add("Authorization", "Bearer " + _configService.TraktAuthToken); request.HttpRequest.Headers.Add("Authorization", "Bearer " + Settings.AccessToken);
} }
yield return request; yield return request;

@ -3,6 +3,7 @@ using NzbDrone.Common.Extensions;
using NzbDrone.Core.Annotations; using NzbDrone.Core.Annotations;
using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation; using NzbDrone.Core.Validation;
using System;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
namespace NzbDrone.Core.NetImport.Trakt namespace NzbDrone.Core.NetImport.Trakt
@ -13,6 +14,9 @@ namespace NzbDrone.Core.NetImport.Trakt
public TraktSettingsValidator() public TraktSettingsValidator()
{ {
RuleFor(c => c.Link).ValidRootUrl(); 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 // List name required for UserCustomList
RuleFor(c => c.Listname) RuleFor(c => c.Listname)
@ -59,6 +63,7 @@ namespace NzbDrone.Core.NetImport.Trakt
public TraktSettings() public TraktSettings()
{ {
Link = "https://api.trakt.tv"; Link = "https://api.trakt.tv";
SignIn = "startOAuth";
ListType = (int)TraktListType.Popular; ListType = (int)TraktListType.Popular;
Username = ""; Username = "";
Listname = ""; Listname = "";
@ -69,6 +74,20 @@ namespace NzbDrone.Core.NetImport.Trakt
Limit = 100; 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.")] [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; } 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)] [FieldDefinition(9, Label = "Additional Parameters", HelpText = "Additional Trakt API parameters", Advanced = true)]
public string TraktAdditionalParameters { get; set; } public string TraktAdditionalParameters { get; set; }
[FieldDefinition(99, Label = "Authenticate with Trakt", Type = FieldType.OAuth)]
public string SignIn { get; set; }
public NzbDroneValidationResult Validate() public NzbDroneValidationResult Validate()
{ {

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

Loading…
Cancel
Save