mirror of
https://github.com/SickGear/SickGear.git
synced 2024-12-18 00:33:37 +00:00
Merge branch 'feature/AddBrowsePersonShows' into dev
This commit is contained in:
commit
8533297323
5 changed files with 157 additions and 15 deletions
|
@ -22,7 +22,8 @@
|
|||
* Update urllib3 2.0.7 (56f01e0) to 2.2.1 (54d6edf)
|
||||
* Change growl notifier location for Apprise update refactor
|
||||
* Change systemd remove py2 and add basic hardening options
|
||||
* Change alphabetically sort list at edit show/Exclude global ignore/require words
|
||||
* Change alphabetically sort list at edit show/Exclude global ignore/require words
|
||||
* Add search on TVmaze, TMDb, or Trakt for other shows with the actor that is viewed on Person page
|
||||
|
||||
|
||||
### 3.31.1 (2024-06-14 01:00:00 UTC)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#import re
|
||||
#import sickgear
|
||||
#from sickgear import TVInfoAPI
|
||||
#from sickgear.indexers.indexer_config import TVINFO_TMDB, TVINFO_TRAKT, TVINFO_TVMAZE
|
||||
#from sickgear.helpers import anon_url
|
||||
#from sickgear.tv import PersonGenders
|
||||
#from sg_helpers import spoken_height
|
||||
|
@ -145,15 +146,17 @@ def param(visible=True, rid=None, cache_person=None, cache_char=None, person=Non
|
|||
#end if
|
||||
|
||||
<style>
|
||||
#vitals{clear:both}
|
||||
.vitals{clear:both}
|
||||
.details-title{width:90px !important}
|
||||
.details-info{margin-left:95px !important}
|
||||
.details-info.akas{max-height:100px; overflow:auto; min-width:300px; word-break:normal}
|
||||
.details-info i{font-style:normal; font-size:smaller}
|
||||
.links{display:block; padding:0}
|
||||
.links{display:block; padding:0; margin:3px 0 0}
|
||||
.links li{display: inline-block; padding:0 10px 0 0}
|
||||
.links img{margin-bottom: -1px; vertical-align:initial}
|
||||
</style>
|
||||
|
||||
<div class="#vitals" data-birthdate="$person.birthday" data-deathdate="$person.deathday">
|
||||
<div class="vitals" data-birthdate="$person.birthday" data-deathdate="$person.deathday">
|
||||
#if $person.real_name
|
||||
<div><span class="details-title">Real name</span><span class="details-info">$person.real_name</span></div>
|
||||
#end if
|
||||
|
@ -207,6 +210,22 @@ def param(visible=True, rid=None, cache_person=None, cache_char=None, person=Non
|
|||
</ul>
|
||||
</span>
|
||||
</div>
|
||||
#end if
|
||||
#set $src = (($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>
|
||||
<span class="details-info">
|
||||
<ul class="links">
|
||||
#for ($cur_src, $cur_api) in $src
|
||||
#if $person.ids.get($cur_src)
|
||||
<img alt="$TVInfoAPI($cur_src).name" height="16" width="16" src="$sbRoot/images/$TVInfoAPI($cur_src).config['icon']">#slurp
|
||||
<li><a href="$sbRoot/add-shows/${cur_api}-person?person_${cur_api}_id=$person.ids.get($cur_src)">$TVInfoAPI($cur_src).name</a></li>
|
||||
#end if
|
||||
#end for
|
||||
</ul>
|
||||
</span>
|
||||
</div>
|
||||
#end if
|
||||
</div>
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#from sickgear import WEB_ROOT, THEME_NAME
|
||||
#from sickgear.common import *
|
||||
#from sickgear.helpers import anon_url, try_float
|
||||
#from lib.tvinfo_base import RoleTypes
|
||||
#from _23 import quote
|
||||
<% def sg_var(varname, default=False): return getattr(sickgear, varname, default) %>#slurp#
|
||||
<% def sg_str(varname, default=''): return getattr(sickgear, varname, default) %>#slurp#
|
||||
|
@ -10,7 +11,7 @@
|
|||
#set $mode = $kwargs and $kwargs.get('mode', '')
|
||||
#set $use_network = $kwargs.get('use_networks', False)
|
||||
#set $use_returning = 'returning' == mode
|
||||
#set $use_filter = $kwargs and $kwargs.get('use_filter', True)
|
||||
#set $use_filter = $kwargs and $kwargs.get('use_filter', True) and not $p_ref
|
||||
#set $use_ratings = $kwargs and $kwargs.get('use_ratings', True)
|
||||
#set $use_votes = $kwargs and $kwargs.get('use_votes', True)
|
||||
#set $term_vote = $kwargs and $kwargs.get('term_vote', 'Votes')
|
||||
|
@ -463,12 +464,19 @@ $(document).ready(function(){
|
|||
<input id="search_show_name" class="search form-control form-control-inline input-sm input200" type="search" placeholder="Filter Show Name#if $use_network#/Network#end if#">
|
||||
<button type="button" class="resetshows btn btn-inline">Reset Filter</button>
|
||||
</div>
|
||||
|
||||
<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']
|
||||
</div>
|
||||
#end if
|
||||
|
||||
#if $p_ref
|
||||
<div class="browse-image" style="margin: 10px 2px 30px; border-radius: 5px">
|
||||
<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>
|
||||
#end if
|
||||
#end if
|
||||
|
||||
<div id="container">
|
||||
|
@ -530,6 +538,13 @@ $(document).ready(function(){
|
|||
<div class="show-title">
|
||||
#echo ((re.sub(r'^((?:A(?!\s+to)n?)|The)\s(\w)', r'<span class="article">\1</span> \2', $this_show['title']), $this_show['title'])[$sg_var('SORT_ARTICLE')], '<span> </span>')['' == $this_show['title']]#
|
||||
</div>
|
||||
#if $this_show.get('p_chars')
|
||||
<div class="show-title">
|
||||
#for $char in $this_show['p_chars']
|
||||
<div>as $char[0]#if $RoleTypes.ActorMain != $char[1]# ($char[2]/$char[3] eps)#end if#</div>
|
||||
#end for
|
||||
</div>
|
||||
#end if
|
||||
#if 'Ani' not in $browse_type
|
||||
<a class="show-toggle-hide" href="$sg_root/add-shows/show-toggle-hide?ids=$show_id" title="#echo ('H', 'Unh')[any($hide)]#ide"><i class="sgicon-delete"></i></a>
|
||||
#end if
|
||||
|
|
|
@ -321,6 +321,11 @@ class TraktIndexer(TVInfoBase):
|
|||
ti_show.imdb_id = c['show']['ids'].get('imdb')
|
||||
ti_show.runtime = c['show']['runtime']
|
||||
ti_show.genre_list = c['show']['genres']
|
||||
ti_show.slug = c['show'].get('ids', {}).get('slug')
|
||||
ti_show.language = c['show'].get('language')
|
||||
ti_show.network_country = c['show'].get('country')
|
||||
ti_show.rating = c['show'].get('rating')
|
||||
ti_show.vote_count = c['show'].get('votes')
|
||||
for ch in c.get('characters') or []:
|
||||
_ti_character = TVInfoCharacter(name=ch, regular=c.get('series_regular'),
|
||||
ti_show=ti_show, person=[result],
|
||||
|
|
|
@ -94,7 +94,7 @@ except ImportError as e:
|
|||
from lib.fuzzywuzzy import fuzz
|
||||
from lib.api_trakt import TraktAPI
|
||||
from lib.api_trakt.exceptions import TraktException, TraktAuthException
|
||||
from lib.tvinfo_base import TVInfoEpisode
|
||||
from lib.tvinfo_base import TVInfoEpisode, RoleTypes
|
||||
from lib.tvinfo_base.base import tv_src_names
|
||||
|
||||
import lib.rarfile.rarfile as rarfile
|
||||
|
@ -108,7 +108,7 @@ if False:
|
|||
from typing import Any, AnyStr, Dict, List, Optional, Set, Tuple, Union
|
||||
from sickgear.providers.generic import TorrentProvider
|
||||
# prevent pyc TVInfoBase resolution by typing the derived used class to TVInfoAPI instantiation
|
||||
from lib.tvinfo_base import TVInfoBase, TVInfoShow
|
||||
from lib.tvinfo_base import TVInfoBase, TVInfoCharacter, TVInfoPerson, TVInfoShow
|
||||
# from api_imdb.imdb_api import IMDbIndexer
|
||||
from api_tmdb.tmdb_api import TmdbIndexer
|
||||
from api_trakt.indexerapiinterface import TraktIndexer
|
||||
|
@ -4324,12 +4324,15 @@ class AddShows(Home):
|
|||
return json_dumps({'results': final_results})
|
||||
|
||||
@staticmethod
|
||||
def _make_cache_image_url(iid, show_info, default_transparent_img=True):
|
||||
def _make_cache_image_url(iid, show_info, default_transparent_img=True, use_source_id=False):
|
||||
img_url = ''
|
||||
trans_param = ('1', '0')[not default_transparent_img]
|
||||
if TVINFO_TRAKT == iid:
|
||||
img_url = 'imagecache?path=browse/thumb/trakt&filename=%s&trans=%s&tmdbid=%s&tvdbid=%s' % \
|
||||
('%s.jpg' % show_info['ids'].trakt, trans_param, show_info['ids'].tmdb, show_info['ids'].tvdb)
|
||||
elif use_source_id and TVINFO_TVMAZE == iid:
|
||||
img_url = 'imagecache?path=browse/thumb/tvmaze&filename=%s&trans=%s&tvmazeid=%s' % \
|
||||
('%s.jpg' % show_info['ids'].tvmaze, trans_param, show_info['ids'].tvmaze)
|
||||
elif iid in (TVINFO_TVDB, TVINFO_TVMAZE, TVINFO_TMDB) and show_info.get('poster'):
|
||||
img_url = 'imagecache?path=browse/thumb/%s&filename=%s&trans=%s&source=%s' % \
|
||||
(tv_src_names[iid], '%s.jpg' % show_info['id'], trans_param, show_info['poster'])
|
||||
|
@ -5342,6 +5345,10 @@ class AddShows(Home):
|
|||
return self.browse_tmdb(
|
||||
'Trending this week at TMDB', mode='trending_week', **kwargs)
|
||||
|
||||
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)
|
||||
|
||||
def browse_tmdb(self, browse_title, **kwargs):
|
||||
|
||||
browse_type = 'TMDB'
|
||||
|
@ -5349,6 +5356,7 @@ class AddShows(Home):
|
|||
|
||||
footnote = None
|
||||
filtered = []
|
||||
p_ref = None
|
||||
|
||||
tvid = TVINFO_TMDB
|
||||
tvinfo_config = sickgear.TVInfoAPI(tvid).api_params.copy()
|
||||
|
@ -5361,6 +5369,21 @@ class AddShows(Home):
|
|||
items = t.get_trending()
|
||||
elif 'trending_week' == mode:
|
||||
items = t.get_trending(time_window='week')
|
||||
elif 'get_person' == mode:
|
||||
items = []
|
||||
p_item = t.get_person(get_show_credits=True, **kwargs) # type: TVInfoPerson
|
||||
if p_item:
|
||||
p_ref = f'{TVINFO_TMDB}:{p_item.id}'
|
||||
dup = {} # type: Dict[int, TVInfoShow]
|
||||
for c in p_item.characters: # type: TVInfoCharacter
|
||||
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.update(c.ti_show.cast)
|
||||
del dup
|
||||
else:
|
||||
p_item = None
|
||||
else:
|
||||
items = t.discover()
|
||||
|
||||
|
@ -5393,6 +5416,9 @@ 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=[(ch.name, 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]],
|
||||
ord_premiered=ord_premiered,
|
||||
str_premiered=str_premiered,
|
||||
started_past=started_past,
|
||||
|
@ -5533,6 +5559,8 @@ class AddShows(Home):
|
|||
mode = kwargs.get('mode', '')
|
||||
items, filtered = ([], [])
|
||||
error_msg = None
|
||||
p_item = None
|
||||
p_ref = None
|
||||
tvid = TVINFO_TRAKT
|
||||
tvinfo_config = sickgear.TVInfoAPI(tvid).api_params.copy()
|
||||
t = sickgear.TVInfoAPI(tvid).setup(**tvinfo_config) # type: Union[TraktIndexer, TVInfoBase]
|
||||
|
@ -5564,6 +5592,21 @@ 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:
|
||||
items = []
|
||||
p_item = t.get_person(get_show_credits=True, **kwargs) # type: TVInfoPerson
|
||||
if p_item:
|
||||
p_ref = f'{TVINFO_TRAKT}:{p_item.id}'
|
||||
dup = {} # type: Dict[int, TVInfoShow]
|
||||
for c in p_item.characters: # type: TVInfoCharacter
|
||||
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.update(c.ti_show.cast)
|
||||
del dup
|
||||
else:
|
||||
p_item = None
|
||||
else:
|
||||
items = t.get_trending()
|
||||
except TraktAuthException as e:
|
||||
|
@ -5603,9 +5646,10 @@ class AddShows(Home):
|
|||
except(BaseException, Exception):
|
||||
episode_info = TVInfoEpisode()
|
||||
|
||||
if rx_ignore.search(cur_show_info.seriesname.strip()) or \
|
||||
not (language_en or country_ok) or \
|
||||
not (cur_show_info.overview or episode_info.overview):
|
||||
if 'get_person' != api_method and \
|
||||
(rx_ignore.search(cur_show_info.seriesname.strip()) or
|
||||
not (language_en or country_ok) or
|
||||
not (cur_show_info.overview or episode_info.overview)):
|
||||
continue
|
||||
try:
|
||||
ord_premiered, str_premiered, started_past, oldest_dt, newest_dt, oldest, newest, \
|
||||
|
@ -5618,6 +5662,10 @@ 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=[(ch.name, 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]],
|
||||
ord_premiered=ord_premiered,
|
||||
str_premiered=str_premiered,
|
||||
ord_returning=ord_returning,
|
||||
|
@ -5653,6 +5701,16 @@ class AddShows(Home):
|
|||
|
||||
return filtered, oldest, newest
|
||||
|
||||
def trakt_person(self, person_trakt_id=None):
|
||||
|
||||
return self.browse_trakt(
|
||||
'get_person',
|
||||
'Person on Trakt',
|
||||
mode='person',
|
||||
footnote='Note; Expect default placeholder images in this list',
|
||||
p_id=person_trakt_id
|
||||
)
|
||||
|
||||
def browse_trakt(self, api_method, browse_title, **kwargs):
|
||||
|
||||
browse_type = 'Trakt'
|
||||
|
@ -5670,9 +5728,12 @@ 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 'recommended' not in mode and 'watchlist' not in mode:
|
||||
if not any(m in mode for m in ('recommended', 'watchlist', 'person')):
|
||||
mode = mode.split('-')
|
||||
if mode:
|
||||
func = 'trakt_%s' % mode[0]
|
||||
|
@ -5923,6 +5984,10 @@ class AddShows(Home):
|
|||
return self.browse_tvm(
|
||||
'Returning at TVmaze', mode='returning', **kwargs)
|
||||
|
||||
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)
|
||||
|
||||
def browse_tvm(self, browse_title, **kwargs):
|
||||
|
||||
browse_type = 'TVmaze'
|
||||
|
@ -5930,12 +5995,28 @@ class AddShows(Home):
|
|||
|
||||
footnote = None
|
||||
filtered = []
|
||||
p_ref = None
|
||||
|
||||
tvid = TVINFO_TVMAZE
|
||||
tvinfo_config = sickgear.TVInfoAPI(tvid).api_params.copy()
|
||||
t = sickgear.TVInfoAPI(tvid).setup(**tvinfo_config) # type: Union[TvmazeIndexer, TVInfoBase]
|
||||
if 'premieres' == mode:
|
||||
items = t.get_premieres()
|
||||
elif 'get_person' == mode:
|
||||
items = []
|
||||
p_item = t.get_person(get_show_credits=True, **kwargs) # type: TVInfoPerson
|
||||
if p_item:
|
||||
p_ref = f'{TVINFO_TVMAZE}:{p_item.id}'
|
||||
dup = {} # type: Dict[int, TVInfoShow]
|
||||
for c in p_item.characters: # type: TVInfoCharacter
|
||||
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.update(c.ti_show.cast)
|
||||
del dup
|
||||
else:
|
||||
p_item = None
|
||||
else:
|
||||
items = t.get_returning()
|
||||
|
||||
|
@ -5967,7 +6048,7 @@ class AddShows(Home):
|
|||
if 'returning' == mode and not ok_returning:
|
||||
continue
|
||||
|
||||
image = self._make_cache_image_url(tvid, cur_show_info)
|
||||
image = self._make_cache_image_url(tvid, cur_show_info, use_source_id='get_person' == mode)
|
||||
images = {} if not image else dict(poster=dict(thumb=image))
|
||||
|
||||
network_name = cur_show_info.network
|
||||
|
@ -5981,6 +6062,9 @@ class AddShows(Home):
|
|||
language = (('jap' in (cur_show_info.language or '').lower()) and 'jp' or 'en')
|
||||
|
||||
filtered.append(dict(
|
||||
p_ref=p_ref,
|
||||
p_chars=[(ch.name, 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]],
|
||||
ord_premiered=ord_premiered,
|
||||
str_premiered=str_premiered,
|
||||
ord_returning=ord_returning,
|
||||
|
@ -5990,7 +6074,7 @@ class AddShows(Home):
|
|||
episode_number=episode_info.episodenumber or '',
|
||||
episode_overview=helpers.xhtml_escape(episode_info.overview[:250:]).strip(),
|
||||
episode_season=getattr(episode_info.season, 'number', episode_info.seasonnumber),
|
||||
genres=(cur_show_info.genre.strip('|').replace('|', ', ')
|
||||
genres=((cur_show_info.genre or '').strip('|').replace('|', ', ')
|
||||
or ', '.join(cur_show_info.show_type) or ''),
|
||||
ids=cur_show_info.ids.__dict__,
|
||||
images=images,
|
||||
|
@ -6106,6 +6190,7 @@ class AddShows(Home):
|
|||
t.submenu = self.home_menu()
|
||||
t.browse_type = browse_type
|
||||
t.browse_title = browse_title
|
||||
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')
|
||||
showsort = t.saved_showsort.split(',')
|
||||
|
@ -9863,7 +9948,7 @@ class CachedImages(MainHandler):
|
|||
for f in ['tmdb', 'tvdb', 'tvmaze']:
|
||||
CachedImages.delete_dummy_image('%s.%s.dummy' % (os.path.splitext(filename)[0], f))
|
||||
|
||||
def index(self, path='', source=None, filename=None, tmdbid=None, tvdbid=None, trans=True):
|
||||
def index(self, path='', source=None, filename=None, tmdbid=None, tvdbid=None, trans=True, tvmazeid=None):
|
||||
|
||||
path = path.strip('/')
|
||||
file_name = ''
|
||||
|
@ -9878,8 +9963,25 @@ class CachedImages(MainHandler):
|
|||
helpers.make_path(basepath)
|
||||
poster_url = ''
|
||||
tmdb_image = False
|
||||
tvmaze_image = False
|
||||
if None is not source and source in sickgear.CACHE_IMAGE_URL_LIST:
|
||||
poster_url = source
|
||||
if None is source and tvmazeid not in [None, 'None', 0, '0'] \
|
||||
and self.should_try_image(image_file, 'tvmaze'):
|
||||
tvmaze_image = True
|
||||
try:
|
||||
tvinfo_config = sickgear.TVInfoAPI(TVINFO_TVMAZE).api_params.copy()
|
||||
t = sickgear.TVInfoAPI(TVINFO_TVMAZE).setup(**tvinfo_config)
|
||||
show_obj = t.get_show(tvmazeid, load_episodes=False, posters=True)
|
||||
if show_obj and show_obj.poster:
|
||||
poster_url = show_obj.poster
|
||||
except (BaseException, Exception):
|
||||
poster_url = ''
|
||||
if poster_url:
|
||||
sg_helpers.download_file(poster_url, image_file, nocache=True)
|
||||
if tvmaze_image and not os.path.isfile(image_file):
|
||||
self.create_dummy_image(image_file, 'tvmaze')
|
||||
|
||||
if None is source and tmdbid not in [None, 'None', 0, '0'] \
|
||||
and self.should_try_image(image_file, 'tmdb'):
|
||||
tmdb_image = True
|
||||
|
|
Loading…
Reference in a new issue