Merge pull request #983 from JackDandy/feature/AddChangeableShowID

Add changeable master Show ID when show no longer found at TV info source.
This commit is contained in:
JackDandy 2017-09-05 00:31:01 +01:00 committed by GitHub
commit 28211b6013
14 changed files with 397 additions and 131 deletions

View file

@ -99,6 +99,13 @@
* Change existing shows in DB are no longer selectable in result list
* Change add image to search result item hover over
* Change improve image load speed on browse Trakt/IMDb/AniDB pages
* Add a changeable master Show ID when show no longer found at TV info source due to an ID change
* Add guiding links to assist user to change TV Info Source ID
* Add "Shows with abandoned master IDs" to Manage/Show Processes Page to link shows that can have their show IDs
adjusted in order to sustain TV info updates
* Add "Shows from defunct TV info sources" to Manage/Show Processes page to link shows that can be switched to a
different default TV info source
* Add shows not found at a TV info source for over 7 days will only be retried once a week
[develop changelog]

View file

@ -4147,6 +4147,13 @@ fieldset.sectionwrap{
margin-top:10px
}
.fullwidth,
.fullwidth div.stepsguide,
.fullwidth div.stepsguide .step{
width:100%;
cursor:default
}
div.stepsguide .step,
legend.legendStep{
margin-bottom:0

View file

@ -12,7 +12,7 @@
#set $css = $getVar('css', 'reg')
#set $has_art = $getVar('has_art', None)
#set $restart = 'Restart SickGear for new features on this page'
#set $show_message = (None, $restart)[None is $has_art]
#set $show_message = ($show_message, $restart)[None is $has_art]
#set global $page_body_attr = 'edit-show" class="' + $css
##
#import os.path
@ -20,7 +20,7 @@
#include $os.path.join($sg_str('PROG_DIR'), 'gui/slick/interfaces/default/inc_top.tmpl')
<script>
var config = {showLang: '$show.lang', showIsAnime: #echo ('!1','!0')[$show.is_anime]#}
var config = {showLang: '$show.lang', showIsAnime: #echo ('!1','!0')[$show.is_anime]#, expandIds: #echo ('!1','!0')[$expand_ids]#}
</script>
<script type="text/javascript" src="$sbRoot/js/qualityChooser.js?v=$sbPID"></script>
<script type="text/javascript" src="$sbRoot/js/editShow.js?v=$sbPID"></script>
@ -301,7 +301,7 @@
#set $dev = True
#set $dev = None
<div id="idmapping-options" style="display:#if $dev#--#end if#none">
#set $is_master_settable = False
#set $is_master_settable = False | $unlock_master_id
#for $src_id, $src_name in $sickbeard.indexerApi().all_indexers.iteritems()
#set $is_master_settable |= ($dev or
($src_id != $show.indexer and $show.ids[$src_id].get('id', 0) > 0 and
@ -328,13 +328,23 @@
#set $data_link = ''
#set $use_search_url = False
#end if
<a id="src-mid-$src_id" class="service" style="margin-right:6px" data-search="#if $use_search_url#y#else#n#end if#" #if $src_search_url#data-search-href="$anon_url($src_search_url % $search_name)" data-search-onclick="window.open(this.href, '_blank'); return !1;" data-search-title="Search for show at $src_name" #end if##if $use_search_url#href="$anon_url($src_search_url % $search_name)" onclick="window.open(this.href, '_blank'); return !1;" title="Search for show at $src_name" #end if#$(data_link)href="$anon_url(sickbeard.indexerApi($src_id).config['show_url'], $show.ids[$src_id]['id'])" $(data_link)onclick="window.open(this.href, '_blank'); return !1;" $(data_link)title="View $src_name info in new tab"><img alt="$src_name" height="16" width="16" src="$sbRoot/images/$sickbeard.indexerApi($src_id).config['icon']" /></a>
<a id="src-mid-$src_id" class="service" style="margin-right:6px" data-search="#if $use_search_url#y#else#n#end if#" #if $src_search_url#data-search-href="$anon_url($src_search_url % $search_name)" data-search-onclick="window.open(this.href, '_blank'); return !1;" data-search-title="Search for show at $src_name" #end if##if $use_search_url#href="$anon_url($src_search_url % $search_name)" onclick="window.open(this.href, '_blank'); return !1;" title="Search for show at $src_name" #end if#$(data_link)href="$anon_url(sickbeard.indexerApi($src_id).config['show_url'], ($show.ids[$src_id]['id'], $srcid)[$expand_ids and ($src_id == $tvsrc)])" $(data_link)onclick="window.open(this.href, '_blank'); return !1;" $(data_link)title="View $src_name info in new tab"><img alt="$src_name" height="16" width="16" src="$sbRoot/images/$sickbeard.indexerApi($src_id).config['icon']" /></a>
#end if
$src_name
</span>
<span class="component-desc">
<input type="text" data-maybe-master="#echo ('0', '1')[bool($maybe_master)]#" name="mid-$src_id" id="#echo ('mid-%s' % $src_id, 'source-id')[$src_id == $show.indexer]#" value="$show.ids.get($src_id, {'id': 0}).get('id')" class="form-control form-control-inline input-sm" #echo ('', $html_disabled)[$src_id == $show.indexer]#>
#if $src_id != $show.indexer
#set $current_showid = $show.ids.get($src_id, {'id': 0}).get('id')
<input type="text" data-maybe-master="#echo ('0', '1')[bool($maybe_master)]#" name="mid-$src_id" id="#echo ('mid-%s' % $src_id, 'source-id')[$src_id == $show.indexer]#" value="#echo ($current_showid, $srcid)[$expand_ids and ($src_id == $tvsrc)]#" class="form-control form-control-inline input-sm#if $src_id == $show.indexer and $unlock_master_id# warning#end if#" #echo ('', $html_disabled)[$src_id == $show.indexer and not $unlock_master_id]#>
#if $src_id == $show.indexer
<label for="the-master">
#if $is_master_settable
<input type="radio" name="set-master" id="the-master" checked data-indexer="$src_id" data-indexerid="$show.ids[$src_id].get('id', 0)">
#end if
<p#if $is_master_settable# style="padding-left:19px"#end if#>#if $unlock_master_id#master id may have changed, <a href="$sbRoot/home/addShows/new_show?show_to_add=$show.indexer|||$showname_enc&use_show_name=True&action=Find&return_to=$sbRoot%2Fhome%2FeditShow%3Fshow%3D$current_showid%26tvsrc%3D%25s%26srcid%3D%25s%23core-component-group3">search replacement here</a>#else#locked master, can't be edited#end if#</p>
</label>
#else
<label for="lockid-$src_id">
<input type="checkbox" name="lockid-$src_id" id="lockid-$src_id"#echo ('', $html_checked)[$show.ids.get($src_id, {'status': $sickbeard.indexermapper.MapStatus.NONE}).get('status') == $sickbeard.indexermapper.MapStatus.NO_AUTOMATIC_CHANGE]#>
<p style="padding-left:19px;margin-right:24px">lock this ID</p>
@ -344,13 +354,6 @@
<input type="radio" name="set-master" id="set-master-$src_id" data-indexer="$src_id" data-indexerid="$show.ids[$src_id].get('id', 0)">set master
</label>
#end if
#else
<label for="the-master">
#if $is_master_settable
<input type="radio" name="set-master" id="the-master" checked>
#end if
<p#if $is_master_settable# style="padding-left:19px"#end if#>locked master, can't be edited</p>
</label>
#end if
</span>
</div>

View file

@ -1,8 +1,8 @@
#import sickbeard
#from sickbeard.helpers import anon_url
##
#set global $header = 'Add from TV info source'
#set global $title = $header
#set global $header = ('Add from TV info source', '<span class="grey-text">%s::</span>%s' % ($kwargs.get('action'), $default_show_name))[any([$kwargs.get('action')])]
#set global $title = ('Add from TV info source', '%s::%s' % ($kwargs.get('action'), $default_show_name))[any([$kwargs.get('action')])]
#set global $sbPath = '../..'
#set global $statpath = '../..'
#set global $topmenu = 'home'
@ -33,38 +33,47 @@
<h1 class="title">$title</h1>
#end if
<image class="preload-image" style="position:absolute;top:-999px" src="$sbRoot/images/loading32#echo ('', '-dark')['dark' == $sg_str('THEME_NAME', 'dark')]#.gif" width="32" height="32" border="0">
<span class="preload-image" style="position:absolute;top:-999px" src="$sbRoot/images/loading32#echo ('', '-dark')['dark' == $sg_str('THEME_NAME', 'dark')]#.gif" width="32" height="32" border="0"></span>
<div id="newShowPortal">
#if not $kwargs.get('action')
<div id="displayText">aoeu</div>
<br />
<br>
#end if
<form id="addShowForm" method="post" action="$sbRoot/home/addShows/addNewShow" accept-charset="utf-8">
<form id="addShowForm"#if $kwargs.get('action')# class="fullwidth"#end if# method="post" action="$sbRoot/home/addShows/addNewShow" accept-charset="utf-8">
<fieldset class="sectionwrap step-one">
<legend class="legendStep"><p>#if $use_provided_info#Using known show information#else#Find show at TV info source#end if#</p></legend>
<div class="stepDiv">
<input type="hidden" id="indexer_timeout" value="$sg_var('INDEXER_TIMEOUT', 20)" />
<input type="hidden" id="indexer_count" value="$indexer_count" />
<input type="hidden" id="indexer_timeout" value="$sg_var('INDEXER_TIMEOUT', 20)">
<input type="hidden" id="indexer_count" value="$indexer_count">
#if $kwargs.get('action')
<input type="hidden" name="providedIndexer" value="$provided_indexer">
<input type="hidden" name="return_to" value="$kwargs.get('return_to')">
<input type="hidden" name="cancel_form" value="0">
<style>
.formpaginate .next{visibility:hidden !important}
</style>
#end if
#if $use_provided_info
#set $provided_indexer_local = $provided_indexer
#set $provided_indexer_id_local = $provided_indexer_id
Show: <a href="<%= anon_url(sickbeard.indexerApi(provided_indexer_local).config['show_url'], provided_indexer_id_local) %>">$provided_indexer_name</a>
<input type="hidden" name="indexerLang" value="en" />
<input type="hidden" name="whichSeries" value="#echo '|'.join([str($provided_indexer), '', str($provided_indexer_id), $provided_indexer_name])#" />
<input type="hidden" id="providedName" value="$provided_indexer_name" />
<input type="hidden" id="providedIndexer" value="$provided_indexer" />
<input type="hidden" name="indexerLang" value="en">
<input type="hidden" name="whichSeries" value="#echo '|'.join([str($provided_indexer), '', str($provided_indexer_id), $provided_indexer_name])#">
<input type="hidden" id="providedName" value="$provided_indexer_name">
<input type="hidden" id="providedIndexer" value="$provided_indexer">
#else
#if 2 > $len($indexers)
<style>
#addShowForm input#nameToSearch{width:611px}
</style>
<input type="hidden" id="providedIndexer" value="$provided_indexer" />
<input type="hidden" id="providedIndexer" value="$provided_indexer">
#end if
<input type="text" id="nameToSearch" value="$default_show_name" placeholder="Enter a show name, TVDB ID, IMDb Url, or IMDb ID" class="form-control form-control-inline input-sm input350" />
<input type="text" id="nameToSearch" value="$default_show_name" placeholder="Enter a show name, TVDB ID, IMDb Url, or IMDb ID" class="form-control form-control-inline input-sm input350">
&nbsp;
<span style="float:right">
<select name="indexerLang" id="indexerLangSelect" class="form-control form-control-inline input-sm">
@ -80,9 +89,9 @@
</select>
#end if
&nbsp;
<input class="btn btn-inline" type="button" id="searchName" value="Search" />
<input class="btn btn-inline" type="button" id="searchName" value="Search">
</span>
<br />
<br>
<p style="margin:5px 0 15px"><span class="add-tip">Enter show name, TVDB ID, IMDb Url, or IMDb ID.&nbsp;&nbsp;</span><b>*</b>SickGear supports english, language is used for show/episode data</p>
<div id="searchResults" style="height: 100%"></div>
@ -92,16 +101,17 @@
<div style="clear:both">&nbsp;</div>
</fieldset>
#if not $kwargs.get('action')
<fieldset class="sectionwrap step-two" style="visibility:hidden">
<legend class="legendStep"><p>Pick parent folder</p></legend>
<div class="stepDiv parent-folder">
#if $provided_show_dir
Pre-chosen Destination Folder: <b>$provided_show_dir</b> <br />
<input type="hidden" id="fullShowPath" name="fullShowPath" value="$provided_show_dir" /><br />
#else
#if $provided_show_dir
Pre-chosen Destination Folder: <b>$provided_show_dir</b> <br>
<input type="hidden" id="fullShowPath" name="fullShowPath" value="$provided_show_dir"><br>
#else
#include $os.path.join($sg_str('PROG_DIR'), 'gui/slick/interfaces/default/inc_rootDirs.tmpl')
#end if
#end if
</div>
<div style="clear:both">&nbsp;</div>
</fieldset>
@ -114,24 +124,30 @@
<div style="clear:both">&nbsp;</div>
</fieldset>
#for $curNextDir in $other_shows
<input type="hidden" name="other_shows" value="$curNextDir" />
#end for
<input type="hidden" name="skipShow" id="skipShow" value="" />
#for $curNextDir in $other_shows
<input type="hidden" name="other_shows" value="$curNextDir">
#end for
<input type="hidden" name="skipShow" id="skipShow" value="">
#end if
</form>
<br />
<br>
<div style="width: 100%; text-align: center;">
<input class="btn" type="button" id="addShowButton" value="Add Show" disabled="disabled" />
#if not $kwargs.get('action')
<input class="btn" type="button" id="addShowButton" value="Add Show" disabled="disabled">
#else
<input class="btn" type="button" id="addShowButton" value="Select Show" disabled="disabled">
<input class="btn btn-danger" type="button" id="cancelShowButton" value="Cancel Select" style="margin-left:10px" disabled="disabled">
#end if
#if $provided_show_dir
<input class="btn" type="button" id="skipShowButton" value="Skip Show" />
<input class="btn" type="button" id="skipShowButton" value="Skip Show">
#end if
</div>
<script type="text/javascript" src="$sbRoot/js/rootDirs.js?v=$sbPID"></script>
<script type="text/javascript" src="$sbRoot/js/blackwhite.js?v=$sbPID"></script>
</div></div>
</div>
#include $os.path.join($sg_str('PROG_DIR'), 'gui/slick/interfaces/default/inc_bottom.tmpl')

View file

@ -51,14 +51,14 @@
<h3>Search Queue:</h3>
#if $queueLength['backlog'] or $queueLength['manual'] or $queueLength['failed']
<input type="button" class="show-all-more btn" id="all-btn-more" value="Expand All"><input type="button" class="show-all-less btn" id="all-btn-less" value="Collapse All"></br>
<input type="button" class="show-all-more btn" id="all-btn-more" value="Expand All"><input type="button" class="show-all-less btn" id="all-btn-less" value="Collapse All"><br>
#end if
</br>
Recent: <i>$queueLength['recent'] item$sickbeard.helpers.maybe_plural($queueLength['recent'])</i></br></br>
Proper: <i>$queueLength['proper'] item$sickbeard.helpers.maybe_plural($queueLength['proper'])</i></br></br>
<br>
Recent: <i>$queueLength['recent'] item$sickbeard.helpers.maybe_plural($queueLength['recent'])</i><br><br>
Proper: <i>$queueLength['proper'] item$sickbeard.helpers.maybe_plural($queueLength['proper'])</i><br><br>
Backlog: <i>$len($queueLength['backlog']) item$sickbeard.helpers.maybe_plural($len($queueLength['backlog']))</i>
#if $queueLength['backlog']
<input type="button" class="shows-more btn" id="backlog-btn-more" value="Expand" #if not $queueLength['backlog']# style="display:none" #end if#><input type="button" class="shows-less btn" id="backlog-btn-less" value="Collapse" style="display:none"></br>
<input type="button" class="shows-more btn" id="backlog-btn-more" value="Expand" #if not $queueLength['backlog']# style="display:none" #end if#><input type="button" class="shows-less btn" id="backlog-btn-less" value="Collapse" style="display:none"><br>
<table class="sickbeardTable manageTable" cellspacing="1" border="0" cellpadding="0" style="display:none">
<thead></thead>
<tbody>
@ -90,12 +90,12 @@ Backlog: <i>$len($queueLength['backlog']) item$sickbeard.helpers.maybe_plural($l
</tbody>
</table>
#else
</br>
<br>
#end if
</br>
<br>
Manual: <i>$len($queueLength['manual']) item$sickbeard.helpers.maybe_plural($len($queueLength['manual']))</i>
#if $queueLength['manual']
<input type="button" class="shows-more btn" id="manual-btn-more" value="Expand" #if not $queueLength['manual']# style="display:none" #end if#><input type="button" class="shows-less btn" id="manual-btn-less" value="Collapse" style="display:none"></br>
<input type="button" class="shows-more btn" id="manual-btn-more" value="Expand" #if not $queueLength['manual']# style="display:none" #end if#><input type="button" class="shows-less btn" id="manual-btn-less" value="Collapse" style="display:none"><br>
<table class="sickbeardTable manageTable" cellspacing="1" border="0" cellpadding="0" style="display:none">
<thead></thead>
<tbody>
@ -110,12 +110,12 @@ Manual: <i>$len($queueLength['manual']) item$sickbeard.helpers.maybe_plural($len
</tbody>
</table>
#else
</br>
<br>
#end if
</br>
<br>
Failed: <i>$len($queueLength['failed']) item$sickbeard.helpers.maybe_plural($len($queueLength['failed']))</i>
#if $queueLength['failed']
<input type="button" class="shows-more btn" id="failed-btn-more" value="Expand" #if not $queueLength['failed']# style="display:none" #end if#><input type="button" class="shows-less btn" id="failed-btn-less" value="Collapse" style="display:none"></br>
<input type="button" class="shows-more btn" id="failed-btn-more" value="Expand" #if not $queueLength['failed']# style="display:none" #end if#><input type="button" class="shows-less btn" id="failed-btn-less" value="Collapse" style="display:none"><br>
<table class="sickbeardTable manageTable" cellspacing="1" border="0" cellpadding="0" style="display:none">
<thead></thead>
<tbody>
@ -130,7 +130,7 @@ Failed: <i>$len($queueLength['failed']) item$sickbeard.helpers.maybe_plural($len
</tbody>
</table>
#else
</br>
<br>
#end if
</div>
</div>

View file

@ -18,26 +18,72 @@
#end if
<div id="summary2" class="align-left">
<h3> Daily Show Update:</h3>
<h3> Daily show update:</h3>
<a id="showupdatebutton" class="btn#if $ShowUpdateRunning# disabled#end if#" href="$sbRoot/manage/showProcesses/forceShowUpdate"><i class="sgicon-play"></i> Force</a>
#if not $ShowUpdateRunning:
Not in progress<br />
#else:
Currently running<br />
#end if
</br>
<h3>Show Queue:</h3>
</br>
#if $queueLength['add'] or $queueLength['update'] or $queueLength['refresh'] or $queueLength['rename'] or $queueLength['subtitle']
<input type="button" class="show-all-more btn" id="all-btn-more" value="Expand All"><input type="button" class="show-all-less btn" id="all-btn-less" value="Collapse All"></br>
<br>
#if $NotFoundShows
<h3>Shows with abandoned master IDs:</h3>
<input type="button" class="shows-more btn" id="notfound-btn-more" value="Expand" style="display:none"><input type="button" class="shows-less btn" id="notfound-btn-less" value="Collapse"><br>
<table class="sickbeardTable manageTable" cellspacing="1" border="0" cellpadding="0">
<thead></thead>
<tbody>
<tr>
<th style="text-align:left">Show name</th>
<th>Last found</th>
</tr>
#set $row = 0
#for $cur_show in $NotFoundShows:
<tr class="#echo ('odd', 'even')[$row % 2]##set $row+=1#">
<td style="width:80%;text-align:left">
<a class="whitelink" href="$sbRoot/home/displayShow?show=$cur_show['indexer_id']">$cur_show['show_name']</a>
</td>
<td style="width:20%;text-align:center;color:white">$cur_show['last_success']</td>
</tr>
#end for
</tbody>
</table>
#end if
</br>
#if $DefunctIndexer
<h3>Shows from defunct TV info sources:</h3>
<input type="button" class="shows-more btn" id="defunct-btn-more" value="Expand" style="display:none"><input type="button" class="shows-less btn" id="defunct-btn-less" value="Collapse"><br>
<table class="sickbeardTable manageTable" cellspacing="1" border="0" cellpadding="0">
<thead></thead>
<tbody>
<tr>
<th style="text-align:left">Show name</th>
</tr>
#set $row = 0
#for $cur_show in $DefunctIndexer:
<tr class="#echo ('odd', 'even')[$row % 2]##set $row+=1#">
<td style="width:80%;text-align:left">
<a class="whitelink" href="$sbRoot/home/displayShow?show=$cur_show['indexer_id']">$cur_show['show_name']</a>
</td>
</tr>
#end for
</tbody>
</table>
#end if
<h3>Show queue:</h3>
<br>
#if $queueLength['add'] or $queueLength['update'] or $queueLength['refresh'] or $queueLength['rename'] or $queueLength['subtitle']
<input type="button" class="show-all-more btn" id="all-btn-more" value="Expand All"><input type="button" class="show-all-less btn" id="all-btn-less" value="Collapse All"><br>
#end if
<br>
Add: <i>$len($queueLength['add']) show$sickbeard.helpers.maybe_plural($len($queueLength['add']))</i>
#if $queueLength['add']
<input type="button" class="shows-more btn" id="add-btn-more" value="Expand" #if not $queueLength['add']# style="display:none" #end if#><input type="button" class="shows-less btn" id="add-btn-less" value="Collapse" style="display:none"></br>
<input type="button" class="shows-more btn" id="add-btn-more" value="Expand" #if not $queueLength['add']# style="display:none" #end if#><input type="button" class="shows-less btn" id="add-btn-less" value="Collapse" style="display:none"><br>
<table class="sickbeardTable manageTable" cellspacing="1" border="0" cellpadding="0" style="display:none">
<thead></thead>
<tbody>
<tr>
<th>Show name</th>
<th></th>
</tr>
#set $row = 0
#for $cur_show in $queueLength['add']:
#set $show_name = str($cur_show['name'])
@ -49,15 +95,19 @@ Add: <i>$len($queueLength['add']) show$sickbeard.helpers.maybe_plural($len($queu
</tbody>
</table>
#else
</br>
<br>
#end if
</br>
<br>
Update <span class="grey-text">(Forced / Forced Web)</span>: <i>$len($queueLength['update']) <span class="grey-text">($len($queueLength['forceupdate']) / $len($queueLength['forceupdateweb']))</span> show$sickbeard.helpers.maybe_plural($len($queueLength['update']))</i>
#if $queueLength['update']
<input type="button" class="shows-more btn" id="update-btn-more" value="Expand" #if not $queueLength['update']# style="display:none" #end if#><input type="button" class="shows-less btn" id="update-btn-less" value="Collapse" style="display:none"></br>
<input type="button" class="shows-more btn" id="update-btn-more" value="Expand" #if not $queueLength['update']# style="display:none" #end if#><input type="button" class="shows-less btn" id="update-btn-less" value="Collapse" style="display:none"><br>
<table class="sickbeardTable manageTable" cellspacing="1" border="0" cellpadding="0" style="display:none">
<thead></thead>
<tbody>
<tr>
<th>Show name</th>
<th>Schedule type</th>
</tr>
#set $row = 0
#for $cur_show in $queueLength['update']:
#set $show = $findCertainShow($showList, $cur_show['indexerid'])
@ -72,15 +122,19 @@ Update <span class="grey-text">(Forced / Forced Web)</span>: <i>$len($queueLengt
</tbody>
</table>
#else
</br>
<br>
#end if
</br>
<br>
Refresh: <i>$len($queueLength['refresh']) show$sickbeard.helpers.maybe_plural($len($queueLength['refresh']))</i>
#if $queueLength['refresh']
<input type="button" class="shows-more btn" id="refresh-btn-more" value="Expand" #if not $queueLength['refresh']# style="display:none" #end if#><input type="button" class="shows-less btn" id="refresh-btn-less" value="Collapse" style="display:none"></br>
<input type="button" class="shows-more btn" id="refresh-btn-more" value="Expand" #if not $queueLength['refresh']# style="display:none" #end if#><input type="button" class="shows-less btn" id="refresh-btn-less" value="Collapse" style="display:none"><br>
<table class="sickbeardTable manageTable" cellspacing="1" border="0" cellpadding="0" style="display:none">
<thead></thead>
<tbody>
<tr>
<th>Show name</th>
<th>Schedule type</th>
</tr>
#set $row = 0
#for $cur_show in $queueLength['refresh']:
#set $show = $findCertainShow($showList, $cur_show['indexerid'])
@ -95,16 +149,20 @@ Refresh: <i>$len($queueLength['refresh']) show$sickbeard.helpers.maybe_plural($l
</tbody>
</table>
#else
</br>
<br>
#end if
</br>
<br>
Rename: <i>$len($queueLength['rename']) show$sickbeard.helpers.maybe_plural($len($queueLength['rename']))</i>
#if $queueLength['rename']
<input type="button" class="shows-more btn" id="rename-btn-more" value="Expand" #if not $queueLength['rename']# style="display:none" #end if#><input type="button" class="shows-less btn" id="rename-btn-less" value="Collapse" style="display:none"></br>
<input type="button" class="shows-more btn" id="rename-btn-more" value="Expand" #if not $queueLength['rename']# style="display:none" #end if#><input type="button" class="shows-less btn" id="rename-btn-less" value="Collapse" style="display:none"><br>
<table class="sickbeardTable manageTable" cellspacing="1" border="0" cellpadding="0" style="display:none">
<thead></thead>
<tbody>
<tr>
<th>Show name</th>
<th>Schedule type</th>
</tr>
#set $row = 0
#for $cur_show in $queueLength['rename']:
#set $show = $findCertainShow($showList, $cur_show['indexerid'])
@ -119,16 +177,20 @@ Rename: <i>$len($queueLength['rename']) show$sickbeard.helpers.maybe_plural($len
</tbody>
</table>
#else
</br>
<br>
#end if
#if $sickbeard.USE_SUBTITLES
</br>
<br>
Subtitle: <i>$len($queueLength['subtitle']) show$sickbeard.helpers.maybe_plural($len($queueLength['subtitle']))</i>
#if $queueLength['subtitle']
<input type="button" class="shows-more btn" id="subtitle-btn-more" value="Expand" #if not $queueLength['subtitle']# style="display:none" #end if#><input type="button" class="shows-less btn" id="subtitle-btn-less" value="Collapse" style="display:none"></br>
<input type="button" class="shows-more btn" id="subtitle-btn-more" value="Expand" #if not $queueLength['subtitle']# style="display:none" #end if#><input type="button" class="shows-less btn" id="subtitle-btn-less" value="Collapse" style="display:none"><br>
<table class="sickbeardTable manageTable" cellspacing="1" border="0" cellpadding="0" style="display:none">
<thead></thead>
<tbody>
<tr>
<th>Show name</th>
<th>Schedule type</th>
</tr>
#set $row = 0
#for $cur_show in $queueLength['subtitle']:
#set $show = $findCertainShow($showList, $cur_show['indexerid'])
@ -143,9 +205,9 @@ Rename: <i>$len($queueLength['rename']) show$sickbeard.helpers.maybe_plural($len
</tbody>
</table>
#else
</br>
<br>
#end if
#end if
</div>
</div>
#include $os.path.join($sickbeard.PROG_DIR, 'gui/slick/interfaces/default/inc_bottom.tmpl')
#include $os.path.join($sickbeard.PROG_DIR, 'gui/slick/interfaces/default/inc_bottom.tmpl')

View file

@ -1,6 +1,7 @@
/** @namespace $.SickGear.Root */
/** @namespace config.showLang */
/** @namespace config.showIsAnime */
/** @namespace config.expandIds */
/*globals $, config, sbRoot, generate_bwlist*/
$(document).ready(function () {
@ -67,7 +68,7 @@ $(document).ready(function () {
$('#SceneException').fadeIn('fast', 'linear');
var option = $('<option>');
if (null == sceneExSeason)
if (null === sceneExSeason)
sceneExSeason = '-1';
option.val(sceneExSeason + '|' + sceneEx);
option.html((config.showIsAnime ? 'S' + ('-1' === sceneExSeason ? '*' : sceneExSeason) + ': ' : '') + sceneEx);
@ -84,7 +85,7 @@ $(document).ready(function () {
$.fn.toggle_SceneException = function () {
var elSceneException = $('#SceneException');
if (0 == getExceptions().length)
if (0 === getExceptions().length)
elSceneException.fadeOut('fast', 'linear');
else
elSceneException.fadeIn('fast', 'linear');
@ -108,7 +109,7 @@ $(document).ready(function () {
if (checked(elAnime)) { isAnime(); }
if (checked(elScene)) { isScene(); }
if (checked(elABD)) { isABD(); }
if (checked(elSports)) { isSports() }
if (checked(elSports)) { isSports(); }
elAnime.on('click', function() {
if (checked(elAnime))
@ -127,6 +128,8 @@ $(document).ready(function () {
elABD.on('click', function() { isABD(); });
elSports.on('click', function() { isSports() });
if (config.expandIds) { elIdMap.click(); }
function undef(value) {
return /undefined/i.test(typeof(value));
}
@ -134,10 +137,10 @@ $(document).ready(function () {
function updateSrcLinks() {
var preventSave = !1, search = 'data-search';
$('[id^=mid-]').each(function (i, selected) {
$('[id^=mid-], #source-id').each(function (i, selected) {
var elSelected = $(selected),
okDigits = !(/[^\d]/.test(elSelected.val()) || ('' == elSelected.val())),
service = '#src-' + elSelected.attr('id'),
okDigits = !(/[^\d]/.test(elSelected.val()) || ('' === elSelected.val())),
service = (('source-id' === elSelected.attr('id')) ? '#src-' + elSelected.attr('name') : '#src-' + elSelected.attr('id')),
elLock = $('#lockid-' + service.replace(/.*?(\d+)$/, '$1')),
elService = $(service),
On = 'data-', Off = '', linkOnly = !1, newLink = '';
@ -150,14 +153,14 @@ $(document).ready(function () {
}
}
$.each(['href', 'title', 'onclick'], function(i, attr) {
if ('n' == elService.attr(search)) {
if ('n' === elService.attr(search)) {
elService.attr(On + attr, elService.attr(Off + attr)).removeAttr(Off + attr);
}
if (linkOnly)
elService.attr(attr, elService.attr(search + '-' + attr));
elService.attr(search, linkOnly ? 'y' : 'n')
});
if (('' == Off) && !linkOnly) {
if (('' === Off) && !linkOnly) {
preventSave = !0;
elSelected.addClass('warning').attr({title: 'Use digits (0-9)'});
elLock.prop('disabled', !0);
@ -178,14 +181,14 @@ $(document).ready(function () {
$('#save-mapping').prop('disabled', preventSave);
}
$('[id^=mid-]').on('input', function() {
$('[id^=mid-], #source-id').on('input', function() {
updateSrcLinks();
});
function saveMapping(paused, markWanted) {
var sbutton = $(this), mid = $('[id^=mid-]'), lock = $('[id^=lockid-]'),
allf = $('[id^=mid-], [id^=lockid-], #reset-mapping, [name^=set-master]'),
radio = $('[name^=set-master]:checked'), isMaster = !radio.length || 'the-master' == radio.attr('id'),
radio = $('[name^=set-master]:checked'), isMaster = !radio.length || ('the-master' === radio.attr('id') && $.trim($('#source-id').val()) == $('#show').val()),
panelSaveGet = $('#panel-save-get'), saveWait = $('#save-wait');
allf.prop('disabled', !0);
@ -197,10 +200,10 @@ $(document).ready(function () {
lock.each(function (i, selected) {
param[$(selected).attr('id')] = $(selected).prop('checked');
});
param['indexer'] = $('#indexer').val();
if (!isMaster) {
param['indexer'] = $('#indexer').val();
param['mindexer'] = radio.attr('data-indexer');
param['mindexerid'] = radio.attr('data-indexerid');
param['mindexerid'] = $.trim(radio.closest('span').find('input:text').val());
param['paused'] = paused ? '1' : '0';
param['markwanted'] = markWanted ? '1' : '0';
panelSaveGet.removeClass('show').addClass('hide');
@ -216,19 +219,19 @@ $(document).ready(function () {
if (undef(data.error)) {
$.each(data.map, function (i, item) {
$('#mid-' + i).val(item.id);
$('#lockid-' + i).prop('checked', -100 == item.status)
$('#lockid-' + i).prop('checked', -100 === item.status)
});
/** @namespace data.switch */
/** @namespace data.switch.mid */
if (!isMaster && data.hasOwnProperty('switch') && data.switch.hasOwnProperty('Success')) {
window.location.replace(sbRoot + '/home/displayShow?show=' + data.mid);
} else if ((0 < $('*[data-maybe-master=1]').length)
&& (((0 == $('[name^=set-master]').length) && (0 < $('*[data-maybe-master=1]').val()))
|| ((0 < $('[name^=set-master]').length) && (0 == $('*[data-maybe-master=1]').val())))) {
&& (((0 === $('[name^=set-master]').length) && (0 < $('*[data-maybe-master=1]').val()))
|| ((0 < $('[name^=set-master]').length) && (0 === $('*[data-maybe-master=1]').val())))) {
location.reload();
}
}})
.fail(function (data) {
.fail(function () {
allf.prop('disabled', !1);
sbutton.prop('disabled', !1);
});
@ -258,22 +261,21 @@ $(document).ready(function () {
$('#the-master').prop('checked', !0).trigger('click');
$.each(data, function (i, item) {
$('#mid-' + i).val(item.id);
$('#lockid-' + i).prop('checked', -100 == item.status);
$('#lockid-' + i).prop('checked', -100 === item.status);
});
updateSrcLinks();
}})
.fail(function (data) {
.fail(function () {
allf.prop('disabled', !1);
fbutton.prop('disabled', !1);
});
}
$('#save-mapping, #reset-mapping').click(function() {
var save = /save/i.test($(this).attr('id')),
radio = $('[name=set-master]:checked'), isMaster = !radio.length || 'the-master' == radio.attr('id'),
var save = /save/i.test(this.id),
radio = $('[name=set-master]:checked'), isMaster = !radio.length || ('the-master' === radio.attr('id') && $.trim($('#source-id').val()) == $('#show').val()),
newMaster = (save && !isMaster),
paused = 'on' == $('#paused:checked').val(),
paused = 'on' === $('#paused:checked').val(),
extraWarn = !newMaster ? '' : 'Warning: Changing the master source can produce undesirable'
+ ' results if episodes do not match at old and new TV info sources<br /><br />'
+ (paused ? '' : '<input type="checkbox" id="mark-wanted" style="margin-right:6px">'
@ -288,7 +290,7 @@ $(document).ready(function () {
'Yes': {
'class': 'green',
'action': function () {
save ? saveMapping(paused, 'on' == $('#mark-wanted:checked').val()) : resetMapping()
save ? saveMapping(paused, 'on' === $('#mark-wanted:checked').val()) : resetMapping()
}
},
'No': {

View file

@ -53,11 +53,13 @@ $(document).ready(function () {
searchRequestXhr.abort();
var elTvDatabase = $('#providedIndexer'),
elIndexerLang = $('#indexerLangSelect');
elIndexerLang = $('#indexerLangSelect'),
tvsrcName = elTvDatabase.find('option:selected').text(),
tvSearchSrc = 0 < tvsrcName.length ? ' on ' + tvsrcName : '';
$('#searchResults').empty().html('<img id="searchingAnim" src="' + sbRoot + '/images/loading32' + themeSpinner + '.gif" height="32" width="32" />'
+ ' searching <span class="boldest">' + cleanseText(elNameToSearch.val(), !0) + '</span>'
+ ' on ' + elTvDatabase.find('option:selected').text() + ' in ' + elIndexerLang.val()
+ tvSearchSrc + ' in ' + elIndexerLang.val()
+ '...');
searchRequestXhr = $.ajax({
@ -122,7 +124,7 @@ $(document).ready(function () {
+ '<span style=\'float:right;clear:both\'>Click for more</span>'
+ '"'
+ ' href="' + anonURL + item[result.SrcUrl] + item[result.ShowID] + ((data.langid && '' != data.langid) ? '&lid=' + data.langid : '') + '"'
+ ' onclick="window.open(this.href, \'_blank\'); return false;"'
+ ' onclick="window.open(this.href, \'_blank\'); return !1;"'
+ '>' + (config.sortArticle ? displayShowName : displayShowName.replace(/^((?:A(?!\s+to)n?)|The)(\s)+(.*)/i, '$3$2<span class="article">($1)</span>')) + '</a>'
+ showstartdate
+ ('' === srcState ? ''
@ -229,14 +231,18 @@ $(document).ready(function () {
elSearchName.click();
}
$('#addShowButton').click(function () {
// if they haven't picked a show don't let them submit
if (!$('input:radio[name="whichSeries"]:checked').val()
&& !$('input:hidden[name="whichSeries"]').val().length) {
alert('You must choose a show to continue');
return false;
$('#addShowButton, #cancelShowButton').click(function () {
if (/cancel/.test(this.id)){
$('input[name=cancel_form]').val('1');
} else {
// if they haven't picked a show don't let them submit
if (!$('input:radio[name="whichSeries"]:checked').val()
&& !$('input:hidden[name="whichSeries"]').val().length) {
alert('You must choose a show to continue');
return !1;
}
generate_bwlist();
}
generate_bwlist();
$('#addShowForm').submit();
});
@ -279,6 +285,11 @@ $(document).ready(function () {
elNameToSearch.focus();
function updateSampleText() {
if (0 === $('#displayText').length) {
$('#cancelShowButton').attr('disabled', !1);
$('#addShowButton').attr('disabled', 0 === $('#holder').find('.results-item').length);
return;
}
// if something's selected then we have some behavior to figure out
var show_name = '',
@ -343,9 +354,9 @@ $(document).ready(function () {
// also toggle the add show button
if ((elRootDirs.find('option:selected').length || (elFullShowPath.length && elFullShowPath.val().length)) &&
(elRadio.length) || (elInput.length && elInput.val().length)) {
$('#addShowButton').attr('disabled', false);
$('#addShowButton').attr('disabled', !1);
} else {
$('#addShowButton').attr('disabled', true);
$('#addShowButton').attr('disabled', !0);
}
}
@ -363,7 +374,7 @@ $(document).ready(function () {
$(this).css('cursor', 'help');
$(this).qtip({
show: {
solo: true
solo: !0
},
position: {
viewport: $(window),
@ -375,7 +386,7 @@ $(document).ready(function () {
},
style: {
tip: {
corner: true,
corner: !0,
method: 'polygon'
},
classes: 'qtip-rounded qtip-bootstrap qtip-shadow ui-tooltip-sb'

View file

@ -109,10 +109,11 @@ $(document).ready(function() {
function setDefault(which, force){
console.log('setting default to '+which);
//console.log('setting default to '+which);
if (which != undefined && !which.length)
return
if (/undefined/i.test(which) || !which.length) {
return;
}
if ($('#whichDefaultRootDir').val() == which && force != true)
return
@ -186,4 +187,4 @@ $(document).ready(function() {
setDefault($('#whichDefaultRootDir').val(), true)
refreshRootDirs();
});
});

View file

@ -20,6 +20,8 @@ import logging
import requests
import requests.exceptions
import datetime
import re
from sickbeard.helpers import getURL, tryInt
import sickbeard
@ -432,6 +434,8 @@ class Tvdb:
self.shows = ShowContainer() # Holds all Show classes
self.corrections = {} # Holds show-name to show_id mapping
self.show_not_found = False
self.not_found = False
self.config = {}
@ -575,6 +579,9 @@ class Tvdb:
session.headers.update({'Accept-Language': language})
resp = None
if re.search(re.escape(self.config['url_seriesInfo']).replace('%s', '.*'), url):
self.show_not_found = False
self.not_found = False
try:
resp = getURL(url.strip(), params=params, session=session, json=True, raise_status_code=True,
raise_exceptions=True)
@ -583,6 +590,10 @@ class Tvdb:
# token expired, get new token, raise error to retry
sickbeard.THETVDB_V2_API_TOKEN = self.get_new_token()
raise tvdb_tokenexpired
elif 404 == e.response.status_code:
if re.search(re.escape(self.config['url_seriesInfo']).replace('%s', '.*'), url):
self.show_not_found = True
self.not_found = True
elif 404 != e.response.status_code:
raise tvdb_error
except (StandardError, Exception):

View file

@ -27,7 +27,7 @@ from sickbeard import encodingKludge as ek
from sickbeard.name_parser.parser import NameParser, InvalidNameException, InvalidShowException
MIN_DB_VERSION = 9 # oldest db version we support migrating from
MAX_DB_VERSION = 20004
MAX_DB_VERSION = 20005
class MainSanityCheck(db.DBSanityCheck):
@ -38,6 +38,7 @@ class MainSanityCheck(db.DBSanityCheck):
self.fix_orphan_episodes()
self.fix_unaired_episodes()
self.fix_scene_exceptions()
self.fix_orphan_not_found_show()
def fix_duplicate_shows(self, column='indexer_id'):
@ -169,6 +170,13 @@ class MainSanityCheck(db.DBSanityCheck):
logger.log('Fixing invalid scene exceptions')
self.connection.action('UPDATE scene_exceptions SET season = -1 WHERE season = "null"')
def fix_orphan_not_found_show(self):
sql_result = self.connection.action('DELETE FROM tv_shows_not_found WHERE NOT EXISTS (SELECT NULL FROM '
'tv_shows WHERE tv_shows_not_found.indexer == tv_shows.indexer AND '
'tv_shows_not_found.indexer_id == tv_shows.indexer_id)')
if sql_result.rowcount:
logger.log('Fixed orphaned not found shows')
# ======================
# = Main DB Migrations =
# ======================
@ -1220,3 +1228,16 @@ class ChangeMapIndexer(db.SchemaUpgrade):
self.setDBVersion(20004)
return self.checkDBVersion()
# 20004 -> 20005
class AddShowNotFoundCounter(db.SchemaUpgrade):
def execute(self):
if not self.hasTable('tv_shows_not_found'):
logger.log(u'Adding table tv_shows_not_found')
db.backup_database('sickbeard.db', self.checkDBVersion())
self.connection.action('CREATE TABLE tv_shows_not_found (indexer NUMERIC NOT NULL, indexer_id NUMERIC NOT NULL, fail_count NUMERIC NOT NULL DEFAULT 0, last_check NUMERIC NOT NULL, last_success NUMERIC, PRIMARY KEY (indexer_id, indexer))')
self.setDBVersion(20005)
return self.checkDBVersion()

View file

@ -453,7 +453,8 @@ def MigrationCode(myDB):
20000: sickbeard.mainDB.DBIncreaseTo20001,
20001: sickbeard.mainDB.AddTvShowOverview,
20002: sickbeard.mainDB.AddTvShowTags,
20003: sickbeard.mainDB.ChangeMapIndexer
20003: sickbeard.mainDB.ChangeMapIndexer,
20004: sickbeard.mainDB.AddShowNotFoundCounter
# 20002: sickbeard.mainDB.AddCoolSickGearFeature3,
}

View file

@ -52,6 +52,7 @@ from sickbeard import postProcessor
from sickbeard import subtitles
from sickbeard import history
from sickbeard import network_timezones
from sickbeard.sbdatetime import sbdatetime
from sickbeard.blackandwhitelist import BlackAndWhiteList
from sickbeard.indexermapper import del_mapping, save_mapping, MapStatus
from sickbeard.generic_queue import QueuePriorities
@ -64,6 +65,8 @@ from common import DOWNLOADED, SNATCHED, SNATCHED_PROPER, SNATCHED_BEST, ARCHIVE
from common import NAMING_DUPLICATE, NAMING_EXTEND, NAMING_LIMITED_EXTEND, NAMING_SEPARATED_REPEAT, \
NAMING_LIMITED_EXTEND_E_PREFIXED
concurrent_show_not_found_days = 7
show_not_found_retry_days = 7
def dirty_setter(attr_name, types=None):
def wrapper(self, val):
@ -114,6 +117,8 @@ class TVShow(object):
self._overview = ''
self._tag = ''
self._mapped_ids = {}
self._not_found_count = -1
self._last_found_on_indexer = -1
self.dirty = True
@ -160,6 +165,53 @@ class TVShow(object):
overview = property(lambda self: self._overview, dirty_setter('_overview'))
tag = property(lambda self: self._tag, dirty_setter('_tag'))
def _helper_load_failed_db(self):
if self._not_found_count == -1 or self._last_found_on_indexer == -1:
myDB = db.DBConnection()
results = myDB.select('SELECT fail_count, last_success FROM tv_shows_not_found WHERE indexer = ? AND indexer_id = ?',
[self.indexer, self.indexerid])
if results:
self._not_found_count = helpers.tryInt(results[0]['fail_count'])
self._last_found_on_indexer = helpers.tryInt(results[0]['last_success'])
else:
self._not_found_count = 0
self._last_found_on_indexer = 0
@property
def not_found_count(self):
self._helper_load_failed_db()
return self._not_found_count
@not_found_count.setter
def not_found_count(self, v):
self._not_found_count = v
@property
def last_found_on_indexer(self):
self._helper_load_failed_db()
return (self._last_found_on_indexer, self.last_update_indexer)[self._last_found_on_indexer <= 0]
def inc_not_found_count(self):
myDB = db.DBConnection()
results = myDB.select('SELECT fail_count, last_check, last_success FROM tv_shows_not_found WHERE indexer = ? AND indexer_id = ?',
[self.indexer, self.indexerid])
days = (show_not_found_retry_days - 1, 0)[self.not_found_count <= concurrent_show_not_found_days]
if not results or datetime.datetime.fromtimestamp(helpers.tryInt(results[0]['last_check'])) + datetime.timedelta(days=days, hours=18) < datetime.datetime.now():
if self.not_found_count <= 0:
last_success = self.last_update_indexer
else:
last_success = helpers.tryInt(results[0]['last_success'], self.last_update_indexer)
self._last_found_on_indexer = last_success
self.not_found_count += 1
myDB.upsert('tv_shows_not_found', {'fail_count': self.not_found_count, 'last_check': sbdatetime.now().totimestamp(default=0), 'last_success': last_success},
{'indexer': self.indexer, 'indexer_id': self.indexerid})
def reset_not_found_count(self):
if self.not_found_count > 0:
self._not_found_count = 0
myDB = db.DBConnection()
myDB.action('DELETE FROM tv_shows_not_found WHERE indexer = ? AND indexer_id = ?', [self.indexer, self.indexerid])
@property
def ids(self):
if not self._mapped_ids:
@ -327,6 +379,12 @@ class TVShow(object):
logger.log('Status missing for showid: [%s] with status: [%s]' %
(cur_indexerid, self.status), logger.DEBUG)
last_update_indexer = datetime.date.fromordinal(self.last_update_indexer)
# if show was not found for 1 week, only retry to update once a week
if concurrent_show_not_found_days < self.not_found_count and (update_date - last_update_indexer) < datetime.timedelta(days=show_not_found_retry_days):
return False
myDB = db.DBConnection()
sql_result = myDB.mass_action(
[['SELECT airdate FROM [tv_episodes] WHERE showid = ? AND season > "0" ORDER BY season DESC, episode DESC LIMIT 1', [cur_indexerid]],
@ -336,8 +394,6 @@ class TVShow(object):
last_airdate = datetime.date.fromordinal(sql_result[1][0]['airdate']) if sql_result and sql_result[1] else datetime.date.fromordinal(1)
last_update_indexer = datetime.date.fromordinal(self.last_update_indexer)
# if show is not 'Ended' and last episode aired less then 460 days ago or don't have an airdate for the last episode always update (status 'Continuing' or '')
update_days_limit = 2013
ended_limit = datetime.timedelta(days=update_days_limit)
@ -921,8 +977,13 @@ class TVShow(object):
myEp = t[self.indexerid, False]
if None is myEp:
logger.log('Show [%s] not found (maybe even removed?)' % self.name, logger.WARNING)
if hasattr(t, 'show_not_found') and t.show_not_found:
self.inc_not_found_count()
logger.log('Show [%s] not found (maybe even removed?)' % self.name, logger.WARNING)
else:
logger.log('Show data [%s] not found' % self.name, logger.WARNING)
return False
self.reset_not_found_count()
try:
self.name = myEp['seriesname'].strip()
@ -1066,7 +1127,8 @@ class TVShow(object):
["DELETE FROM scene_numbering WHERE indexer_id = ? AND indexer = ?", [self.indexerid, self.indexer]],
["DELETE FROM whitelist WHERE show_id = ?", [self.indexerid]],
["DELETE FROM blacklist WHERE show_id = ?", [self.indexerid]],
["DELETE FROM indexer_mapping WHERE indexer_id = ? AND indexer = ?", [self.indexerid, self.indexer]]]
["DELETE FROM indexer_mapping WHERE indexer_id = ? AND indexer = ?", [self.indexerid, self.indexer]],
["DELETE FROM tv_shows_not_found WHERE indexer = ? AND indexer_id = ?", [self.indexer, self.indexerid]]]
myDB = db.DBConnection()
myDB.mass_action(sql_l)
@ -1229,13 +1291,15 @@ class TVShow(object):
[self.indexer, self.indexerid, old_indexer, old_indexerid]],
['UPDATE whitelist SET show_id = ? WHERE show_id = ?', [self.indexerid, old_indexerid]],
['UPDATE xem_refresh SET indexer = ?, indexer_id = ? WHERE indexer = ? AND indexer_id = ?',
[self.indexer, self.indexerid, old_indexer, old_indexerid]]])
[self.indexer, self.indexerid, old_indexer, old_indexerid]],
['DELETE FROM tv_shows_not_found WHERE indexer = ? AND indexer_id = ?', [old_indexer, old_indexerid]]])
myFailedDB = db.DBConnection('failed.db')
myFailedDB.action('UPDATE history SET showid = ? WHERE showid = ?', [self.indexerid, old_indexerid])
del_mapping(old_indexer, old_indexerid)
self.ids[old_indexer]['status'] = MapStatus.NONE
self.ids[self.indexer]['status'] = MapStatus.SOURCE
self.ids[self.indexer]['id'] = self.indexerid
save_mapping(self)
name_cache.remove_from_namecache(old_indexerid)
@ -1266,6 +1330,7 @@ class TVShow(object):
sickbeard.save_config()
name_cache.buildNameCache(self)
self.reset_not_found_count()
# force the update
try:

View file

@ -46,7 +46,7 @@ from sickbeard.providers import newznab, rsstorrent
from sickbeard.common import Quality, Overview, statusStrings, qualityPresetStrings
from sickbeard.common import SNATCHED, UNAIRED, IGNORED, ARCHIVED, WANTED, FAILED, SKIPPED, DOWNLOADED, SNATCHED_BEST, SNATCHED_PROPER
from sickbeard.common import SD, HD720p, HD1080p, UHD2160p
from sickbeard.exceptions import ex
from sickbeard.exceptions import ex, MultipleShowObjectsException
from sickbeard.helpers import has_image_ext, remove_article, starify
from sickbeard.indexers.indexer_config import INDEXER_TVDB, INDEXER_TVRAGE, INDEXER_TRAKT
from sickbeard.scene_numbering import get_scene_numbering, set_scene_numbering, get_scene_numbering_for_show, \
@ -57,6 +57,7 @@ from sickbeard.browser import foldersAtPath
from sickbeard.blackandwhitelist import BlackAndWhiteList, short_group_names
from sickbeard.search_backlog import FORCED_BACKLOG
from sickbeard.indexermapper import MapStatus, save_mapping, map_indexers_to_show
from sickbeard.tv import show_not_found_retry_days, concurrent_show_not_found_days
from tornado import gen
from tornado.web import RequestHandler, StaticFileHandler, authenticated
from lib import adba
@ -1318,6 +1319,14 @@ class Home(MainHandler):
elif sickbeard.showQueueScheduler.action.isInSubtitleQueue(showObj): # @UndefinedVariable
show_message = 'This show is queued and awaiting subtitles download.'
if 0 < showObj.not_found_count:
last_found = ('', ' since %s' % sbdatetime.sbdatetime.fromordinal(
showObj.last_found_on_indexer).sbfdate())[1 < showObj.last_found_on_indexer]
show_message = (
'The master ID of this show has been abandoned%s, ' % last_found
+ '<a href="%s/home/editShow?show=%s&tvsrc=0&srcid=%s#core-component-group3">replace it here</a>' % (
sickbeard.WEB_ROOT, show, show)
+ ('', '<br>%s' % show_message)[0 < len(show_message)])
t.force_update = 'home/updateShow?show=%d&amp;force=1&amp;web=1' % showObj.indexerid
if not sickbeard.showQueueScheduler.action.isBeingAdded(showObj): # @UndefinedVariable
if not sickbeard.showQueueScheduler.action.isBeingUpdated(showObj): # @UndefinedVariable
@ -1592,7 +1601,8 @@ class Home(MainHandler):
return {'Success': 'Switched to new TV info source'}
def saveMapping(self, show, **kwargs):
show_obj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(show))
show = helpers.tryInt(show)
show_obj = sickbeard.helpers.findCertainShow(sickbeard.showList, show)
response = {}
if not show_obj:
return json.dumps(response)
@ -1632,10 +1642,22 @@ class Home(MainHandler):
else:
ui.notifications.message('Mappings unchanged, not saving.')
master_ids = [show] + [kwargs.get(x) for x in 'indexer', 'mindexerid', 'mindexer']
if all([helpers.tryInt(x) > 0 for x in master_ids]):
master_ids += [bool(helpers.tryInt(kwargs.get(x))) for x in 'paused', 'markwanted']
response = {'switch': self.switchIndexer(*master_ids), 'mid': kwargs['mindexerid']}
master_ids = [show] + [helpers.tryInt(kwargs.get(x)) for x in 'indexer', 'mindexerid', 'mindexer']
if all([x > 0 for x in master_ids]) and sickbeard.indexerApi(kwargs['mindexer']).config.get('active') and \
not sickbeard.indexerApi(kwargs['mindexer']).config.get('defunct') and \
not sickbeard.indexerApi(kwargs['mindexer']).config.get('mapped_only') and \
(helpers.tryInt(kwargs['mindexer']) != helpers.tryInt(kwargs['indexer']) or
helpers.tryInt(kwargs['mindexerid']) != show):
try:
new_show_obj = helpers.find_show_by_id(sickbeard.showList, {helpers.tryInt(kwargs['mindexer']): helpers.tryInt(kwargs['mindexerid'])},no_mapped_ids=False)
if not new_show_obj or (new_show_obj.indexer == show_obj.indexer and new_show_obj.indexerid == show_obj.indexerid):
master_ids += [bool(helpers.tryInt(kwargs.get(x))) for x in 'paused', 'markwanted']
response = {'switch': self.switchIndexer(*master_ids), 'mid': kwargs['mindexerid']}
else:
ui.notifications.message('Master ID unchanged, because show from %s with ID: %s exists in DB.' %
(sickbeard.indexerApi(kwargs['mindexer']).name, kwargs['mindexerid']))
except MultipleShowObjectsException:
pass
response.update({
'map': {k: {r: w for r, w in v.iteritems() if r != 'date'} for k, v in show_obj.ids.iteritems()}
@ -1730,6 +1752,10 @@ class Home(MainHandler):
t = PageTemplate(headers=self.request.headers, file='editShow.tmpl')
t.submenu = self.HomeMenu()
t.expand_ids = all([kwargs.get('tvsrc'), kwargs.get('srcid')])
t.tvsrc = int(kwargs.get('tvsrc', 0))
t.srcid = kwargs.get('srcid')
myDB = db.DBConnection()
t.seasonResults = myDB.select(
'SELECT DISTINCT season FROM tv_episodes WHERE showid = ? ORDER BY season asc', [showObj.indexerid])
@ -1758,6 +1784,20 @@ class Home(MainHandler):
self.fanart_tmpl(t)
t.num_ratings = len(sickbeard.FANART_RATINGS.get(str(t.show.indexerid), {}))
t.unlock_master_id = 0 < showObj.not_found_count
t.showname_enc = urllib.quote_plus(showObj.name.encode('utf-8'))
show_message = ''
if 0 < showObj.not_found_count:
# noinspection PyUnresolvedReferences
last_found = ('', ' since %s' % sbdatetime.sbdatetime.fromordinal(
showObj.last_found_on_indexer).sbfdate())[1 < showObj.last_found_on_indexer]
show_message = 'The master ID of this show has been abandoned%s<br>search for ' % last_found + \
'a replacement in the "<b>Related show IDs</b>" section of the "<b>Other</b>" tab'
t.show_message = show_message
return t.respond()
flatten_folders = config.checkbox_to_value(flatten_folders)
@ -3595,11 +3635,18 @@ class NewHomeAddShows(Home):
def addNewShow(self, whichSeries=None, indexerLang='en', rootDir=None, defaultStatus=None,
quality_preset=None, anyQualities=None, bestQualities=None, flatten_folders=None, subtitles=None,
fullShowPath=None, other_shows=None, skipShow=None, providedIndexer=None, anime=None,
scene=None, blacklist=None, whitelist=None, wanted_begin=None, wanted_latest=None, tag=None):
scene=None, blacklist=None, whitelist=None, wanted_begin=None, wanted_latest=None, tag=None,
return_to=None, cancel_form=None):
"""
Receive tvdb id, dir, and other options and create a show from them. If extra show dirs are
provided then it forwards back to new_show, if not it goes to /home.
"""
if None is not return_to:
indexer, void, indexer_id, show_name = self.split_extra_show(whichSeries)
if bool(helpers.tryInt(cancel_form)):
indexer = indexer or providedIndexer or '1'
indexer_id = re.findall('show=([\d]+)', return_to)[0]
return self.redirect(return_to % (indexer, indexer_id))
# grab our list of other dirs if given
if not other_shows:
@ -4561,6 +4608,18 @@ class showProcesses(Manage):
t.showList = sickbeard.showList
t.ShowUpdateRunning = sickbeard.showQueueScheduler.action.isShowUpdateRunning() or sickbeard.showUpdateScheduler.action.amActive
myDb = db.DBConnection(row_type='dict')
sql_results = myDb.select('SELECT n.indexer, n.indexer_id, n.last_success, s.show_name FROM tv_shows_not_found as n INNER JOIN tv_shows as s ON (n.indexer == s.indexer AND n.indexer_id == s.indexer_id)')
for s in sql_results:
date = helpers.tryInt(s['last_success'])
s['last_success'] = ('never', sbdatetime.sbdatetime.fromordinal(date).sbfdate())[date > 1]
defunct_indexer = [i for i in sickbeard.indexerApi().all_indexers if sickbeard.indexerApi(i).config.get('defunct')]
sql_r = None
if defunct_indexer:
sql_r = myDb.select('SELECT indexer, indexer_id, show_name FROM tv_shows WHERE indexer IN (%s)' % ','.join(['?'] * len(defunct_indexer)), defunct_indexer)
t.DefunctIndexer = sql_r
t.NotFoundShows = sql_results
t.submenu = self.ManageMenu('Processes')
return t.respond()