Merge pull request #559 from JackDandy/feature/ChangeTraktV2-libtrakt

Feature/change trakt v2 libtrakt
This commit is contained in:
JackDandy 2015-11-16 11:52:04 +00:00
commit f418c245fb
13 changed files with 271 additions and 196 deletions

View file

@ -60,6 +60,9 @@
* Change to throttle connection rate on thread initiation for adba library * Change to throttle connection rate on thread initiation for adba library
* Change default manage episodes selector to Snatched episodes if items exist else Wanted on Episode Status Manage page * Change default manage episodes selector to Snatched episodes if items exist else Wanted on Episode Status Manage page
* Change snatched row colour on Episode Status Manage page to match colour used on the show details page * Change snatched row colour on Episode Status Manage page to match colour used on the show details page
* Change replace trakt with libtrakt for API v2
* Change Trakt notification config to only handle PIN authentication with the service
* Remove all other Trakt deprecated API V1 service features pending reconsideration
[develop changelog] [develop changelog]
Enable Alpha Ratio again now that the secure login page over https is fixed Enable Alpha Ratio again now that the secure login page over https is fixed

View file

@ -1,5 +1,6 @@
#import sickbeard #import sickbeard
#import re #import re
#from lib.libtrakt import TraktAPI
#from sickbeard.helpers import anon_url, starify #from sickbeard.helpers import anon_url, starify
## ##
#set global $title = 'Config - Notifications' #set global $title = 'Config - Notifications'
@ -1465,7 +1466,7 @@
<div class="component-group-desc"> <div class="component-group-desc">
<img class="notifier-icon" src="$sbRoot/images/notifiers/trakt.png" alt="" title="Trakt"/> <img class="notifier-icon" src="$sbRoot/images/notifiers/trakt.png" alt="" title="Trakt"/>
<h3><a href="<%= anon_url('http://trakt.tv/') %>" rel="noreferrer" onclick="window.open(this.href, '_blank'); return false;">Trakt</a></h3> <h3><a href="<%= anon_url('http://trakt.tv/') %>" rel="noreferrer" onclick="window.open(this.href, '_blank'); return false;">Trakt</a></h3>
<p>trakt helps keep a record of what TV shows and movies you are watching. Based on your favorites, trakt recommends additional shows and movies you'll enjoy!</p> <p>Trakt can keep a record of what TV shows you are watching and recommend additional shows based on your show data.</p>
</div> </div>
<fieldset class="component-group-list"> <fieldset class="component-group-list">
<div class="field-pair"> <div class="field-pair">
@ -1473,42 +1474,24 @@
<span class="component-title">Enable</span> <span class="component-title">Enable</span>
<span class="component-desc"> <span class="component-desc">
<input type="checkbox" class="enabler" name="use_trakt" id="use_trakt" #if $sickbeard.USE_TRAKT then 'checked="checked"' else ''# /> <input type="checkbox" class="enabler" name="use_trakt" id="use_trakt" #if $sickbeard.USE_TRAKT then 'checked="checked"' else ''# />
<p>should SickGear send Trakt.tv notifications ?</p> <p>should SickGear use Trakt.tv ?</p>
</span> </span>
</label> </label>
</div> </div>
<div id="content_use_trakt"> <div id="content_use_trakt">
<div class="field-pair"> <div class="field-pair">
<label for="trakt_username"> <label for="trakt_pin">
<span class="component-title">Trakt username</span> <span class="component-title">Trakt PIN:</span>
<input type="text" name="trakt_username" id="trakt_username" value="$sickbeard.TRAKT_USERNAME" class="form-control input-sm input250" /> <span class="component-desc">
</label> <input type="text" name="trakt_pin" id="trakt_pin" value="" class="form-control input-sm input250" />
<label> <input type="button" class="btn" value="Connect" id="trakt-authenticate" />
<span class="component-title">&nbsp;</span> <div class="clear-left"><p>get your PIN at: <a href="<%= anon_url(sickbeard.TRAKT_PIN_URL) %>" rel="noreferrer" onclick="window.open(this.href, '_blank'); return false;"><b>$sickbeard.TRAKT_PIN_URL</b></a></p></div>
<span class="component-desc">username of your Trakt account.</span> </span>
</label>
</div>
<div class="field-pair">
<label for="trakt_password">
<span class="component-title">Trakt password</span>
<input type="password" name="trakt_password" id="trakt_password" value="#echo '*' * len($sickbeard.TRAKT_PASSWORD)#" class="form-control input-sm input250" />
</label>
<label>
<span class="component-title">&nbsp;</span>
<span class="component-desc">password of your Trakt account.</span>
</label>
</div>
<div class="field-pair">
<label for="trakt_api">
<span class="component-title">Trakt API key:</span>
<input type="text" name="trakt_api" id="trakt_api" value="<%= starify(sickbeard.TRAKT_API) %>" class="form-control input-sm input250" />
</label>
<label>
<span class="component-title">&nbsp;</span>
<span class="component-desc">get your key at: <a href="<%= anon_url('http://trakt.tv/settings/api') %>" rel="noreferrer" onclick="window.open(this.href, '_blank'); return false;"><b>http://trakt.tv/settings/api</b></a></span>
</label> </label>
<div class="testNotification" id="trakt-authentication-result"></div>
</div> </div>
<!--
<div class="field-pair"> <div class="field-pair">
<label for="trakt_default_indexer"> <label for="trakt_default_indexer">
<span class="component-title">Default indexer:</span> <span class="component-title">Default indexer:</span>
@ -1582,8 +1565,7 @@
</label> </label>
</div> </div>
</div> </div>
<div class="testNotification" id="testTrakt-result">Click below to test.</div> -->
<input type="button" class="btn" value="Test Trakt" id="testTrakt" />
<input type="submit" class="btn config_submitter" value="Save Changes" /> <input type="submit" class="btn config_submitter" value="Save Changes" />
</div><!-- /content_use_trakt //--> </div><!-- /content_use_trakt //-->
</fieldset> </fieldset>

View file

@ -352,39 +352,30 @@ $(document).ready(function(){
}); });
}); });
$('#testTrakt').click(function () { var elTraktAuth = $('#trakt-authenticate'), elTraktAuthResult = $('#trakt-authentication-result');
var trakt_api = $.trim($('#trakt_api').val()); elTraktAuth.click(function() {
var trakt_username = $.trim($('#trakt_username').val()); var elTrakt = $('#trakt_pin'), traktPin = $.trim(elTrakt.val());
var trakt_password = $.trim($('#trakt_password').val()); if(!traktPin) {
if (!trakt_api || !trakt_username || !trakt_password) { elTrakt.addClass('warning');
$('#testTrakt-result').html('Please fill out the necessary fields above.'); elTraktAuthResult.html('Please enter a required PIN above.');
if (!trakt_api) { } else {
$('#trakt_api').addClass('warning'); elTrakt.removeClass('warning');
} else { $(this).prop('disabled', true);
$('#trakt_api').removeClass('warning'); elTraktAuthResult.html(loading);
} $.get(sbRoot + '/home/trakt_authenticate', {'pin': traktPin})
if (!trakt_username) { .done(function(data) {
$('#trakt_username').addClass('warning'); elTraktAuthResult.html(data);
} else { elTraktAuth.prop('disabled', false);
$('#trakt_username').removeClass('warning'); });
}
if (!trakt_password) {
$('#trakt_password').addClass('warning');
} else {
$('#trakt_password').removeClass('warning');
}
return;
} }
$('#trakt_api,#trakt_username,#trakt_password').removeClass('warning');
$(this).prop('disabled', true);
$('#testTrakt-result').html(loading);
$.get(sbRoot + '/home/testTrakt', {'api': trakt_api, 'username': trakt_username, 'password': trakt_password})
.done(function (data) {
$('#testTrakt-result').html(data);
$('#testTrakt').prop('disabled', false);
});
}); });
elTraktAuthResult.html(loading);
$.get(sbRoot + '/home/trakt_get_connected_account')
.done(function(data) {
elTraktAuthResult.html(data);
});
$('#testEmail').click(function () { $('#testEmail').click(function () {
var status, host, port, tls, from, user, pwd, err, to; var status, host, port, tls, from, user, pwd, err, to;
status = $('#testEmail-result'); status = $('#testEmail-result');

1
lib/libtrakt/__init__.py Normal file
View file

@ -0,0 +1 @@
from trakt import TraktAPI

View file

@ -0,0 +1,10 @@
class traktException(Exception):
pass
class traktAuthException(traktException):
pass
class traktServerBusy(traktException):
pass

141
lib/libtrakt/trakt.py Normal file
View file

@ -0,0 +1,141 @@
import requests
import certifi
import json
import sickbeard
import time
from sickbeard import logger
from exceptions import traktException, traktAuthException # , traktServerBusy
class TraktAPI:
def __init__(self, ssl_verify=True, timeout=None):
self.session = requests.Session()
self.verify = ssl_verify and sickbeard.TRAKT_VERIFY and certifi.where()
self.timeout = timeout or sickbeard.TRAKT_TIMEOUT
self.auth_url = sickbeard.TRAKT_BASE_URL
self.api_url = sickbeard.TRAKT_BASE_URL
self.headers = {
'Content-Type': 'application/json',
'trakt-api-version': '2',
'trakt-api-key': sickbeard.TRAKT_CLIENT_ID
}
def trakt_token(self, trakt_pin=None, refresh=False, count=0):
if 3 <= count:
sickbeard.TRAKT_ACCESS_TOKEN = ''
return False
elif 0 < count:
time.sleep(3)
data = {
'client_id': sickbeard.TRAKT_CLIENT_ID,
'client_secret': sickbeard.TRAKT_CLIENT_SECRET,
'redirect_uri': 'urn:ietf:wg:oauth:2.0:oob'
}
if refresh:
data['grant_type'] = 'refresh_token'
data['refresh_token'] = sickbeard.TRAKT_REFRESH_TOKEN
else:
data['grant_type'] = 'authorization_code'
if trakt_pin:
data['code'] = trakt_pin
headers = {
'Content-Type': 'application/json'
}
resp = self.trakt_request('oauth/token', data=data, headers=headers, url=self.auth_url, method='POST', count=count)
if 'access_token' in resp:
sickbeard.TRAKT_TOKEN = resp['access_token']
if 'refresh_token' in resp:
sickbeard.TRAKT_REFRESH_TOKEN = resp['refresh_token']
return True
return False
def validate_account(self):
resp = self.trakt_request('users/settings')
return 'account' in resp
def get_connected_user(self):
if sickbeard.TRAKT_TOKEN:
response = 'Connected to Trakt user account: %s'
if sickbeard.TRAKT_CONNECTED_ACCOUNT and sickbeard.TRAKT_TOKEN == sickbeard.TRAKT_CONNECTED_ACCOUNT[1] and sickbeard.TRAKT_CONNECTED_ACCOUNT[0]:
return response % sickbeard.TRAKT_CONNECTED_ACCOUNT[0]
resp = self.trakt_request('users/settings')
if 'user' in resp:
sickbeard.TRAKT_CONNECTED_ACCOUNT = [resp['user']['username'], sickbeard.TRAKT_TOKEN]
return response % sickbeard.TRAKT_CONNECTED_ACCOUNT[0]
return 'Not connected to Trakt'
def trakt_request(self, path, data=None, headers=None, url=None, method='GET', count=0):
if None is sickbeard.TRAKT_TOKEN:
logger.log(u'You must get a Trakt token. Check your Trakt settings', logger.WARNING)
return {}
headers = headers or self.headers
url = url or self.api_url
count += 1
headers['Authorization'] = 'Bearer ' + sickbeard.TRAKT_TOKEN
try:
resp = self.session.request(method, url + path, headers=headers, timeout=self.timeout,
data=json.dumps(data) if data else [], verify=self.verify)
# check for http errors and raise if any are present
resp.raise_for_status()
# convert response to json
resp = resp.json()
except requests.RequestException as e:
code = getattr(e.response, 'status_code', None)
if not code:
if 'timed out' in e:
logger.log(u'Timeout connecting to Trakt. Try to increase timeout value in Trakt settings', logger.WARNING)
# This is pretty much a fatal error if there is no status_code
# It means there basically was no response at all
else:
logger.log(u'Could not connect to Trakt. Error: {0}'.format(e), logger.WARNING)
elif 502 == code:
# Retry the request, Cloudflare had a proxying issue
logger.log(u'Retrying trakt api request: %s' % path, logger.WARNING)
return self.trakt_request(path, data, headers, url, method, count=count)
elif 401 == code:
if self.trakt_token(refresh=True, count=count):
sickbeard.save_config()
return self.trakt_request(path, data, headers, url, method, count=count)
else:
logger.log(u'Unauthorized. Please check your Trakt settings', logger.WARNING)
raise traktAuthException()
elif code in (500, 501, 503, 504, 520, 521, 522):
# http://docs.trakt.apiary.io/#introduction/status-codes
logger.log(u'Trakt may have some issues and it\'s unavailable. Try again later please', logger.WARNING)
elif 404 == code:
logger.log(u'Trakt error (404) the resource does not exist: %s' % url + path, logger.WARNING)
else:
logger.log(u'Could not connect to Trakt. Code error: {0}'.format(code), logger.ERROR)
return {}
# check and confirm Trakt call did not fail
if isinstance(resp, dict) and 'failure' == resp.get('status', None):
if 'message' in resp:
raise traktException(resp['message'])
if 'error' in resp:
raise traktException(resp['error'])
else:
raise traktException('Unknown Error')
return resp

View file

@ -1,67 +0,0 @@
from urllib2 import Request, urlopen, HTTPError, URLError
import base64
from sha import new as sha1
try:
import json
except ImportError:
from lib import simplejson as json
def TraktCall(method, api, username=None, password=None, data={}):
"""
A generic method for communicating with trakt. Uses the method and data provided along
with the auth info to send the command.
method: The URL to use at trakt, relative, no leading slash.
api: The API string to provide to trakt
username: The username to use when logging in
password: The unencrypted password to use when logging in
Returns: A boolean representing success
"""
#logger.log("trakt: Call method " + method, logger.DEBUG)
# if the API isn't given then it failed
if not api:
return None
# replace the API string with what we found
method = method.replace("%API%", api)
# make the full url
url = 'https://api-v2launch.trakt.tv/' + method
# take the URL params and make a json object out of them
encoded_data = json.JSONEncoder().encode(data)
request = Request(url, encoded_data)
# if the username isn't given then it failed
if username and password:
pwdsha1 = sha1(password).hexdigest()
base64string = base64.encodestring('%s:%s' % (username, pwdsha1)).replace('\n', '')
request.add_header("Accept", "*/*")
request.add_header("User-Agent", "CPython/2.7.5 Unknown/Unknown")
request.add_header("Authorization", "Basic %s" % base64string)
# request the URL from trakt and parse the result as json
try:
#logger.log("trakt: Calling method http://api.trakt.tv/" + method + ", with data" + encoded_data, logger.DEBUG)
stream = urlopen(request).read()
# check if results are valid
if stream == '[]':
resp = 'NULL'
else:
resp = json.JSONDecoder().decode(stream)
if ("error" in resp):
raise Exception(resp["error"])
except (IOError):
#logger.log("trakt: Failed calling method", logger.ERROR)
return None
#logger.log("trakt: Failed calling method", logger.ERROR)
return resp

View file

@ -356,15 +356,13 @@ SYNOLOGYNOTIFIER_NOTIFY_ONDOWNLOAD = False
SYNOLOGYNOTIFIER_NOTIFY_ONSUBTITLEDOWNLOAD = False SYNOLOGYNOTIFIER_NOTIFY_ONSUBTITLEDOWNLOAD = False
USE_TRAKT = False USE_TRAKT = False
TRAKT_USERNAME = None TRAKT_TOKEN = ''
TRAKT_PASSWORD = None TRAKT_REFRESH_TOKEN = ''
TRAKT_API = ''
TRAKT_REMOVE_WATCHLIST = False TRAKT_REMOVE_WATCHLIST = False
TRAKT_REMOVE_SERIESLIST = False TRAKT_REMOVE_SERIESLIST = False
TRAKT_USE_WATCHLIST = False TRAKT_USE_WATCHLIST = False
TRAKT_METHOD_ADD = 0 TRAKT_METHOD_ADD = 0
TRAKT_START_PAUSED = False TRAKT_START_PAUSED = False
TRAKT_USE_RECOMMENDED = False
TRAKT_SYNC = False TRAKT_SYNC = False
TRAKT_DEFAULT_INDEXER = None TRAKT_DEFAULT_INDEXER = None
@ -449,7 +447,26 @@ REQUIRE_WORDS = ''
CALENDAR_UNPROTECTED = False CALENDAR_UNPROTECTED = False
TMDB_API_KEY = 'edc5f123313769de83a71e157758030b' TMDB_API_KEY = 'edc5f123313769de83a71e157758030b'
TRAKT_API_KEY = 'abd806c54516240c76e4ebc9c5ccf394'
# to switch between staging and production TRAKT environment
TRAKT_STAGING = False
TRAKT_TIMEOUT = 60
TRAKT_VERIFY = True
TRAKT_CONNECTED_ACCOUNT = None
if TRAKT_STAGING:
# staging trakt values:
TRAKT_CLIENT_ID = '2aae3052f90b14235d184cc8f709b12b4fd8ae35f339a060a890c70db92be87a'
TRAKT_CLIENT_SECRET = '900e03471220503843d4a856bfbef17080cddb630f2b7df6a825e96e3ff3c39e'
TRAKT_PIN_URL = 'https://staging.trakt.tv/pin/638'
TRAKT_BASE_URL = 'http://api.staging.trakt.tv/'
else:
# production trakt values:
TRAKT_CLIENT_ID = 'f1c453c67d81f1307f9118172c408a883eb186b094d5ea33080d59ddedb7fc7c'
TRAKT_CLIENT_SECRET = '12efb6fb6e863a08934d9904032a90008325df7e23514650cade55e7e7c118c5'
TRAKT_PIN_URL = 'https://trakt.tv/pin/6314'
TRAKT_BASE_URL = 'https://api-v2launch.trakt.tv/'
COOKIE_SECRET = base64.b64encode(uuid.uuid4().bytes + uuid.uuid4().bytes) COOKIE_SECRET = base64.b64encode(uuid.uuid4().bytes + uuid.uuid4().bytes)
@ -472,7 +489,7 @@ def initialize(consoleLogging=True):
USE_XBMC, XBMC_ALWAYS_ON, XBMC_NOTIFY_ONSNATCH, XBMC_NOTIFY_ONDOWNLOAD, XBMC_NOTIFY_ONSUBTITLEDOWNLOAD, XBMC_UPDATE_FULL, XBMC_UPDATE_ONLYFIRST, \ USE_XBMC, XBMC_ALWAYS_ON, XBMC_NOTIFY_ONSNATCH, XBMC_NOTIFY_ONDOWNLOAD, XBMC_NOTIFY_ONSUBTITLEDOWNLOAD, XBMC_UPDATE_FULL, XBMC_UPDATE_ONLYFIRST, \
XBMC_UPDATE_LIBRARY, XBMC_HOST, XBMC_USERNAME, XBMC_PASSWORD, BACKLOG_FREQUENCY, \ XBMC_UPDATE_LIBRARY, XBMC_HOST, XBMC_USERNAME, XBMC_PASSWORD, BACKLOG_FREQUENCY, \
USE_KODI, KODI_ALWAYS_ON, KODI_NOTIFY_ONSNATCH, KODI_NOTIFY_ONDOWNLOAD, KODI_NOTIFY_ONSUBTITLEDOWNLOAD, KODI_UPDATE_FULL, KODI_UPDATE_ONLYFIRST, KODI_UPDATE_LIBRARY, KODI_HOST, KODI_USERNAME, KODI_PASSWORD, \ USE_KODI, KODI_ALWAYS_ON, KODI_NOTIFY_ONSNATCH, KODI_NOTIFY_ONDOWNLOAD, KODI_NOTIFY_ONSUBTITLEDOWNLOAD, KODI_UPDATE_FULL, KODI_UPDATE_ONLYFIRST, KODI_UPDATE_LIBRARY, KODI_HOST, KODI_USERNAME, KODI_PASSWORD, \
USE_TRAKT, TRAKT_USERNAME, TRAKT_PASSWORD, TRAKT_API, TRAKT_REMOVE_WATCHLIST, TRAKT_USE_WATCHLIST, TRAKT_METHOD_ADD, TRAKT_START_PAUSED, traktCheckerScheduler, TRAKT_USE_RECOMMENDED, TRAKT_SYNC, TRAKT_DEFAULT_INDEXER, TRAKT_REMOVE_SERIESLIST, \ USE_TRAKT, TRAKT_CONNECTED_ACCOUNT, TRAKT_VERIFY, TRAKT_REMOVE_WATCHLIST, TRAKT_TOKEN, TRAKT_TIMEOUT, TRAKT_REFRESH_TOKEN, TRAKT_USE_WATCHLIST, TRAKT_METHOD_ADD, TRAKT_START_PAUSED, traktCheckerScheduler, TRAKT_SYNC, TRAKT_DEFAULT_INDEXER, TRAKT_REMOVE_SERIESLIST, \
USE_PLEX, PLEX_NOTIFY_ONSNATCH, PLEX_NOTIFY_ONDOWNLOAD, PLEX_NOTIFY_ONSUBTITLEDOWNLOAD, PLEX_UPDATE_LIBRARY, \ USE_PLEX, PLEX_NOTIFY_ONSNATCH, PLEX_NOTIFY_ONDOWNLOAD, PLEX_NOTIFY_ONSUBTITLEDOWNLOAD, PLEX_UPDATE_LIBRARY, \
PLEX_SERVER_HOST, PLEX_HOST, PLEX_USERNAME, PLEX_PASSWORD, DEFAULT_BACKLOG_FREQUENCY, MIN_BACKLOG_FREQUENCY, MAX_BACKLOG_FREQUENCY, BACKLOG_STARTUP, SKIP_REMOVED_FILES, \ PLEX_SERVER_HOST, PLEX_HOST, PLEX_USERNAME, PLEX_PASSWORD, DEFAULT_BACKLOG_FREQUENCY, MIN_BACKLOG_FREQUENCY, MAX_BACKLOG_FREQUENCY, BACKLOG_STARTUP, SKIP_REMOVED_FILES, \
showUpdateScheduler, __INITIALIZED__, LAUNCH_BROWSER, TRASH_REMOVE_SHOW, TRASH_ROTATE_LOGS, HOME_SEARCH_FOCUS, SORT_ARTICLE, showList, loadingShowList, UPDATE_SHOWS_ON_START, SHOW_UPDATE_HOUR, ALLOW_INCOMPLETE_SHOWDATA, \ showUpdateScheduler, __INITIALIZED__, LAUNCH_BROWSER, TRASH_REMOVE_SHOW, TRASH_ROTATE_LOGS, HOME_SEARCH_FOCUS, SORT_ARTICLE, showList, loadingShowList, UPDATE_SHOWS_ON_START, SHOW_UPDATE_HOUR, ALLOW_INCOMPLETE_SHOWDATA, \
@ -860,15 +877,13 @@ def initialize(consoleLogging=True):
check_setting_int(CFG, 'SynologyNotifier', 'synologynotifier_notify_onsubtitledownload', 0)) check_setting_int(CFG, 'SynologyNotifier', 'synologynotifier_notify_onsubtitledownload', 0))
USE_TRAKT = bool(check_setting_int(CFG, 'Trakt', 'use_trakt', 0)) USE_TRAKT = bool(check_setting_int(CFG, 'Trakt', 'use_trakt', 0))
TRAKT_USERNAME = check_setting_str(CFG, 'Trakt', 'trakt_username', '') TRAKT_TOKEN = check_setting_str(CFG, 'Trakt', 'trakt_token', '')
TRAKT_PASSWORD = check_setting_str(CFG, 'Trakt', 'trakt_password', '') TRAKT_REFRESH_TOKEN = check_setting_str(CFG, 'Trakt', 'trakt_refresh_token', '')
TRAKT_API = check_setting_str(CFG, 'Trakt', 'trakt_api', '')
TRAKT_REMOVE_WATCHLIST = bool(check_setting_int(CFG, 'Trakt', 'trakt_remove_watchlist', 0)) TRAKT_REMOVE_WATCHLIST = bool(check_setting_int(CFG, 'Trakt', 'trakt_remove_watchlist', 0))
TRAKT_REMOVE_SERIESLIST = bool(check_setting_int(CFG, 'Trakt', 'trakt_remove_serieslist', 0)) TRAKT_REMOVE_SERIESLIST = bool(check_setting_int(CFG, 'Trakt', 'trakt_remove_serieslist', 0))
TRAKT_USE_WATCHLIST = bool(check_setting_int(CFG, 'Trakt', 'trakt_use_watchlist', 0)) TRAKT_USE_WATCHLIST = bool(check_setting_int(CFG, 'Trakt', 'trakt_use_watchlist', 0))
TRAKT_METHOD_ADD = check_setting_int(CFG, 'Trakt', 'trakt_method_add', 0) TRAKT_METHOD_ADD = check_setting_int(CFG, 'Trakt', 'trakt_method_add', 0)
TRAKT_START_PAUSED = bool(check_setting_int(CFG, 'Trakt', 'trakt_start_paused', 0)) TRAKT_START_PAUSED = bool(check_setting_int(CFG, 'Trakt', 'trakt_start_paused', 0))
TRAKT_USE_RECOMMENDED = bool(check_setting_int(CFG, 'Trakt', 'trakt_use_recommended', 0))
TRAKT_SYNC = bool(check_setting_int(CFG, 'Trakt', 'trakt_sync', 0)) TRAKT_SYNC = bool(check_setting_int(CFG, 'Trakt', 'trakt_sync', 0))
TRAKT_DEFAULT_INDEXER = check_setting_int(CFG, 'Trakt', 'trakt_default_indexer', 1) TRAKT_DEFAULT_INDEXER = check_setting_int(CFG, 'Trakt', 'trakt_default_indexer', 1)
@ -1673,15 +1688,13 @@ def save_config():
new_config['Trakt'] = {} new_config['Trakt'] = {}
new_config['Trakt']['use_trakt'] = int(USE_TRAKT) new_config['Trakt']['use_trakt'] = int(USE_TRAKT)
new_config['Trakt']['trakt_username'] = TRAKT_USERNAME new_config['Trakt']['trakt_token'] = TRAKT_TOKEN
new_config['Trakt']['trakt_password'] = helpers.encrypt(TRAKT_PASSWORD, ENCRYPTION_VERSION) new_config['Trakt']['trakt_refresh_token'] = TRAKT_REFRESH_TOKEN
new_config['Trakt']['trakt_api'] = TRAKT_API
new_config['Trakt']['trakt_remove_watchlist'] = int(TRAKT_REMOVE_WATCHLIST) new_config['Trakt']['trakt_remove_watchlist'] = int(TRAKT_REMOVE_WATCHLIST)
new_config['Trakt']['trakt_remove_serieslist'] = int(TRAKT_REMOVE_SERIESLIST) new_config['Trakt']['trakt_remove_serieslist'] = int(TRAKT_REMOVE_SERIESLIST)
new_config['Trakt']['trakt_use_watchlist'] = int(TRAKT_USE_WATCHLIST) new_config['Trakt']['trakt_use_watchlist'] = int(TRAKT_USE_WATCHLIST)
new_config['Trakt']['trakt_method_add'] = int(TRAKT_METHOD_ADD) new_config['Trakt']['trakt_method_add'] = int(TRAKT_METHOD_ADD)
new_config['Trakt']['trakt_start_paused'] = int(TRAKT_START_PAUSED) new_config['Trakt']['trakt_start_paused'] = int(TRAKT_START_PAUSED)
new_config['Trakt']['trakt_use_recommended'] = int(TRAKT_USE_RECOMMENDED)
new_config['Trakt']['trakt_sync'] = int(TRAKT_SYNC) new_config['Trakt']['trakt_sync'] = int(TRAKT_SYNC)
new_config['Trakt']['trakt_default_indexer'] = int(TRAKT_DEFAULT_INDEXER) new_config['Trakt']['trakt_default_indexer'] = int(TRAKT_DEFAULT_INDEXER)

View file

@ -37,7 +37,7 @@ import pushalot
import pushbullet import pushbullet
import tweet import tweet
import trakt from lib import libtrakt
import emailnotify import emailnotify
from sickbeard.common import * from sickbeard.common import *
@ -62,7 +62,7 @@ pushalot_notifier = pushalot.PushalotNotifier()
pushbullet_notifier = pushbullet.PushbulletNotifier() pushbullet_notifier = pushbullet.PushbulletNotifier()
# social # social
twitter_notifier = tweet.TwitterNotifier() twitter_notifier = tweet.TwitterNotifier()
trakt_notifier = trakt.TraktNotifier() #trakt_notifier = trakt.TraktNotifier()
email_notifier = emailnotify.EmailNotifier() email_notifier = emailnotify.EmailNotifier()
notifiers = [ notifiers = [
@ -83,7 +83,7 @@ notifiers = [
pushalot_notifier, pushalot_notifier,
pushbullet_notifier, pushbullet_notifier,
twitter_notifier, twitter_notifier,
trakt_notifier, # trakt_notifier,
email_notifier, email_notifier,
] ]

View file

@ -18,7 +18,7 @@
import sickbeard import sickbeard
from sickbeard import logger from sickbeard import logger
from lib.trakt import * from lib.libtrakt import TraktAPI
class TraktNotifier: class TraktNotifier:

View file

@ -1034,7 +1034,7 @@ class PostProcessor(object):
notifiers.pytivo_notifier.update_library(ep_obj) notifiers.pytivo_notifier.update_library(ep_obj)
# do the library update for Trakt # do the library update for Trakt
notifiers.trakt_notifier.update_library(ep_obj) # notifiers.trakt_notifier.update_library(ep_obj)
self._run_extra_scripts(ep_obj) self._run_extra_scripts(ep_obj)

View file

@ -26,7 +26,7 @@ from sickbeard import logger
from sickbeard import helpers from sickbeard import helpers
from sickbeard import search_queue from sickbeard import search_queue
from sickbeard.common import SKIPPED, WANTED from sickbeard.common import SKIPPED, WANTED
from lib.trakt import * from lib import libtrakt
class TraktChecker(): class TraktChecker():

View file

@ -54,7 +54,9 @@ from lib import adba
from lib import subliminal from lib import subliminal
from lib.dateutil import tz from lib.dateutil import tz
from lib.unrar2 import RarFile from lib.unrar2 import RarFile
from lib.trakt import TraktCall from lib.libtrakt import TraktAPI
from lib.libtrakt.exceptions import traktException, traktAuthException
try: try:
import json import json
@ -879,19 +881,24 @@ class Home(MainHandler):
return '{"message": "Unable to find NMJ Database at location: %(dbloc)s. Is the right location selected and PCH running?", "database": ""}' % { return '{"message": "Unable to find NMJ Database at location: %(dbloc)s. Is the right location selected and PCH running?", "database": ""}' % {
"dbloc": dbloc} "dbloc": dbloc}
def testTrakt(self, api=None, username=None, password=None): def trakt_authenticate(self, pin=None):
self.set_header('Cache-Control', 'max-age=0,no-cache,no-store') self.set_header('Cache-Control', 'max-age=0,no-cache,no-store')
if None is not api and starify(api, True): if None is pin:
api = sickbeard.TRAKT_API return 'Trakt PIN required for authentication'
if None is not password and set('*') == set(password):
password = sickbeard.TRAKT_PASSWORD
result = notifiers.trakt_notifier.test_notify(api, username, password) try:
if result: TraktAPI().trakt_token(pin)
return 'Test notice sent successfully to Trakt' except traktAuthException:
else: return 'Fail: Trakt NOT authenticated'
return 'Test notice failed to Trakt'
sickbeard.USE_TRAKT = True
sickbeard.save_config()
return '%s %s' % ('Success: Trakt authenticated.', self.trakt_get_connected_account())
@staticmethod
def trakt_get_connected_account():
return TraktAPI().get_connected_user()
def loadShowNotifyLists(self, *args, **kwargs): def loadShowNotifyLists(self, *args, **kwargs):
self.set_header('Cache-Control', 'max-age=0,no-cache,no-store') self.set_header('Cache-Control', 'max-age=0,no-cache,no-store')
@ -2273,22 +2280,27 @@ class NewHomeAddShows(Home):
t = PageTemplate(headers=self.request.headers, file='home_trendingShows.tmpl') t = PageTemplate(headers=self.request.headers, file='home_trendingShows.tmpl')
t.submenu = self.HomeMenu() t.submenu = self.HomeMenu()
t.trending_shows = TraktCall('shows/trending.json/%API%', sickbeard.TRAKT_API_KEY) trakt_api = TraktAPI()
t.trending_inlibrary = 0 limit_show = 50
if None is not t.trending_shows: try:
for item in t.trending_shows: t.trending_shows = trakt_api.trakt_request("shows/trending?limit=" + str(limit_show) + "&extended=full,images") or []
tvdbs = ['tvdb_id', 'tvrage_id'] t.trending_inlibrary = 0
for index, tvdb in enumerate(tvdbs): if None is not t.trending_shows:
try: for item in t.trending_shows:
item[u'show_id'] = str(item[tvdb]) tvdbs = ['tvdb_id', 'tvrage_id']
tvshow = helpers.findCertainShow(sickbeard.showList, int(item[tvdb])) for index, tvdb in enumerate(tvdbs):
except: try:
continue item[u'show_id'] = str(item[tvdb])
# check tvshow indexer is not using the same id from another indexer tvshow = helpers.findCertainShow(sickbeard.showList, int(item[tvdb]))
if tvshow and (index + 1) == tvshow.indexer: except:
item[u'show_id'] = u'%s:%s' % (tvshow.indexer, item[tvdb]) continue
t.trending_inlibrary += 1 # check tvshow indexer is not using the same id from another indexer
break if tvshow and (index + 1) == tvshow.indexer:
item[u'show_id'] = u'%s:%s' % (tvshow.indexer, item[tvdb])
t.trending_inlibrary += 1
break
except traktException as e:
logger.log(u"Could not connect to Trakt service: %s" % ex(e), logger.WARNING)
return t.respond() return t.respond()
@ -4368,9 +4380,9 @@ class ConfigNotifications(Config):
libnotify_notify_onsubtitledownload=None, libnotify_notify_onsubtitledownload=None,
use_nmj=None, nmj_host=None, nmj_database=None, nmj_mount=None, use_synoindex=None, use_nmj=None, nmj_host=None, nmj_database=None, nmj_mount=None, use_synoindex=None,
use_nmjv2=None, nmjv2_host=None, nmjv2_dbloc=None, nmjv2_database=None, use_nmjv2=None, nmjv2_host=None, nmjv2_dbloc=None, nmjv2_database=None,
use_trakt=None, trakt_username=None, trakt_password=None, trakt_api=None, use_trakt=None, trakt_pin=None,
trakt_remove_watchlist=None, trakt_use_watchlist=None, trakt_method_add=None, trakt_remove_watchlist=None, trakt_use_watchlist=None, trakt_method_add=None,
trakt_start_paused=None, trakt_use_recommended=None, trakt_sync=None, trakt_start_paused=None, trakt_sync=None,
trakt_default_indexer=None, trakt_remove_serieslist=None, trakt_default_indexer=None, trakt_remove_serieslist=None,
use_synologynotifier=None, synologynotifier_notify_onsnatch=None, use_synologynotifier=None, synologynotifier_notify_onsnatch=None,
synologynotifier_notify_ondownload=None, synologynotifier_notify_onsubtitledownload=None, synologynotifier_notify_ondownload=None, synologynotifier_notify_onsubtitledownload=None,
@ -4497,25 +4509,14 @@ class ConfigNotifications(Config):
synologynotifier_notify_onsubtitledownload) synologynotifier_notify_onsubtitledownload)
sickbeard.USE_TRAKT = config.checkbox_to_value(use_trakt) sickbeard.USE_TRAKT = config.checkbox_to_value(use_trakt)
sickbeard.TRAKT_USERNAME = trakt_username sickbeard.traktCheckerScheduler.silent = not sickbeard.USE_TRAKT
if set('*') != set(trakt_password): # sickbeard.TRAKT_DEFAULT_INDEXER = int(trakt_default_indexer)
sickbeard.TRAKT_PASSWORD = trakt_password # sickbeard.TRAKT_SYNC = config.checkbox_to_value(trakt_sync)
key = trakt_api.strip() # sickbeard.TRAKT_USE_WATCHLIST = config.checkbox_to_value(trakt_use_watchlist)
if not starify(key, True): # sickbeard.TRAKT_METHOD_ADD = int(trakt_method_add)
sickbeard.TRAKT_API = key # sickbeard.TRAKT_REMOVE_WATCHLIST = config.checkbox_to_value(trakt_remove_watchlist)
sickbeard.TRAKT_REMOVE_WATCHLIST = config.checkbox_to_value(trakt_remove_watchlist) # sickbeard.TRAKT_REMOVE_SERIESLIST = config.checkbox_to_value(trakt_remove_serieslist)
sickbeard.TRAKT_REMOVE_SERIESLIST = config.checkbox_to_value(trakt_remove_serieslist) # sickbeard.TRAKT_START_PAUSED = config.checkbox_to_value(trakt_start_paused)
sickbeard.TRAKT_USE_WATCHLIST = config.checkbox_to_value(trakt_use_watchlist)
sickbeard.TRAKT_METHOD_ADD = int(trakt_method_add)
sickbeard.TRAKT_START_PAUSED = config.checkbox_to_value(trakt_start_paused)
sickbeard.TRAKT_USE_RECOMMENDED = config.checkbox_to_value(trakt_use_recommended)
sickbeard.TRAKT_SYNC = config.checkbox_to_value(trakt_sync)
sickbeard.TRAKT_DEFAULT_INDEXER = int(trakt_default_indexer)
if sickbeard.USE_TRAKT:
sickbeard.traktCheckerScheduler.silent = False
else:
sickbeard.traktCheckerScheduler.silent = True
sickbeard.USE_EMAIL = config.checkbox_to_value(use_email) sickbeard.USE_EMAIL = config.checkbox_to_value(use_email)
sickbeard.EMAIL_NOTIFY_ONSNATCH = config.checkbox_to_value(email_notify_onsnatch) sickbeard.EMAIL_NOTIFY_ONSNATCH = config.checkbox_to_value(email_notify_onsnatch)