SickGear/lib/libtrakt/indexerapiinterface.py
Prinz23 07d72e05f1 Add Fuzzywuzzy lib to sort search results.
Change remove search results filtering from tv info source.
Change suppress startup warnings for Fuzzywuzzy and Cheetah libs.
Change show name aliases get a score -1 to give the main names priority.
Change replace findCertainShow with find_show_by_id for mapped multi-indexer.
Change add Trakt info source search interface.
Change directly send image after it's been cached.
Fix loading CachedImages images with TVDB API v2 changes.
2017-09-04 01:23:30 +01:00

177 lines
6 KiB
Python

import logging
import re
import time
from .exceptions import TraktShowNotFound, TraktException
from sickbeard.exceptions import ex
from trakt import TraktAPI
class ShowContainer(dict):
"""Simple dict that holds a series of Show instances
"""
def __init__(self, **kwargs):
super(ShowContainer, self).__init__(**kwargs)
self._stack = []
self._lastgc = time.time()
def __setitem__(self, key, value):
self._stack.append(key)
# keep only the 100th latest results
if time.time() - self._lastgc > 20:
for o in self._stack[:-100]:
del self[o]
self._stack = self._stack[-100:]
self._lastgc = time.time()
super(ShowContainer, self).__setitem__(key, value)
def log():
return logging.getLogger('trakt_api')
class TraktSearchTypes:
text = 1
trakt_id = 'trakt'
tvdb_id = 'tvdb'
imdb_id = 'imdb'
tmdb_id = 'tmdb'
tvrage_id = 'tvrage'
all = [text, trakt_id, tvdb_id, imdb_id, tmdb_id, tvrage_id]
def __init__(self):
pass
class TraktResultTypes:
show = 'show'
episode = 'episode'
movie = 'movie'
person = 'person'
list = 'list'
all = [show, episode, movie, person, list]
def __init__(self):
pass
class TraktIndexer:
# noinspection PyUnusedLocal
# noinspection PyDefaultArgument
def __init__(self, custom_ui=None, sleep_retry=None, search_type=TraktSearchTypes.text,
result_types=[TraktResultTypes.show], *args, **kwargs):
self.config = {
'apikey': '',
'debug_enabled': False,
'custom_ui': custom_ui,
'proxy': None,
'cache_enabled': False,
'cache_location': '',
'valid_languages': [],
'langabbv_to_id': {},
'language': 'en',
'base_url': '',
'search_type': search_type if search_type in TraktSearchTypes.all else TraktSearchTypes.text,
'sleep_retry': sleep_retry,
'result_types': result_types if isinstance(result_types, list) and all(x in TraktResultTypes.all for x in result_types) else [TraktResultTypes.show],
}
self.corrections = {}
self.shows = ShowContainer()
def _get_series(self, series):
"""This searches Trakt for the series name,
If a custom_ui UI is configured, it uses this to select the correct
series.
"""
all_series = self.search(series)
if not isinstance(all_series, list):
all_series = [all_series]
if 0 == len(all_series):
log().debug('Series result returned zero')
raise TraktShowNotFound('Show-name search returned zero results (cannot find show on TVDB)')
if None is not self.config['custom_ui']:
log().debug('Using custom UI %s' % (repr(self.config['custom_ui'])))
custom_ui = self.config['custom_ui']
ui = custom_ui(config=self.config)
return ui.select_series(all_series)
return all_series
def __getitem__(self, key):
"""Handles trakt_instance['seriesname'] calls.
The dict index should be the show id
"""
if isinstance(key, tuple) and 2 == len(key):
key = key[0]
self.config['searchterm'] = key
selected_series = self._get_series(key)
if isinstance(selected_series, dict):
selected_series = [selected_series]
return selected_series
def __repr__(self):
return str(self.shows)
def _clean_data(self, data):
"""Cleans up strings, lists, dicts returned
Issues corrected:
- Replaces & with &
- Trailing whitespace
"""
if isinstance(data, list):
return [self._clean_data(d) for d in data]
if isinstance(data, dict):
return {k: self._clean_data(v) for k, v in data.iteritems()}
return data if not isinstance(data, (str, unicode)) else data.strip().replace(u'&', u'&')
@staticmethod
def _dict_prevent_none(d, key, default):
v = None
if isinstance(d, dict):
v = d.get(key, default)
return (v, default)[None is v]
def search(self, series):
if TraktSearchTypes.text != self.config['search_type']:
url = '/search/%s/%s?type=%s&extended=full&limit=100' % (self.config['search_type'], series,
','.join(self.config['result_types']))
else:
url = '/search/%s?query=%s&extended=full&limit=100' % (','.join(self.config['result_types']), series)
filtered = []
kwargs = {}
if None is not self.config['sleep_retry']:
kwargs['sleep_retry'] = self.config['sleep_retry']
try:
resp = TraktAPI().trakt_request(url, **kwargs)
if len(resp):
for d in resp:
if isinstance(d, dict) and 'type' in d and d['type'] in self.config['result_types']:
for k, v in d.iteritems():
d[k] = self._clean_data(v)
if 'show' in d and TraktResultTypes.show == d['type']:
d.update(d['show'])
del d['show']
d['seriesname'] = self._dict_prevent_none(d, 'title', '')
d['genres_list'] = d.get('genres', [])
d['genres'] = ', '.join(['%s' % v for v in d.get('genres', []) or [] if v])
d['firstaired'] = (d.get('first_aired') and
re.sub(r'T.*$', '', str(d.get('first_aired'))) or d.get('year'))
filtered.append(d)
except TraktException as e:
log().debug('Could not connect to Trakt service: %s' % ex(e))
return filtered