Added per-show option that allows you to set the default status that gets applied to new and missing show episodes, default is SKIPPED

Fixed issues for failed/manual snatches always failing to complete
This commit is contained in:
echel0n 2014-11-23 01:17:37 -08:00
parent 81128f6cf2
commit cf35e9778c
6 changed files with 126 additions and 91 deletions

View File

@ -198,19 +198,6 @@
<div id="summary">
<table class="summaryTable pull-left">
#if $show.network and $show.airs:
<tr><td class="showLegend">Originally Airs: </td><td>$show.airs #if not $network_timezones.test_timeformat($show.airs) then " <font color='#FF0000'><b>(invalid Timeformat)</b></font> " else ""# on $show.network</td></tr>
#else if $show.network:
<tr><td class="showLegend">Originally Airs: </td><td>$show.network</td></tr>
#else if $show.airs:
<tr><td class="showLegend">Originally Airs: </td><td>>$show.airs #if not $network_timezones.test_timeformat($show.airs) then " <font color='#FF0000'><b>(invalid Timeformat)</b></font> " else ""#</td></tr>
#end if
<tr><td class="showLegend">Status: </td><td>$show.status</td></tr>
#if $showLoc[1]:
<tr><td class="showLegend">Location: </td><td>$showLoc[0]</td></tr>
#else:
<tr><td class="showLegend"><span style="color: red;">Location: </span></td><td><span style="color: red;">$showLoc[0]</span> (dir is missing)</td></tr>
#end if
#set $anyQualities, $bestQualities = $Quality.splitQuality(int($show.quality))
<tr><td class="showLegend">Quality: </td><td>
#if $show.quality in $qualityPresets:
@ -222,6 +209,21 @@
#if $bestQualities:
<i>Replace with:</i> <%=", ".join([Quality.qualityStrings[x] for x in sorted(bestQualities)])%>
#end if
#end if
#if $show.network and $show.airs:
<tr><td class="showLegend">Originally Airs: </td><td>$show.airs #if not $network_timezones.test_timeformat($show.airs) then " <font color='#FF0000'><b>(invalid Timeformat)</b></font> " else ""# on $show.network</td></tr>
#else if $show.network:
<tr><td class="showLegend">Originally Airs: </td><td>$show.network</td></tr>
#else if $show.airs:
<tr><td class="showLegend">Originally Airs: </td><td>>$show.airs #if not $network_timezones.test_timeformat($show.airs) then " <font color='#FF0000'><b>(invalid Timeformat)</b></font> " else ""#</td></tr>
#end if
<tr><td class="showLegend">Show Status: </td><td>$show.status</td></tr>
<tr><td class="showLegend">Default EP Status: </td><td>$statusStrings[$show.default_ep_status]</td></tr>
#if $showLoc[1]:
<tr><td class="showLegend">Location: </td><td>$showLoc[0]</td></tr>
#else:
<tr><td class="showLegend"><span style="color: red;">Location: </span></td><td><span style="color: red;">$showLoc[0]</span> (dir is missing)</td></tr>
#end if
<tr><td class="showLegend">Scene Name:</td><td>#if $show.exceptions then $exceptions_string else $show.name#</td></tr>
@ -263,14 +265,13 @@
#end if
</table>
</div>
</div>
</div>
<div class="clearfix"></div>
<div class="pull-left" style="padding-bottom: 10px;">
Change selected episodes to
<div class="pull-left" >
Change selected episodes to:</br>
<select id="statusSelect" class="form-control form-control-inline input-sm">
#for $curStatus in [$WANTED, $SKIPPED, $ARCHIVED, $IGNORED, $FAILED] + sorted($Quality.DOWNLOADED):
#if $curStatus == $DOWNLOADED:
@ -284,6 +285,8 @@
<input class="btn btn-inline" type="button" id="changeStatus" value="Go" />
</div>
</br>
<div class="pull-right clearfix" id="checkboxControls">
<div style="padding-bottom: 5px;">
<label for="wanted"><span class="wanted"><input type="checkbox" id="wanted" checked="checked" /> Wanted: <b>$epCounts[$Overview.WANTED]</b></span></label>
@ -298,7 +301,6 @@
<button class="btn btn-xs clearAll">Clear All</button>
</div>
</div>
<br />
<table class="sickbeardTable display_show" cellspacing="0" border="0" cellpadding="0">

View File

@ -1,6 +1,7 @@
#import sickbeard
#import lib.adba as adba
#from sickbeard import common
#from sickbeard.common import *
#from sickbeard import exceptions
#from sickbeard import scene_exceptions
#from sickbeard.blackandwhitelist import *
@ -63,35 +64,21 @@
<form action="editShow" method="post">
<input type="hidden" name="show" value="$show.indexerid" />
<b>Location:</b> <input type="text" name="location" id="location" value="$show._location" class="form-control form-control-inline input-sm input350" /><br />
<br />
<b>Quality:</b>
#set $qualities = $common.Quality.splitQuality(int($show.quality))
#set global $anyQualities = $qualities[0]
#set global $bestQualities = $qualities[1]
#include $os.path.join($sickbeard.PROG_DIR, "gui/slick/interfaces/default/inc_qualityChooser.tmpl")
<b>Location:</b></br>
<input type="text" name="location" id="location" value="$show._location" class="form-control form-control-inline input-sm input350" /><br />
<br />
#if $anyQualities + $bestQualities
<b>Archive on first match: </b>
<input type="checkbox" name="archive_firstmatch" #if $show.archive_firstmatch == 1 then "checked=\"checked\"" else ""# /><br>
(check this to have the episode archived after the first best match is found from your archive quality list)
<br />
<br />
#end if
<b>Scene Exception:</b>
<input type="text" id="SceneName" class="form-control form-control-inline input-sm input200">
<b>Scene Exception:</b><br />
<input type="text" id="SceneName" class="form-control form-control-inline input-sm input200">
<input class="btn btn-inline" type="button" value="Add" id="addSceneName"><br />
<div id="SceneException" >
<div>
<p>This will <b>affect the episode show search</b> on nzb and torrent provider.<br />
This list overrides the original name, it doesn't append to it.<br />
</p>
</div>
</div>
<div class="pull-left" style="text-align:center;">
<h4>Exceptions List</h4>
<select id="exceptions_list" name="exceptions_list" multiple="multiple" style="min-width:10em;" >
@ -99,54 +86,84 @@
<option value="$cur_exception">$cur_exception</option>
#end for
</select>
<div>
<div>
<input id="removeSceneName" value="Remove" class="btn float-left" type="button" style="margin-top: 10px;"/>
</div>
</div>
<br />
</div>
</div>
</div>
<div class="clearfix"></div>
<br />
<b>Info Language:</b> <select name="indexerLang" id="indexerLangSelect" class="form-control form-control-inline input-sm"></select><br />
Note: This will only affect the language of the retrieved metadata file contents and episode filenames.<br />
This <b>DOES NOT</b> allow SickRage to download non-english TV episodes!<br />
<b>Quality:</b><br />
#set $qualities = $common.Quality.splitQuality(int($show.quality))
#set global $anyQualities = $qualities[0]
#set global $bestQualities = $qualities[1]
#include $os.path.join($sickbeard.PROG_DIR, "gui/slick/interfaces/default/inc_qualityChooser.tmpl")
<br />
<b>Flatten files (no folders):</b> <input type="checkbox" name="flatten_folders" #if $show.flatten_folders == 1 and not $sickbeard.NAMING_FORCE_FOLDERS then "checked=\"checked\"" else ""# #if $sickbeard.NAMING_FORCE_FOLDERS then "disabled=\"disabled\"" else ""#/><br /><br />
<b>Paused:</b> <input type="checkbox" name="paused" #if $show.paused == 1 then "checked=\"checked\"" else ""# /><br /><br />
<b>Subtitles:</b> <input type="checkbox" name="subtitles"#if $show.subtitles == 1 and $sickbeard.USE_SUBTITLES then " checked=\"checked\"" else ""##if not $sickbeard.USE_SUBTITLES then " disabled=\"disabled\"" else ""#/><br /><br />
<b>Default Episode Status:</b><br />
(this will set a default status to be applied to any newly added episodes)<br />
<select name="defaultEpStatus" id="defaultEpStatusSelect" class="form-control form-control-inline input-sm">
#for $curStatus in [$WANTED, $SKIPPED, $ARCHIVED, $IGNORED]:
<option value="$curStatus">$statusStrings[$curStatus]</option>
#end for
</select><br />
<br />
<b>Info Language:</b><br />
(this will only affect the language of the retrieved metadata file contents and episode filenames)<br />
<select name="indexerLang" id="indexerLangSelect" class="form-control form-control-inline input-sm"></select><br />
<br />
<b>Flatten files (no folders):</b> <input type="checkbox" name="flatten_folders" #if $show.flatten_folders == 1 and not $sickbeard.NAMING_FORCE_FOLDERS then "checked=\"checked\"" else ""# #if $sickbeard.NAMING_FORCE_FOLDERS then "disabled=\"disabled\"" else ""#/><br />
<b>Paused:</b> <input type="checkbox" name="paused" #if $show.paused == 1 then "checked=\"checked\"" else ""# /><br />
<b>Subtitles:</b> <input type="checkbox" name="subtitles"#if $show.subtitles == 1 and $sickbeard.USE_SUBTITLES then " checked=\"checked\"" else ""##if not $sickbeard.USE_SUBTITLES then " disabled=\"disabled\"" else ""#/><br />
<br/>
<b>Scene Numbering: </b>
<input type="checkbox" name="scene" #if $show.scene == 1 then "checked=\"checked\"" else ""# /><br/>
(check this if you wish to search by scene numbering, uncheck to search by indexer numbering)
<br/><br/>
<b>Air by date: </b>
(check this if you wish to search by scene numbering, uncheck to search by indexer numbering)<br/>
<br/>
<b>Air by date: </b>
<input type="checkbox" name="air_by_date" #if $show.air_by_date == 1 then "checked=\"checked\"" else ""# /><br />
(check this if the show is released as Show.03.02.2010 rather than Show.S02E03)
<br /><br />
(check this if the show is released as Show.03.02.2010 rather than Show.S02E03)<br />
<br />
<b>Sports: </b>
<input type="checkbox" name="sports" #if $show.sports == 1 then "checked=\"checked\"" else ""# /><br />
(check this if the show is a sporting or MMA event)
<br /><br />
(check this if the show is a sporting or MMA event)<br />
<br />
<b>Anime: </b>
<input type="checkbox" name="anime" #if $show.is_anime then "CHECKED" else ""#><br />
(check this if the show is released as Show.265 rather than Show.S02E03, this show is an anime)
<br /><br />
(check this if the show is released as Show.265 rather than Show.S02E03, this show is an anime)<br />
<br />
<b>DVD Order: </b>
<input type="checkbox" name="dvdorder" #if $show.dvdorder == 1 then "checked=\"checked\"" else ""# /><br/>
(check this if you wish to use the DVD order instead of the Airing order)
<br/><br/>
<b>Ignored Words:</b> <input type="text" name="rls_ignore_words" id="rls_ignore_words" value="$show.rls_ignore_words" class="form-control form-control-inline input-sm input350" /><br />
Results with any of these words in the title will be filtered out <br />
Separate words with a comma, e.g. "word1,word2,word3"
<br /><br />
#if $anyQualities + $bestQualities
<b>Archive on first match:</b>
<input type="checkbox" name="archive_firstmatch" #if $show.archive_firstmatch == 1 then "checked=\"checked\"" else ""# /><br>
(check this to have the episode archived after the first best match is found from your archive quality list)</br>
<br />
#end if
<b>Required Words:</b> <input type="text" name="rls_require_words" id="rls_require_words" value="$show.rls_require_words" class="form-control form-control-inline input-sm input350" /><br />
<b>Ignored Words:</b></br>
<input type="text" name="rls_ignore_words" id="rls_ignore_words" value="$show.rls_ignore_words" class="form-control form-control-inline input-sm input350" /><br />
Results with any of these words in the title will be filtered out<br />
Separate words with a comma, e.g. "word1,word2,word3"<br />
<br />
<b>Required Words:</b></br>
<input type="text" name="rls_require_words" id="rls_require_words" value="$show.rls_require_words" class="form-control form-control-inline input-sm input350" /><br />
Results without one of these words in the title will be filtered out <br />
Separate words with a comma, e.g. "word1,word2,word3"
<br /><br />
Separate words with a comma, e.g. "word1,word2,word3"<br />
<br />
#if $show.is_anime:
#from sickbeard.blackandwhitelist import *

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 = 40
MAX_DB_VERSION = 41
class MainSanityCheck(db.DBSanityCheck):
def check(self):
@ -915,3 +915,15 @@ class AddVersionToTvEpisodes(AddIndexerMapping):
self.addColumn("history", "version", "NUMERIC", "-1")
self.incDBVersion()
class AddDefaultEpStatusToTvShows(AddVersionToTvEpisodes):
def test(self):
return self.checkDBVersion() >= 41
def execute(self):
backupDatabase(41)
logger.log(u"Adding column default_ep_status to tv_shows")
self.addColumn("tv_shows", "default_ep_status", "TEXT", "")
self.incDBVersion()

View File

@ -293,6 +293,10 @@ class QueueItemAdd(ShowQueueItem):
self.show.scene = self.scene if self.scene != None else sickbeard.SCENE_DEFAULT
self.show.paused = self.paused if self.paused != None else False
# set up default new/missing episode status
self.show.default_ep_status = self.default_status
logger.log(u"Setting all episodes to the specified default status: " + str(self.show.default_ep_status))
# be smartish about this
if self.show.genre and "talk show" in self.show.genre.lower():
self.show.air_by_date = 1
@ -364,17 +368,10 @@ class QueueItemAdd(ShowQueueItem):
logger.log(u"Error searching dir for episodes: " + ex(e), logger.ERROR)
logger.log(traceback.format_exc(), logger.DEBUG)
# if they gave a custom status then change all the eps to it
if self.default_status != SKIPPED:
logger.log(u"Setting all episodes to the specified default status: " + str(self.default_status))
myDB = db.DBConnection()
myDB.action("UPDATE tv_episodes SET status = ? WHERE status = ? AND showid = ? AND season != 0",
[self.default_status, SKIPPED, self.show.indexerid])
# if they started with WANTED eps then run the backlog
if self.default_status == WANTED:
# if they set default ep status to WANTED then run the backlog to search for episodes
if self.show.default_ep_status == WANTED:
logger.log(u"Launching backlog for this show since its episodes are WANTED")
sickbeard.backlogSearchScheduler.action.searchBacklog([self.show]) #@UndefinedVariable
sickbeard.backlogSearchScheduler.action.searchBacklog([self.show])
self.show.writeMetadata()
self.show.updateMetadata()
@ -539,17 +536,21 @@ class QueueItemUpdate(ShowQueueItem):
self.show.indexer).name + ", the show info will not be refreshed: " + ex(e), logger.ERROR)
IndexerEpList = None
foundMissingEps = False
if IndexerEpList == None:
logger.log(u"No data returned from " + sickbeard.indexerApi(
self.show.indexer).name + ", unable to update this show", logger.ERROR)
else:
# for each ep we found on TVDB delete it from the DB list
# for each ep we found on the Indexer delete it from the DB list
for curSeason in IndexerEpList:
for curEpisode in IndexerEpList[curSeason]:
logger.log(u"Removing " + str(curSeason) + "x" + str(curEpisode) + " from the DB list",
logger.DEBUG)
if curSeason in DBEpList and curEpisode in DBEpList[curSeason]:
del DBEpList[curSeason][curEpisode]
else:
# found missing episodes
foundMissingEps = True
# for the remaining episodes in the DB list just delete them from the DB
for curSeason in DBEpList:
@ -562,8 +563,12 @@ class QueueItemUpdate(ShowQueueItem):
except exceptions.EpisodeDeletedException:
pass
sickbeard.showQueueScheduler.action.refreshShow(self.show, self.force)
# if they set default ep status to WANTED then run the backlog
if foundMissingEps and self.show.default_ep_status == WANTED:
logger.log(u"Launching backlog for this show since we found missing episodes")
sickbeard.backlogSearchScheduler.action.searchBacklog([self.show])
sickbeard.showQueueScheduler.action.refreshShow(self.show, self.force)
class QueueItemForceUpdate(QueueItemUpdate):
def __init__(self, show=None):

View File

@ -97,7 +97,7 @@ class TVShow(object):
self._scene = 0
self._rls_ignore_words = ""
self._rls_require_words = ""
self._default_ep_status = ""
self.dirty = True
self._location = ""
@ -139,6 +139,7 @@ class TVShow(object):
scene = property(lambda self: self._scene, dirty_setter("_scene"))
rls_ignore_words = property(lambda self: self._rls_ignore_words, dirty_setter("_rls_ignore_words"))
rls_require_words = property(lambda self: self._rls_require_words, dirty_setter("_rls_require_words"))
default_ep_status = property(lambda self: self._default_ep_status, dirty_setter("_default_ep_status"))
@property
def is_anime(self):
@ -577,7 +578,6 @@ class TVShow(object):
myDB = db.DBConnection()
myDB.mass_action(sql_l)
# Done updating save last update date
self.last_update_indexer = datetime.date.today().toordinal()
self.saveToDB()
@ -770,9 +770,11 @@ class TVShow(object):
self.status = sqlResults[0]["status"]
if not self.status:
self.status = ""
self.airs = sqlResults[0]["airs"]
if not self.airs:
self.airs = ""
self.startyear = sqlResults[0]["startyear"]
if not self.startyear:
self.startyear = 0
@ -825,6 +827,8 @@ class TVShow(object):
self.rls_ignore_words = sqlResults[0]["rls_ignore_words"]
self.rls_require_words = sqlResults[0]["rls_require_words"]
self.default_ep_status = int(sqlResults[0]["default_ep_status"])
if not self.imdbid:
self.imdbid = sqlResults[0]["imdb_id"]
@ -1156,7 +1160,8 @@ class TVShow(object):
"imdb_id": self.imdbid,
"last_update_indexer": self.last_update_indexer,
"rls_ignore_words": self.rls_ignore_words,
"rls_require_words": self.rls_require_words
"rls_require_words": self.rls_require_words,
"default_ep_status": self.default_ep_status
}
myDB = db.DBConnection()
@ -1741,9 +1746,9 @@ class TVEpisode(object):
if self.status == UNAIRED:
self.status = WANTED
# if we somehow are still UNKNOWN then just skip it
# if we somehow are still UNKNOWN then just use the shows defined default status
elif self.status == UNKNOWN:
self.status = SKIPPED
self.status = self.show.default_ep_status
else:
logger.log(
@ -2024,7 +2029,6 @@ class TVEpisode(object):
'%SN S%0SE%E',
'%SN S%SE%E',
'%SN S%0SE%0E'
]
strings = []
@ -2062,7 +2066,6 @@ class TVEpisode(object):
if len(self.relatedEps) == 0:
goodName = self.name
else:
goodName = ''

View File

@ -3833,7 +3833,7 @@ class Home(MainHandler):
flatten_folders=None, paused=None, directCall=False, air_by_date=None, sports=None, dvdorder=None,
indexerLang=None, subtitles=None, archive_firstmatch=None, rls_ignore_words=None,
rls_require_words=None, anime=None, blackWords=None, whiteWords=None, blacklist=None, whitelist=None,
scene=None):
scene=None, defaultEpStatus=None):
if show is None:
errString = "Invalid show ID: " + str(show)
@ -4007,6 +4007,7 @@ class Home(MainHandler):
showObj.dvdorder = dvdorder
showObj.rls_ignore_words = rls_ignore_words.strip()
showObj.rls_require_words = rls_require_words.strip()
showObj.default_ep_status = defaultEpStatus
# if we change location clear the db of episodes, change it, write to db, and rescan
if os.path.normpath(showObj._location) != os.path.normpath(location):
@ -4405,8 +4406,6 @@ class Home(MainHandler):
sickbeard.searchQueueScheduler.action.add_item(ep_queue_item) # @UndefinedVariable
if ep_queue_item.success:
return returnManualSearchResult(ep_queue_item)
if not ep_queue_item.started and ep_queue_item.success is None:
return json.dumps({'result': 'success'}) #I Actually want to call it queued, because the search hasnt been started yet!
if ep_queue_item.started and ep_queue_item.success is None:
@ -4422,10 +4421,11 @@ class Home(MainHandler):
episodes = []
currentManualSearchThreadsQueued = []
currentManualSearchThreadActive = []
finishedManualSearchThreadItems= []
finishedManualSearchThreadItems = []
# Queued Searches
currentManualSearchThreadsQueued = sickbeard.searchQueueScheduler.action.get_all_ep_from_queue(show)
# Running Searches
if (sickbeard.searchQueueScheduler.action.is_manualsearch_in_progress()):
currentManualSearchThreadActive = sickbeard.searchQueueScheduler.action.currentItem
@ -4492,8 +4492,6 @@ class Home(MainHandler):
return json.dumps({'show': show, 'episodes' : episodes})
#return json.dumps()
def getQualityClass(self, ep_obj):
# return the correct json value
@ -4617,8 +4615,6 @@ class Home(MainHandler):
ep_queue_item = search_queue.FailedQueueItem(ep_obj.show, [ep_obj])
sickbeard.searchQueueScheduler.action.add_item(ep_queue_item) # @UndefinedVariable
if ep_queue_item.success:
return returnManualSearchResult(ep_queue_item)
if not ep_queue_item.started and ep_queue_item.success is None:
return json.dumps({'result': 'success'}) #I Actually want to call it queued, because the search hasnt been started yet!
if ep_queue_item.started and ep_queue_item.success is None: