Browse Source

Add menu Shows/"TVmaze Cards".

Add show name/networks card user input filter.
Change only auto refresh card view if a recoverable error occurs.
tags/release_0.25.1
JackDandy 4 years ago
parent
commit
042e1da903
  1. 3
      CHANGES.md
  2. 3
      gui/slick/css/style.css
  3. 85
      gui/slick/interfaces/default/home_browseShows.tmpl
  4. 4
      gui/slick/interfaces/default/inc_top.tmpl
  5. 110
      lib/tvmaze_api/tvmaze_api.py
  6. 9
      sickbeard/__init__.py
  7. 158
      sickbeard/webserve.py

3
CHANGES.md

@ -79,6 +79,9 @@
* Add fetch extra data fallback from TMDB for persons
* Change fanart icon
* Add provider TorrentDB
* Add menu Shows/"TVmaze Cards"
* Add show name/networks card user input filter
* Change only auto refresh card view if a recoverable error occurs
[develop changelog]

3
gui/slick/css/style.css

@ -707,7 +707,8 @@ inc_top.tmpl
}
.sgicon-tvmaze:before{
content:"\e89a"
content:"\e89a";
margin-right:14px
}
.sgicon-emby:before{

85
gui/slick/interfaces/default/home_browseShows.tmpl

@ -8,6 +8,8 @@
<% def sg_str(varname, default=''): return getattr(sickbeard, varname, default) %>#slurp#
##
#set $mode = $kwargs and $kwargs.get('mode', '')
#set $use_network = $kwargs.get('use_networks', False)
#set $use_returning = 'returning' == mode
#set $use_votes = $kwargs and $kwargs.get('use_votes', True)
#set $use_ratings = $kwargs and $kwargs.get('use_ratings', True)
##
@ -20,7 +22,11 @@
##
#import os.path
#include $os.path.join($sg_str('PROG_DIR'), 'gui/slick/interfaces/default/inc_top.tmpl')
<script>
var config = {
homeSearchFocus: #echo ['!1','!0'][$sg_var('HOME_SEARCH_FOCUS', True)]#,
};
</script>
<script type="text/javascript" src="$sg_root/js/plotTooltip.js?v=$sbPID"></script>
<script type="text/javascript" charset="utf-8">
@ -78,6 +84,13 @@ $(document).ready(function(){
#end if
return name.toLowerCase();
},
#if $use_returning
#raw
returning: function( itemElem ) {
return $( itemElem ).attr('data-returning') || '';
},
#end raw
#end if
#if $use_ratings
rating: '[data-rating] parseFloat',
#end if
@ -98,6 +111,9 @@ $(document).ready(function(){
#end raw
case 'order':
case 'premiered':
#if $use_returning
case 'returning':
#end if
#if $use_votes
case 'votes':
#end if
@ -222,7 +238,8 @@ $(document).ready(function(){
$('#showfilter').on('change', function(){
var filterValue = this.value;
if (-1 == filterValue.indexOf('trakt') && -1 == filterValue.indexOf('imdb') && -1 == filterValue.indexOf('mc_')
&& -1 == filterValue.indexOf('tvc_') && -1 == filterValue.indexOf('ne_') && -1 == filterValue.indexOf('_ne')
&& -1 == filterValue.indexOf('tvc_') && -1 == filterValue.indexOf('tvm_')
&& -1 == filterValue.indexOf('ne_') && -1 == filterValue.indexOf('_ne')
&& -1 == filterValue.indexOf('default')) {
var el$ = $('#container')
el$.on('layoutComplete', llUpdate);
@ -241,6 +258,34 @@ $(document).ready(function(){
});
$('.service, .browse-image').each(addQTip);
if (config.homeSearchFocus) {
$('#search_show_name').focus();
}
llUpdate = (function(){
$.ll.handleScroll();
});
$('#search_show_name').on('input', function() {
var obj = $('#container');
obj.one('layoutComplete', llUpdate);
obj.isotope({
filter: function () {
var reSearch = RegExp($('#search_show_name').val(), 'i');
return reSearch.test($(this).attr('data-name'))#end raw##slurp#
#if $use_network#
|| reSearch.test(\$(this).attr('data-network'))#end if#;
#raw
}
});
});
$('.resetshows').click(function() {
var input = $('#search_show_name');
if ('' !== input.val()){
input.val('').trigger('input').change();
if (config.homeSearchFocus)
input.focus();
}
});
});
#end raw
@ -279,8 +324,14 @@ $(document).ready(function(){
</optgroup>
<optgroup label="Sort by">
<option value="by_name"#if 'by_name' in $saved_showsort_sortby and not $reset_showsort_sortby#$selected>>&nbsp;#else#>#end if#Name</option>
# omit for TVMaze as Original == First Aired
#if 'TVmaze' not in $browse_type
<option value="by_order"#if 'by_order' in $saved_showsort_sortby or $reset_showsort_sortby#$selected>>&nbsp;#else#>#end if#Original</option>
#end if
<option value="by_premiered"#if 'by_premiered' in $saved_showsort_sortby and not $reset_showsort_sortby#$selected>>&nbsp;#else#>#end if#First aired</option>
#if $use_returning
<option value="by_returning"#if 'by_returning' in $saved_showsort_sortby and not $reset_showsort_sortby#$selected>>&nbsp;#else#>#end if#Returning</option>
#end if
#if $use_votes
<option value="by_votes"#if 'by_votes' in $saved_showsort_sortby#$selected>>&nbsp;#else#>#end if#Votes</option>
#end if
@ -381,6 +432,11 @@ $(document).ready(function(){
#end for
<option value="tvc_latest"#echo ('', selected)['latest' == $mode]#>Latest additions</option>
</optgroup>
#elif 'TVmaze' == $browse_type
<optgroup label="TVmaze">
<option value="tvm_premieres"#echo ('', selected)['premieres' == $mode]#>Premieres</option>
<option value="tvm_returning"#echo ('', selected)['returning' == $mode]#>Returning</option>
</optgroup>
#elif 'Nextepisode' == $browse_type
<optgroup label="Nextepisode">
<option value="ne_newpop"#echo ('', selected)['newpop' == $mode]#>Popular premiered</option>
@ -393,9 +449,13 @@ $(document).ready(function(){
</select>
#end if
</div>
<div class="pull-right" style="clear:right">
<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#">
&nbsp;<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:both;margin-left:2px;font-size:0.85em">
<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
@ -421,11 +481,14 @@ $(document).ready(function(){
#set $hide = ('', '%shide ' % ('', 'to-')['.hide' in $saved_showsort_view])[bool($this_show.get('hide'))]
#set $data_rating = $try_float($this_show['rating'])
<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['premiered']" data-order="$this_show['order']">
<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['premiered']"#if $use_returning# data-returning="$this_show['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: rgb(66, 139, 202)'>$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#
title="<span style='color: rgb(66, 139, 202)'>$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#
#if $kwargs and $use_returning#<span style='font-weight:bold;font-size:0.9em;color:#888'><em>Season $this_show['episode_season'] returns $this_show['returning_str']</em></span>#end if#
#if $this_show.get('country') or $this_show.get('language')
<p style='line-height:15px;margin-bottom:2px'>
#if $this_show.get('country')
@ -496,18 +559,18 @@ $(document).ready(function(){
$kwargs['error_msg']
#else
$browse_type did not return results, this can happen from time to time.
<br /><br />This view should auto refresh every 10 mins.
#end if
</p>
</div>
</div>
#end if
<br><br>This view should auto refresh every 10 mins.
<script type="text/javascript" charset="utf-8">
<!--
window.setInterval('location.reload(true)', 600000); // Refresh every 10 minutes
//-->
</script>
#end if
</p>
</div>
</div>
#end if
<script type="text/javascript" src="$sg_root/js/lazyload/lazyload.min.js?v=$sbPID"></script>
<script type="text/javascript" src="$sg_root/js/inc_bottom.js?v=$sbPID"></script>

4
gui/slick/interfaces/default/inc_top.tmpl

@ -188,6 +188,10 @@
#set $tvc_mode = $tvc_modes.get($sg_var('TVC_MRU'), 'new shows')
<li><a href="$sbRoot/add-shows/tvc-default/" tabindex="$tab#set $tab += 1#"><i class="sgicon-tvc"></i>TV Calendar Cards
<div class="menu-item-desc opacity60">$tvc_mode...</div></a></li>
#set $tvm_modes = dict(tvm_premieres='new shows', tvm_returning='returning')
#set $tvm_mode = $tvm_modes.get($sg_var('TVM_MRU'), 'new shows')
<li><a href="$sbRoot/add-shows/tvm-default/" tabindex="$tab#set $tab += 1#"><i class="sgicon-tvmaze"></i>TVmaze Cards
<div class="menu-item-desc opacity60">$tvm_mode...</div></a></li>
#set $ne_modes = dict(ne_newpop='new popular', ne_newtop='new top rated', ne_upcoming='upcoming', ne_trending='trending')
#set $ne_mode = $ne_modes.get($sg_var('NE_MRU'), 'new popular')
<li><a href="$sbRoot/add-shows/ne-default/" tabindex="$tab#set $tab += 1#"><i class="sgicon-ne"></i>Next Episode Cards

110
lib/tvmaze_api/tvmaze_api.py

@ -6,18 +6,21 @@ __author__ = 'Prinz23'
__version__ = '1.0'
__api_version__ = '1.0.0'
import logging
import datetime
import logging
import re
import requests
from requests.packages.urllib3.util.retry import Retry
from urllib3.util.retry import Retry
from requests.adapters import HTTPAdapter
from six import iteritems
from sg_helpers import get_url, try_int
from lib.dateutil.parser import parser
# noinspection PyProtectedMember
from lib.dateutil.tz.tz import _datetime_to_timestamp
from lib.exceptions_helper import ConnectionSkipException, ex
from .tvmaze_exceptions import *
# from .tvmaze_exceptions import *
from lib.tvinfo_base import TVInfoBase, TVInfoImage, TVInfoImageSize, TVInfoImageType, Character, Crew, \
crew_type_names, Person, RoleTypes, TVInfoShow, TVInfoEpisode, TVInfoIDs, TVInfoSeason, PersonGenders, \
TVINFO_TVMAZE, TVINFO_TVDB, TVINFO_IMDB
@ -25,7 +28,7 @@ from lib.pytvmaze import tvmaze
# noinspection PyUnreachableCode
if False:
from typing import Any, AnyStr, Dict, List, Optional, Union
from typing import Any, AnyStr, Dict, List, Optional
from six import integer_types
log = logging.getLogger('tvmaze.api')
@ -38,8 +41,10 @@ def tvmaze_endpoint_standard_get(url):
retries = Retry(total=5,
backoff_factor=0.1,
status_forcelist=[429])
# noinspection HttpUrlsUsage
s.mount('http://', HTTPAdapter(max_retries=retries))
s.mount('https://', HTTPAdapter(max_retries=retries))
# noinspection PyProtectedMember
return get_url(url, json=True, session=s, hooks={'response': tvmaze._record_hook}, raise_skip_exception=True)
@ -139,10 +144,10 @@ class TvMaze(TVInfoBase):
return {'seriesname': s.name, 'id': s.id, 'firstaired': s.premiered,
'network': s.network and s.network.name,
'genres': s.genres, 'overview': s.summary,
'aliases': [a.name for a in s.akas], 'image': s.image and s.image.get('original'),
'ids': TVInfoIDs(tvdb=s.externals.get('thetvdb'), rage=s.externals.get('tvrage'), tvmaze=s.id,
imdb=s.externals.get('imdb') and try_int(s.externals.get('imdb').replace('tt', ''),
None))}
'aliases': [a.name for a in s.akas], 'image': s.image and s.image.get('original'),
'ids': TVInfoIDs(
tvdb=s.externals.get('thetvdb'), rage=s.externals.get('tvrage'), tvmaze=s.id,
imdb=s.externals.get('imdb') and try_int(s.externals.get('imdb').replace('tt', ''), None))}
results = []
if ids:
for t, p in iteritems(ids):
@ -201,11 +206,11 @@ class TvMaze(TVInfoBase):
return results
def _set_episode(self, sid, ep_obj):
for _k, _s in [('seasonnumber', 'season_number'), ('episodenumber', 'episode_number'),
('episodename', 'title'), ('overview', 'summary'), ('firstaired', 'airdate'),
('airtime', 'airtime'), ('runtime', 'runtime'),
('seriesid', 'maze_id'), ('id', 'maze_id'), ('is_special', 'special'),
('filename', 'image')]:
for _k, _s in (
('seasonnumber', 'season_number'), ('episodenumber', 'episode_number'),
('episodename', 'title'), ('overview', 'summary'), ('firstaired', 'airdate'),
('airtime', 'airtime'), ('runtime', 'runtime'),
('seriesid', 'maze_id'), ('id', 'maze_id'), ('is_special', 'special'), ('filename', 'image')):
if 'filename' == _k:
image = getattr(ep_obj, _s, {}) or {}
image = image.get('original') or image.get('medium')
@ -221,7 +226,8 @@ class TvMaze(TVInfoBase):
except (BaseException, Exception):
pass
def _set_network(self, show_obj, network, is_stream):
@staticmethod
def _set_network(show_obj, network, is_stream):
show_obj['network'] = network.name
show_obj['network_timezone'] = network.timezone
show_obj['network_country'] = network.country
@ -229,17 +235,21 @@ class TvMaze(TVInfoBase):
show_obj['network_id'] = network.maze_id
show_obj['network_is_stream'] = is_stream
def _get_show_data(self, sid, language, get_ep_info=False, banners=False, posters=False, seasons=False,
seasonwides=False, fanart=False, actors=False, **kwargs):
log.debug('Getting all series data for %s' % sid)
def _get_tvm_show(self, show_id, get_ep_info):
try:
self.show_not_found = False
show_data = tvm_obj.get_show(maze_id=sid, embed='cast%s' % ('', ',episodeswithspecials')[get_ep_info])
return tvm_obj.get_show(maze_id=show_id, embed='cast%s' % ('', ',episodeswithspecials')[get_ep_info])
except tvmaze.ShowNotFound:
self.show_not_found = True
return False
except (BaseException, Exception) as e:
log.debug('Error getting data for tvmaze show id: %s' % sid)
except (BaseException, Exception):
log.debug('Error getting data for tvmaze show id: %s' % show_id)
def _get_show_data(self, sid, language, get_ep_info=False, banners=False, posters=False, seasons=False,
seasonwides=False, fanart=False, actors=False, **kwargs):
log.debug('Getting all series data for %s' % sid)
show_data = self._get_tvm_show(sid, get_ep_info)
if not show_data:
return False
show_obj = self.shows[sid].__dict__
@ -330,19 +340,20 @@ class TvMaze(TVInfoBase):
except (BaseException, Exception):
print('error')
pass
existing_person.p_id, existing_person.name, existing_person.image, existing_person.gender, \
existing_person.birthdate, existing_person.deathdate, existing_person.country, \
existing_person.country_code, existing_person.country_timezone, existing_person.thumb_url, \
existing_person.url, existing_person.ids = \
ch.person.id, ch.person.name, ch.person.image and ch.person.image.get('original'), \
PersonGenders.named.get(ch.person.gender and ch.person.gender.lower(),
PersonGenders.unknown),\
person.birthdate, person.deathdate,\
ch.person.country and ch.person.country.get('name'),\
ch.person.country and ch.person.country.get('code'),\
ch.person.country and ch.person.country.get('timezone'),\
ch.person.image and ch.person.image.get('medium'),\
ch.person.url, {TVINFO_TVMAZE: ch.person.id}
(existing_person.p_id, existing_person.name, existing_person.image, existing_person.gender,
existing_person.birthdate, existing_person.deathdate, existing_person.country,
existing_person.country_code, existing_person.country_timezone, existing_person.thumb_url,
existing_person.url, existing_person.ids) = \
(ch.person.id, ch.person.name,
ch.person.image and ch.person.image.get('original'),
PersonGenders.named.get(
ch.person.gender and ch.person.gender.lower(), PersonGenders.unknown),
person.birthdate, person.deathdate,
ch.person.country and ch.person.country.get('name'),
ch.person.country and ch.person.country.get('code'),
ch.person.country and ch.person.country.get('timezone'),
ch.person.image and ch.person.image.get('medium'),
ch.person.url, {TVINFO_TVMAZE: ch.person.id})
else:
existing_character.person.append(person)
else:
@ -396,7 +407,7 @@ class TvMaze(TVInfoBase):
show_obj['ids'] = TVInfoIDs(tvdb=show_data.externals.get('thetvdb'),
rage=show_data.externals.get('tvrage'),
imdb=show_data.externals.get('imdb') and
try_int(show_data.externals.get('imdb').replace('tt', ''), None))
try_int(show_data.externals.get('imdb').replace('tt', ''), None))
if show_data.network:
self._set_network(show_obj, show_data.network, False)
@ -406,15 +417,8 @@ class TvMaze(TVInfoBase):
if get_ep_info and not getattr(self.shows.get(sid), 'ep_loaded', False):
log.debug('Getting all episodes of %s' % sid)
if None is show_data:
try:
self.show_not_found = False
show_data = tvm_obj.get_show(maze_id=sid, embed='cast%s' % ('', ',episodeswithspecials')[
get_ep_info])
except tvmaze.ShowNotFound:
self.show_not_found = True
return False
except (BaseException, Exception) as e:
log.debug('Error getting data for tvmaze show id: %s' % sid)
show_data = self._get_tvm_show(sid, get_ep_info)
if not show_data:
return False
if show_data.episodes:
@ -543,3 +547,21 @@ class TvMaze(TVInfoBase):
p = None
if p:
return self._convert_person(p)
def get_premieres(self):
# type: (...) -> List[tvmaze.Episode]
return self.filtered_schedule(lambda e: all([1 == e.season_number, 1 == e.episode_number]))
def get_returning(self):
# type: (...) -> List[tvmaze.Episode]
return self.filtered_schedule(lambda e: all([1 != e.season_number, 1 == e.episode_number]))
@staticmethod
def filtered_schedule(condition):
try:
return sorted([
e for e in tvmaze.get_full_schedule()
if condition(e) and (None is e.show.language or re.search('(?i)eng|jap', e.show.language))],
key=lambda x: x.show.premiered or x.airstamp)
except(BaseException, Exception):
return []

9
sickbeard/__init__.py

@ -618,6 +618,7 @@ else:
MC_MRU = ''
TVC_MRU = ''
TVM_MRU = ''
NE_MRU = ''
COOKIE_SECRET = b64encodestring(uuid.uuid4().bytes + uuid.uuid4().bytes)
@ -763,7 +764,7 @@ def init_stage_1(console_logging):
global USE_TRAKT, TRAKT_CONNECTED_ACCOUNT, TRAKT_ACCOUNTS, TRAKT_MRU, TRAKT_VERIFY, \
TRAKT_USE_WATCHLIST, TRAKT_REMOVE_WATCHLIST, TRAKT_TIMEOUT, TRAKT_METHOD_ADD, TRAKT_START_PAUSED, \
TRAKT_SYNC, TRAKT_DEFAULT_INDEXER, TRAKT_REMOVE_SERIESLIST, TRAKT_UPDATE_COLLECTION, \
MC_MRU, TVC_MRU, NE_MRU, \
MC_MRU, TVC_MRU, TVM_MRU, NE_MRU, \
USE_SLACK, SLACK_NOTIFY_ONSNATCH, SLACK_NOTIFY_ONDOWNLOAD, SLACK_NOTIFY_ONSUBTITLEDOWNLOAD, \
SLACK_CHANNEL, SLACK_AS_AUTHED, SLACK_BOT_NAME, SLACK_ICON_URL, SLACK_ACCESS_TOKEN, \
USE_DISCORD, DISCORD_NOTIFY_ONSNATCH, DISCORD_NOTIFY_ONDOWNLOAD, \
@ -1207,6 +1208,7 @@ def init_stage_1(console_logging):
MC_MRU = check_setting_str(CFG, 'Metacritic', 'mc_mru', '')
TVC_MRU = check_setting_str(CFG, 'TVCalendar', 'tvc_mru', '')
TVM_MRU = check_setting_str(CFG, 'TVmaze', 'tvm_mru', '')
NE_MRU = check_setting_str(CFG, 'NextEpisode', 'ne_mru', '')
USE_PYTIVO = bool(check_setting_int(CFG, 'pyTivo', 'use_pytivo', 0))
@ -1692,7 +1694,7 @@ def init_stage_2():
run_delay=datetime.timedelta(minutes=5),
threadName='PLEXWATCHEDSTATE')
MEMCACHE['history_tab_limit'] = 10
MEMCACHE['history_tab_limit'] = 11
MEMCACHE['history_tab'] = History.menu_tab(MEMCACHE['history_tab_limit'])
try:
@ -2212,6 +2214,9 @@ def save_config():
('TVCalendar', [
('mru', TVC_MRU)
]),
('TVmaze', [
('mru', TVM_MRU)
]),
('NextEpisode', [
('mru', NE_MRU)
]),

158
sickbeard/webserve.py

@ -93,6 +93,7 @@ from lib.dateutil.relativedelta import relativedelta
from lib.fuzzywuzzy import fuzz
from lib.libtrakt import TraktAPI
from lib.libtrakt.exceptions import TraktException, TraktAuthException
from lib.tvmaze_api.tvmaze_api import TvMaze
import lib.rarfile.rarfile as rarfile
@ -5168,6 +5169,157 @@ class AddShows(Home):
return self.new_show('|'.join(['', '', '', show_name]), use_show_name=True)
def tvm_default(self):
return self.redirect('/add-shows/%s' % ('tvm_premieres', sickbeard.TVM_MRU)[any(sickbeard.TVM_MRU)])
def tvm_premieres(self, **kwargs):
return self.browse_tvm(
'New Shows at TVmaze', mode='premieres', **kwargs)
def tvm_returning(self, **kwargs):
return self.browse_tvm(
'Returning Shows at TVmaze', mode='returning', **kwargs)
def browse_tvm(self, browse_title, **kwargs):
browse_type = 'TVmaze'
footnote = None
filtered = []
def card_cache(mem_key):
# noinspection PyProtectedMember
from lib.dateutil.tz.tz import _datetime_to_timestamp
if (int(_datetime_to_timestamp(datetime.datetime.now()))
< sickbeard.MEMCACHE.get(mem_key, {}).get('last_update', 0)):
return sickbeard.MEMCACHE.get(mem_key).get('data')
if 'prem' in mem_key:
data = TvMaze().get_premieres()
else:
data = TvMaze().get_returning()
sickbeard.MEMCACHE[mem_key] = dict(
last_update=(30*60) + int(_datetime_to_timestamp(datetime.datetime.now())), data=data)
return data
if 'New' in browse_title:
episodes = card_cache('tvmaze_premiere')
else:
episodes = card_cache('tvmaze_returning')
oldest, newest, oldest_dt, newest_dt, use_networks = None, None, 9999999, 0, False
dedupe = []
parseinfo = dateutil.parser.parserinfo(dayfirst=False, yearfirst=True)
for cur_episode_info in episodes:
if cur_episode_info.show.maze_id in dedupe:
continue
dedupe += [cur_episode_info.show.maze_id]
try:
if cur_episode_info.airtime:
airtime = dateutil.parser.parse(cur_episode_info.airtime).time()
else:
airtime = cur_episode_info.airstamp and dateutil.parser.parse(cur_episode_info.airstamp).time()
if (0, 0) == (airtime.hour, airtime.minute):
airtime = dateutil.parser.parse('23:59').time()
dt = datetime.datetime.combine(
dateutil.parser.parse(
(cur_episode_info.show.premiered or cur_episode_info.airdate), parseinfo).date(), airtime)
dt_ordinal = dt.toordinal()
now_ordinal = datetime.datetime.now().toordinal()
when_past = dt_ordinal < now_ordinal
dt_string = SGDatetime.sbfdate(dt)
if dt_ordinal < oldest_dt:
oldest_dt = dt_ordinal
oldest = dt_string
if dt_ordinal > newest_dt:
newest_dt = dt_ordinal
newest = dt_string
returning = returning_str = None
if 'Return' in browse_title:
returning = '9'
returning_str = 'TBC'
if cur_episode_info.airdate:
returning = cur_episode_info.airdate
dt_returning = datetime.datetime.combine(
dateutil.parser.parse(returning, parseinfo).date(), airtime)
when_past = dt_returning.toordinal() < now_ordinal
returning_str = SGDatetime.sbfdate(dt_returning)
try:
img_uri = next(i for i in cur_episode_info.show.images
if i.main and 'poster' == i.type).resolutions['original']['url']
images = dict(poster=dict(thumb='imagecache?path=browse/thumb/tvmaze&source=%s' % img_uri))
sickbeard.CACHE_IMAGE_URL_LIST.add_url(img_uri)
except(BaseException, Exception):
images = {}
ids = dict(tvmaze=cur_episode_info.maze_id)
imdb_id = cur_episode_info.show.externals.get('imdb')
if imdb_id:
ids.update(dict(imdb=imdb_id))
tvdb_id = cur_episode_info.show.externals.get('thetvdb')
if tvdb_id:
ids.update(dict(tvdb=tvdb_id))
network_name = (getattr(cur_episode_info.show.network, 'name', None)
or getattr(cur_episode_info.show.web_channel, 'name', None) or '')
cc = 'US'
if network_name:
use_networks = True
cc = (getattr(cur_episode_info.show.network, 'code', None)
or getattr(cur_episode_info.show.web_channel, 'code', None) or 'US')
language = ((cur_episode_info.show.language and 'jap' in cur_episode_info.show.language.lower())
and 'jp' or 'en')
filtered.append(dict(
ids=ids,
premiered=dt_ordinal,
premiered_str=dt_string,
returning=returning,
returning_str=returning_str,
when_past=when_past,
episode_number=cur_episode_info.episode_number,
episode_season=cur_episode_info.season_number,
episode_overview='' if not cur_episode_info.summary else cur_episode_info.summary.strip(),
genres=(', '.join(['%s' % v for v in cur_episode_info.show.genres])
or cur_episode_info.show.type or ''),
images=images,
overview=('No overview yet' if not cur_episode_info.show.summary
else helpers.xhtml_escape(cur_episode_info.show.summary.strip()[:250:])
.strip('*').strip()),
title=cur_episode_info.show.name,
language=language,
language_img=sickbeard.MEMCACHE_FLAG_IMAGES.get(language, False),
country=cc,
country_img=sickbeard.MEMCACHE_FLAG_IMAGES.get(cc.lower(), False),
network=network_name,
rating=cur_episode_info.show.weight or 0,
url_src_db=cur_episode_info.show.url,
))
except (BaseException, Exception):
pass
kwargs.update(dict(oldest=oldest, newest=newest))
kwargs.update(dict(footnote=footnote, use_votes=False, use_networks=use_networks))
mode = kwargs.get('mode', '')
if mode:
func = 'tvm_%s' % mode
if callable(getattr(self, func, None)):
sickbeard.TVM_MRU = func
sickbeard.save_config()
return self.browse_shows(browse_type, browse_title, filtered, **kwargs)
# noinspection PyUnusedLocal
def info_tvmaze(self, ids, show_name):
if not filter_list(lambda tvid_prodid: helpers.find_show_by_id(tvid_prodid), ids.split(' ')):
return self.new_show('|'.join(['', '', '', ' '.join([ids, show_name])]), use_show_name=True)
def tvc_default(self):
return self.redirect('/add-shows/%s' % ('tvc_newshows', sickbeard.TVC_MRU)[any(sickbeard.TVC_MRU)])
@ -5525,7 +5677,7 @@ class AddShows(Home):
@staticmethod
def browse_mru(browse_type, **kwargs):
save_config = False
if browse_type in ('AniDB', 'IMDb', 'Metacritic', 'Trakt', 'TVCalendar', 'Nextepisode'):
if browse_type in ('AniDB', 'IMDb', 'Metacritic', 'Trakt', 'TVCalendar', 'TVmaze', 'Nextepisode'):
save_config = True
sickbeard.BROWSELIST_MRU[browse_type] = dict(
showfilter=kwargs.get('showfilter', ''), showsort=kwargs.get('showsort', ''))
@ -5547,7 +5699,8 @@ class AddShows(Home):
showsort = t.saved_showsort.split(',')
t.saved_showsort_sortby = 3 == len(showsort) and showsort[2] or 'by_order'
t.reset_showsort_sortby = ('votes' in t.saved_showsort_sortby and not kwargs.get('use_votes', True)
or 'rating' in t.saved_showsort_sortby and not kwargs.get('use_ratings', True))
or 'rating' in t.saved_showsort_sortby and not kwargs.get('use_ratings', True)
or 'returning' in t.saved_showsort_sortby and 'Returning' not in browse_title)
t.is_showsort_desc = ('desc' == (2 <= len(showsort) and showsort[1] or 'asc')) and not t.reset_showsort_sortby
t.saved_showsort_view = 1 <= len(showsort) and showsort[0] or '*'
t.all_shows = []
@ -5635,6 +5788,7 @@ class AddShows(Home):
('order', lambda _x: _x['order']),
('name', lambda _x: _title(_x['title'])),
('premiered', lambda _x: (_x['premiered'], _title(_x['title']))),
('returning', lambda _x: (_x['returning'], _title(_x['title']))),
('votes', lambda _x: (helpers.try_int(_x['votes']), _title(_x['title']))),
('rating', lambda _x: (helpers.try_float(_x['rating']), _title(_x['title']))),
('rating_votes', lambda _x: (helpers.try_float(_x['rating']), helpers.try_int(_x['votes']),

Loading…
Cancel
Save