You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

143 lines
5.6 KiB

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=30):
self.session = requests.Session()
self.verify = certifi.where() if ssl_verify else False
self.timeout = timeout if timeout else None
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 count > 3:
sickbeard.TRAKT_ACCESS_TOKEN = ''
return False
elif count > 0:
time.sleep(2)
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 None is not 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')
if 'account' in resp:
return True
return False
def get_connected_user(self):
if sickbeard.TRAKT_TOKEN:
if sickbeard.TRAKT_CONNECTED_ACCOUNT and sickbeard.TRAKT_TOKEN == sickbeard.TRAKT_CONNECTED_ACCOUNT[1] and sickbeard.TRAKT_CONNECTED_ACCOUNT[0]:
return 'Connected to Trakt user account: ' + str(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 'Connected to Trakt user account: ' + str(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 url:
url = self.api_url
count += 1
if None is headers:
headers = self.headers
if None is sickbeard.TRAKT_TOKEN:
logger.log(u'You must get a Trakt TOKEN. Check your Trakt settings', logger.WARNING)
return {}
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)
elif 401 == code:
if self.trakt_token(refresh=True, count=count):
sickbeard.save_config()
return self.trakt_request(path, data, headers, url, method)
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', False):
if 'message' in resp:
raise traktException(resp['message'])
if 'error' in resp:
raise traktException(resp['error'])
else:
raise traktException('Unknown Error')
return resp