Change popup on browse shows person view to hide on unfocus when long user adjustable scrollable lists of character roles are used, e.g. Evan Peters in AHS.

Change hide ratings on browse shows cards in person view for TVmaze as not provided.
Change replace test code for consistency at "Other shows" for sub title across all sources.
Make overview parser centralised for consistent reusability.
Fix add dynamic fetch to fill show data on person view when a role is non main and the API does not expose.
Add logic for when there are no genres.
Fix mitigate MRU issue where browse default and param person view conflicted.
Change make TMDB person genre lowercase for consistency with other sources.
Filter out TMDB roles that have no actual name.
Add expose `show_type` to TVmaze api for cases where genres are None (e.g. Taylor Swift vs. Scooter Braun).
Fix images on Shows -> MC cards view.
Change ensure genres on NE browse shows view are lowercase consistent with other sources.
Change browse shows view, replace \r\n in show overviews to a single whitespace on cards.
Change TMDB browse shows expose ratings.
Fix TMDB browse shows use alternative term_vote in drop down.
This commit is contained in:
JackDandy 2024-06-19 15:04:04 +01:00
parent 4e52d2da08
commit 53cc79ee8c
3 changed files with 232 additions and 74 deletions

View file

@ -42,6 +42,62 @@
$(this).css('cursor', 'help');
$(this).qtip({
show: {solo:true},
// Change qTip to manual hide when it contains many roles to scroll
hide: {event:(5 < $(this).closest('div.show-card').attr('data-nroles')) ? 'unfocus' : 'mouseleave'},
events: { // Callback events
render: function(event, api) {
// Grab the tooltip element from the API
var tooltip = api.elements.tooltip
tooltip.bind('tooltipshow', function(event, api) {
var showcardEl = $(api.target).closest('div.show-card')
if ('1' === showcardEl.attr('data-ajax')) { // do a one time fetch
var qtipEl = $(this).find('.qtip-content'),
premiereEl = qtipEl.find('.premiere'),
genreEl = qtipEl.find('.genre'),
overviewEl = qtipEl.find('.overview'),
oldestEl = $('#oldest'),
newestEl = $('#newest');
// Set initial text
overviewEl.html('Fetching overview...');
$.getJSON($.SickGear.Root + '/add-shows/tvm-get-showinfo', {
tvid_prodid: showcardEl.attr('data-id'),
oldest_dt: $('#oldest').attr('data-oldest-dt'),
newest_dt: $('#newest').attr('data-newest-dt'),
},
function (data) {
if (undefined !== data.overview) {
showcardEl.attr('data-ajax', '0'); // mark one time fetch as completed
if (undefined !== data.oldest) {
oldestEl.attr('data-oldest-dt', data.oldest_dt)
oldestEl.html(data.oldest);
} else if (undefined !== data.newest) {
newestEl.attr('data-newest-dt', data.newest_dt)
newestEl.html(data.newest);
}
var premiere = '';
if (data.str_premiered.length) {
showcardEl.attr('data-premiered', data.ord_premiered);
premiere = "<span style='font-weight:bold;font-size:0.9em;color:#888'><em>First air" + (data.started_past ? 'ed' : 's') + ": " + data.str_premiered + "</em></span>";
}
if (data.genres) {
genreEl.css('display', 'block');
genreEl.find('em').html(data.genres);
}
overviewEl.html(data.overview);
if (data.network.length) {
premiere += "<span style='display:block;clear:both;font-weight:bold;font-size:0.9em;color:#888'><em>On: " + data.network + "</em></span>";
}
premiereEl.html(premiere);
} else {
overviewEl.html('Failed to fetch TVmaze overview' );
}
}
)
}
})
}
},
position: {viewport:$(window), my:'left center', adjust:{y: -10,x: 2 }},
style: {tip: {corner:true, method:'polygon'}, classes:'qtip-rounded qtip-bootstrap qtip-shadow ui-tooltip-sb'}
});
@ -264,7 +320,7 @@ $(function() {
}
});
$('.service, .browse-image').each(addQTip);
$('.service, a.browse-image').each(addQTip);
if (config.homeSearchFocus) {
$('#search_show_name').focus();
@ -309,9 +365,10 @@ $(function() {
<style>
#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}
#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}
#person{min-height:130px; height:auto; width:215px; margin:auto; display:block}
.main-image{margin:15px auto}
.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; background:url(/images/poster-person.jpg) center center no-repeat}
.person-bg{margin:0 auto !important}
</style>
<div class="bfr"><img src="$sg_root/images/loading16${theme_suffix}.gif" /></div>
@ -356,7 +413,7 @@ $(function() {
<option value="by_rating"#if 'by_rating' in $saved_showsort_sortby#$selected>>&nbsp;#else#>#end if#% Rating</option>
#end if
#if $use_ratings and $use_votes
<option value="by_rating_votes"#if 'by_rating_votes' in $saved_showsort_sortby#$selected>>&nbsp;#else#>#end if#% Rating > Votes</option>
<option value="by_rating_votes"#if 'by_rating_votes' in $saved_showsort_sortby#$selected>>&nbsp;#else#>#end if#% Rating > $term_vote</option>
#end if
</optgroup>
</select>
@ -483,7 +540,7 @@ $(function() {
<h4 style="float:left;margin:0 0 0 2px">$browse_title</h4>
#if $kwargs and $kwargs.get('oldest')
<div class="grey-text" style="clear:left;margin-left:2px;font-size:0.85em">
First aired from $kwargs['oldest'] until $kwargs['newest']
First aired from <span id="oldest" data-oldest-dt="$kwargs.get('oldest_dt', '')">$kwargs['oldest']</span> until <span id="newest" data-newest-dt="$kwargs.get('newest_dt', '')">$kwargs['newest']</span>
</div>
#end if
@ -506,7 +563,7 @@ $(function() {
#if 'returning' == $mode
#set $overview = '%s: %s' % (
'Season %s' % $this_show['episode_season'],
$this_show['episode_overview'] or $this_show['overview'])
$this_show[('episode_overview', 'overview')['No overview yet' == $this_show['episode_overview']]])
#else
#set $overview = $this_show['overview']
#end if
@ -517,14 +574,13 @@ $(function() {
#if $use_ratings:
#set $data_rating = $try_float($this_show['rating'])
#end if
<div class="show-card ${hide}${known}inlibrary" data-name="#echo re.sub(r'([\'\"])', r'', $this_show['title'])#" data_id="$show_id"#if $use_ratings# data-rating="$data_rating"#end if##if $use_votes# data-votes="$this_show['votes']"#end if# data-premiered="$this_show['ord_premiered']"#if $use_returning# data-returning="$this_show['ord_returning']"#end if# data-order="$this_show['order']"#if $use_network# data-network="$this_show['network']"#end if#>
<div class="show-card ${hide}${known}inlibrary" data-name="#echo re.sub(r'([\'\"])', r'', $this_show['title'])#" data-id="$show_id" data-ajax="$this_show.get('overview_ajax', '0')" data-nroles="#echo len($this_show.get('p_chars', []))#" #if $use_ratings# data-rating="$data_rating"#end if##if $use_votes# data-votes="$this_show['votes']"#end if# data-premiered="$this_show['ord_premiered']"#if $use_returning# data-returning="$this_show['ord_returning']"#end if# data-order="$this_show['order']"#if $use_network# data-network="$this_show['network']"#end if#>
<div class="show-card-inner">
<div class="browse-image">
<a class="browse-image" href="<%= anon_url(this_show['url_src_db']) %>" target="_blank"
title="<span style='color: #226baa'>$re.sub(r'(?m)\s+\((?:19|20)\d\d\)\s*$', '', $title_html)</span>
#if $this_show['genres']#<br><div style='font-weight:bold'>(<em>$this_show['genres']</em>)</div>#end if#
<div class='genre' style='display:#echo ('none', 'block')[bool($this_show['genres'])]#;font-weight:bold'>(<em>$this_show['genres']</em>)</div>
#if $kwargs and $use_returning#<span style='display:block;clear:both;font-weight:bold;font-size:0.9em;color:#888'><em>Season $this_show['episode_season'] return#echo ('s', 'ed')[$this_show['return_past']]# $this_show['str_returning']</em></span>#end if#
#if $this_show.get('country') or $this_show.get('language')
<p style='line-height:15px;margin-bottom:2px'>
@ -537,14 +593,14 @@ $(function() {
</p>
#end if
#if $this_show.get('p_chars')
<p>
<p style='overflow-y:auto;max-height:152px'>
#for $char in $this_show['p_chars']
<span style='display:block;clear:both;font-weight:bold;font-size:0.9em;color:#393'>as $char[0]#if $RoleTypes.ActorMain != $char[1]# ($char[2]/$char[3] eps)#end if#</span>
#end for
</p>
#end if
<p style='margin:0 0 2px'>#echo re.sub(r'([,\.!][^,\.!]*?)$', '...', re.sub(r'([!\?\.])(?=\w)', r'\1 ', $overview)).replace('.....', '...')#</p>
<p>#if $this_show['str_premiered']#<span style='font-weight:bold;font-size:0.9em;color:#888'><em>#if 'Trakt' == $browse_type and $kwargs and 'returning' == $mode#Air#else#First air#end if##echo ('s', 'ed')[$this_show['started_past']]#: $this_show['str_premiered']</em></span>#end if#
<p class='overview' style='margin:0 0 2px'>$overview</p>
<p class='premiere'>#if $this_show['str_premiered']#<span style='font-weight:bold;font-size:0.9em;color:#888'><em>#if 'Trakt' == $browse_type and $kwargs and 'returning' == $mode#Air#else#First air#end if##echo ('s', 'ed')[$this_show['started_past']]#: $this_show['str_premiered']</em></span>#end if#
#if $this_show.get('ended_str')# - <span style='font-weight:bold;font-size:0.9em;color:#888'><em>Ended: $this_show['ended_str']</em></span>#end if#
#if $this_show.get('network')#<span style='display:block;clear:both;font-weight:bold;font-size:0.9em;color:#888'><em>On: $this_show['network']</em></span>#end if#
</p>
@ -568,6 +624,8 @@ $(function() {
<div class="clearfix">
#if $use_ratings or $use_votes
<p>#if $use_ratings#<span class="rating">$this_show['rating']#if $re.search(r'^\d+(\.\d+)?$', (str($this_show['rating'])))#%</span>#end if##end if##if $use_votes#<i class="heart icon-glyph"></i><i>$this_show['votes'] $term_vote.lower()</i>#end if#</p>#slurp#
#else
<p>&nbsp;</p>
#end if
#if 'url_tvdb' in $this_show and $this_show['url_tvdb']
<a class="service" href="<%= anon_url(this_show['url_tvdb']) %>" onclick="window.open(this.href, '_blank'); return false;"

View file

@ -425,6 +425,10 @@ class TvMaze(TVInfoBase):
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 [])
ti_show.show_type = clean_data((
isinstance(c.show.type, string_types) and [c.show.type.lower()] or
isinstance(c.show.type, list) and [x.lower() for x in c.show.type] or []
))
if net:
ti_show.network = clean_data(net.name)
ti_show.network_id = net.maze_id

View file

@ -4779,7 +4779,7 @@ class AddShows(Home):
genres=', '.join(row.get('metadata', {}).get('genres', {})) or 'No genre yet',
ids=ids,
images='' if not img_uri else images,
overview='No overview yet' if not overview else helpers.xhtml_escape(overview[:250:]),
overview=self.clean_overview(overview),
rating=int(helpers.try_float(rating) * 10),
title=row.get('primary').get('title'),
url_src_db='https://www.imdb.com/%s/' % row.get('primary').get('href').strip('/'),
@ -4855,7 +4855,7 @@ class AddShows(Home):
genres='',
ids=ids,
images='' if not img_uri else images,
overview='No overview yet' if not overview else helpers.xhtml_escape(overview[:250:]),
overview=self.clean_overview(overview),
rating=0 if not len(rating) else int(helpers.try_float(rating) * 10),
title=title,
url_src_db='https://www.imdb.com/%s/' % url_path.strip('/'),
@ -5040,6 +5040,19 @@ class AddShows(Home):
f'?releaseYearMin={this_year}&releaseYearMax={this_year}{page}'
html = helpers.get_url(url, headers={'User-Agent': browser_ua.get_ua()})
if html:
items_data = []
try:
items_html = html[6 + html.index('items:[{awards'):]
items_bufr = re.split(r'\btype:"', items_html)
for cur_item in items_bufr[1:]: # iterates from the first true type:"show" record
if not cur_item.startswith('show'):
break
items_data.append(f'type:"{cur_item}')
del items_html
del items_bufr
except (BaseException, Exception):
pass
try:
if re.findall('(c-navigationPagination_item--next)', html)[0]:
kwargs.update(dict(more=1))
@ -5053,7 +5066,7 @@ class AddShows(Home):
rc_id = re.compile(r'(?i)[^A-Z0-9]')
rc_img = re.compile(r'(.*?)(/resize/[^?]+)?(/catalog/provider.*?\.(?:jpg|png)).*')
rc_season = re.compile(r'(\d+)(?:[.]\d*?)?$')
for idx, cur_row in enumerate(items):
for cur_idx, cur_row in enumerate(items):
try:
title = rc_title.sub(
'', cur_row.find('div', class_='c-finderProductCard_title').get('data-title').strip())
@ -5068,6 +5081,24 @@ class AddShows(Home):
images = None
img_src = (cur_row.find('img') or {}).get('src', '').strip()
if not img_src and items_data: # items_data is the sites' image method from 2024
buffer_idx = None
if title in items_data[cur_idx]:
buffer_idx = cur_idx
else:
for cur_data_idx, cur_item in enumerate(items_data):
if title in cur_item:
buffer_idx = cur_data_idx
break
if None is not buffer_idx:
try:
img_rel = re.findall(
r'bucketPath[^:]*?:[^"]*?"([^"]+?)"',
items_data[buffer_idx], re.I)[0].encode().decode('unicode-escape')
img_src = f'https://www.metacritic.com/a/img/catalog/{img_rel.strip("/")}'
except (BaseException, Exception):
pass
if img_src:
img_uri = rc_img.sub(r'\1\3', img_src)
images = dict(poster=dict(thumb=f'imagecache?path=browse/thumb/metac&source={img_uri}'))
@ -5102,7 +5133,7 @@ class AddShows(Home):
overview = cur_row.find('div', class_='c-finderProductCard_description')
if overview:
overview = helpers.xhtml_escape(overview.get_text().strip()[:250:])
overview = overview.get_text()
try:
season = rc_season.findall(url_path)[0]
@ -5117,7 +5148,7 @@ class AddShows(Home):
genres='',
ids=ids,
images=images or '',
overview=overview or 'No overview yet',
overview=self.clean_overview(overview),
rating=0 if not rating else rating or 'TBD',
rating_user='tbd' if not rating_user else int(helpers.try_float(rating_user) * 10) or 'tbd',
title=title,
@ -5273,7 +5304,7 @@ class AddShows(Home):
genres = row.find(class_='genre')
if genres:
genres = re.sub(r',(\S)', r', \1', genres.get_text(strip=True))
genres = re.sub(r',(\S)', r', \1', genres.get_text(strip=True)).lower()
overview = row.find(class_='summary')
if overview:
overview = overview.get_text(strip=True)
@ -5293,7 +5324,7 @@ class AddShows(Home):
ids=ids,
images='' if not img_uri else images,
network=network or None,
overview='No overview yet' if not overview else helpers.xhtml_escape(overview[:250:]),
overview=self.clean_overview(overview),
rating=(rating, 'TBD')[None is rating],
title=title,
url_src_db='https://next-episode.net/%s/' % url_path.strip('/'),
@ -5323,12 +5354,17 @@ class AddShows(Home):
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]]
for r_t in cur_show_info.cast or [] for ch in cur_show_info.cast[r_t] if ch.name]
@staticmethod
def allow_browse_mru(mode_or_mru):
# Fix an issue where a default view mixed with a deriviative view that requires a param will break the default
# Disallows default views from using derivative mru's
return 'person' not in mode_or_mru
def tmdb_default(self):
method = getattr(self, sickgear.TMDB_MRU, None)
if not callable(method):
if not callable(method) or not self.allow_browse_mru(sickgear.TMDB_MRU):
return self.tmdb_upcoming()
return method()
@ -5354,7 +5390,7 @@ class AddShows(Home):
def tmdb_person(self, person_tmdb_id=None, **kwargs):
return self.browse_tmdb(
'Person at TMDB', mode='get_person', p_id=person_tmdb_id, **kwargs)
'Person at TMDB', mode='person', p_id=person_tmdb_id, **kwargs)
def browse_tmdb(self, browse_title, **kwargs):
@ -5376,7 +5412,7 @@ class AddShows(Home):
items = t.get_trending()
elif 'trending_week' == mode:
items = t.get_trending(time_window='week')
elif 'get_person' == mode:
elif 'person' == mode:
items = []
p_item = t.get_person(get_show_credits=True, **kwargs) # type: TVInfoPerson
if p_item:
@ -5390,8 +5426,6 @@ class AddShows(Home):
else:
dup[c.ti_show.id].cast[RoleTypes.ActorMain].extend(c.ti_show.cast[RoleTypes.ActorMain])
del dup
else:
p_item = None
else:
items = t.discover()
@ -5427,19 +5461,17 @@ class AddShows(Home):
language = ((cur_show_info.language and 'jap' in cur_show_info.language.lower())
and 'jp' or 'en')
filtered.append(dict(
p_ref=p_ref,
p_chars=self._make_char_person_list(cur_show_info),
ord_premiered=ord_premiered,
str_premiered=str_premiered,
started_past=started_past,
episode_overview=helpers.xhtml_escape(cur_show_info.overview[:250:]).strip('*').strip(),
episode_overview=self.clean_overview(cur_show_info),
episode_season=cur_show_info.season,
genres=', '.join(cur_show_info.genre_list)
or (cur_show_info.genre and (cur_show_info.genre.strip('|').replace('|', ', ')) or ''),
genres=(', '.join(cur_show_info.genre_list)
or (cur_show_info.genre and (cur_show_info.genre.strip('|').replace('|', ', ')) or '')
).lower(),
ids=cur_show_info.ids.__dict__,
images=images,
overview=(helpers.xhtml_escape(cur_show_info.overview[:250:]).strip('*').strip()
or 'No overview yet'),
overview=self.clean_overview(cur_show_info),
title=cur_show_info.seriesname,
language=language,
language_img=sickgear.MEMCACHE_FLAG_IMAGES.get(language, False),
@ -5447,15 +5479,23 @@ class AddShows(Home):
country_img=sickgear.MEMCACHE_FLAG_IMAGES.get(cc.lower(), False),
network=network_name,
url_src_db=base_url % cur_show_info.id,
votes=cur_show_info.popularity or 0,
rating=0 < (cur_show_info.rating or 0) and
('%.2f' % (cur_show_info.rating * 10)).replace('.00', '') or 0,
votes=('%.2f' % cur_show_info.popularity) or 0,
))
if p_ref:
filtered[-1].update(dict(
p_name=p_item.name,
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, use_filter=True, term_vote='Score'))
kwargs.update(dict(oldest=oldest, newest=newest, use_filter=True, term_vote='Score'))
kwargs.update(dict(footnote=footnote, use_networks=use_networks))
if mode:
if mode and self.allow_browse_mru(mode):
func = 'tmdb_%s' % mode
if callable(getattr(self, func, None)):
sickgear.TMDB_MRU = func
@ -5470,7 +5510,7 @@ class AddShows(Home):
def trakt_default(self):
method = getattr(self, sickgear.TRAKT_MRU, None)
if not callable(method):
if not callable(method) or not self.allow_browse_mru(sickgear.TMDB_MRU):
return self.trakt_trending()
return method()
@ -5602,7 +5642,7 @@ class AddShows(Home):
if not items:
error_msg = 'No items in watchlist. Use the "Add to watchlist" button at the Trakt website'
raise ValueError(error_msg)
elif 'get_person' == api_method:
elif 'person' == mode:
items = []
p_item = t.get_person(get_show_credits=True, **kwargs) # type: TVInfoPerson
if p_item:
@ -5613,8 +5653,6 @@ class AddShows(Home):
dup[c.ti_show.id] = c.ti_show
items.append(c.ti_show)
del dup
else:
p_item = None
else:
items = t.get_trending()
except TraktAuthException as e:
@ -5670,9 +5708,6 @@ class AddShows(Home):
images = {} if not image else dict(poster=dict(thumb=image))
filtered.append(dict(
p_ref=p_ref,
p_item=p_item,
p_chars=self._make_char_person_list(cur_show_info),
ord_premiered=ord_premiered,
str_premiered=str_premiered,
ord_returning=ord_returning,
@ -5680,14 +5715,13 @@ class AddShows(Home):
started_past=started_past, # air time not yet available 16.11.2015
return_past=return_past,
episode_number=episode_info.episodenumber,
episode_overview=helpers.xhtml_escape(episode_info.overview[:250:]).strip('*').strip(),
episode_overview=self.clean_overview(episode_info),
episode_season=getattr(episode_info.season, 'number', 1),
genres=(', '.join(['%s' % v for v in cur_show_info.genre_list])),
ids=cur_show_info.ids.__dict__,
images=images,
network=network_name,
overview=(helpers.xhtml_escape(cur_show_info.overview[:250:]).strip('*').strip()
or 'No overview yet'),
overview=self.clean_overview(cur_show_info),
rating=0 < (cur_show_info.rating or 0) and
('%.2f' % (cur_show_info.rating * 10)).replace('.00', '') or 0,
title=(cur_show_info.seriesname or '').strip(),
@ -5699,7 +5733,14 @@ class AddShows(Home):
url_tvdb=(
'' if not (isinstance(cur_show_info.ids.tvdb, integer_types) and 0 < cur_show_info.ids.tvdb)
else sickgear.TVInfoAPI(TVINFO_TVDB).config['show_url'] % cur_show_info.ids.tvdb),
votes=cur_show_info.vote_count or '0'))
votes=cur_show_info.vote_count or '0'
))
if p_ref:
filtered[-1].update(dict(
p_name=p_item.name,
p_ref=p_ref,
p_chars=self._make_char_person_list(cur_show_info)
))
except (BaseException, Exception):
pass
@ -5712,7 +5753,7 @@ class AddShows(Home):
return self.browse_trakt(
'get_person',
'Person on Trakt',
'Person at Trakt',
mode='person',
footnote='Note; Expect default placeholder images in this list',
p_id=person_trakt_id
@ -5735,14 +5776,11 @@ class AddShows(Home):
error_msg = 'No items in watchlist. Use the "Add to watchlist" button at the Trakt website'
return self.browse_shows(browse_type, browse_title, filtered, error_msg=error_msg, show_header=1, **kwargs)
if 'get_person' == api_method and filtered:
browse_title = f'{getattr(filtered[0]["p_item"], "name", "")} (Person) on Trakt'
kwargs.update(dict(oldest=oldest, newest=newest, error_msg=error_msg, use_networks=use_networks))
if not any(m in mode for m in ('recommended', 'watchlist', 'person')):
mode = mode.split('-')
if mode:
if mode and self.allow_browse_mru(mode):
func = 'trakt_%s' % mode[0]
if callable(getattr(self, func, None)):
param = '' if 1 == len(mode) or mode[1] not in ['year', 'month', 'week', 'all'] else \
@ -5951,7 +5989,7 @@ class AddShows(Home):
network=network or None,
ids=ids,
images='' if not img_uri else images,
overview='No overview yet' if not overview else helpers.xhtml_escape(overview[:250:]),
overview=self.clean_overview(overview),
rating=None,
title=title,
url_src_db='https://www.pogdesign.co.uk/%s' % url_path.strip('/'),
@ -5979,7 +6017,7 @@ class AddShows(Home):
def tvm_default(self):
method = getattr(self, sickgear.TVM_MRU, None)
if not callable(method):
if not callable(method) or not self.allow_browse_mru(sickgear.TMDB_MRU):
return self.tvm_premieres()
return method()
@ -5993,7 +6031,52 @@ class AddShows(Home):
def tvm_person(self, person_tvm_id=None, **kwargs):
return self.browse_tvm(
'Person at TVmaze', mode='get_person', p_id=person_tvm_id, **kwargs)
'Person at TVmaze', mode='person', p_id=person_tvm_id, **kwargs)
@staticmethod
def clean_overview(info=None):
# type (AnyStr, TVInfoShow) -> AnyStr
text = info if isinstance(info, str) else info.overview
if text:
result = helpers.xhtml_escape(re.sub(r'[\r\n]+', ' ', text[:250:])).strip('*').strip()
result = re.sub(r'([!?.])(?=\w)', r'\1 ', result)
result = re.sub(r'([,.!][^,.!]*?)$', '...', result)
return result.replace('.....', '...')
return 'No overview yet'
def tvm_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)
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)
def browse_tvm(self, browse_title, **kwargs):
@ -6009,7 +6092,7 @@ class AddShows(Home):
t = sickgear.TVInfoAPI(tvid).setup(**tvinfo_config) # type: Union[TvmazeIndexer, TVInfoBase]
if 'premieres' == mode:
items = t.get_premieres()
elif 'get_person' == mode:
elif 'person' == mode:
items = []
p_item = t.get_person(get_show_credits=True, **kwargs) # type: TVInfoPerson
if p_item:
@ -6024,16 +6107,15 @@ class AddShows(Home):
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_returning()
# handle switching between returning and premieres
sickgear.BROWSELIST_MRU.setdefault(browse_type, dict())
if mode in ('premieres', 'returning'):
showfilter = ('by_returning', 'by_premiered')['premieres' == mode]
saved_showsort = sickgear.BROWSELIST_MRU[browse_type].get('tvm_%s' % mode) or '*,asc'
showsort = saved_showsort + (',%s' % showfilter, '')[3 == len(saved_showsort.split(','))]
showsort = saved_showsort + (f',{showfilter}', '')[3 == len(saved_showsort.split(','))]
sickgear.BROWSELIST_MRU[browse_type].update(dict(showfilter=showfilter, showsort=showsort))
oldest, newest, oldest_dt, newest_dt, dedupe = None, None, 9999999, 0, []
@ -6057,7 +6139,7 @@ class AddShows(Home):
if 'returning' == mode and not ok_returning:
continue
image = self._make_cache_image_url(tvid, cur_show_info, use_source_id='get_person' == mode)
image = self._make_cache_image_url(tvid, cur_show_info, use_source_id='person' == mode)
images = {} if not image else dict(poster=dict(thumb=image))
network_name = cur_show_info.network
@ -6070,9 +6152,11 @@ class AddShows(Home):
language = (('jap' in (cur_show_info.language or '').lower()) and 'jp' or 'en')
overview = self.clean_overview(cur_show_info)
overview_ajax = ("No overview yet" == overview
and p_ref and not bool(cur_show_info.cast[RoleTypes.ActorMain]))
filtered.append(dict(
p_ref=p_ref,
p_chars=self._make_char_person_list(cur_show_info),
ord_premiered=ord_premiered,
str_premiered=str_premiered,
ord_returning=ord_returning,
@ -6080,14 +6164,15 @@ class AddShows(Home):
started_past=started_past,
return_past=return_past,
episode_number=episode_info.episodenumber or '',
episode_overview=helpers.xhtml_escape(episode_info.overview[:250:]).strip(),
episode_overview=self.clean_overview(episode_info),
episode_season=getattr(episode_info.season, 'number', episode_info.seasonnumber),
genres=((cur_show_info.genre or '').strip('|').replace('|', ', ')
or ', '.join(cur_show_info.show_type) or ''),
genres=((cur_show_info.genre or '')
or ', '.join(cur_show_info.genre_list)
or ', '.join(cur_show_info.show_type) or '').strip('|').replace('|', ', ').lower(),
ids=cur_show_info.ids.__dict__,
images=images,
overview=(helpers.xhtml_escape(cur_show_info.overview[:250:]).strip('*').strip()
or 'No overview yet'),
overview_ajax=(0, 1)[overview_ajax],
overview=overview,
rating=cur_show_info.rating or cur_show_info.popularity or 0,
title=cur_show_info.seriesname,
language=language,
@ -6097,13 +6182,23 @@ class AddShows(Home):
network=network_name,
url_src_db=base_url % cur_show_info.id,
))
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))
kwargs.update(dict(footnote=footnote, use_votes=False, use_networks=use_networks))
kwargs.update(dict(oldest=oldest, newest=newest, oldest_dt=oldest_dt, newest_dt=newest_dt))
if mode:
params = dict(footnote=footnote, use_votes=False, use_networks=use_networks)
if p_ref:
params.update(dict(use_ratings=False))
kwargs.update(params)
if mode and self.allow_browse_mru(mode):
func = 'tvm_%s' % mode
if callable(getattr(self, func, None)):
sickgear.TVM_MRU = func
@ -6200,7 +6295,8 @@ class AddShows(Home):
t = PageTemplate(web_handler=self, file='home_browseShows.tmpl')
t.submenu = self.home_menu()
t.browse_type = browse_type
t.browse_title = browse_title
t.browse_title = browse_title if ('person' != kwargs.get('mode') or not shows) \
else f'{shows[0].get("p_name", "")} (Person) on {browse_type}'
t.p_ref = (0 < len(shows) and shows[0].get('p_ref')) or None
t.saved_showfilter = sickgear.BROWSELIST_MRU.get(browse_type, {}).get('showfilter', '')
t.saved_showsort = sickgear.BROWSELIST_MRU.get(browse_type, {}).get('showsort', '*,asc,by_order')