1
0
mirror of https://github.com/moparisthebest/SickRage synced 2025-01-07 03:48:02 -05:00

Overhaul of Trakt.TV API handler

This commit is contained in:
echel0n 2014-11-28 14:07:26 -08:00
parent dcd4a0c602
commit c6b7348c37
6 changed files with 193 additions and 122 deletions

View File

@ -1,20 +1,2 @@
import hashlib from trakt import TraktAPI
import requests from trakt.exceptions import traktException, traktAuthException, traktServerBusy
def TraktCall(method, api, username=None, password=None, data={}):
base_url = 'http://api.trakt.tv/'
# if username and password given then encode password with sha1
auth = None
if username and password:
auth = (username, hashlib.sha1(password.encode('utf-8')).hexdigest())
# request the URL from trakt and parse the result as json
try:
resp = requests.get(base_url + method.replace("%API%", api), auth=auth, data=data).json()
if isinstance(resp, dict) and resp.get('status', False) == 'failure':
raise Exception(resp.get('error', 'Unknown Error'))
except:
return None
return resp

8
lib/trakt/exceptions.py Normal file
View File

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

53
lib/trakt/trakt.py Normal file
View File

@ -0,0 +1,53 @@
import hashlib
import requests
from . import traktException, traktAuthException, traktServerBusy
class TraktAPI():
def __init__(self, apikey, username=None, password=None, use_https=False, timeout=5):
self.apikey = apikey
self.username = username
self.password = password
if password: hashlib.sha1(password.encode('utf-8')).hexdigest()
self.protocol = 'https://' if use_https else 'http://'
self.timeout = timeout
def validateAccount(self):
url = '/account/test/%APIKEY%'
return self.traktRequest(url)
def traktRequest(self, url, data=None):
base_url = self.protocol + 'api.trakt.tv/%s' % url.replace('%APIKEY%', self.apikey).replace('%USER%',
self.username)
# request the URL from trakt and parse the result as json
try:
resp = requests.get(base_url,
auth=(self.username, self.password) if self.username and self.password else None,
data=data if data else [])
# check for http errors and raise if any are present
resp.raise_for_status()
# convert response to json
resp = resp.json()
except (requests.HTTPError, requests.ConnectionError) as e:
if e.code == 401:
raise traktAuthException(e.message, e.code)
elif e.code == 503:
raise traktServerBusy(e.message, e.code)
else:
raise traktException(e.message, e.code)
# check and confirm trakt call did not fail
if isinstance(resp, dict) and resp.get('status', False) == 'failure':
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

@ -18,8 +18,11 @@
import sickbeard import sickbeard
from sickbeard import logger from sickbeard import logger
from lib.trakt import *
from lib.trakt import TraktAPI
from lib.trakt.exceptions import traktException, traktServerBusy, traktAuthException
trakt_api = TraktAPI(sickbeard.TRAKT_API, sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_USERNAME)
class TraktNotifier: class TraktNotifier:
""" """
@ -48,63 +51,64 @@ class TraktNotifier:
trakt_id = sickbeard.indexerApi(ep_obj.show.indexer).config['trakt_id'] trakt_id = sickbeard.indexerApi(ep_obj.show.indexer).config['trakt_id']
if sickbeard.USE_TRAKT: if sickbeard.USE_TRAKT:
# URL parameters try:
data = { # URL parameters
'title': ep_obj.show.name,
'year': ep_obj.show.startyear,
'episodes': [{
'season': ep_obj.season,
'episode': ep_obj.episode
}]
}
if trakt_id == 'tvdb_id':
data[trakt_id] = ep_obj.show.indexerid
# update library
TraktCall("show/episode/library/%API%", self._api(), self._username(), self._password(), data)
# remove from watchlist
if sickbeard.TRAKT_REMOVE_WATCHLIST:
TraktCall("show/episode/unwatchlist/%API%", self._api(), self._username(), self._password(), data)
if sickbeard.TRAKT_REMOVE_SERIESLIST:
data = { data = {
'shows': [ 'title': ep_obj.show.name,
{ 'year': ep_obj.show.startyear,
'title': ep_obj.show.name, 'episodes': [{
'year': ep_obj.show.startyear 'season': ep_obj.season,
} 'episode': ep_obj.episode
] }]
} }
if trakt_id == 'tvdb_id': if trakt_id == 'tvdb_id':
data['shows'][trakt_id] = ep_obj.show.indexerid data[trakt_id] = ep_obj.show.indexerid
TraktCall("show/unwatchlist/%API%", self._api(), self._username(), self._password(), data) # update library
trakt_api.traktRequest("show/episode/library/%APIKEY%", data)
# Remove all episodes from episode watchlist # remove from watchlist
# Start by getting all episodes in the watchlist if sickbeard.TRAKT_REMOVE_WATCHLIST:
watchlist = TraktCall("user/watchlist/episodes.json/%API%/" + sickbeard.TRAKT_USERNAME, trakt_api.traktRequest("show/episode/unwatchlist/%APIKEY%", data)
sickbeard.TRAKT_API, sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_PASSWORD)
# Convert watchlist to only contain current show if sickbeard.TRAKT_REMOVE_SERIESLIST:
if watchlist: data = {
for show in watchlist: 'shows': [
if show[trakt_id] == ep_obj.show.indexerid: {
data_show = { 'title': ep_obj.show.name,
'title': show['title'], 'year': ep_obj.show.startyear
trakt_id: show[trakt_id],
'episodes': []
} }
]
}
# Add series and episode (number) to the array if trakt_id == 'tvdb_id':
for episodes in show['episodes']: data['shows'][trakt_id] = ep_obj.show.indexerid
ep = {'season': episodes['season'], 'episode': episodes['number']}
data_show['episodes'].append(ep)
TraktCall("show/episode/unwatchlist/%API%", sickbeard.TRAKT_API, sickbeard.TRAKT_USERNAME, trakt_api.traktRequest("show/unwatchlist/%APIKEY%", data)
sickbeard.TRAKT_PASSWORD, data_show)
# Remove all episodes from episode watchlist
# Start by getting all episodes in the watchlist
watchlist = trakt_api.traktRequest("user/watchlist/episodes.json/%APIKEY%/%USER%")
# Convert watchlist to only contain current show
if watchlist:
for show in watchlist:
if show[trakt_id] == ep_obj.show.indexerid:
data_show = {
'title': show['title'],
trakt_id: show[trakt_id],
'episodes': []
}
# Add series and episode (number) to the array
for episodes in show['episodes']:
ep = {'season': episodes['season'], 'episode': episodes['number']}
data_show['episodes'].append(ep)
trakt_api.traktRequest("show/episode/unwatchlist/%APIKEY%", data_show)
except (traktException, traktAuthException, traktServerBusy) as e:
logger.log(u"Could not connect to Trakt service: %s" % e.message, logger.ERROR)
def test_notify(self, api, username, password): def test_notify(self, api, username, password):
""" """
@ -118,21 +122,10 @@ class TraktNotifier:
Returns: True if the request succeeded, False otherwise Returns: True if the request succeeded, False otherwise
""" """
data = TraktCall("account/test/%API%", api, username, password) try:
if data and data["status"] == "success": if trakt_api.validateAccount():
return True return True
except (traktException, traktAuthException, traktServerBusy) as e:
def _username(self): logger.log(u"Could not connect to Trakt service: %s" % e.message, logger.ERROR)
return sickbeard.TRAKT_USERNAME
def _password(self):
return sickbeard.TRAKT_PASSWORD
def _api(self):
return sickbeard.TRAKT_API
def _use_me(self):
return sickbeard.USE_TRAKT
notifier = TraktNotifier notifier = TraktNotifier

View File

@ -27,9 +27,13 @@ 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.trakt import *
from trakt.exceptions import traktException
trakt_api = TraktAPI(sickbeard.TRAKT_API, sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_USERNAME)
class TraktChecker(): class TraktChecker():
def __init__(self): def __init__(self):
self.todoWanted = [] self.todoWanted = []
@ -51,17 +55,24 @@ class TraktChecker():
logger.log(traceback.format_exc(), logger.DEBUG) logger.log(traceback.format_exc(), logger.DEBUG)
def findShow(self, indexer, indexerid): def findShow(self, indexer, indexerid):
library = TraktCall("user/library/shows/all.json/%API%/" + sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_API, sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_PASSWORD) traktShow = None
if not library: try:
logger.log(u"Could not connect to trakt service, aborting library check", logger.ERROR) library = trakt_api.traktRequest("user/library/shows/all.json/%APIKEY%/%USER%")
return
if not len(library): if not library:
logger.log(u"No shows found in your library, aborting library update", logger.DEBUG) logger.log(u"Could not connect to trakt service, aborting library check", logger.ERROR)
return return
return filter(lambda x: int(indexerid) in [int(x['tvdb_id']) or 0, int(x['tvrage_id'])] or 0, library) if not len(library):
logger.log(u"No shows found in your library, aborting library update", logger.DEBUG)
return
traktShow = filter(lambda x: int(indexerid) in [int(x['tvdb_id']) or 0, int(x['tvrage_id'])] or 0, library)
except (traktException, traktAuthException, traktServerBusy) as e:
logger.log(u"Could not connect to Trakt service: %s" % e.message, logger.ERROR)
return traktShow
def syncLibrary(self): def syncLibrary(self):
logger.log(u"Syncing Trakt.tv show library", logger.DEBUG) logger.log(u"Syncing Trakt.tv show library", logger.DEBUG)
@ -71,6 +82,7 @@ class TraktChecker():
def removeShowFromTraktLibrary(self, show_obj): def removeShowFromTraktLibrary(self, show_obj):
data = {} data = {}
if self.findShow(show_obj.indexer, show_obj.indexerid): if self.findShow(show_obj.indexer, show_obj.indexerid):
# URL parameters # URL parameters
data['tvdb_id'] = helpers.mapIndexersToShow(show_obj)[1] data['tvdb_id'] = helpers.mapIndexersToShow(show_obj)[1]
@ -79,8 +91,11 @@ class TraktChecker():
if len(data): if len(data):
logger.log(u"Removing " + show_obj.name + " from trakt.tv library", logger.DEBUG) logger.log(u"Removing " + show_obj.name + " from trakt.tv library", logger.DEBUG)
TraktCall("show/unlibrary/%API%", sickbeard.TRAKT_API, sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_PASSWORD,
data) try:
trakt_api.traktRequest("show/unlibrary/%APIKEY%", data)
except (traktException, traktAuthException, traktServerBusy) as e:
logger.log(u"Could not connect to Trakt service: %s" % e.message, logger.ERROR)
def addShowToTraktLibrary(self, show_obj): def addShowToTraktLibrary(self, show_obj):
""" """
@ -99,15 +114,19 @@ class TraktChecker():
if len(data): if len(data):
logger.log(u"Adding " + show_obj.name + " to trakt.tv library", logger.DEBUG) logger.log(u"Adding " + show_obj.name + " to trakt.tv library", logger.DEBUG)
TraktCall("show/library/%API%", sickbeard.TRAKT_API, sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_PASSWORD,
data) try:
trakt_api.traktRequest("show/library/%APIKEY%", data)
except (traktException, traktAuthException, traktServerBusy) as e:
logger.log(u"Could not connect to Trakt service: %s" % e.message, logger.ERROR)
def updateShows(self): def updateShows(self):
logger.log(u"Starting trakt show watchlist check", logger.DEBUG) logger.log(u"Starting trakt show watchlist check", logger.DEBUG)
watchlist = TraktCall("user/watchlist/shows.json/%API%/" + sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_API, sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_PASSWORD)
if not watchlist: try:
logger.log(u"Could not connect to trakt service, aborting watchlist update", logger.ERROR) watchlist = trakt_api.traktRequest("user/watchlist/shows.json/%APIKEY%/%USER%")
except (traktException, traktAuthException, traktServerBusy) as e:
logger.log(u"Could not connect to Trakt service: %s" % e.message, logger.ERROR)
return return
if not len(watchlist): if not len(watchlist):
@ -138,10 +157,11 @@ class TraktChecker():
Sets episodes to wanted that are in trakt watchlist Sets episodes to wanted that are in trakt watchlist
""" """
logger.log(u"Starting trakt episode watchlist check", logger.DEBUG) logger.log(u"Starting trakt episode watchlist check", logger.DEBUG)
watchlist = TraktCall("user/watchlist/episodes.json/%API%/" + sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_API, sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_PASSWORD)
if not watchlist: try:
logger.log(u"Could not connect to trakt service, aborting watchlist update", logger.ERROR) watchlist = trakt_api.traktRequest("user/watchlist/episodes.json/%APIKEY%/%USER%")
except (traktException, traktAuthException, traktServerBusy) as e:
logger.log(u"Could not connect to Trakt service: %s" % e.message, logger.ERROR)
return return
if not len(watchlist): if not len(watchlist):

View File

@ -65,7 +65,9 @@ from lib.dateutil import tz
from lib.unrar2 import RarFile from lib.unrar2 import RarFile
from lib import adba, subliminal from lib import adba, subliminal
from lib.trakt import TraktCall
from lib.trakt import TraktAPI
from lib.trakt.exceptions import traktException, traktAuthException, traktServerBusy
try: try:
import json import json
@ -77,7 +79,6 @@ try:
except ImportError: except ImportError:
import xml.etree.ElementTree as etree import xml.etree.ElementTree as etree
from Cheetah.Template import Template from Cheetah.Template import Template
from tornado.web import RequestHandler, HTTPError, asynchronous from tornado.web import RequestHandler, HTTPError, asynchronous
@ -282,6 +283,7 @@ class MainHandler(RequestHandler):
image_path = image_file_name image_path = image_file_name
from mimetypes import MimeTypes from mimetypes import MimeTypes
mime_type, encoding = MimeTypes().guess_type(image_path) mime_type, encoding = MimeTypes().guess_type(image_path)
self.set_header('Content-Type', mime_type) self.set_header('Content-Type', mime_type)
with file(image_path, 'rb') as img: with file(image_path, 'rb') as img:
@ -2934,7 +2936,8 @@ class NewHomeAddShows(MainHandler):
if not show_dir: if not show_dir:
t.default_show_name = '' t.default_show_name = ''
elif not show_name: elif not show_name:
t.default_show_name = re.sub(' \(\d{4}\)','', ek.ek(os.path.basename, ek.ek(os.path.normpath, show_dir)).replace('.', ' ')) t.default_show_name = re.sub(' \(\d{4}\)', '',
ek.ek(os.path.basename, ek.ek(os.path.normpath, show_dir)).replace('.', ' '))
else: else:
t.default_show_name = show_name t.default_show_name = show_name
@ -2969,16 +2972,22 @@ class NewHomeAddShows(MainHandler):
final_results = [] final_results = []
logger.log(u"Getting recommended shows from Trakt.tv", logger.DEBUG) logger.log(u"Getting recommended shows from Trakt.tv", logger.DEBUG)
recommendedlist = TraktCall("recommendations/shows.json/%API%", sickbeard.TRAKT_API, sickbeard.TRAKT_USERNAME,
sickbeard.TRAKT_PASSWORD)
if recommendedlist: trakt_api = TraktAPI(sickbeard.TRAKT_API, sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_USERNAME)
indexers = ['tvdb_id', 'tvrage_id']
map(final_results.append, ( try:
[int(show[indexers[sickbeard.TRAKT_DEFAULT_INDEXER - 1]]), show['url'], show['title'], show['overview'], recommendedlist = trakt_api.traktRequest("recommendations/shows.json/%APIKEY%")
datetime.date.fromtimestamp(int(show['first_aired']) / 1000.0).strftime('%Y%m%d')]
for show in recommendedlist if not helpers.findCertainShow(sickbeard.showList, [ if recommendedlist:
int(show[indexers[sickbeard.TRAKT_DEFAULT_INDEXER - 1]])]))) indexers = ['tvdb_id', 'tvrage_id']
map(final_results.append, (
[int(show[indexers[sickbeard.TRAKT_DEFAULT_INDEXER - 1]]), show['url'], show['title'],
show['overview'],
datetime.date.fromtimestamp(int(show['first_aired']) / 1000.0).strftime('%Y%m%d')]
for show in recommendedlist if not helpers.findCertainShow(sickbeard.showList, [
int(show[indexers[sickbeard.TRAKT_DEFAULT_INDEXER - 1]])])))
except (traktException, traktAuthException, traktServerBusy) as e:
logger.log(u"Could not connect to Trakt service: %s" % e.message, logger.ERROR)
return json.dumps({'results': final_results}) return json.dumps({'results': final_results})
@ -3009,14 +3018,20 @@ class NewHomeAddShows(MainHandler):
t.trending_shows = [] t.trending_shows = []
trending_shows = TraktCall("shows/trending.json/%API%", sickbeard.TRAKT_API_KEY) trakt_api = TraktAPI(sickbeard.TRAKT_API, sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_USERNAME)
if trending_shows:
for show in trending_shows: try:
try: trending_shows = trakt_api.traktRequest("shows/trending.json/%APIKEY%")
if not helpers.findCertainShow(sickbeard.showList, [int(show['tvdb_id']), int(show['tvrage_id'])]):
t.trending_shows += [show] if trending_shows:
except exceptions.MultipleShowObjectsException: for show in trending_shows:
continue try:
if not helpers.findCertainShow(sickbeard.showList, [int(show['tvdb_id']), int(show['tvrage_id'])]):
t.trending_shows += [show]
except exceptions.MultipleShowObjectsException:
continue
except (traktException, traktAuthException, traktServerBusy) as e:
logger.log(u"Could not connect to Trakt service: %s" % e.message, logger.ERROR)
return _munge(t) return _munge(t)