diff --git a/CHANGES.md b/CHANGES.md
index aa67d92c..55824c0a 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,4 +1,4 @@
-### 0.x.x (2015-xx-xx xx:xx:xx UTC)
+### 0.x.x (2015-xx-xx xx:xx:xx UTC)
* Change network names to only display on top line of Day by Day layout on Episode View
* Reposition country part of network name into the hover over in Day by Day layout
@@ -6,6 +6,7 @@
* Fix Backlog scheduler initialization and change backlog frequency from minutes to days
* Change to consolidate and tidy some provider code
* Fix restore table row colours on the Manage/Episode Status Management page
+* Add option "Search for unaired episodes" to config/Search Settings
### 0.8.3 (2015-04-25 08:48:00 UTC)
diff --git a/gui/slick/interfaces/default/config_search.tmpl b/gui/slick/interfaces/default/config_search.tmpl
index 6cb246dc..8576300c 100755
--- a/gui/slick/interfaces/default/config_search.tmpl
+++ b/gui/slick/interfaces/default/config_search.tmpl
@@ -100,6 +100,15 @@
+
+
+ Search for unaired episodes
+
+ >
+
+
+
+
Usenet retention
diff --git a/sickbeard/__init__.py b/sickbeard/__init__.py
index 267d39bd..4533c4a7 100755
--- a/sickbeard/__init__.py
+++ b/sickbeard/__init__.py
@@ -31,6 +31,7 @@ import sys
import os.path
import uuid
import base64
+import sickbeard
sys.path.append(os.path.abspath('../lib'))
from sickbeard import providers, metadata, config, webserveInit
from sickbeard.providers.generic import GenericProvider
@@ -225,6 +226,7 @@ MAX_BACKLOG_FREQUENCY = 35
MIN_UPDATE_FREQUENCY = 1
BACKLOG_DAYS = 7
+SEARCH_UNAIRED = False
ADD_SHOWS_WO_DIR = False
CREATE_MISSING_SHOW_DIRS = False
@@ -528,7 +530,7 @@ def initialize(consoleLogging=True):
USE_FAILED_DOWNLOADS, DELETE_FAILED, ANON_REDIRECT, LOCALHOST_IP, TMDB_API_KEY, DEBUG, PROXY_SETTING, PROXY_INDEXERS, \
AUTOPOSTPROCESSER_FREQUENCY, DEFAULT_AUTOPOSTPROCESSER_FREQUENCY, MIN_AUTOPOSTPROCESSER_FREQUENCY, \
ANIME_DEFAULT, NAMING_ANIME, USE_ANIDB, ANIDB_USERNAME, ANIDB_PASSWORD, ANIDB_USE_MYLIST, \
- ANIME_SPLIT_HOME, SCENE_DEFAULT, BACKLOG_DAYS, ANIME_TREAT_AS_HDTV, \
+ ANIME_SPLIT_HOME, SCENE_DEFAULT, BACKLOG_DAYS, SEARCH_UNAIRED, ANIME_TREAT_AS_HDTV, \
COOKIE_SECRET, USE_IMDB_INFO, DISPLAY_BACKGROUND, DISPLAY_BACKGROUND_TRANSPARENT, DISPLAY_ALL_SEASONS
if __INITIALIZED__:
@@ -736,6 +738,7 @@ def initialize(consoleLogging=True):
UPDATE_FREQUENCY = MIN_UPDATE_FREQUENCY
BACKLOG_DAYS = check_setting_int(CFG, 'General', 'backlog_days', 7)
+ SEARCH_UNAIRED = bool(check_setting_int(CFG, 'General', 'search_unaired', 0))
NZB_DIR = check_setting_str(CFG, 'Blackhole', 'nzb_dir', '')
TORRENT_DIR = check_setting_str(CFG, 'Blackhole', 'torrent_dir', '')
@@ -1170,13 +1173,15 @@ def initialize(consoleLogging=True):
cycleTime=update_interval,
threadName="RECENTSEARCHER",
run_delay=update_now if RECENTSEARCH_STARTUP
- else datetime.timedelta(minutes=5))
+ else datetime.timedelta(minutes=5),
+ prevent_cycle_run=sickbeard.searchQueueScheduler.action.is_recentsearch_in_progress)
backlogSearchScheduler = searchBacklog.BacklogSearchScheduler(searchBacklog.BacklogSearcher(),
cycleTime=datetime.timedelta(minutes=get_backlog_cycle_time()),
threadName="BACKLOG",
run_delay=update_now if BACKLOG_STARTUP
- else datetime.timedelta(minutes=10))
+ else datetime.timedelta(minutes=10),
+ prevent_cycle_run=sickbeard.searchQueueScheduler.action.is_standard_backlog_in_progress)
search_intervals = {'15m': 15, '45m': 45, '90m': 90, '4h': 4 * 60, 'daily': 24 * 60}
if CHECK_PROPERS_INTERVAL in search_intervals:
@@ -1495,6 +1500,7 @@ def save_config():
new_config['General']['metadata_kodi'] = METADATA_KODI
new_config['General']['backlog_days'] = int(BACKLOG_DAYS)
+ new_config['General']['search_unaired'] = int(SEARCH_UNAIRED)
new_config['General']['cache_dir'] = ACTUAL_CACHE_DIR if ACTUAL_CACHE_DIR else 'cache'
new_config['General']['root_dirs'] = ROOT_DIRS if ROOT_DIRS else ''
diff --git a/sickbeard/common.py b/sickbeard/common.py
index c47956e1..f95e8a1e 100644
--- a/sickbeard/common.py
+++ b/sickbeard/common.py
@@ -206,26 +206,26 @@ class Quality:
return Quality.UNKNOWN
if checkName(['(pdtv|hdtv|dsr|tvrip).(xvid|x264|h.?264)'], all) and not checkName(['(720|1080)[pi]'], all) \
- and not checkName(['hr.ws.pdtv.x264'], any):
+ and not checkName(['hr.ws.pdtv.(x264|h.?264)'], any):
return Quality.SDTV
- elif checkName(['web.dl|webrip', 'xvid|x264|h.?264'], all) and not checkName(['(720|1080)[pi]'], all):
+ elif checkName(['web.?dl|web.?rip', 'xvid|x264|h.?264'], all) and not checkName(['(720|1080)[pi]'], all):
return Quality.SDTV
- elif checkName(['(dvdrip|b[r|d]rip)(.ws)?.(xvid|divx|x264)'], any) and not checkName(['(720|1080)[pi]'], all):
+ elif checkName(['(dvd.?rip|b[r|d]rip)(.ws)?(.(xvid|divx|x264|h.?264))?'], any) and not checkName(['(720|1080)[pi]'], all):
return Quality.SDDVD
- elif checkName(['720p', 'hdtv', 'x264'], all) or checkName(['hr.ws.pdtv.x264'], any) \
+ elif checkName(['720p', 'hdtv', 'x264|h.?264'], all) or checkName(['hr.ws.pdtv.(x264|h.?264)'], any) \
and not checkName(['(1080)[pi]'], all):
return Quality.HDTV
elif checkName(['720p|1080i', 'hdtv', 'mpeg-?2'], all) or checkName(['1080[pi].hdtv', 'h.?264'], all):
return Quality.RAWHDTV
elif checkName(['1080p', 'hdtv', 'x264'], all):
return Quality.FULLHDTV
- elif checkName(['720p', 'web.dl|webrip'], all) or checkName(['720p', 'itunes', 'h.?264'], all):
+ elif checkName(['720p', 'web.?dl|web.?rip'], all) or checkName(['720p', 'itunes', 'x264|h.?264'], all):
return Quality.HDWEBDL
- elif checkName(['1080p', 'web.dl|webrip'], all) or checkName(['1080p', 'itunes', 'h.?264'], all):
+ elif checkName(['1080p', 'web.?dl|web.?rip'], all) or checkName(['1080p', 'itunes', 'x264|h.?264'], all):
return Quality.FULLHDWEBDL
- elif checkName(['720p', 'bluray|hddvd|b[r|d]rip', 'x264'], all):
+ elif checkName(['720p', 'blu.?ray|hddvd|b[r|d]rip', 'x264|h.?264'], all):
return Quality.HDBLURAY
- elif checkName(['1080p', 'bluray|hddvd|b[r|d]rip', 'x264'], all):
+ elif checkName(['1080p', 'blu.?ray|hddvd|b[r|d]rip', 'x264|h.?264'], all):
return Quality.FULLHDBLURAY
else:
return Quality.UNKNOWN
diff --git a/sickbeard/scheduler.py b/sickbeard/scheduler.py
index 3e3e70b0..65e5086d 100644
--- a/sickbeard/scheduler.py
+++ b/sickbeard/scheduler.py
@@ -27,13 +27,14 @@ from sickbeard.exceptions import ex
class Scheduler(threading.Thread):
def __init__(self, action, cycleTime=datetime.timedelta(minutes=10), run_delay=datetime.timedelta(minutes=0),
- start_time=None, threadName="ScheduledThread", silent=True):
+ start_time=None, threadName="ScheduledThread", silent=True, prevent_cycle_run=None):
super(Scheduler, self).__init__()
self.lastRun = datetime.datetime.now() + run_delay - cycleTime
self.action = action
self.cycleTime = cycleTime
self.start_time = start_time
+ self.prevent_cycle_run = prevent_cycle_run
self.name = threadName
self.silent = silent
@@ -70,6 +71,12 @@ class Scheduler(threading.Thread):
else:
should_run = True
+ if should_run and self.prevent_cycle_run is not None and self.prevent_cycle_run():
+ logger.log(u'%s skipping this cycleTime' % self.name, logger.WARNING)
+ # set lastRun to only check start_time after another cycleTime
+ self.lastRun = current_time
+ should_run = False
+
if should_run:
self.lastRun = current_time
diff --git a/sickbeard/search.py b/sickbeard/search.py
index 6c1234ab..ab27b236 100644
--- a/sickbeard/search.py
+++ b/sickbeard/search.py
@@ -317,49 +317,78 @@ def isFirstBestMatch(result):
return False
-def wantedEpisodes(show, fromDate):
- anyQualities, bestQualities = common.Quality.splitQuality(show.quality) # @UnusedVariable
- allQualities = list(set(anyQualities + bestQualities))
+def wantedEpisodes(show, fromDate, make_dict=False):
+ initialQualities, archiveQualities = common.Quality.splitQuality(show.quality)
+ allQualities = list(set(initialQualities + archiveQualities))
myDB = db.DBConnection()
if show.air_by_date:
- sqlResults = myDB.select(
- "SELECT ep.status, ep.season, ep.episode FROM tv_episodes ep, tv_shows show WHERE season != 0 AND ep.showid = show.indexer_id AND show.paused = 0 AND ep.airdate > ? AND ep.showid = ? AND show.air_by_date = 1",
- [fromDate.toordinal(), show.indexerid])
+ sqlString = 'SELECT ep.status, ep.season, ep.episode, ep.airdate FROM [tv_episodes] AS ep, [tv_shows] AS show WHERE season != 0 AND ep.showid = show.indexer_id AND show.paused = 0 AND ep.showid = ? AND show.air_by_date = 1'
else:
- sqlResults = myDB.select(
- "SELECT status, season, episode FROM tv_episodes WHERE showid = ? AND season > 0 and airdate > ?",
- [show.indexerid, fromDate.toordinal()])
+ sqlString = 'SELECT status, season, episode, airdate FROM [tv_episodes] WHERE showid = ? AND season > 0'
+
+ if sickbeard.SEARCH_UNAIRED:
+ statusList = [common.WANTED, common.FAILED, common.UNAIRED]
+ sqlString += ' AND ( airdate > ? OR airdate = 1 )'
+ else:
+ statusList = [common.WANTED, common.FAILED]
+ sqlString += ' AND airdate > ?'
+
+ sqlResults = myDB.select(sqlString, [show.indexerid, fromDate.toordinal()])
# check through the list of statuses to see if we want any
- wanted = []
- total_wanted = total_replacing = 0
+ if make_dict:
+ wanted = {}
+ else:
+ wanted = []
+ total_wanted = total_replacing = total_unaired = 0
+ downloadedStatusList = (common.DOWNLOADED, common.SNATCHED, common.SNATCHED_PROPER, common.SNATCHED_BEST)
for result in sqlResults:
+ not_downloaded = True
curCompositeStatus = int(result["status"])
curStatus, curQuality = common.Quality.splitCompositeStatus(curCompositeStatus)
- if bestQualities:
- highestBestQuality = max(allQualities)
+ if show.archive_firstmatch and curStatus in downloadedStatusList and curQuality in archiveQualities:
+ continue
+
+ # special case: already downloaded quality is not in any of the wanted Qualities
+ other_quality_downloaded = False
+ if curStatus in downloadedStatusList and curQuality not in allQualities:
+ other_quality_downloaded = True
+ wantedQualities = allQualities
else:
- highestBestQuality = 0
+ wantedQualities = archiveQualities
+
+ if archiveQualities:
+ highestWantedQuality = max(wantedQualities)
+ else:
+ if other_quality_downloaded:
+ highestWantedQuality = max(initialQualities)
+ else:
+ highestWantedQuality = 0
# if we need a better one then say yes
- if (curStatus in (common.DOWNLOADED, common.SNATCHED, common.SNATCHED_PROPER,
- common.SNATCHED_BEST) and curQuality < highestBestQuality) or curStatus == common.WANTED:
+ if (curStatus in downloadedStatusList and curQuality < highestWantedQuality) or curStatus in statusList or (sickbeard.SEARCH_UNAIRED and result['airdate'] == 1 and curStatus in (common.SKIPPED, common.IGNORED, common.UNAIRED, common.UNKNOWN, common.FAILED)):
- if curStatus == common.WANTED:
+ if curStatus in (common.WANTED, common.FAILED):
total_wanted += 1
+ elif curStatus in (common.UNAIRED, common.SKIPPED, common.IGNORED, common.UNKNOWN):
+ total_unaired += 1
else:
total_replacing += 1
+ not_downloaded = False
epObj = show.getEpisode(int(result["season"]), int(result["episode"]))
- epObj.wantedQuality = [i for i in allQualities if (i > curQuality and i != common.Quality.UNKNOWN)]
- wanted.append(epObj)
+ if make_dict:
+ wanted.setdefault(epObj.season, []).append(epObj)
+ else:
+ epObj.wantedQuality = [i for i in (initialQualities if not_downloaded else wantedQualities) if (i > curQuality and i != common.Quality.UNKNOWN)]
+ wanted.append(epObj)
- if 0 < total_wanted + total_replacing:
+ if 0 < total_wanted + total_replacing + total_unaired:
actions = []
- for msg, total in ['%d episode%s', total_wanted], ['to upgrade %d episode%s', total_replacing]:
+ for msg, total in ['%d episode%s', total_wanted], ['to upgrade %d episode%s', total_replacing], ['%d unaired episode%s', total_unaired]:
if 0 < total:
actions.append(msg % (total, helpers.maybe_plural(total)))
logger.log(u'We want %s for %s' % (' and '.join(actions), show.name))
@@ -393,11 +422,6 @@ def searchForNeededEpisodes(episodes):
continue
# find the best result for the current episode
- bestResult = None
- for curResult in curFoundResults[curEp]:
- if not bestResult or bestResult.quality < curResult.quality:
- bestResult = curResult
-
bestResult = pickBestResult(curFoundResults[curEp], curEp.show)
# if all results were rejected move on to the next episode
diff --git a/sickbeard/searchBacklog.py b/sickbeard/searchBacklog.py
index 81a2ff29..3a775d81 100644
--- a/sickbeard/searchBacklog.py
+++ b/sickbeard/searchBacklog.py
@@ -28,6 +28,7 @@ from sickbeard import search_queue
from sickbeard import logger
from sickbeard import ui
from sickbeard import common
+from sickbeard.search import wantedEpisodes
class BacklogSearchScheduler(scheduler.Scheduler):
@@ -78,8 +79,10 @@ class BacklogSearcher:
if which_shows:
show_list = which_shows
+ standard_backlog = False
else:
show_list = sickbeard.showList
+ standard_backlog = True
self._get_lastBacklog()
@@ -99,12 +102,12 @@ class BacklogSearcher:
if curShow.paused:
continue
- segments = self._get_segments(curShow, fromDate)
+ segments = wantedEpisodes(curShow, fromDate, make_dict=True)
for season, segment in segments.items():
self.currentSearchInfo = {'title': curShow.name + " Season " + str(season)}
- backlog_queue_item = search_queue.BacklogQueueItem(curShow, segment)
+ backlog_queue_item = search_queue.BacklogQueueItem(curShow, segment, standard_backlog=standard_backlog)
sickbeard.searchQueueScheduler.action.add_item(backlog_queue_item) # @UndefinedVariable
else:
logger.log(u'Nothing needs to be downloaded for %s, skipping' % str(curShow.name), logger.DEBUG)
@@ -136,55 +139,6 @@ class BacklogSearcher:
self._lastBacklog = lastBacklog
return self._lastBacklog
- def _get_segments(self, show, fromDate):
- anyQualities, bestQualities = common.Quality.splitQuality(show.quality) # @UnusedVariable
-
- myDB = db.DBConnection()
- if show.air_by_date:
- sqlResults = myDB.select(
- "SELECT ep.status, ep.season, ep.episode FROM tv_episodes ep, tv_shows show WHERE season != 0 AND ep.showid = show.indexer_id AND show.paused = 0 AND ep.airdate > ? AND ep.showid = ? AND show.air_by_date = 1",
- [fromDate.toordinal(), show.indexerid])
- else:
- sqlResults = myDB.select(
- "SELECT status, season, episode FROM tv_episodes WHERE showid = ? AND season > 0 and airdate > ?",
- [show.indexerid, fromDate.toordinal()])
-
- # check through the list of statuses to see if we want any
- wanted = {}
- total_wanted = total_replacing = 0
- for result in sqlResults:
- curCompositeStatus = int(result["status"])
- curStatus, curQuality = common.Quality.splitCompositeStatus(curCompositeStatus)
-
- if bestQualities:
- highestBestQuality = max(bestQualities)
- else:
- highestBestQuality = 0
-
- # if we need a better one then say yes
- if (curStatus in (common.DOWNLOADED, common.SNATCHED, common.SNATCHED_PROPER,
- common.SNATCHED_BEST) and curQuality < highestBestQuality) or curStatus == common.WANTED:
-
- if curStatus == common.WANTED:
- total_wanted += 1
- else:
- total_replacing += 1
-
- epObj = show.getEpisode(int(result["season"]), int(result["episode"]))
- if epObj.season not in wanted:
- wanted[epObj.season] = [epObj]
- else:
- wanted[epObj.season].append(epObj)
-
- if 0 < total_wanted + total_replacing:
- actions = []
- for msg, total in ['%d episode%s', total_wanted], ['to upgrade %d episode%s', total_replacing]:
- if 0 < total:
- actions.append(msg % (total, helpers.maybe_plural(total)))
- logger.log(u'We want %s for %s' % (' and '.join(actions), show.name))
-
- return wanted
-
def _set_lastBacklog(self, when):
logger.log(u"Setting the last backlog in the DB to " + str(when), logger.DEBUG)
diff --git a/sickbeard/search_queue.py b/sickbeard/search_queue.py
index ba805dcc..aa4b654f 100644
--- a/sickbeard/search_queue.py
+++ b/sickbeard/search_queue.py
@@ -94,6 +94,12 @@ class SearchQueue(generic_queue.GenericQueue):
return True
return False
+ def is_standard_backlog_in_progress(self):
+ for cur_item in self.queue + [self.currentItem]:
+ if isinstance(cur_item, BacklogQueueItem) and cur_item.standard_backlog:
+ return True
+ return False
+
def is_recentsearch_in_progress(self):
for cur_item in self.queue + [self.currentItem]:
if isinstance(cur_item, RecentSearchQueueItem):
@@ -308,13 +314,14 @@ class ManualSearchQueueItem(generic_queue.QueueItem):
class BacklogQueueItem(generic_queue.QueueItem):
- def __init__(self, show, segment):
+ def __init__(self, show, segment, standard_backlog=False):
generic_queue.QueueItem.__init__(self, 'Backlog', BACKLOG_SEARCH)
self.priority = generic_queue.QueuePriorities.LOW
self.name = 'BACKLOG-' + str(show.indexerid)
self.success = None
self.show = show
self.segment = segment
+ self.standard_backlog = standard_backlog
def run(self):
generic_queue.QueueItem.run(self)
diff --git a/sickbeard/tv.py b/sickbeard/tv.py
index 3cab9af3..018822b4 100644
--- a/sickbeard/tv.py
+++ b/sickbeard/tv.py
@@ -1243,11 +1243,12 @@ class TVShow(object):
Quality.qualityStrings[quality], logger.DEBUG)
# if the quality isn't one we want under any circumstances then just say no
- anyQualities, bestQualities = Quality.splitQuality(self.quality)
- logger.log(u"any,best = " + str(anyQualities) + " " + str(bestQualities) + " and found " + str(quality),
+ initialQualities, archiveQualities = Quality.splitQuality(self.quality)
+ allQualities = list(set(initialQualities + archiveQualities))
+ logger.log(u"initial + archive = (" + ",".join([Quality.qualityStrings[qual] for qual in initialQualities]) + ") + (" + ",".join([Quality.qualityStrings[qual] for qual in archiveQualities]) + ") and found " + Quality.qualityStrings[quality],
logger.DEBUG)
- if quality not in anyQualities + bestQualities:
+ if quality not in allQualities:
logger.log(u"Don't want this quality, ignoring found episode", logger.DEBUG)
return False
@@ -1270,9 +1271,9 @@ class TVShow(object):
return False
# if it's one of these then we want it as long as it's in our allowed initial qualities
- if quality in anyQualities + bestQualities:
- if epStatus in (WANTED, UNAIRED, SKIPPED):
- logger.log(u"Existing episode status is wanted/unaired/skipped, getting found episode", logger.DEBUG)
+ if quality in allQualities:
+ if epStatus in (WANTED, UNAIRED, SKIPPED, FAILED):
+ logger.log(u"Existing episode status is wanted/unaired/skipped/failed, getting found episode", logger.DEBUG)
return True
elif manualSearch:
logger.log(
@@ -1284,9 +1285,15 @@ class TVShow(object):
logger.DEBUG)
curStatus, curQuality = Quality.splitCompositeStatus(epStatus)
+ downloadedStatusList = (DOWNLOADED, SNATCHED, SNATCHED_PROPER, SNATCHED_BEST)
+ # special case: already downloaded quality is not in any of the wanted Qualities
+ if curStatus in downloadedStatusList and curQuality not in allQualities:
+ wantedQualities = allQualities
+ else:
+ wantedQualities = archiveQualities
- # if we are re-downloading then we only want it if it's in our bestQualities list and better than what we have
- if curStatus in Quality.DOWNLOADED + Quality.SNATCHED + Quality.SNATCHED_PROPER + Quality.SNATCHED_BEST and quality in bestQualities and quality > curQuality:
+ # if we are re-downloading then we only want it if it's in our archiveQualities list and better than what we have
+ if curStatus in downloadedStatusList and quality in wantedQualities and quality > curQuality:
logger.log(u"Episode already exists but the found episode has better quality, getting found episode",
logger.DEBUG)
return True
@@ -1767,7 +1774,7 @@ class TVEpisode(object):
# if it hasn't aired yet set the status to UNAIRED
if self.airdate >= datetime.date.today() and self.status in [SKIPPED, UNAIRED, UNKNOWN, WANTED]:
- logger.log(u"Episode airs in the future, marking it " + str(UNAIRED), logger.DEBUG)
+ logger.log(u"Episode airs in the future, marking it " + statusStrings[UNAIRED], logger.DEBUG)
self.status = UNAIRED
# if there's no airdate then set it to skipped (and respect ignored)
diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py
index db0f7af1..4ccb6385 100644
--- a/sickbeard/webserve.py
+++ b/sickbeard/webserve.py
@@ -1618,7 +1618,7 @@ class Home(MainHandler):
msg += ''
for season, segment in segments.items():
- cur_failed_queue_item = search_queue.FailedQueueItem(showObj, [segment])
+ cur_failed_queue_item = search_queue.FailedQueueItem(showObj, segment)
sickbeard.searchQueueScheduler.action.add_item(cur_failed_queue_item) # @UndefinedVariable
msg += 'Season ' + str(season) + ' '
@@ -1793,12 +1793,21 @@ class Home(MainHandler):
searchstatus = 'finished'
else:
searchstatus = 'searching'
- episodes.append({'episode': searchThread.segment.episode,
- 'episodeindexid': searchThread.segment.indexerid,
- 'season' : searchThread.segment.season,
- 'searchstatus' : searchstatus,
- 'status' : statusStrings[searchThread.segment.status],
- 'quality': self.getQualityClass(searchThread.segment)})
+ if isinstance(searchThread, sickbeard.search_queue.ManualSearchQueueItem):
+ episodes.append({'episode': searchThread.segment.episode,
+ 'episodeindexid': searchThread.segment.indexerid,
+ 'season' : searchThread.segment.season,
+ 'searchstatus' : searchstatus,
+ 'status' : statusStrings[searchThread.segment.status],
+ 'quality': self.getQualityClass(searchThread.segment)})
+ else:
+ for epObj in searchThread.segment:
+ episodes.append({'episode': epObj.episode,
+ 'episodeindexid': epObj.indexerid,
+ 'season' : epObj.season,
+ 'searchstatus' : searchstatus,
+ 'status' : statusStrings[epObj.status],
+ 'quality': self.getQualityClass(epObj)})
if finishedManualSearchThreadItems:
for searchThread in finishedManualSearchThreadItems:
@@ -3558,7 +3567,7 @@ class ConfigSearch(Config):
def saveSearch(self, use_nzbs=None, use_torrents=None, nzb_dir=None, sab_username=None, sab_password=None,
sab_apikey=None, sab_category=None, sab_host=None, nzbget_username=None, nzbget_password=None,
nzbget_category=None, nzbget_priority=None, nzbget_host=None, nzbget_use_https=None,
- backlog_days=None, backlog_frequency=None, recentsearch_frequency=None,
+ backlog_days=None, backlog_frequency=None, search_unaired=None, recentsearch_frequency=None,
nzb_method=None, torrent_method=None, usenet_retention=None,
download_propers=None, check_propers_interval=None, allow_high_priority=None,
torrent_dir=None, torrent_username=None, torrent_password=None, torrent_host=None,
@@ -3591,6 +3600,8 @@ class ConfigSearch(Config):
sickbeard.DOWNLOAD_PROPERS = config.checkbox_to_value(download_propers)
sickbeard.CHECK_PROPERS_INTERVAL = check_propers_interval
+ sickbeard.SEARCH_UNAIRED = config.checkbox_to_value(search_unaired)
+
sickbeard.ALLOW_HIGH_PRIORITY = config.checkbox_to_value(allow_high_priority)
sickbeard.SAB_USERNAME = sab_username
diff --git a/tests/common_tests.py b/tests/common_tests.py
index 1fdaaf4c..21f1367c 100644
--- a/tests/common_tests.py
+++ b/tests/common_tests.py
@@ -22,6 +22,7 @@ class QualityTests(unittest.TestCase):
self.assertEqual(common.Quality.SDTV, common.Quality.nameQuality("Test.Show.S01E02.TVRip.x264-GROUP"))
self.assertEqual(common.Quality.SDTV, common.Quality.nameQuality("Test.Show.S01E02.WEBRip.XViD-GROUP"))
self.assertEqual(common.Quality.SDTV, common.Quality.nameQuality("Test.Show.S01E02.WEBRip.x264-GROUP"))
+ self.assertEqual(common.Quality.SDTV, common.Quality.nameQuality("Test.Show.S01E02.Web-Rip.x264.GROUP"))
self.assertEqual(common.Quality.SDTV, common.Quality.nameQuality("Test.Show.S01E02.WEB-DL.x264-GROUP"))
self.assertEqual(common.Quality.SDTV, common.Quality.nameQuality("Test.Show.S01E02.WEB-DL.AAC2.0.H.264-GROUP"))
self.assertEqual(common.Quality.SDTV, common.Quality.nameQuality("Test.Show.S01E02 WEB-DL H 264-GROUP"))
@@ -35,6 +36,7 @@ class QualityTests(unittest.TestCase):
self.assertEqual(common.Quality.SDDVD, common.Quality.nameQuality("Test.Show.S01E02.DVDRip.WS.XViD-GROUP"))
self.assertEqual(common.Quality.SDDVD, common.Quality.nameQuality("Test.Show.S01E02.DVDRip.WS.DiVX-GROUP"))
self.assertEqual(common.Quality.SDDVD, common.Quality.nameQuality("Test.Show.S01E02.DVDRip.WS.x264-GROUP"))
+ self.assertEqual(common.Quality.SDDVD, common.Quality.nameQuality("Test.Show-S01E02-Test.Dvd Rip"))
self.assertEqual(common.Quality.SDDVD, common.Quality.nameQuality("Test.Show.S01E02.BDRIP.XViD-GROUP"))
self.assertEqual(common.Quality.SDDVD, common.Quality.nameQuality("Test.Show.S01E02.BDRIP.DiVX-GROUP"))
self.assertEqual(common.Quality.SDDVD, common.Quality.nameQuality("Test.Show.S01E02.BDRIP.x264-GROUP"))
@@ -65,6 +67,10 @@ class QualityTests(unittest.TestCase):
self.assertEqual(common.Quality.HDWEBDL, common.Quality.nameQuality("Test_Show.S01E02_720p_WEB-DL_AAC2.0_H264-GROUP"))
self.assertEqual(common.Quality.HDWEBDL, common.Quality.nameQuality("Test.Show.S01E02.720p.WEB-DL.AAC2.0.H264-GROUP"))
self.assertEqual(common.Quality.HDWEBDL, common.Quality.nameQuality("Test.Show.S01E02.720p.iTunes.Rip.H264.AAC-GROUP"))
+ self.assertEqual(common.Quality.HDWEBDL, common.Quality.nameQuality("Test.Show.s01e02.WEBDL.720p.GROUP"))
+ self.assertEqual(common.Quality.HDWEBDL, common.Quality.nameQuality("Test Show s01e02 WEBDL 720p GROUP"))
+ self.assertEqual(common.Quality.HDWEBDL, common.Quality.nameQuality("Test Show S01E02 720p WEB-DL AVC-GROUP"))
+ self.assertEqual(common.Quality.HDWEBDL, common.Quality.nameQuality("Test.Show.S01E02.WEB-RIP.720p.GROUP"))
def test_FULLHDWEBDL(self):
self.assertEqual(common.Quality.FULLHDWEBDL, common.Quality.nameQuality("Test.Show.S01E02.1080p.WEB-DL-GROUP"))
@@ -74,14 +80,20 @@ class QualityTests(unittest.TestCase):
self.assertEqual(common.Quality.FULLHDWEBDL, common.Quality.nameQuality("Test.Show.S01E02.1080p.iTunes.H.264.AAC-GROUP"))
self.assertEqual(common.Quality.FULLHDWEBDL, common.Quality.nameQuality("Test Show S01E02 1080p iTunes H 264 AAC-GROUP"))
self.assertEqual(common.Quality.FULLHDWEBDL, common.Quality.nameQuality("Test_Show_S01E02_1080p_iTunes_H_264_AAC-GROUP"))
+ self.assertEqual(common.Quality.FULLHDWEBDL, common.Quality.nameQuality("Test.Show.s01e02.WEBDL.1080p.GROUP"))
+ self.assertEqual(common.Quality.FULLHDWEBDL, common.Quality.nameQuality("Test Show s01e02 WEBDL 1080p GROUP"))
+ self.assertEqual(common.Quality.FULLHDWEBDL, common.Quality.nameQuality("Test Show S01E02 1080p WEB-DL AVC-GROUP"))
+ self.assertEqual(common.Quality.FULLHDWEBDL, common.Quality.nameQuality("Test.Show.S01E02.WEB-RIP.1080p.GROUP"))
def test_HDBLURAY(self):
self.assertEqual(common.Quality.HDBLURAY, common.Quality.nameQuality("Test.Show.S01E02.720p.BluRay.x264-GROUP"))
self.assertEqual(common.Quality.HDBLURAY, common.Quality.nameQuality("Test.Show.S01E02.720p.HDDVD.x264-GROUP"))
+ self.assertEqual(common.Quality.HDBLURAY, common.Quality.nameQuality("Test.Show.S01E02.720p.Blu-ray.x264-GROUP"))
def test_FULLHDBLURAY(self):
self.assertEqual(common.Quality.FULLHDBLURAY, common.Quality.nameQuality("Test.Show.S01E02.1080p.BluRay.x264-GROUP"))
self.assertEqual(common.Quality.FULLHDBLURAY, common.Quality.nameQuality("Test.Show.S01E02.1080p.HDDVD.x264-GROUP"))
+ self.assertEqual(common.Quality.FULLHDBLURAY, common.Quality.nameQuality("Test.Show.S01E02.1080p.Blu-ray.x264-GROUP"))
def test_UNKNOWN(self):
self.assertEqual(common.Quality.UNKNOWN, common.Quality.nameQuality("Test.Show.S01E02-SiCKBEARD"))