mirror of
https://github.com/SickGear/SickGear.git
synced 2024-11-15 01:15:05 +00:00
Add TVDb person search
fix handle tvdb error on browse tvdb page adjust for datetime import changes in webserve remove any references to sickgear in tvdb api libs replace deprecated old method_whitelist with allowed_methods
This commit is contained in:
parent
da9a6a829c
commit
b59084d27d
6 changed files with 108 additions and 57 deletions
|
@ -2,7 +2,7 @@
|
|||
#import re
|
||||
#import sickgear
|
||||
#from sickgear import TVInfoAPI
|
||||
#from sickgear.indexers.indexer_config import TVINFO_TMDB, TVINFO_TRAKT, TVINFO_TVMAZE
|
||||
#from sickgear.indexers.indexer_config import TVINFO_TMDB, TVINFO_TVDB, TVINFO_TRAKT, TVINFO_TVMAZE
|
||||
#from sickgear.helpers import anon_url
|
||||
#from sickgear.tv import PersonGenders
|
||||
#from sg_helpers import spoken_height
|
||||
|
@ -212,7 +212,7 @@ def param(visible=True, rid=None, cache_person=None, cache_char=None, person=Non
|
|||
</span>
|
||||
</div>
|
||||
#end if
|
||||
#set $src = (($TVINFO_TVMAZE, 'tvm'), ($TVINFO_TMDB, 'tmdb'), ($TVINFO_TRAKT, 'trakt'))
|
||||
#set $src = (($TVINFO_TVDB, 'tvdb'), ($TVINFO_TVMAZE, 'tvm'), ($TVINFO_TMDB, 'tmdb'), ($TVINFO_TRAKT, 'trakt'))
|
||||
#if any([$person.ids.get($cur_src) for ($cur_src, _) in $src])
|
||||
<div>
|
||||
<span class="details-title">Other shows</span>
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
|
||||
// Set initial text
|
||||
overviewEl.html('Fetching overview...');
|
||||
$.getJSON($.SickGear.Root + '/add-shows/tvm-get-showinfo', {
|
||||
$.getJSON($.SickGear.Root + '/add-shows/tvi-get-showinfo', {
|
||||
tvid_prodid: showcardEl.attr('data-id'),
|
||||
oldest_dt: $('#oldest').attr('data-oldest-dt'),
|
||||
newest_dt: $('#newest').attr('data-newest-dt'),
|
||||
|
|
|
@ -27,7 +27,6 @@ import warnings
|
|||
from bs4_parser import BS4Parser
|
||||
from collections import OrderedDict
|
||||
from sg_helpers import clean_data, get_url, try_int
|
||||
from sickgear import ENV
|
||||
|
||||
from lib.cachecontrol import CacheControl, caches
|
||||
from lib.dateutil.parser import parse
|
||||
|
@ -46,6 +45,8 @@ if False:
|
|||
from typing import Any, AnyStr, Dict, List, Optional, Union
|
||||
|
||||
|
||||
ENV = os.environ
|
||||
|
||||
THETVDB_V2_API_TOKEN = {'token': None, 'datetime': datetime.datetime.fromordinal(1)}
|
||||
log = logging.getLogger('tvdb.api')
|
||||
log.addHandler(logging.NullHandler())
|
||||
|
|
|
@ -9,6 +9,7 @@ __api_version__ = '1.0.0'
|
|||
import base64
|
||||
import datetime
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
|
||||
from bs4_parser import BS4Parser
|
||||
|
@ -29,13 +30,15 @@ from lib.tvinfo_base import (
|
|||
TVINFO_MID_SEASON_FINALE, TVINFO_SEASON_FINALE, TVINFO_SERIES_FINALE, TVINFO_TIKTOK, TVINFO_TMDB, TVINFO_TVDB,
|
||||
TVINFO_TVDB_SLUG, TVINFO_TVMAZE, TVINFO_TWITTER, TVINFO_WIKIDATA, TVINFO_WIKIPEDIA, TVINFO_YOUTUBE)
|
||||
from sg_helpers import clean_data, clean_str, enforce_type, get_url, try_date, try_int
|
||||
from sickgear import ENV
|
||||
|
||||
from six import integer_types, iteritems, PY3, string_types
|
||||
# noinspection PyUnreachableCode
|
||||
if False:
|
||||
from typing import Any, AnyStr, Dict, List, Optional, Tuple, Union
|
||||
|
||||
|
||||
ENV = os.environ
|
||||
|
||||
log = logging.getLogger('tvdb_v4.api')
|
||||
log.addHandler(logging.NullHandler())
|
||||
|
||||
|
@ -101,7 +104,10 @@ class TvdbAuth(RequestsAuthBase):
|
|||
@property
|
||||
def token(self):
|
||||
if not self._token:
|
||||
self.get_token()
|
||||
try:
|
||||
self.get_token()
|
||||
except TvdbTokenFailure as e:
|
||||
log.error(f'Tvdb Taken Failure: {e}')
|
||||
return self._token
|
||||
|
||||
def handle_401(self, r, **kwargs):
|
||||
|
@ -146,7 +152,7 @@ s = requests.Session()
|
|||
retries = Retry(total=3,
|
||||
backoff_factor=1,
|
||||
status_forcelist=[429, 500, 502, 503, 504],
|
||||
method_whitelist=['HEAD', 'GET', 'PUT', 'DELETE', 'OPTIONS', 'TRACE', 'POST'])
|
||||
allowed_methods=['HEAD', 'GET', 'PUT', 'DELETE', 'OPTIONS', 'TRACE', 'POST'])
|
||||
# noinspection HttpUrlsUsage
|
||||
s.mount('http://', HTTPAdapter(TimeoutHTTPAdapter(max_retries=retries)))
|
||||
s.mount('https://', HTTPAdapter(TimeoutHTTPAdapter(max_retries=retries)))
|
||||
|
@ -280,12 +286,13 @@ class TvdbAPIv4(TVInfoBase):
|
|||
if f'?page={page}' in ((resp.get('links') or {}).get('next') or ''):
|
||||
return page
|
||||
|
||||
def _convert_person(self, p, ids=None):
|
||||
# type: (Dict, Dict) -> List[TVInfoPerson]
|
||||
def _convert_person(self, p, ids=None, include_guests=False):
|
||||
# type: (Dict, Dict, bool) -> List[TVInfoPerson]
|
||||
ch, ids = [], ids or {}
|
||||
p_types = ([3], [3, 4])[include_guests]
|
||||
for cur_c in sorted(filter(
|
||||
lambda a: (3 == a['type'] or 'Actor' == a['peopleType'])
|
||||
and a['name'] and a['seriesId'] and not a.get('episodeId'),
|
||||
lambda a: (a['type'] in p_types or 'Actor' == a['peopleType'])
|
||||
and a['seriesId'] and ((not a.get('episodeId') and a['name']) or include_guests),
|
||||
p.get('characters') or []),
|
||||
key=lambda a: (not a['isFeatured'], a['sort'])):
|
||||
ti_show = TVInfoShow()
|
||||
|
@ -392,8 +399,8 @@ class TvdbAPIv4(TVInfoBase):
|
|||
resp = None
|
||||
return resp
|
||||
|
||||
def get_person(self, p_id, get_show_credits=False, get_images=False, try_cache=True, **kwargs):
|
||||
# type: (integer_types, bool, bool, bool, ...) -> Optional[TVInfoPerson]
|
||||
def get_person(self, p_id, get_show_credits=False, get_images=False, try_cache=True, include_guests=False, **kwargs):
|
||||
# type: (integer_types, bool, bool, bool, bool, ...) -> Optional[TVInfoPerson]
|
||||
"""
|
||||
get person's data for id or list of matching persons for name
|
||||
|
||||
|
@ -401,12 +408,13 @@ class TvdbAPIv4(TVInfoBase):
|
|||
:param get_show_credits: get show credits
|
||||
:param get_images: get person images
|
||||
:param try_cache: use cached data if available
|
||||
:param include_guests: include guest roles
|
||||
:return: person object or None
|
||||
"""
|
||||
if bool(p_id) and self._check_resp(dict, resp := self.get_cached_or_url(
|
||||
f'/people/{p_id}/extended',
|
||||
f'p-v4-{p_id}', try_cache=try_cache)):
|
||||
return self._convert_person(resp['data'])[0]
|
||||
return self._convert_person(resp['data'], include_guests=include_guests)[0]
|
||||
|
||||
def _search_person(self, name=None, ids=None):
|
||||
# type: (AnyStr, Dict[integer_types, integer_types]) -> List[TVInfoPerson]
|
||||
|
|
|
@ -1195,14 +1195,15 @@ class TVInfoBase(object):
|
|||
except (BaseException, Exception) as e:
|
||||
log.error('Error setting %s to cache: %s' % (key, ex(e)))
|
||||
|
||||
def get_person(self, p_id, get_show_credits=False, get_images=False, **kwargs):
|
||||
# type: (integer_types, bool, bool, Any) -> Optional[TVInfoPerson]
|
||||
def get_person(self, p_id, get_show_credits=False, get_images=False, include_guests=False, **kwargs):
|
||||
# type: (integer_types, bool, bool, bool, Any) -> Optional[TVInfoPerson]
|
||||
"""
|
||||
get person's data for id or list of matching persons for name
|
||||
|
||||
:param p_id: persons id
|
||||
:param get_show_credits: get show credits
|
||||
:param get_images: get person images
|
||||
:param include_guests: include guest roles
|
||||
:return: person object
|
||||
"""
|
||||
pass
|
||||
|
|
|
@ -96,6 +96,7 @@ from lib.api_trakt import TraktAPI
|
|||
from lib.api_trakt.exceptions import TraktException, TraktAuthException
|
||||
from lib.tvinfo_base import TVInfoEpisode, RoleTypes
|
||||
from lib.tvinfo_base.base import tv_src_names
|
||||
from lib.tvinfo_base.exceptions import *
|
||||
|
||||
import lib.rarfile.rarfile as rarfile
|
||||
|
||||
|
@ -6039,7 +6040,7 @@ class AddShows(Home):
|
|||
|
||||
def tvdb_default(self):
|
||||
method = getattr(self, sickgear.TVDB_MRU, None)
|
||||
if not callable(method):
|
||||
if not callable(method) or not self.allow_browse_mru(sickgear.TVDB_MRU):
|
||||
return self.tvdb_upcoming()
|
||||
return method()
|
||||
|
||||
|
@ -6051,6 +6052,10 @@ class AddShows(Home):
|
|||
return self.browse_tvdb(
|
||||
'Top rated at TVDb', mode='toprated', **kwargs)
|
||||
|
||||
def tvdb_person(self, person_tvdb_id=None, **kwargs):
|
||||
return self.browse_tvdb(
|
||||
'Person at TVDb', mode='person', p_id=person_tvdb_id, **kwargs)
|
||||
|
||||
def browse_tvdb(self, browse_title, **kwargs):
|
||||
|
||||
browse_type = 'TVDb'
|
||||
|
@ -6058,20 +6063,41 @@ class AddShows(Home):
|
|||
|
||||
footnote = None
|
||||
filtered = []
|
||||
p_ref = None
|
||||
overview_ajax = 'person' == mode
|
||||
|
||||
tvid = TVINFO_TVDB
|
||||
tvinfo_config = sickgear.TVInfoAPI(tvid).api_params.copy()
|
||||
t = sickgear.TVInfoAPI(tvid).setup(**tvinfo_config) # type: Union[TvdbIndexer, TVInfoBase]
|
||||
|
||||
top_year = helpers.try_int(kwargs.get('year'), None)
|
||||
if 'upcoming' == mode:
|
||||
items = t.discover()
|
||||
else:
|
||||
items = t.get_top_rated(year=top_year,
|
||||
in_last_year=1 == datetime.date.today().month and 7 > datetime.date.today().day)
|
||||
try:
|
||||
if 'upcoming' == mode:
|
||||
items = t.discover()
|
||||
elif 'person' == mode:
|
||||
items = []
|
||||
p_item = t.get_person(get_show_credits=True, include_guests=True, **kwargs) # type: TVInfoPerson
|
||||
if p_item:
|
||||
p_ref = f'{TVINFO_TVDB}:{p_item.id}'
|
||||
dup = {} # type: Dict[int, TVInfoShow]
|
||||
for c in p_item.characters: # type: TVInfoCharacter
|
||||
c.ti_show.cast[(RoleTypes.ActorGuest, RoleTypes.ActorMain)[True is c.regular]].append(c)
|
||||
if c.ti_show.id not in dup:
|
||||
dup[c.ti_show.id] = c.ti_show
|
||||
items.append(c.ti_show)
|
||||
else:
|
||||
dup[c.ti_show.id].cast[RoleTypes.ActorMain].extend(c.ti_show.cast[RoleTypes.ActorMain])
|
||||
dup[c.ti_show.id].cast[RoleTypes.ActorGuest].extend(c.ti_show.cast[RoleTypes.ActorGuest])
|
||||
del dup
|
||||
else:
|
||||
p_item = None
|
||||
else:
|
||||
items = t.get_top_rated(year=top_year, in_last_year=1 == dt_date.today().month and 7 > dt_date.today().day)
|
||||
except (BaseTVinfoError, BaseException, Exception) as e:
|
||||
return self.browse_shows(browse_type, browse_title, filtered, **kwargs)
|
||||
|
||||
ranking = dict((val, idx+1) for idx, val in
|
||||
enumerate(sorted([cur_show_info.rating for cur_show_info in items], reverse=True)))
|
||||
enumerate(sorted([cur_show_info.rating or 0 for cur_show_info in items], reverse=True)))
|
||||
oldest, newest, oldest_dt, newest_dt, dedupe = None, None, 9999999, 0, []
|
||||
use_networks = False
|
||||
parseinfo = dateutil.parser.parserinfo(dayfirst=False, yearfirst=True)
|
||||
|
@ -6085,7 +6111,7 @@ class AddShows(Home):
|
|||
airtime = cur_show_info.airs_time
|
||||
if not airtime or (0, 0) == (airtime.hour, airtime.minute):
|
||||
airtime = dateutil.parser.parse('23:59').time()
|
||||
dt = datetime.datetime.combine(
|
||||
dt = datetime.combine(
|
||||
dateutil.parser.parse(cur_show_info.firstaired, parseinfo).date(), airtime)
|
||||
ord_premiered, str_premiered, started_past, oldest_dt, newest_dt, oldest, newest, _, _, _, _ \
|
||||
= self.sanitise_dates(dt, oldest_dt, newest_dt, oldest, newest)
|
||||
|
@ -6118,6 +6144,7 @@ class AddShows(Home):
|
|||
ids=ids,
|
||||
images=images,
|
||||
overview=self.clean_overview(cur_show_info),
|
||||
overview_ajax=(0, 1)[overview_ajax],
|
||||
title=cur_show_info.seriesname,
|
||||
language=language,
|
||||
language_img=sickgear.MEMCACHE_FLAG_IMAGES.get(language, False),
|
||||
|
@ -6129,11 +6156,17 @@ class AddShows(Home):
|
|||
votes=cur_show_info.rating or 0,
|
||||
rank=cur_show_info.rating and ranking.get(cur_show_info.rating) or 0,
|
||||
))
|
||||
if p_ref:
|
||||
filtered[-1].update(dict(
|
||||
p_name=p_item.name or None,
|
||||
p_ref=p_ref,
|
||||
p_chars=self._make_char_person_list(cur_show_info)
|
||||
))
|
||||
except (BaseException, Exception):
|
||||
pass
|
||||
kwargs.update(dict(oldest=oldest, newest=newest, use_ratings=False, term_vote='Score'))
|
||||
kwargs.update(dict(oldest=oldest, newest=newest, oldest_dt=oldest_dt, newest_dt=newest_dt, use_ratings=False, term_vote='Score'))
|
||||
|
||||
this_year = datetime.date.today().year
|
||||
this_year = dt_date.today().year
|
||||
years = [
|
||||
(this_year - cur_y,
|
||||
'tvdb_toprated?year=%s' % (this_year - cur_y),
|
||||
|
@ -6141,7 +6174,7 @@ class AddShows(Home):
|
|||
for cur_y in range(0, 10)]
|
||||
kwargs.update(dict(footnote=footnote, use_networks=use_networks, year=top_year or '', rate_years=years))
|
||||
|
||||
if mode:
|
||||
if mode and self.allow_browse_mru(mode):
|
||||
func = 'tvdb_%s' % mode
|
||||
if callable(getattr(self, func, None)):
|
||||
sickgear.TVDB_MRU = func
|
||||
|
@ -6183,37 +6216,45 @@ class AddShows(Home):
|
|||
return result.replace('.....', '...')
|
||||
return 'No overview yet'
|
||||
|
||||
def tvm_get_showinfo(self, tvid_prodid=None, oldest_dt=9999999, newest_dt=0):
|
||||
def tvi_get_showinfo(self, tvid_prodid=None, oldest_dt=9999999, newest_dt=0):
|
||||
result = {}
|
||||
if 'tvmaze' in tvid_prodid:
|
||||
tvid = TVINFO_TVMAZE
|
||||
tvinfo_config = sickgear.TVInfoAPI(tvid).api_params.copy()
|
||||
t = sickgear.TVInfoAPI(tvid).setup(**tvinfo_config) # type: Union[TvmazeIndexer, TVInfoBase]
|
||||
show_info = t.get_show(int(tvid_prodid.replace('tvmaze:','')), load_episodes=False)
|
||||
if isinstance(tvid_prodid, str):
|
||||
if tvid_prodid.startswith('tvmaze'):
|
||||
tvid = TVINFO_TVMAZE
|
||||
prod_id = int(tvid_prodid.replace('tvmaze:',''))
|
||||
elif tvid_prodid.startswith('tvdb'):
|
||||
tvid = TVINFO_TVDB
|
||||
prod_id = int(tvid_prodid.replace('tvdb:', ''))
|
||||
else:
|
||||
tvid = None
|
||||
if tvid:
|
||||
tvinfo_config = sickgear.TVInfoAPI(tvid).api_params.copy()
|
||||
t = sickgear.TVInfoAPI(tvid).setup(**tvinfo_config) # type: Union[TvmazeIndexer, TVInfoBase]
|
||||
show_info = t.get_show(prod_id, load_episodes=False)
|
||||
|
||||
oldest_dt, newest_dt = int(oldest_dt), int(newest_dt)
|
||||
ord_premiered, str_premiered, started_past, old_dt, new_dt, oldest, newest, \
|
||||
ok_returning, ord_returning, str_returning, return_past \
|
||||
= self.sanitise_dates(show_info.firstaired, oldest_dt, newest_dt, None, None)
|
||||
result = dict(
|
||||
ord_premiered=ord_premiered,
|
||||
str_premiered=str_premiered,
|
||||
#ord_returning=ord_returning,
|
||||
#str_returning=str_returning,
|
||||
started_past=started_past,
|
||||
#return_past=return_past,
|
||||
genres=((show_info.genre or '')
|
||||
or ', '.join(show_info.genre_list)
|
||||
or ', '.join(show_info.show_type) or '').strip('|').replace('|', ', ').lower(),
|
||||
overview=self.clean_overview(show_info),
|
||||
network=show_info.network or ', '.join(show_info.networks) or '',
|
||||
)
|
||||
if old_dt < oldest_dt:
|
||||
result['oldest_dt'] = old_dt
|
||||
result['oldest'] = oldest
|
||||
elif new_dt > newest_dt:
|
||||
result['newest_dt'] = old_dt
|
||||
result['newest'] = newest,
|
||||
oldest_dt, newest_dt = int(oldest_dt), int(newest_dt)
|
||||
ord_premiered, str_premiered, started_past, old_dt, new_dt, oldest, newest, \
|
||||
ok_returning, ord_returning, str_returning, return_past \
|
||||
= self.sanitise_dates(show_info.firstaired, oldest_dt, newest_dt, None, None)
|
||||
result = dict(
|
||||
ord_premiered=ord_premiered,
|
||||
str_premiered=str_premiered,
|
||||
#ord_returning=ord_returning,
|
||||
#str_returning=str_returning,
|
||||
started_past=started_past,
|
||||
#return_past=return_past,
|
||||
genres=((show_info.genre or '')
|
||||
or ', '.join(show_info.genre_list)
|
||||
or ', '.join(show_info.show_type) or '').strip('|').replace('|', ', ').lower(),
|
||||
overview=self.clean_overview(show_info),
|
||||
network=show_info.network or ', '.join(show_info.networks) or '',
|
||||
)
|
||||
if old_dt < oldest_dt:
|
||||
result['oldest_dt'] = old_dt
|
||||
result['oldest'] = oldest
|
||||
elif new_dt > newest_dt:
|
||||
result['newest_dt'] = old_dt
|
||||
result['newest'] = newest,
|
||||
|
||||
return json_dumps(result)
|
||||
|
||||
|
@ -6352,7 +6393,7 @@ class AddShows(Home):
|
|||
|
||||
@staticmethod
|
||||
def sanitise_dates(date, oldest_dt, newest_dt, oldest, newest, episode_info=None, combine_ep_airtime=False):
|
||||
# in case of person search (tvmaze) guest starring entires have only show name/id, no dates
|
||||
# in case of person search (tvmaze) guest starring entries have only show name/id, no dates
|
||||
if None is date:
|
||||
return 9, '', True, oldest_dt, newest_dt, oldest, newest, True, 9, 'TBC', False
|
||||
parseinfo = dateutil.parser.parserinfo(dayfirst=False, yearfirst=True)
|
||||
|
|
Loading…
Reference in a new issue