Add try to retrieve TVmaze id for persons

Fix person image scaler
Change make a unified generator for the p_chars var in persons search
Change add plays_self to TMDB, TVmaze, Trakt
Fix TMDb person search page for shows without first aired date (future shows for example)
Add also display guest appearances in TVmaze person search
Add parsing of vote_average / rating for main cast
Add genres to person show data
Fix, auto close qTip if mouse is over nav menu
Change add rating, vote_average, vote_count, popularity to TMDB person characters shows
Change TVmaze character name TBA|D to ''
Change add person gender to Trakt
This commit is contained in:
Prinz23 2024-06-17 03:32:37 +01:00 committed by JackDandy
parent 31f5b3ea23
commit 4e52d2da08
8 changed files with 119 additions and 33 deletions

View file

@ -50,6 +50,8 @@
$.ll.handleScroll(); $.ll.handleScroll();
}); });
$('.nav').on('mouseover', function() {$('.service, .browse-image').qtip('hide')})
savePrefs = (function(){ savePrefs = (function(){
var showsort = [], showfilter = []; var showsort = [], showfilter = [];
@ -294,11 +296,8 @@ $(function() {
objectFitImages(); objectFitImages();
$('#content').find('img.browse-image').each(function(i, oImage){ $('#person .person-bg').each(function(i, oImage){
removeImageBackground(oImage); removeImageBackground(oImage);
});
$('#content').find('img.browse-image').each(function (i, oImage){
scaleImage(oImage); scaleImage(oImage);
}); });
}); });
@ -310,6 +309,9 @@ $(function() {
<style> <style>
#set theme_suffix = ('', '-dark')['dark' == $getVar('sbThemeName', THEME_NAME)] #set theme_suffix = ('', '-dark')['dark' == $getVar('sbThemeName', THEME_NAME)]
.bfr{position:absolute;left:-999px;top:-999px}.bfr img{width:16px;height:16px}.spinner{display:inline-block;width:16px;height:16px;background:url(${sg_root}/images/loading16${theme_suffix}.gif) no-repeat 0 0} .bfr{position:absolute;left:-999px;top:-999px}.bfr img{width:16px;height:16px}.spinner{display:inline-block;width:16px;height:16px;background:url(${sg_root}/images/loading16${theme_suffix}.gif) no-repeat 0 0}
#person{height:300px;width:215px;display:block;}
.main-image{float:left;margin:0 20px 20px 0; }
.person-bg{height:300px;width:215px;display:block; background-color:#181818 !important; border:1px solid #181818; object-fit: contain; font-family: 'object-fit: contain;'; -moz-border-radius:10px; -webkit-border-radius:10px; border-radius:10px; margin:0 auto; background:url(/images/poster-person.jpg) center center no-repeat}
</style> </style>
<div class="bfr"><img src="$sg_root/images/loading16${theme_suffix}.gif" /></div> <div class="bfr"><img src="$sg_root/images/loading16${theme_suffix}.gif" /></div>
@ -486,8 +488,10 @@ $(function() {
#end if #end if
#if $p_ref #if $p_ref
<div class="browse-image" style="margin: 10px 2px 30px; border-radius: 5px"> <div id="person">
<a class="browse-image" href="$sbRoot/imagecache/person?pid=$p_ref&thumb=1" rel="dialog"><img class="browse-image" src="$sbRoot/imagecache/person?pid=$p_ref&thumb=0"></a> <div id="person-content" class="main-image">
<a class="thumb" href="$sbRoot/imagecache/person?pid=$p_ref&thumb=1" rel="dialog"><img class="person-bg" src="$sbRoot/imagecache/person?pid=$p_ref&thumb=0"></a>
</div>
</div> </div>
#end if #end if
#end if #end if

View file

@ -310,8 +310,9 @@ class TmdbIndexer(TVInfoBase):
self.img_base_url, self.size_map[TVInfoImageType.person_poster][TVInfoImageSize.medium], self.img_base_url, self.size_map[TVInfoImageType.person_poster][TVInfoImageSize.medium],
tmdb_person_obj['profile_path']) tmdb_person_obj['profile_path'])
clean_person_name = clean_data(tmdb_person_obj.get('name'))
_it_person_obj = TVInfoPerson( _it_person_obj = TVInfoPerson(
p_id=tmdb_person_obj.get('id'), ids=TVInfoIDs(ids=person_ids), name=clean_data(tmdb_person_obj.get('name')), p_id=tmdb_person_obj.get('id'), ids=TVInfoIDs(ids=person_ids), name=clean_person_name,
akas=clean_data(set(tmdb_person_obj.get('also_known_as') or [])), akas=clean_data(set(tmdb_person_obj.get('also_known_as') or [])),
bio=clean_data(tmdb_person_obj.get('biography')), gender=gender, bio=clean_data(tmdb_person_obj.get('biography')), gender=gender,
image=main_image, images=image_list, thumb_url=main_thumb, image=main_image, images=image_list, thumb_url=main_thumb,
@ -331,6 +332,10 @@ class TmdbIndexer(TVInfoBase):
ti_show.overview = self._enforce_text(character.get('overview')) ti_show.overview = self._enforce_text(character.get('overview'))
ti_show.firstaired = clean_data(character.get('first_air_date')) ti_show.firstaired = clean_data(character.get('first_air_date'))
ti_show.language = clean_data(character.get('original_language')) ti_show.language = clean_data(character.get('original_language'))
ti_show.popularity = character.get('popularity')
ti_show.vote_count = character.get('vote_count')
ti_show.vote_average = character.get('vote_average')
ti_show.rating = ti_show.vote_average
ti_show.genre_list = [] ti_show.genre_list = []
for g in character.get('genre_ids') or []: for g in character.get('genre_ids') or []:
if g in self.tv_genres: if g in self.tv_genres:
@ -350,9 +355,13 @@ class TmdbIndexer(TVInfoBase):
(self.img_base_url, (self.img_base_url,
self.size_map[TVInfoImageType.person_poster][TVInfoImageSize.original], self.size_map[TVInfoImageType.person_poster][TVInfoImageSize.original],
character['backdrop_path']) character['backdrop_path'])
clean_char_name = clean_data(character.get('character'))
clean_lower_person_name = (clean_person_name or '').lower() or None
characters.append( characters.append(
TVInfoCharacter(name=clean_data(character.get('character')), ti_show=ti_show, person=[_it_person_obj], TVInfoCharacter(name=clean_char_name, ti_show=ti_show, person=[_it_person_obj],
episode_count=character.get('episode_count')) episode_count=character.get('episode_count'),
plays_self=clean_char_name and
(clean_char_name or '').lower() in ('self', clean_lower_person_name))
) )
_it_person_obj.characters = characters _it_person_obj.characters = characters
@ -754,11 +763,16 @@ class TmdbIndexer(TVInfoBase):
for character in sorted(list(filter(lambda b: b['credit_id'] in main_cast_credit_ids, for character in sorted(list(filter(lambda b: b['credit_id'] in main_cast_credit_ids,
person_obj.get('roles', []) or [])), person_obj.get('roles', []) or [])),
key=lambda c: c['episode_count'], reverse=True): key=lambda c: c['episode_count'], reverse=True):
clean_char_name = clean_data(character['character'])
clean_person_name = clean_data(person_obj['name'])
clean_lower_person_name = (clean_person_name or '').lower() or None
character_obj = TVInfoCharacter( character_obj = TVInfoCharacter(
name=clean_data(character['character']), name=clean_char_name,
plays_self=clean_char_name and
(clean_char_name or '').lower() in ('self', clean_lower_person_name),
person=[ person=[
TVInfoPerson( TVInfoPerson(
p_id=person_obj['id'], name=clean_data(person_obj['name']), p_id=person_obj['id'], name=clean_person_name,
ids=TVInfoIDs(ids={TVINFO_TMDB: person_obj['id']}), ids=TVInfoIDs(ids={TVINFO_TMDB: person_obj['id']}),
image='%s%s%s' % ( image='%s%s%s' % (
self.img_base_url, self.img_base_url,

View file

@ -6,7 +6,7 @@ from exceptions_helper import ConnectionSkipException, ex
from six import iteritems from six import iteritems
from .trakt import TraktAPI from .trakt import TraktAPI
from lib.tvinfo_base.exceptions import BaseTVinfoShownotfound from lib.tvinfo_base.exceptions import BaseTVinfoShownotfound
from lib.tvinfo_base import TVInfoBase, TVINFO_TRAKT, TVINFO_TMDB, TVINFO_TVDB, TVINFO_TVRAGE, TVINFO_IMDB, \ from lib.tvinfo_base import PersonGenders, TVInfoBase, TVINFO_TRAKT, TVINFO_TMDB, TVINFO_TVDB, TVINFO_TVRAGE, TVINFO_IMDB, \
TVINFO_SLUG, TVInfoPerson, TVINFO_TWITTER, TVINFO_FACEBOOK, TVINFO_WIKIPEDIA, TVINFO_INSTAGRAM, TVInfoCharacter, \ TVINFO_SLUG, TVInfoPerson, TVINFO_TWITTER, TVINFO_FACEBOOK, TVINFO_WIKIPEDIA, TVINFO_INSTAGRAM, TVInfoCharacter, \
TVInfoShow, TVInfoIDs, TVInfoSocialIDs, TVINFO_TRAKT_SLUG, TVInfoEpisode, TVInfoSeason, RoleTypes TVInfoShow, TVInfoIDs, TVInfoSocialIDs, TVINFO_TRAKT_SLUG, TVInfoEpisode, TVInfoSeason, RoleTypes
from sg_helpers import clean_data, enforce_type, try_int from sg_helpers import clean_data, enforce_type, try_int
@ -262,6 +262,7 @@ class TraktIndexer(TVInfoBase):
deathdate=deathdate, deathdate=deathdate,
homepage=person_obj['homepage'], homepage=person_obj['homepage'],
birthplace=person_obj['birthplace'], birthplace=person_obj['birthplace'],
gender=PersonGenders.trakt_map.get(person_obj['gender'], PersonGenders.unknown),
social_ids=TVInfoSocialIDs( social_ids=TVInfoSocialIDs(
ids={TVINFO_TWITTER: person_obj['social_ids']['twitter'], ids={TVINFO_TWITTER: person_obj['social_ids']['twitter'],
TVINFO_FACEBOOK: person_obj['social_ids']['facebook'], TVINFO_FACEBOOK: person_obj['social_ids']['facebook'],
@ -308,6 +309,7 @@ class TraktIndexer(TVInfoBase):
if resp: if resp:
if show_credits: if show_credits:
pc = [] pc = []
clean_lower_person_name = (result.name or '').lower()
for c in resp.get('cast') or []: for c in resp.get('cast') or []:
ti_show = TVInfoShow() ti_show = TVInfoShow()
ti_show.id = c['show']['ids'].get('trakt') ti_show.id = c['show']['ids'].get('trakt')
@ -327,9 +329,11 @@ class TraktIndexer(TVInfoBase):
ti_show.rating = c['show'].get('rating') ti_show.rating = c['show'].get('rating')
ti_show.vote_count = c['show'].get('votes') ti_show.vote_count = c['show'].get('votes')
for ch in c.get('characters') or []: for ch in c.get('characters') or []:
_ti_character = TVInfoCharacter(name=ch, regular=c.get('series_regular'), clean_ch = clean_data(ch)
ti_show=ti_show, person=[result], _ti_character = TVInfoCharacter(
episode_count=c.get('episode_count')) name=clean_ch, regular=c.get('series_regular'), ti_show=ti_show, person=[result],
episode_count=c.get('episode_count'),
plays_self=(clean_ch or '').lower() in ('self', clean_lower_person_name))
pc.append(_ti_character) pc.append(_ti_character)
ti_show.cast[(RoleTypes.ActorGuest, RoleTypes.ActorMain)[ ti_show.cast[(RoleTypes.ActorGuest, RoleTypes.ActorMain)[
c.get('series_regular', False)]].append(_ti_character) c.get('series_regular', False)]].append(_ti_character)

View file

@ -57,6 +57,8 @@ empty_ep = TVInfoEpisode()
empty_se = TVInfoSeason() empty_se = TVInfoSeason()
tz_p = parser() tz_p = parser()
character_clean_regex = re.compile(r'^tb(a|d)$', flags=re.I)
img_type_map = { img_type_map = {
'poster': TVInfoImageType.poster, 'poster': TVInfoImageType.poster,
'banner': TVInfoImageType.banner, 'banner': TVInfoImageType.banner,
@ -397,6 +399,14 @@ class TvMaze(TVInfoBase):
# type: (...) -> Dict[integer_types, integer_types] # type: (...) -> Dict[integer_types, integer_types]
return {sid: v.seconds_since_epoch for sid, v in iteritems(tvmaze.show_updates().updates)} return {sid: v.seconds_since_epoch for sid, v in iteritems(tvmaze.show_updates().updates)}
@staticmethod
def _clean_character_name(name):
# type: (Optional[str]) -> str
name = clean_data(name)
if isinstance(name, str):
return enforce_type(character_clean_regex.sub('', name), str, '')
return enforce_type(name, str, '')
def _convert_person(self, tvmaze_person_obj, load_credits=True): def _convert_person(self, tvmaze_person_obj, load_credits=True):
# type: (tvmaze.Person, bool) -> TVInfoPerson # type: (tvmaze.Person, bool) -> TVInfoPerson
ch = [] ch = []
@ -410,7 +420,11 @@ class TvMaze(TVInfoBase):
ti_show.ids = TVInfoIDs(ids={TVINFO_TVMAZE: ti_show.id}) ti_show.ids = TVInfoIDs(ids={TVINFO_TVMAZE: ti_show.id})
ti_show.overview = clean_data(c.show.summary) ti_show.overview = clean_data(c.show.summary)
ti_show.status = clean_data(c.show.status) ti_show.status = clean_data(c.show.status)
ti_show.vote_average = clean_data((c.show.rating and c.show.rating.get('average'))) or None
ti_show.rating = ti_show.vote_average
net = c.show.network or c.show.web_channel net = c.show.network or c.show.web_channel
ti_show.genre_list = clean_data(c.show.genres or [])
ti_show.genre = '|'.join(ti_show.genre_list or [])
if net: if net:
ti_show.network = clean_data(net.name) ti_show.network = clean_data(net.name)
ti_show.network_id = net.maze_id ti_show.network_id = net.maze_id
@ -418,7 +432,18 @@ class TvMaze(TVInfoBase):
ti_show.network_country_code = clean_data(net.code) ti_show.network_country_code = clean_data(net.code)
ti_show.network_timezone = clean_data(net.timezone) ti_show.network_timezone = clean_data(net.timezone)
ti_show.network_is_stream = None is not c.show.web_channel ti_show.network_is_stream = None is not c.show.web_channel
ch.append(TVInfoCharacter(name=clean_data(c.character.name), ti_show=ti_show, episode_count=1)) _images = None
if c.character.image and all(i_s in c.character.image and c.character.image[i_s]
for i_s in ('original', 'medium')):
_images = [TVInfoImage(TVInfoImageType.poster,
sizes={TVInfoImageSize.original: c.character.image['original'],
TVInfoImageSize.medium: c.character.image['medium']})]
ch.append(TVInfoCharacter(name=self._clean_character_name(c.character.name),
ti_show=ti_show, episode_count=1, plays_self=c.character.plays_self,
voice=c.character.voice,
image= c.character.image and c.character.image.get('original'),
thumb_url= c.character.image and c.character.image.get('medium'),
p_id=c.character.id, images=_images))
try: try:
birthdate = tvmaze_person_obj.birthday and tz_p.parse(tvmaze_person_obj.birthday).date() birthdate = tvmaze_person_obj.birthday and tz_p.parse(tvmaze_person_obj.birthday).date()
except (BaseException, Exception): except (BaseException, Exception):
@ -446,7 +471,7 @@ class TvMaze(TVInfoBase):
(tvmaze_person_obj.guestcastcredits or [], False)]: (tvmaze_person_obj.guestcastcredits or [], False)]:
for c in c_t: # type: tvmaze.CastCredit for c in c_t: # type: tvmaze.CastCredit
_show = c.show or c.episode.show _show = c.show or c.episode.show
_clean_char_name = clean_data(c.character.name) _clean_char_name = self._clean_character_name(c.character.name)
ti_show = TVInfoShow() ti_show = TVInfoShow()
if None is not _show: if None is not _show:
_clean_show_name = clean_data(_show.name) _clean_show_name = clean_data(_show.name)
@ -478,6 +503,8 @@ class TvMaze(TVInfoBase):
ti_show.ids = TVInfoIDs(ids={TVINFO_TVMAZE: ti_show.id}) ti_show.ids = TVInfoIDs(ids={TVINFO_TVMAZE: ti_show.id})
ti_show.overview = enforce_type(clean_data(_show.summary), str, '') ti_show.overview = enforce_type(clean_data(_show.summary), str, '')
ti_show.status = clean_data(_show.status) ti_show.status = clean_data(_show.status)
ti_show.vote_average = clean_data(_show.rating and _show.rating.get('average')) or None
ti_show.rating = ti_show.vote_average
net = _show.network or _show.web_channel net = _show.network or _show.web_channel
if net: if net:
ti_show.network = clean_data(net.name) ti_show.network = clean_data(net.name)
@ -499,8 +526,18 @@ class TvMaze(TVInfoBase):
_g_kw = {'guest_episodes_numbers': {c.episode.season_number: [c.episode.episode_number or 0]}} _g_kw = {'guest_episodes_numbers': {c.episode.season_number: [c.episode.episode_number or 0]}}
else: else:
_g_kw = {} _g_kw = {}
_images = None
if c.character.image and all(i_s in c.character.image and c.character.image[i_s]
for i_s in ('original', 'medium')):
_images = [TVInfoImage(TVInfoImageType.poster,
sizes={TVInfoImageSize.original: c.character.image['original'],
TVInfoImageSize.medium: c.character.image['medium']})]
ch.append(TVInfoCharacter(name=_clean_char_name, ti_show=ti_show, regular=regular, episode_count=1, ch.append(TVInfoCharacter(name=_clean_char_name, ti_show=ti_show, regular=regular, episode_count=1,
person=[_ti_person_obj], **_g_kw)) person=[_ti_person_obj], plays_self=c.character.plays_self,
voice=c.character.voice,
image=c.character.image and c.character.image.get('original'),
thumb_url=c.character.image and c.character.image.get('medium'),
p_id=c.character.id, images=_images, **_g_kw))
_ti_person_obj.characters = ch _ti_person_obj.characters = ch
return _ti_person_obj return _ti_person_obj
@ -588,7 +625,7 @@ class TvMaze(TVInfoBase):
else: else:
_s_o.cast[RoleTypes.ActorMain].append( _s_o.cast[RoleTypes.ActorMain].append(
TVInfoCharacter(image=cur_ch.image and cur_ch.image.get('original'), TVInfoCharacter(image=cur_ch.image and cur_ch.image.get('original'),
name=clean_data(cur_ch.name), name=self._clean_character_name(cur_ch.name),
ids=TVInfoIDs({TVINFO_TVMAZE: cur_ch.id}), ids=TVInfoIDs({TVINFO_TVMAZE: cur_ch.id}),
p_id=cur_ch.id, person=[person], plays_self=cur_ch.plays_self, p_id=cur_ch.id, person=[person], plays_self=cur_ch.plays_self,
thumb_url=cur_ch.image and cur_ch.image.get('medium'), thumb_url=cur_ch.image and cur_ch.image.get('medium'),

View file

@ -12,6 +12,18 @@ if False:
from typing import Any, AnyStr, Dict, List, Optional, Union from typing import Any, AnyStr, Dict, List, Optional, Union
url_maze_id_regex = re.compile(r'^https?://(?:(?:api|wwww)\.)?tvmaze\.com/shows/(\d+)', flags=re.I)
def _parse_show_id_from_url(url):
# type: (str) -> Optional[int]
if isinstance(url, str):
try:
return int(url_maze_id_regex.search(url).group(1))
except (BaseException, Exception):
pass
class Show(object): class Show(object):
def __init__(self, data): def __init__(self, data):
self.status = data.get('status') # type: Optional[AnyStr] self.status = data.get('status') # type: Optional[AnyStr]
@ -36,7 +48,7 @@ class Show(object):
self.runtime = data.get('runtime') # type: Optional[int] self.runtime = data.get('runtime') # type: Optional[int]
self.average_runtime = data.get('averageRuntime') self.average_runtime = data.get('averageRuntime')
self.type = data.get('type') # type: Optional[AnyStr] self.type = data.get('type') # type: Optional[AnyStr]
self.id = data.get('id') # type: int self.id = data.get('id') or ('href' in data and _parse_show_id_from_url(data['href'])) or None # type: int
self.maze_id = self.id # type: int self.maze_id = self.id # type: int
if data.get('network'): if data.get('network'):
self.network = Network(data.get('network')) # type: Optional[Network] self.network = Network(data.get('network')) # type: Optional[Network]
@ -428,9 +440,12 @@ class CastCredit(object):
def populate(self, data): def populate(self, data):
if data.get('_embedded'): if data.get('_embedded'):
if data['_embedded'].get('character'): if data['_embedded'].get('character'):
self.character = Character(data['_embedded']['character']) self.character = Character(data['_embedded']['character'], base_data=data)
if data['_embedded'].get('show'): if data['_embedded'].get('show'):
self.show = Show(data['_embedded']['show']) self.show = Show(data['_embedded']['show'])
elif ('episode' in data['_embedded'] and '_links' in data['_embedded']['episode'] and
'show' in data['_embedded']['episode']['_links']):
self.show = Show(data['_embedded']['episode']['_links']['show'])
if data['_embedded'].get('episode'): if data['_embedded'].get('episode'):
self.episode = Episode(data['_embedded']['episode']) self.episode = Episode(data['_embedded']['episode'])

View file

@ -884,6 +884,7 @@ class PersonGenders(object):
tmdb_map = {0: unknown, 1: female, 2: male} tmdb_map = {0: unknown, 1: female, 2: male}
imdb_map = {'female': female, 'male': male} imdb_map = {'female': female, 'male': male}
tvdb_map = {0: unknown, 1: male, 2: female, 3: unknown} # 3 is technically: other tvdb_map = {0: unknown, 1: male, 2: female, 3: unknown} # 3 is technically: other
trakt_map = {'female': female, 'male': male}
class Crew(PersonBase): class Crew(PersonBase):

View file

@ -724,7 +724,7 @@ class Person(Referential):
self._data_fetched = True self._data_fetched = True
tvsrc_result, found_persons, found_on_src, search_sources, \ tvsrc_result, found_persons, found_on_src, search_sources, \
found_ids, ids_to_check, imdb_confirmed, source_confirmed = \ found_ids, ids_to_check, imdb_confirmed, source_confirmed = \
None, {}, set(), [TVINFO_TRAKT, TVINFO_TMDB, TVINFO_IMDB, TVINFO_TVDB], \ None, {}, set(), [TVINFO_TRAKT, TVINFO_TMDB, TVINFO_IMDB, TVINFO_TVDB, TVINFO_TVMAZE], \
set([_k for _k, _v in iteritems(self.ids) if _v] + ['text']), {}, False, {} set([_k for _k, _v in iteritems(self.ids) if _v] + ['text']), {}, False, {}
# confirmed_character = False # confirmed_character = False
max_search_src = len(search_sources) max_search_src = len(search_sources)

View file

@ -5319,6 +5319,13 @@ class AddShows(Home):
return self.new_show('|'.join(['', '', '', show_name]), use_show_name=True) return self.new_show('|'.join(['', '', '', show_name]), use_show_name=True)
@staticmethod
def _make_char_person_list(cur_show_info):
# type: (TVInfoShow) -> List[Tuple[str, int, str, int]]
return [(ch.name.replace('"', "'"), r_t, RoleTypes.reverse[r_t], ch.episode_count)
for r_t in cur_show_info.cast or [] for ch in cur_show_info.cast[r_t]]
def tmdb_default(self): def tmdb_default(self):
method = getattr(self, sickgear.TMDB_MRU, None) method = getattr(self, sickgear.TMDB_MRU, None)
if not callable(method): if not callable(method):
@ -5376,11 +5383,12 @@ class AddShows(Home):
p_ref = f'{TVINFO_TMDB}:{p_item.id}' p_ref = f'{TVINFO_TMDB}:{p_item.id}'
dup = {} # type: Dict[int, TVInfoShow] dup = {} # type: Dict[int, TVInfoShow]
for c in p_item.characters: # type: TVInfoCharacter for c in p_item.characters: # type: TVInfoCharacter
c.ti_show.cast[RoleTypes.ActorMain].append(c)
if c.ti_show.id not in dup: if c.ti_show.id not in dup:
dup[c.ti_show.id] = c.ti_show dup[c.ti_show.id] = c.ti_show
items.append(c.ti_show) items.append(c.ti_show)
else: else:
dup[c.ti_show.id].cast.update(c.ti_show.cast) dup[c.ti_show.id].cast[RoleTypes.ActorMain].extend(c.ti_show.cast[RoleTypes.ActorMain])
del dup del dup
else: else:
p_item = None p_item = None
@ -5400,7 +5408,10 @@ class AddShows(Home):
airtime = cur_show_info.airs_time airtime = cur_show_info.airs_time
if not airtime or (0, 0) == (airtime.hour, airtime.minute): if not airtime or (0, 0) == (airtime.hour, airtime.minute):
airtime = dateutil.parser.parse('23:59').time() airtime = dateutil.parser.parse('23:59').time()
dt = datetime.combine(dateutil.parser.parse(cur_show_info.firstaired, parseinfo).date(), airtime) try:
dt = datetime.combine(dateutil.parser.parse(cur_show_info.firstaired, parseinfo).date(), airtime)
except (BaseException, Exception):
dt = None
ord_premiered, str_premiered, started_past, oldest_dt, newest_dt, oldest, newest, _, _, _, _ \ ord_premiered, str_premiered, started_past, oldest_dt, newest_dt, oldest, newest, _, _, _, _ \
= self.sanitise_dates(dt, oldest_dt, newest_dt, oldest, newest) = self.sanitise_dates(dt, oldest_dt, newest_dt, oldest, newest)
@ -5417,8 +5428,7 @@ class AddShows(Home):
and 'jp' or 'en') and 'jp' or 'en')
filtered.append(dict( filtered.append(dict(
p_ref=p_ref, p_ref=p_ref,
p_chars=[(ch.name, r_t, RoleTypes.reverse[r_t], ch.episode_count) p_chars=self._make_char_person_list(cur_show_info),
for r_t in cur_show_info.cast or [] for ch in cur_show_info.cast[r_t]],
ord_premiered=ord_premiered, ord_premiered=ord_premiered,
str_premiered=str_premiered, str_premiered=str_premiered,
started_past=started_past, started_past=started_past,
@ -5602,8 +5612,6 @@ class AddShows(Home):
if c.ti_show.id not in dup: if c.ti_show.id not in dup:
dup[c.ti_show.id] = c.ti_show dup[c.ti_show.id] = c.ti_show
items.append(c.ti_show) items.append(c.ti_show)
else:
dup[c.ti_show.id].cast.update(c.ti_show.cast)
del dup del dup
else: else:
p_item = None p_item = None
@ -5664,8 +5672,7 @@ class AddShows(Home):
filtered.append(dict( filtered.append(dict(
p_ref=p_ref, p_ref=p_ref,
p_item=p_item, p_item=p_item,
p_chars=[(ch.name, r_t, RoleTypes.reverse[r_t], ch.episode_count) p_chars=self._make_char_person_list(cur_show_info),
for r_t in cur_show_info.cast or [] for ch in cur_show_info.cast[r_t]],
ord_premiered=ord_premiered, ord_premiered=ord_premiered,
str_premiered=str_premiered, str_premiered=str_premiered,
ord_returning=ord_returning, ord_returning=ord_returning,
@ -6009,11 +6016,13 @@ class AddShows(Home):
p_ref = f'{TVINFO_TVMAZE}:{p_item.id}' p_ref = f'{TVINFO_TVMAZE}:{p_item.id}'
dup = {} # type: Dict[int, TVInfoShow] dup = {} # type: Dict[int, TVInfoShow]
for c in p_item.characters: # type: TVInfoCharacter 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: if c.ti_show.id not in dup:
dup[c.ti_show.id] = c.ti_show dup[c.ti_show.id] = c.ti_show
items.append(c.ti_show) items.append(c.ti_show)
else: else:
dup[c.ti_show.id].cast.update(c.ti_show.cast) 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 del dup
else: else:
p_item = None p_item = None
@ -6063,8 +6072,7 @@ class AddShows(Home):
filtered.append(dict( filtered.append(dict(
p_ref=p_ref, p_ref=p_ref,
p_chars=[(ch.name, r_t, RoleTypes.reverse[r_t], ch.episode_count) p_chars=self._make_char_person_list(cur_show_info),
for r_t in cur_show_info.cast or [] for ch in cur_show_info.cast[r_t]],
ord_premiered=ord_premiered, ord_premiered=ord_premiered,
str_premiered=str_premiered, str_premiered=str_premiered,
ord_returning=ord_returning, ord_returning=ord_returning,
@ -6110,6 +6118,9 @@ class AddShows(Home):
@staticmethod @staticmethod
def sanitise_dates(date, oldest_dt, newest_dt, oldest, newest, episode_info=None, combine_ep_airtime=False): 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
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) parseinfo = dateutil.parser.parserinfo(dayfirst=False, yearfirst=True)
dt = date if isinstance(date, datetime) else dateutil.parser.parse(date) dt = date if isinstance(date, datetime) else dateutil.parser.parse(date)
if episode_info: if episode_info: