mirror of
https://github.com/Radarr/Radarr.git
synced 2024-10-03 22:57:18 +02:00
fully functional traktAuthentication
using api.couchpota.to with comments for when updated RadarrAPI is deployed
This commit is contained in:
parent
e0f72e4853
commit
aa977eb2d5
@ -40,6 +40,7 @@
|
|||||||
"run-sequence": "1.1.1",
|
"run-sequence": "1.1.1",
|
||||||
"streamqueue": "1.1.0",
|
"streamqueue": "1.1.0",
|
||||||
"tar.gz": "0.1.1",
|
"tar.gz": "0.1.1",
|
||||||
|
"url-search-params": "^0.6.1",
|
||||||
"webpack": "1.12.0",
|
"webpack": "1.12.0",
|
||||||
"webpack-stream": "2.1.0"
|
"webpack-stream": "2.1.0"
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,9 @@ 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
|
||||||
@ -19,6 +22,9 @@ public static NetImportConfigResource ToResource(IConfigService model)
|
|||||||
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,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,6 +118,45 @@ public int NetImportSyncInterval
|
|||||||
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"); }
|
||||||
|
@ -51,6 +51,12 @@ public interface IConfigService
|
|||||||
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; }
|
||||||
@ -60,6 +66,7 @@ public interface IConfigService
|
|||||||
string LongDateFormat { get; set; }
|
string LongDateFormat { get; set; }
|
||||||
string TimeFormat { get; set; }
|
string TimeFormat { get; set; }
|
||||||
bool ShowRelativeDates { get; set; }
|
bool ShowRelativeDates { get; set; }
|
||||||
|
|
||||||
bool EnableColorImpairedMode { get; set; }
|
bool EnableColorImpairedMode { get; set; }
|
||||||
|
|
||||||
//Internal
|
//Internal
|
||||||
|
@ -10,14 +10,15 @@ public class TraktImport : HttpNetImportBase<TraktSettings>
|
|||||||
public override string Name => "Trakt List";
|
public override string Name => "Trakt List";
|
||||||
public override bool Enabled => true;
|
public override bool Enabled => true;
|
||||||
public override bool EnableAuto => false;
|
public override bool EnableAuto => false;
|
||||||
|
public IConfigService _configService;
|
||||||
|
|
||||||
public TraktImport(IHttpClient httpClient, IConfigService configService, IParsingService parsingService, Logger logger)
|
public TraktImport(IHttpClient httpClient, IConfigService configService, IParsingService parsingService, Logger logger)
|
||||||
: base(httpClient, configService, parsingService, logger)
|
: base(httpClient, configService, parsingService, logger)
|
||||||
{ }
|
{ _configService = configService; }
|
||||||
|
|
||||||
public override INetImportRequestGenerator GetRequestGenerator()
|
public override INetImportRequestGenerator GetRequestGenerator()
|
||||||
{
|
{
|
||||||
return new TraktRequestGenerator() { Settings = Settings };
|
return new TraktRequestGenerator() { Settings = Settings, _configService=_configService };
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IParseNetImportResponse GetParser()
|
public override IParseNetImportResponse GetParser()
|
||||||
|
@ -1,10 +1,31 @@
|
|||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Net;
|
||||||
|
using System.IO;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using NzbDrone.Core.Configuration;
|
||||||
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.NetImport.Trakt
|
namespace NzbDrone.Core.NetImport.Trakt
|
||||||
{
|
{
|
||||||
|
public class refreshRequestResponse
|
||||||
|
{
|
||||||
|
//the next 3 lines can eventually be removed and replaced with the ones marked below
|
||||||
|
public bool success { get; set; }
|
||||||
|
public string oauth { get; set; }
|
||||||
|
public string refresh { get; set; }
|
||||||
|
/*//replace with the lines below when radarrAPI changes have been merged
|
||||||
|
public string access_token { get; set; }
|
||||||
|
public string token_type { get; set; }
|
||||||
|
public int expires_in { get; set; }
|
||||||
|
public string refresh_token { get; set; }
|
||||||
|
public string scope { get; set; }*/
|
||||||
|
}
|
||||||
|
|
||||||
public class TraktRequestGenerator : INetImportRequestGenerator
|
public class TraktRequestGenerator : INetImportRequestGenerator
|
||||||
{
|
{
|
||||||
|
public IConfigService _configService;
|
||||||
public TraktSettings Settings { get; set; }
|
public TraktSettings Settings { get; set; }
|
||||||
|
|
||||||
public virtual NetImportPageableRequestChain GetMovies()
|
public virtual NetImportPageableRequestChain GetMovies()
|
||||||
@ -58,10 +79,56 @@ private IEnumerable<NetImportRequest> GetMovies(string searchParameters)
|
|||||||
link = link + "/movies/watched/all" + filters;
|
link = link + "/movies/watched/all" + filters;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
Int32 unixTime= (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
|
||||||
|
|
||||||
|
if ( unixTime > _configService.TraktTokenExpiry)
|
||||||
|
{
|
||||||
|
//the next line should eventually be removed and replaced with the one commented out below it
|
||||||
|
var url = "https://api.couchpota.to/authorize/trakt_refresh?token="+_configService.TraktRefreshToken;
|
||||||
|
//var url = "https://radarr.aeonlucid.com/authorize/trakt_refresh?token="+_configService.TraktRefreshToken;
|
||||||
|
|
||||||
|
HttpWebRequest rquest = (HttpWebRequest)WebRequest.Create(url);
|
||||||
|
string rsponseString = string.Empty;
|
||||||
|
using (HttpWebResponse rsponse = (HttpWebResponse)rquest.GetResponse())
|
||||||
|
using (Stream stream = rsponse.GetResponseStream())
|
||||||
|
using (StreamReader reader = new StreamReader(stream))
|
||||||
|
{
|
||||||
|
rsponseString = reader.ReadToEnd();
|
||||||
|
}
|
||||||
|
refreshRequestResponse j1 = Newtonsoft.Json.JsonConvert.DeserializeObject<refreshRequestResponse>(rsponseString);
|
||||||
|
_configService.TraktAuthToken = j1.oauth; //eventually replace with j1.access_token
|
||||||
|
_configService.TraktRefreshToken = j1.refresh; //eventually replace with j1.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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", "657bb899dcb81ec8ee838ff09f6e013ff7c740bf0ccfa54dd41e791b9a70b2f0");
|
//request.HttpRequest.Headers.Add("trakt-api-key", "657bb899dcb81ec8ee838ff09f6e013ff7c740bf0ccfa54dd41e791b9a70b2f0"); //radarr
|
||||||
|
//the line below should eventually be replaced with the one commented out above
|
||||||
|
request.HttpRequest.Headers.Add("trakt-api-key", "8a54ed7b5e1b56d874642770ad2e8b73e2d09d6e993c3a92b1e89690bb1c9014"); //couchpotato
|
||||||
|
if (_configService.TraktAuthToken != null)
|
||||||
|
{
|
||||||
|
request.HttpRequest.Headers.Add("Authorization", "Bearer " + _configService.TraktAuthToken);
|
||||||
|
}
|
||||||
|
|
||||||
yield return request;
|
yield return request;
|
||||||
}
|
}
|
||||||
|
@ -6,11 +6,45 @@ require('../../../Mixins/TagInput');
|
|||||||
require('bootstrap');
|
require('bootstrap');
|
||||||
require('bootstrap.tagsinput');
|
require('bootstrap.tagsinput');
|
||||||
|
|
||||||
|
//if ('searchParams' in HTMLAnchorElement.prototype) {
|
||||||
|
// var URLSearchParams = require('url-search-params-polyfill');
|
||||||
|
//}
|
||||||
|
|
||||||
|
var URLSearchParams = require('url-search-params');
|
||||||
|
|
||||||
|
var q = window.location;
|
||||||
|
var callback_url = q.protocol+'//'+q.hostname+(q.port ? ':' + q.port : '')+'/settings/netimport';
|
||||||
var view = Marionette.ItemView.extend({
|
var view = Marionette.ItemView.extend({
|
||||||
template : 'Settings/NetImport/Options/NetImportOptionsViewTemplate',
|
template : 'Settings/NetImport/Options/NetImportOptionsViewTemplate',
|
||||||
|
events : {
|
||||||
|
'click .x-reset-trakt-tokens' : '_resetTraktTokens',
|
||||||
|
'click .x-revoke-trakt-tokens' : '_revokeTraktTokens'
|
||||||
|
},
|
||||||
|
|
||||||
|
initialize : function() {
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
onShow : function() {
|
||||||
|
var params = new URLSearchParams(window.location.search);
|
||||||
|
var oauth = params.get('oauth');
|
||||||
|
var refresh=params.get('refresh');
|
||||||
|
if (oauth && refresh){
|
||||||
|
history.pushState('object', 'title', callback_url);
|
||||||
|
this.ui.authToken.val(oauth).trigger('change');
|
||||||
|
this.ui.refreshToken.val(refresh).trigger('change');
|
||||||
|
this.ui.tokenExpiry.val(Math.floor(Date.now() / 1000) + 4838400).trigger('change'); // this means the token will expire in 8 weeks (4838400 seconds)
|
||||||
|
//this.model.isSaved = false;
|
||||||
|
window.alert("Trakt Authentication Complete - Click Save to make the change take effect");
|
||||||
|
}
|
||||||
|
if (this.ui.authToken.val() && this.ui.refreshToken.val()){
|
||||||
|
this.ui.resetTokensButton.hide();
|
||||||
|
this.ui.revokeTokensButton.show();
|
||||||
|
} else {
|
||||||
|
this.ui.resetTokensButton.show();
|
||||||
|
this.ui.revokeTokensButton.hide();
|
||||||
|
}
|
||||||
|
|
||||||
ui : {
|
|
||||||
importExclusions : '.x-import-exclusions'
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onRender : function() {
|
onRender : function() {
|
||||||
@ -65,8 +99,38 @@ var view = Marionette.ItemView.extend({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
ui : {
|
||||||
|
resetTraktTokens : '.x-reset-trakt-tokens',
|
||||||
|
authToken : '.x-trakt-auth-token',
|
||||||
|
refreshToken : '.x-trakt-refresh-token',
|
||||||
|
resetTokensButton : '.x-reset-trakt-tokens',
|
||||||
|
revokeTokensButton : '.x-revoke-trakt-tokens',
|
||||||
|
tokenExpiry : '.x-trakt-token-expiry',
|
||||||
|
importExclusions : '.x-import-exclusions'
|
||||||
|
},
|
||||||
|
|
||||||
|
_resetTraktTokens : function() {
|
||||||
|
if (window.confirm("Proceed to trakt.tv for authentication?\nYou will then be redirected back here.")){
|
||||||
|
window.location='https://api.couchpota.to/authorize/trakt/?target='+callback_url; //this eventually can be removed and replaced with the line below
|
||||||
|
//window.location='https://radarr.aeonlucid.com/authorize/trakt?target='+callback_url;
|
||||||
|
//this.ui.resetTokensButton.hide();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_revokeTraktTokens : function() {
|
||||||
|
if (window.confirm("Log out of trakt.tv?")){
|
||||||
|
//TODO: need to implement this: http://docs.trakt.apiary.io/#reference/authentication-oauth/revoke-token/revoke-an-access_token
|
||||||
|
this.ui.authToken.val('').trigger('change');
|
||||||
|
this.ui.refreshToken.val('').trigger('change');
|
||||||
|
this.ui.tokenExpiry.val(0).trigger('change');
|
||||||
|
this.ui.resetTokensButton.show();
|
||||||
|
this.ui.revokeTokensButton.hide();
|
||||||
|
window.alert("Logged out of Trakt.tv - Click Save to make the change take effect");
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
AsModelBoundView.call(view);
|
AsModelBoundView.call(view);
|
||||||
AsValidatedView.call(view);
|
AsValidatedView.call(view);
|
||||||
|
|
||||||
|
@ -41,4 +41,22 @@
|
|||||||
<input type="text" name="importExclusions" class="form-control x-import-exclusions"/>
|
<input type="text" name="importExclusions" class="form-control x-import-exclusions"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<legend>Trakt Authentication</legend>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-1 control-label">Auth Token</label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input type="text" readonly="readonly" name="traktAuthToken" class="form-control x-trakt-auth-token"/>
|
||||||
|
<input type="hidden" readonly="readonly" name="traktTokenExpiry" class="form-control x-trakt-token-expiry"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-1 control-label">Refresh Token</label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input type="text" readonly="readonly" name="traktRefreshToken" class="form-control x-trakt-refresh-token"/>
|
||||||
|
</div>
|
||||||
|
<div class="input-group-btn">
|
||||||
|
<button class="btn btn-danger btn-icon-only x-reset-trakt-tokens" title="Reset Trakt Tokens"><i class="icon-sonarr-refresh"></i></button>
|
||||||
|
<button class="btn btn-danger btn-icon-only x-revoke-trakt-tokens" title="Revoke Trakt Tokens"><i class="icon-sonarr-logout"></i></button>
|
||||||
|
</div >
|
||||||
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
Loading…
Reference in New Issue
Block a user