Major changes made to search code, tvcache code, and name parser

This commit is contained in:
echel0n 2014-05-03 02:23:26 -07:00
parent 4b5fa9582a
commit d5f183c171
25 changed files with 333 additions and 459 deletions

View file

@ -206,6 +206,8 @@ class Proper:
self.indexerid = -1
self.season = -1
self.episode = -1
self.scene_season = -1
self.scene_episode = -1
def __str__(self):
return str(self.date) + " " + self.name + " " + str(self.season) + "x" + str(self.episode) + " of " + str(

View file

@ -27,7 +27,7 @@ from sickbeard import encodingKludge as ek
from sickbeard.name_parser.parser import NameParser, InvalidNameException
MIN_DB_VERSION = 9 # oldest db version we support migrating from
MAX_DB_VERSION = 30
MAX_DB_VERSION = 31
class MainSanityCheck(db.DBSanityCheck):
def check(self):
@ -35,6 +35,7 @@ class MainSanityCheck(db.DBSanityCheck):
self.fix_duplicate_shows()
self.fix_duplicate_episodes()
self.fix_orphan_episodes()
self.fix_scene_numbering()
def fix_duplicate_shows(self):
@ -124,6 +125,29 @@ class MainSanityCheck(db.DBSanityCheck):
self.connection.action("CREATE INDEX idx_sta_epi_sta_air ON tv_episodes (season,episode, status, airdate)")
def fix_scene_numbering(self):
ql = []
sqlResults = self.connection.select(
"SELECT showid, indexerid, indexer, episode_id, season, episode FROM tv_episodes WHERE scene_season = 0 OR scene_episode = 0")
for epResult in sqlResults:
logger.log(
u"Repairing any scene numbering issues for showid: " + str(epResult["showid"]) + u" season: " + str(
epResult["season"]) + u" episode: " + str(epResult["episode"]), logger.DEBUG)
scene_season, scene_episode = sickbeard.scene_numbering.get_scene_numbering(epResult["showid"],
epResult["indexer"],
epResult["season"],
epResult["episode"])
ql.append(["UPDATE tv_episodes SET scene_season = ? WHERE indexerid = ?", [scene_season, epResult["indexerid"]]])
ql.append(
["UPDATE tv_episodes SET scene_episode = ? WHERE indexerid = ?", [scene_episode, epResult["indexerid"]]])
self.connection.mass_action(ql)
def backupDatabase(version):
logger.log(u"Backing up database before upgrade")
if not helpers.backupVersionedFile(db.dbFilename(), version):
@ -745,4 +769,20 @@ class AddSportsOption(AddRequireAndIgnoreWords):
ql.append(["UPDATE tv_shows SET air_by_date = 0 WHERE show_id = ?", [cur_entry["show_id"]]])
self.connection.mass_action(ql)
self.incDBVersion()
class AddSceneNumberingToTvEpisodes(AddSportsOption):
def test(self):
return self.checkDBVersion() >= 31
def execute(self):
backupDatabase(31)
logger.log(u"Adding column scene_season and scene_episode to tvepisodes")
if not self.hasColumn("tv_episodes", "scene_season"):
self.addColumn("tv_episodes", "scene_season", "NUMERIC", "0")
if not self.hasColumn("tv_episodes", "scene_episode"):
self.addColumn("tv_episodes", "scene_episode", "NUMERIC", "0")
self.incDBVersion()

View file

@ -54,7 +54,7 @@ class FailedProcessor(object):
parser = NameParser(False)
try:
parsed = parser.parse(releaseName).convert()
parsed = parser.parse(releaseName)
except InvalidNameException:
self._log(u"Error: release name is invalid: " + releaseName, logger.WARNING)
raise exceptions.FailedProcessingFailed()
@ -68,16 +68,20 @@ class FailedProcessor(object):
logger.log(u" - " + str(parsed.air_date), logger.DEBUG)
logger.log(u" - " + str(parsed.sports_event_date), logger.DEBUG)
self._show_obj = parsed.show
self._show_obj = sickbeard.helpers.get_show_by_name(parsed.series_name)
if self._show_obj is None:
self._log(
u"Could not create show object. Either the show hasn't been added to SickBeard, or it's still loading (if SB was restarted recently)",
logger.WARNING)
raise exceptions.FailedProcessingFailed()
episodes = []
for episode in parsed.episode_numbers:
cur_failed_queue_item = search_queue.FailedQueueItem(self._show_obj, {parsed.season_number: episode})
sickbeard.searchQueueScheduler.action.add_item(cur_failed_queue_item)
epObj = self._show_obj.getEpisode(parsed.season_number, episode)
episodes.append(epObj)
cur_failed_queue_item = search_queue.FailedQueueItem(self._show_obj, episodes)
sickbeard.searchQueueScheduler.action.add_item(cur_failed_queue_item)
return True

View file

@ -306,7 +306,9 @@ def searchDBForShow(regShowName):
logger.log(u"Multiple results for " + showName + " in the DB, unable to match show name", logger.DEBUG)
continue
else:
return (int(sqlResults[0]["indexer"]), int(sqlResults[0]["indexer_id"]), sqlResults[0]["show_name"])
return int(sqlResults[0]["indexer_id"])
return
def searchIndexerForShowID(regShowName, indexer=None, indexer_id=None, ui=None):
showNames = list(set([re.sub('[. -]', ' ', regShowName), regShowName]))
@ -942,79 +944,37 @@ def _check_against_names(name, show):
return False
def get_show_by_name(name, checkIndexers=False):
if not sickbeard.showList: return
def get_show_by_name(name):
showObj = None
in_cache = False
foundResult = None
logger.log(
u"Checking the cache for:" + str(name),
logger.DEBUG)
if not sickbeard.showList:
return
cacheResult = sickbeard.name_cache.retrieveNameFromCache(name)
if cacheResult:
foundResult = findCertainShow(sickbeard.showList, cacheResult)
if foundResult:
in_cache = True
logger.log(
u"Cache lookup found Indexer ID:" + repr(
foundResult.indexerid) + ", using that for " + name,
logger.DEBUG)
indexerid = sickbeard.name_cache.retrieveNameFromCache(name)
if indexerid or indexerid == 0:
in_cache = True
if not foundResult:
logger.log(
u"Checking the database for:" + str(name),
logger.DEBUG)
showNames = list(set(sickbeard.show_name_helpers.sceneToNormalShowNames(name)))
for showName in showNames if not in_cache else []:
try:
showObj = [x for x in sickbeard.showList if _check_against_names(showName, x)][0]
indexerid = showObj.indexerid
except:
indexerid = 0
dbResult = searchDBForShow(name)
if dbResult:
foundResult = findCertainShow(sickbeard.showList, dbResult[1])
if foundResult:
logger.log(
u"Database lookup found Indexer ID:" + str(
foundResult.indexerid) + ", using that for " + name, logger.DEBUG)
if not foundResult:
logger.log(
u"Checking the scene exceptions list for:" + str(name),
logger.DEBUG)
for show in sickbeard.showList:
if _check_against_names(name, show):
logger.log(
u"Scene exceptions lookup found Indexer ID:" + str(show.indexerid) + ", using that for " + name,
logger.DEBUG)
foundResult = show
if not foundResult and checkIndexers:
logger.log(
u"Checking the Indexers for:" + str(name),
logger.DEBUG)
for indexer in sickbeard.indexerApi().indexers:
try:
lINDEXER_API_PARMS = sickbeard.indexerApi(indexer).api_params.copy()
lINDEXER_API_PARMS['custom_ui'] = classes.ShowListUI
lINDEXER_API_PARMS['search_all_languages'] = True
t = sickbeard.indexerApi(indexer).indexer(**lINDEXER_API_PARMS)
showObj = t[name]
except:
continue
if showObj:
foundResult = findCertainShow(sickbeard.showList, int(showObj[0]['id']))
if foundResult:
logger.log(
u"Indexers lookup found Indexer ID:" + str(
foundResult.indexerid) + ", using that for " + name, logger.DEBUG)
if indexerid:
break
# add to name cache if we didn't get it from the cache
if foundResult and not in_cache:
sickbeard.name_cache.addNameToCache(name, foundResult.indexerid)
if not in_cache:
sickbeard.name_cache.addNameToCache(name, indexerid if indexerid else 0)
return foundResult
if indexerid:
logger.log(u"Found Indexer ID:[" + repr(indexerid) + "], using that for [" + name + "}",logger.DEBUG)
if not showObj:
showObj = [x for x in sickbeard.showList if x.indexerid == indexerid][0]
return showObj
def is_hidden_folder(folder):
"""

View file

@ -20,7 +20,7 @@ from sickbeard import db
from sickbeard.helpers import sanitizeSceneName
def addNameToCache(name, indexer_id):
def addNameToCache(name, indexer_id=0):
"""
Adds the show & tvdb id to the scene_names table in cache.db.
@ -28,11 +28,10 @@ def addNameToCache(name, indexer_id):
indexer_id: the TVDB and TVRAGE id that this show should be cached with (can be None/0 for unknown)
"""
if indexer_id:
# standardize the name we're using to account for small differences in providers
name = sanitizeSceneName(name)
cacheDB = db.DBConnection('cache.db')
cacheDB.action("INSERT INTO scene_names (indexer_id, name) VALUES (?, ?)", [indexer_id, name])
# standardize the name we're using to account for small differences in providers
name = sanitizeSceneName(name)
cacheDB = db.DBConnection('cache.db')
cacheDB.action("INSERT INTO scene_names (indexer_id, name) VALUES (?, ?)", [indexer_id, name])
def retrieveNameFromCache(name):
@ -53,7 +52,6 @@ def retrieveNameFromCache(name):
if cache_results:
return int(cache_results[0]["indexer_id"])
def clearCache():
"""
Deletes all "unknown" entries from the cache (names with indexer_id of 0).

View file

@ -106,11 +106,6 @@ class NameParser(object):
result.series_name = match.group('series_name')
if result.series_name:
result.series_name = self.clean_series_name(result.series_name)
name_list = sickbeard.show_name_helpers.sceneToNormalShowNames(result.series_name)
for name in name_list:
result.show = helpers.get_show_by_name(name)
if result.show:
break
if 'season_num' in named_groups:
tmp_season = int(match.group('season_num'))
@ -245,8 +240,6 @@ class NameParser(object):
# parse the dirname for extra info if needed
dir_name_result = self._parse_string(dir_name)
final_result.show = self._combine_results(file_name_result, dir_name_result, 'show')
# build the ParseResult object
final_result.air_date = self._combine_results(file_name_result, dir_name_result, 'air_date')
@ -323,8 +316,6 @@ class ParseResult(object):
if not other:
return False
if self.show != other.show:
return False
if self.series_name != other.series_name:
return False
if self.season_number != other.season_number:
@ -376,11 +367,14 @@ class ParseResult(object):
return to_return.encode('utf-8')
def convert(self):
if not self.show: return self
if self.air_by_date: return self # scene numbering does not apply to air-by-date
if self.season_number == None: return self # can't work without a season
if len(self.episode_numbers) == 0: return self # need at least one episode
self.show = helpers.get_show_by_name(self.series_name)
if not self.show:
return self
new_episode_numbers = []
new_season_numbers = []
for epNo in self.episode_numbers:

View file

@ -114,7 +114,7 @@ def splitResult(result):
# parse the season ep name
try:
np = NameParser(False)
parse_result = np.parse(result.name).convert()
parse_result = np.parse(result.name)
except InvalidNameException:
logger.log(u"Unable to parse the filename " + result.name + " into a valid episode", logger.WARNING)
return False
@ -133,7 +133,7 @@ def splitResult(result):
# parse the name
try:
np = NameParser(False)
parse_result = np.parse(newNZB).convert()
parse_result = np.parse(newNZB)
except InvalidNameException:
logger.log(u"Unable to parse the filename " + newNZB + " into a valid episode", logger.WARNING)
return False

View file

@ -484,7 +484,7 @@ class PostProcessor(object):
# parse the name to break it into show name, season, and episode
np = NameParser(file)
parse_result = np.parse(name).convert()
parse_result = np.parse(name)
self._log("Parsed " + name + " into " + str(parse_result).decode('utf-8'), logger.DEBUG)
@ -625,7 +625,7 @@ class PostProcessor(object):
# now that we've figured out which episode this file is just load it manually
try:
# convert scene numbered release and load episode from database
curEp = show_obj.getEpisode(season, cur_episode)
curEp = show_obj.getEpisode(scene_season=season, scene_episode=cur_episode)
except exceptions.EpisodeNotFoundException, e:
self._log(u"Unable to create episode: " + ex(e), logger.DEBUG)
raise exceptions.PostProcessingFailed()

View file

@ -100,17 +100,11 @@ class ProperFinder():
# parse the file name
try:
myParser = NameParser(False)
parse_result = myParser.parse(curProper.name).convert()
parse_result = myParser.parse(curProper.name)
except InvalidNameException:
logger.log(u"Unable to parse the filename " + curProper.name + " into a valid episode", logger.DEBUG)
continue
# if we can't find the show then there's nothing we can really do
if not parse_result.show:
logger.log(u"This show isn't in your list, skipping ...",
logger.DEBUG)
continue
if not parse_result.episode_numbers:
logger.log(
u"Ignoring " + curProper.name + " because it's for a full season rather than specific episode",
@ -122,8 +116,8 @@ class ProperFinder():
curProper.season = -1
curProper.episode = parse_result.air_date
else:
curProper.season = parse_result.season_number if parse_result.season_number != None else 1
curProper.episode = parse_result.episode_numbers[0]
curProper.scene_season = parse_result.season_number if parse_result.season_number != None else 1
curProper.scene_episode = parse_result.episode_numbers[0]
curProper.quality = Quality.nameQuality(curProper.name)

View file

@ -46,8 +46,8 @@ class DTTProvider(generic.TorrentProvider):
quality = Quality.sceneQuality(url)
return quality
def getSearchResults(self, show, season, ep_objs, seasonSearch=False, manualSearch=False):
return generic.TorrentProvider.getSearchResults(self, show, season, ep_objs, seasonSearch, manualSearch)
def getSearchResults(self, show, season, episodes, seasonSearch=False, manualSearch=False):
return generic.TorrentProvider.getSearchResults(self, show, season, episodes, seasonSearch, manualSearch)
def _dtt_show_id(self, show_name):
return sanitizeSceneName(show_name).replace('.', '-').lower()

View file

@ -57,7 +57,7 @@ class EZRSSProvider(generic.TorrentProvider):
return quality
def getSearchResults(self, show, season, ep_objs, seasonSearch=False, manualSearch=False):
def getSearchResults(self, show, season, episodes, seasonSearch=False, manualSearch=False):
self.show = show
@ -68,7 +68,7 @@ class EZRSSProvider(generic.TorrentProvider):
logger.WARNING)
return results
results = generic.TorrentProvider.getSearchResults(self, show, season, ep_objs, seasonSearch, manualSearch)
results = generic.TorrentProvider.getSearchResults(self, show, season, episodes, seasonSearch, manualSearch)
return results

View file

@ -247,7 +247,7 @@ class GenericProvider:
return (title, url)
def getSearchResults(self, show, season, ep_objs, seasonSearch=False, manualSearch=False):
def findSearchResults(self, show, season, episodes, manualSearch=False):
self._checkAuth()
self.show = show
@ -255,133 +255,86 @@ class GenericProvider:
itemList = []
results = {}
useDate = False
if self.show.air_by_date or self.show.sports:
useDate = True
for epObj in episodes:
cacheResult = self.cache.searchCache(epObj, manualSearch)
if len(cacheResult):
return cacheResult
for ep_obj in ep_objs:
logger.log(u'Searching "%s" for "%s" as "%s"' % (self.name, ep_obj.prettyName(), ep_obj.scene_prettyName()))
logger.log(u'Searching "%s" for "%s" as "%s"' % (self.name, epObj.prettyName(), epObj.scene_prettyName()))
for curString in self._get_episode_search_strings(epObj):
itemList += self._doSearch(curString)
if seasonSearch:
for curString in self._get_season_search_strings(ep_obj):
itemList += self._doSearch(curString)
else:
for curString in self._get_episode_search_strings(ep_obj):
itemList += self._doSearch(curString)
for item in itemList:
for item in itemList:
(title, url) = self._get_title_and_url(item)
(title, url) = self._get_title_and_url(item)
quality = self.getQuality(item)
quality = self.getQuality(item)
# parse the file name
try:
myParser = NameParser(False)
parse_result = myParser.parse(title).convert()
except InvalidNameException:
logger.log(u"Unable to parse the filename " + title + " into a valid episode", logger.WARNING)
continue
if not useDate:
# this check is meaningless for non-season searches
if (parse_result.season_number is not None and parse_result.season_number != season) or (
parse_result.season_number is None and season != 1):
logger.log(u"The result " + title + " doesn't seem to be a valid episode for season " + str(
season) + ", ignoring", logger.DEBUG)
# parse the file name
try:
myParser = NameParser(False)
parse_result = myParser.parse(title)
except InvalidNameException:
logger.log(u"Unable to parse the filename " + title + " into a valid episode", logger.WARNING)
continue
if manualSearch and (
parse_result.season_number != season or ep_objs[0].episode not in parse_result.episode_numbers):
logger.log(u"Episode " + title + " isn't " + str(season) + "x" + str(
ep_objs[0].episode) + ", skipping it", logger.DEBUG)
continue
# we just use the existing info for normal searches
actual_season = season if manualSearch else parse_result.season_number
actual_episodes = [ep_objs[0].episode] if manualSearch else parse_result.episode_numbers
else:
if not (parse_result.air_by_date or parse_result.sports):
logger.log(
u"This is supposed to be a date search but the result " + title + " didn't parse as one, skipping it",
logger.DEBUG)
continue
if manualSearch and ((parse_result.air_date != ep_objs[0].airdate and parse_result.air_by_date) or (
parse_result.sports_event_date != ep_objs[0].airdate and parse_result.sports)):
logger.log(u"Episode " + title + " didn't air on " + str(ep_objs[0].airdate) + ", skipping it",
logger.DEBUG)
continue
if not manualSearch:
myDB = db.DBConnection()
if parse_result.air_by_date:
sql_results = myDB.select(
"SELECT season, episode FROM tv_episodes WHERE showid = ? AND airdate = ?",
[self.show.indexerid, parse_result.air_date.toordinal()])
elif parse_result.sports:
sql_results = myDB.select(
"SELECT season, episode FROM tv_episodes WHERE showid = ? AND airdate = ?",
[self.show.indexerid, parse_result.sports_event_date.toordinal()])
if len(sql_results) != 1:
logger.log(
u"Tried to look up the date for the episode " + title + " but the database didn't give proper results, skipping it",
logger.WARNING)
if not (self.show.air_by_date or self.show.sports):
if not (self.show.air_by_date or self.show.sports):
if (parse_result.season_number != season or epObj.episode not in parse_result.episode_numbers):
logger.log(u"Episode " + title + " isn't " + str(season) + "x" + str(
epObj.episode) + ", skipping it", logger.DEBUG)
continue
actual_season = season if manualSearch else int(sql_results[0]["season"])
actual_episodes = [ep_objs[0].episode] if manualSearch else [int(sql_results[0]["episode"])]
else:
if not (parse_result.air_by_date or parse_result.sports):
logger.log(
u"This is supposed to be a date search but the result " + title + " didn't parse as one, skipping it",
logger.DEBUG)
continue
if ((parse_result.air_date != epObj.airdate and parse_result.air_by_date) or (
parse_result.sports_event_date != epObj.airdate and parse_result.sports)):
logger.log(u"Episode " + title + " didn't air on " + str(epObj.airdate) + ", skipping it",
logger.DEBUG)
continue
# make sure we want the episode
epObj = None
wantEp = True
for epNo in actual_episodes:
epObj = self.show.getEpisode(actual_season, epNo)
if not epObj or not self.show.wantEpisode(epObj.season, epObj.episode, quality,manualSearch=manualSearch):
wantEp = False
break
# make sure we want the episode
if not self.show.wantEpisode(epObj.season, epObj.episode, quality, manualSearch=manualSearch):
logger.log(
u"Ignoring result " + title + " because we don't want an episode that is " + Quality.qualityStrings[
quality], logger.DEBUG)
continue
if not epObj:
logger.log(u"Ignoring result " + title + " because episode scene info is invalid.")
continue
logger.log(u"Found result " + title + " at " + url, logger.DEBUG)
if not wantEp:
logger.log(
u"Ignoring result " + title + " because we don't want an episode that is " + Quality.qualityStrings[
quality], logger.DEBUG)
continue
# make a result object
epObjs = [epObj]
logger.log(u"Found result " + title + " at " + url, logger.DEBUG)
result = self.getResult(epObjs)
result.url = url
result.name = title
result.quality = quality
result.provider = self
result.content = None
# make a result object
epObjs = [epObj]
if len(epObjs) == 1:
epNum = epObjs[0].episode
logger.log(u"Single episode result.", logger.DEBUG)
elif len(epObjs) > 1:
epNum = MULTI_EP_RESULT
logger.log(u"Separating multi-episode result to check for later - result contains episodes: " + str(
parse_result.episode_numbers), logger.DEBUG)
elif len(epObjs) == 0:
epNum = SEASON_RESULT
result.extraInfo = [self.show]
logger.log(u"Separating full season result to check for later", logger.DEBUG)
result = self.getResult(epObjs)
result.url = url
result.name = title
result.quality = quality
result.provider = self
result.content = None
if epNum in results:
results[epNum].append(result)
else:
results[epNum] = [result]
if len(epObjs) == 1:
epNum = epObjs[0].episode
elif len(epObjs) > 1:
epNum = MULTI_EP_RESULT
logger.log(u"Separating multi-episode result to check for later - result contains episodes: " + str(
parse_result.episode_numbers), logger.DEBUG)
elif len(epObjs) == 0:
epNum = SEASON_RESULT
result.extraInfo = [self.show]
logger.log(u"Separating full season result to check for later", logger.DEBUG)
if epNum in results:
results[epNum].append(result)
else:
results = {epNum: [result]}
return results
return results
def findPropers(self, search_date=None):

View file

@ -117,7 +117,7 @@ class HDBitsProvider(generic.TorrentProvider):
# parse the file name
try:
myParser = NameParser()
parse_result = myParser.parse(title).convert()
parse_result = myParser.parse(title)
except InvalidNameException:
logger.log(u"Unable to parse the filename " + title + " into a valid episode", logger.WARNING)
continue

View file

@ -148,7 +148,7 @@ class KATProvider(generic.TorrentProvider):
try:
myParser = NameParser()
parse_result = myParser.parse(fileName).convert()
parse_result = myParser.parse(fileName)
except InvalidNameException:
return None

View file

@ -113,13 +113,14 @@ class NewznabProvider(generic.NZBProvider):
# search
params['q'] = helpers.sanitizeSceneName(self.show.name)
date_str = str(ep_obj.airdate)
if self.show.air_by_date:
date_str = str(ep_obj.airdate)
params['season'] = date_str.partition('-')[0]
params['ep'] = date_str.partition('-')[2].replace('-', '/')
elif self.show.sports:
date_str = str(ep_obj.airdate)
params['season'] = date_str.partition('-')[0]
params['ep'] = date_str.partition('-')[0]
params['ep'] = date_str.partition('-')[2].replace('-', '/')
else:
params['season'] = ep_obj.scene_season
params['ep'] = ep_obj.scene_episode

View file

@ -54,8 +54,8 @@ class NyaaProvider(generic.TorrentProvider):
quality = Quality.sceneQuality(title)
return quality
def getSearchResults(self, show, season, ep_objs, seasonSearch=False, manualSearch=False):
results = generic.TorrentProvider.getSearchResults(self, show, season, ep_objs, seasonSearch, manualSearch)
def getSearchResults(self, show, season, episodes, seasonSearch=False, manualSearch=False):
results = generic.TorrentProvider.getSearchResults(self, show, season, episodes, seasonSearch, manualSearch)
return results
def _get_season_search_strings(self, ep_obj):

View file

@ -157,7 +157,7 @@ class ThePirateBayProvider(generic.TorrentProvider):
try:
myParser = NameParser()
parse_result = myParser.parse(fileName).convert()
parse_result = myParser.parse(fileName)
except InvalidNameException:
return None

View file

@ -33,14 +33,13 @@ import sickbeard
from sickbeard import logger
from sickbeard import db
from sickbeard import helpers
from sickbeard.exceptions import ex
from lib import requests
MAX_XEM_AGE_SECS = 86400 # 1 day
def get_scene_numbering(indexer_id, season, episode, fallback_to_xem=True):
def get_scene_numbering(indexer_id, indexer, season, episode, fallback_to_xem=True):
"""
Returns a tuple, (season, episode), with the scene numbering (if there is one),
otherwise returns the xem numbering (if fallback_to_xem is set), otherwise
@ -56,28 +55,24 @@ def get_scene_numbering(indexer_id, season, episode, fallback_to_xem=True):
if indexer_id is None or season is None or episode is None:
return (season, episode)
result = find_scene_numbering(indexer_id, season, episode)
result = find_scene_numbering(indexer_id, indexer, season, episode)
if result:
return result
else:
if fallback_to_xem:
xem_result = find_xem_numbering(indexer_id, season, episode)
xem_result = find_xem_numbering(indexer_id, indexer, season, episode)
if xem_result:
return xem_result
return (season, episode)
def find_scene_numbering(indexer_id, season, episode):
def find_scene_numbering(indexer_id, indexer, season, episode):
"""
Same as get_scene_numbering(), but returns None if scene numbering is not set
"""
if indexer_id is None or season is None or episode is None:
return (season, episode)
showObj = helpers.findCertainShow(sickbeard.showList, indexer_id)
if showObj is None: return (season, episode)
indexer = showObj.indexer
myDB = db.DBConnection()
rows = myDB.select(
@ -87,7 +82,7 @@ def find_scene_numbering(indexer_id, season, episode):
return (int(rows[0]["scene_season"]), int(rows[0]["scene_episode"]))
def get_indexer_numbering(indexer_id, sceneSeason, sceneEpisode, fallback_to_xem=True):
def get_indexer_numbering(indexer_id, indexer, sceneSeason, sceneEpisode, fallback_to_xem=True):
"""
Returns a tuple, (season, episode) with the TVDB and TVRAGE numbering for (sceneSeason, sceneEpisode)
(this works like the reverse of get_scene_numbering)
@ -95,10 +90,6 @@ def get_indexer_numbering(indexer_id, sceneSeason, sceneEpisode, fallback_to_xem
if indexer_id is None or sceneSeason is None or sceneEpisode is None:
return (sceneSeason, sceneEpisode)
showObj = helpers.findCertainShow(sickbeard.showList, indexer_id)
if showObj is None: return (sceneSeason, sceneEpisode)
indexer = showObj.indexer
myDB = db.DBConnection()
rows = myDB.select(
@ -108,11 +99,11 @@ def get_indexer_numbering(indexer_id, sceneSeason, sceneEpisode, fallback_to_xem
return (int(rows[0]["season"]), int(rows[0]["episode"]))
else:
if fallback_to_xem:
return get_indexer_numbering_for_xem(indexer_id, sceneSeason, sceneEpisode)
return get_indexer_numbering_for_xem(indexer_id, indexer, sceneSeason, sceneEpisode)
return (sceneSeason, sceneEpisode)
def get_scene_numbering_for_show(indexer_id):
def get_scene_numbering_for_show(indexer_id, indexer):
"""
Returns a dict of (season, episode) : (sceneSeason, sceneEpisode) mappings
for an entire show. Both the keys and values of the dict are tuples.
@ -121,10 +112,6 @@ def get_scene_numbering_for_show(indexer_id):
if indexer_id is None:
return {}
showObj = helpers.findCertainShow(sickbeard.showList, indexer_id)
if showObj is None: return {}
indexer = showObj.indexer
myDB = db.DBConnection()
rows = myDB.select(
@ -137,7 +124,7 @@ def get_scene_numbering_for_show(indexer_id):
return result
def set_scene_numbering(indexer_id, season, episode, sceneSeason=None, sceneEpisode=None):
def set_scene_numbering(indexer_id, indexer, season, episode, sceneSeason=None, sceneEpisode=None):
"""
Set scene numbering for a season/episode.
To clear the scene numbering, leave both sceneSeason and sceneEpisode as None.
@ -146,10 +133,6 @@ def set_scene_numbering(indexer_id, season, episode, sceneSeason=None, sceneEpis
if indexer_id is None or season is None or episode is None:
return
showObj = helpers.findCertainShow(sickbeard.showList, indexer_id)
if showObj is None: return
indexer = showObj.indexer
myDB = db.DBConnection()
# sanity
@ -167,7 +150,7 @@ def set_scene_numbering(indexer_id, season, episode, sceneSeason=None, sceneEpis
[indexer, indexer_id, season, episode, sceneSeason, sceneEpisode])
def find_xem_numbering(indexer_id, season, episode):
def find_xem_numbering(indexer_id, indexer, season, episode):
"""
Returns the scene numbering, as retrieved from xem.
Refreshes/Loads as needed.
@ -180,12 +163,8 @@ def find_xem_numbering(indexer_id, season, episode):
if indexer_id is None or season is None or episode is None:
return None
showObj = helpers.findCertainShow(sickbeard.showList, indexer_id)
if showObj is None: return None
indexer = showObj.indexer
if _xem_refresh_needed(indexer_id):
_xem_refresh(indexer_id)
if _xem_refresh_needed(indexer_id, indexer):
_xem_refresh(indexer_id, indexer)
cacheDB = db.DBConnection('cache.db')
rows = cacheDB.select(
@ -197,7 +176,7 @@ def find_xem_numbering(indexer_id, season, episode):
return None
def get_indexer_numbering_for_xem(indexer_id, sceneSeason, sceneEpisode):
def get_indexer_numbering_for_xem(indexer_id, indexer, sceneSeason, sceneEpisode):
"""
Reverse of find_xem_numbering: lookup a tvdb season and episode using scene numbering
@ -209,12 +188,8 @@ def get_indexer_numbering_for_xem(indexer_id, sceneSeason, sceneEpisode):
if indexer_id is None or sceneSeason is None or sceneEpisode is None:
return None
showObj = helpers.findCertainShow(sickbeard.showList, indexer_id)
if showObj is None: return None
indexer = showObj.indexer
if _xem_refresh_needed(indexer_id):
_xem_refresh(indexer_id)
if _xem_refresh_needed(indexer_id, indexer):
_xem_refresh(indexer_id, indexer)
cacheDB = db.DBConnection('cache.db')
rows = cacheDB.select(
"SELECT season, episode FROM xem_numbering WHERE indexer = ? and indexer_id = ? and scene_season = ? and scene_episode = ?",
@ -225,7 +200,7 @@ def get_indexer_numbering_for_xem(indexer_id, sceneSeason, sceneEpisode):
return (sceneSeason, sceneEpisode)
def _xem_refresh_needed(indexer_id):
def _xem_refresh_needed(indexer_id, indexer):
"""
Is a refresh needed on a show?
@ -235,10 +210,6 @@ def _xem_refresh_needed(indexer_id):
if indexer_id is None:
return False
showObj = helpers.findCertainShow(sickbeard.showList, indexer_id)
if showObj is None: return False
indexer = showObj.indexer
cacheDB = db.DBConnection('cache.db')
rows = cacheDB.select("SELECT last_refreshed FROM xem_refresh WHERE indexer = ? and indexer_id = ?",
[indexer, indexer_id])
@ -248,7 +219,7 @@ def _xem_refresh_needed(indexer_id):
return True
def _xem_refresh(indexer_id):
def _xem_refresh(indexer_id, indexer):
"""
Refresh data from xem for a tv show
@ -257,10 +228,6 @@ def _xem_refresh(indexer_id):
if indexer_id is None:
return
showObj = helpers.findCertainShow(sickbeard.showList, indexer_id)
if showObj is None: return
indexer = showObj.indexer
try:
logger.log(
u'Looking up XEM scene mapping for show %s on %s' % (indexer_id, sickbeard.indexerApi(indexer).name,),
@ -311,7 +278,7 @@ def _xem_refresh(indexer_id):
return None
def get_xem_numbering_for_show(indexer_id):
def get_xem_numbering_for_show(indexer_id, indexer):
"""
Returns a dict of (season, episode) : (sceneSeason, sceneEpisode) mappings
for an entire show. Both the keys and values of the dict are tuples.
@ -320,12 +287,8 @@ def get_xem_numbering_for_show(indexer_id):
if indexer_id is None:
return {}
showObj = helpers.findCertainShow(sickbeard.showList, indexer_id)
if showObj is None: return {}
indexer = showObj.indexer
if _xem_refresh_needed(indexer_id):
_xem_refresh(indexer_id)
if _xem_refresh_needed(indexer_id, indexer):
_xem_refresh(indexer_id, indexer)
cacheDB = db.DBConnection('cache.db')
@ -340,7 +303,7 @@ def get_xem_numbering_for_show(indexer_id):
return result
def get_xem_numbering_for_season(indexer_id, season):
def get_xem_numbering_for_season(indexer_id, indexer, season):
"""
Returns a dict of (season, episode) : (sceneSeason, sceneEpisode) mappings
for an entire show. Both the keys and values of the dict are tuples.
@ -349,17 +312,13 @@ def get_xem_numbering_for_season(indexer_id, season):
if indexer_id is None or season is None:
return {}
showObj = helpers.findCertainShow(sickbeard.showList, indexer_id)
if showObj is None: return {}
indexer = showObj.indexer
if _xem_refresh_needed(indexer_id):
_xem_refresh(indexer_id)
if _xem_refresh_needed(indexer_id, indexer):
_xem_refresh(indexer_id, indexer)
cacheDB = db.DBConnection('cache.db')
rows = cacheDB.select(
'SELECT season, scene_season FROM xem_numbering WHERE indexer = ? and indexer_id = ? AND season = ? ORDER BY season, [indexer, indexer_id, season]')
'SELECT season, scene_season FROM xem_numbering WHERE indexer = ? and indexer_id = ? AND season = ? ORDER BY season', [indexer, indexer_id, season])
result = {}
if rows:

View file

@ -184,8 +184,6 @@ def searchForNeededEpisodes():
if not curProvider.isActive():
continue
curFoundResults = {}
try:
curFoundResults = curProvider.searchRSS()
except exceptions.AuthException, e:
@ -365,62 +363,33 @@ def filterSearchResults(show, results):
return foundResults
def searchProviders(show, season, episode=None, manualSearch=False):
def searchProviders(show, season, episodes, manualSearch=False):
logger.log(u"Searching for stuff we need from " + show.name + " season " + str(season))
foundResults = {}
didSearch = False
seasonSearch = False
# gather all episodes for season and then pick out the wanted episodes and compare to determin if we want whole season or just a few episodes
if episode is None:
seasonEps = show.getAllEpisodes(season)
wantedEps = [x for x in seasonEps if show.getOverview(x.status) in (Overview.WANTED, Overview.QUAL)]
if len(seasonEps) == len(wantedEps):
seasonSearch = True
else:
ep_obj = show.getEpisode(season, episode)
wantedEps = [ep_obj]
for curProvider in providers.sortedProviderList():
if not curProvider.isActive():
continue
# update cache
if manualSearch:
curProvider.cache.updateCache()
try:
curResults = curProvider.findSearchResults(show, season, episodes, manualSearch)
except exceptions.AuthException, e:
logger.log(u"Authentication error: " + ex(e), logger.ERROR)
continue
except Exception, e:
logger.log(u"Error while searching " + curProvider.name + ", skipping: " + ex(e), logger.ERROR)
logger.log(traceback.format_exc(), logger.DEBUG)
continue
# search cache first for wanted episodes
for ep_obj in wantedEps:
curResults = curProvider.cache.searchCache(ep_obj, manualSearch)
curResults = filterSearchResults(show, curResults)
if len(curResults):
foundResults.update(curResults)
logger.log(u"Cache results: " + repr(foundResults), logger.DEBUG)
didSearch = True
# finished searching this provider successfully
didSearch = True
if not len(foundResults):
for curProvider in providers.sortedProviderList():
if not curProvider.isActive():
continue
try:
curResults = curProvider.getSearchResults(show, season, wantedEps, seasonSearch, manualSearch)
except exceptions.AuthException, e:
logger.log(u"Authentication error: " + ex(e), logger.ERROR)
continue
except Exception, e:
logger.log(u"Error while searching " + curProvider.name + ", skipping: " + ex(e), logger.ERROR)
logger.log(traceback.format_exc(), logger.DEBUG)
continue
# finished searching this provider successfully
didSearch = True
curResults = filterSearchResults(show, curResults)
if len(curResults):
foundResults.update(curResults)
logger.log(u"Provider search results: " + str(foundResults), logger.DEBUG)
curResults = filterSearchResults(show, curResults)
if len(curResults):
foundResults.update(curResults)
logger.log(u"Provider search results: " + str(foundResults), logger.DEBUG)
if not didSearch:
logger.log(u"No NZB/Torrent providers found or enabled in the sickbeard config. Please check your settings.",

View file

@ -96,7 +96,6 @@ class BacklogSearcher:
# get separate lists of the season/date shows
#season_shows = [x for x in show_list if not x.air_by_date]
air_by_date_shows = [x for x in show_list if x.air_by_date]
sports_shows = [x for x in show_list if x.sports]
# figure out how many segments of air by date shows we're going to do
air_by_date_segments = []
@ -105,12 +104,6 @@ class BacklogSearcher:
logger.log(u"Air-by-date segments: " + str(air_by_date_segments), logger.DEBUG)
sports_segments = []
for cur_id in [x.indexerid for x in sports_shows]:
sports_segments += self._get_sports_segments(cur_id, fromDate)
logger.log(u"Sports segments: " + str(sports_segments), logger.DEBUG)
#totalSeasons = float(len(numSeasonResults) + len(air_by_date_segments))
#numSeasonsDone = 0.0
@ -122,10 +115,8 @@ class BacklogSearcher:
if curShow.air_by_date:
segments = [x[1] for x in self._get_air_by_date_segments(curShow.indexerid, fromDate)]
elif curShow.sports:
segments = self._get_sports_segments(curShow.indexerid, fromDate)
else:
segments = self._get_season_segments(curShow.indexerid, fromDate)
segments = self._get_segments(curShow.indexerid, fromDate)
for cur_segment in segments:
@ -133,12 +124,12 @@ class BacklogSearcher:
backlog_queue_item = search_queue.BacklogQueueItem(curShow, cur_segment)
if not backlog_queue_item.wantSeason:
if backlog_queue_item.wantedEpisodes:
sickbeard.searchQueueScheduler.action.add_item(backlog_queue_item) #@UndefinedVariable
else:
logger.log(
u"Nothing in season " + str(cur_segment) + " needs to be downloaded, skipping this season",
logger.DEBUG)
else:
sickbeard.searchQueueScheduler.action.add_item(backlog_queue_item) #@UndefinedVariable
# don't consider this an actual backlog search if we only did recent eps
# or if we only did certain shows
@ -167,11 +158,12 @@ class BacklogSearcher:
self._lastBacklog = lastBacklog
return self._lastBacklog
def _get_season_segments(self, indexer_id, fromDate):
def _get_segments(self, indexer_id, fromDate):
myDB = db.DBConnection()
sqlResults = myDB.select(
"SELECT DISTINCT(season) as season FROM tv_episodes WHERE showid = ? AND season > 0 and airdate > ?",
[indexer_id, fromDate.toordinal()])
return [int(x["season"]) for x in sqlResults]
def _get_air_by_date_segments(self, indexer_id, fromDate):
@ -194,12 +186,6 @@ class BacklogSearcher:
return air_by_date_segments
def _get_sports_segments(self, indexer_id, fromDate):
myDB = db.DBConnection()
sqlResults = myDB.select(
"SELECT DISTINCT(season) as season FROM tv_episodes WHERE showid = ? AND season > 0 and airdate > ?",
[indexer_id, fromDate.toordinal()])
return [int(x["season"]) for x in sqlResults]
def _set_lastBacklog(self, when):

View file

@ -68,7 +68,6 @@ class SearchQueue(generic_queue.GenericQueue):
def add_item(self, item):
if isinstance(item, RSSSearchQueueItem):
generic_queue.GenericQueue.add_item(self, item)
# don't do duplicates
elif isinstance(item, BacklogQueueItem) and not self.is_in_queue(item.show, item.segment):
generic_queue.GenericQueue.add_item(self, item)
elif isinstance(item, ManualSearchQueueItem) and not self.is_ep_in_queue(item.ep_obj):
@ -93,7 +92,7 @@ class ManualSearchQueueItem(generic_queue.QueueItem):
logger.log("Beginning manual search for " + self.ep_obj.prettyName())
foundResults = search.searchProviders(self.ep_obj.show, self.ep_obj.season, self.ep_obj.episode, manualSearch=True)
foundResults = search.searchProviders(self.ep_obj.show, self.ep_obj.season, [self.ep_obj], manualSearch=True)
result = False
if not foundResults:
@ -186,6 +185,7 @@ class BacklogQueueItem(generic_queue.QueueItem):
self.show = show
self.segment = segment
self.wantedEpisodes = []
logger.log(u"Seeing if we need any episodes from " + self.show.name + " season " + str(self.segment))
@ -193,7 +193,7 @@ class BacklogQueueItem(generic_queue.QueueItem):
# see if there is anything in this season worth searching for
if not self.show.air_by_date:
statusResults = myDB.select("SELECT status FROM tv_episodes WHERE showid = ? AND season = ?",
statusResults = myDB.select("SELECT status, episode FROM tv_episodes WHERE showid = ? AND season = ?",
[self.show.indexerid, self.segment])
else:
season_year, season_month = map(int, self.segment.split('-'))
@ -206,17 +206,17 @@ class BacklogQueueItem(generic_queue.QueueItem):
max_date = datetime.date(season_year, season_month + 1, 1) - datetime.timedelta(days=1)
statusResults = myDB.select(
"SELECT status FROM tv_episodes WHERE showid = ? AND airdate >= ? AND airdate <= ?",
"SELECT status, episode FROM tv_episodes WHERE showid = ? AND airdate >= ? AND airdate <= ?",
[self.show.indexerid, min_date.toordinal(), max_date.toordinal()])
anyQualities, bestQualities = common.Quality.splitQuality(self.show.quality) #@UnusedVariable
self.wantSeason = self._need_any_episodes(statusResults, bestQualities)
self.wantedEpisodes = self._need_any_episodes(statusResults, bestQualities)
def execute(self):
generic_queue.QueueItem.execute(self)
results = search.searchProviders(self.show, self.segment)
results = search.searchProviders(self.show, self.segment, self.wantedEpisodes)
# download whatever we find
for curResult in results:
@ -226,13 +226,13 @@ class BacklogQueueItem(generic_queue.QueueItem):
self.finish()
def _need_any_episodes(self, statusResults, bestQualities):
wantSeason = False
wantedEpisodes = []
# check through the list of statuses to see if we want any
for curStatusResult in statusResults:
curCompositeStatus = int(curStatusResult["status"])
curStatus, curQuality = common.Quality.splitCompositeStatus(curCompositeStatus)
episode = int(curStatusResult["episode"])
if bestQualities:
highestBestQuality = max(bestQualities)
@ -242,44 +242,45 @@ class BacklogQueueItem(generic_queue.QueueItem):
# 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:
wantSeason = True
break
epObj = self.show.getEpisode(self.segment,episode)
wantedEpisodes.append(epObj)
return wantSeason
return wantedEpisodes
class FailedQueueItem(generic_queue.QueueItem):
def __init__(self, show, segment):
def __init__(self, show, episodes):
generic_queue.QueueItem.__init__(self, 'Retry', MANUAL_SEARCH)
self.priority = generic_queue.QueuePriorities.HIGH
self.thread_name = 'RETRY-' + str(show.indexerid)
self.show = show
self.segment = segment
self.episodes = episodes
self.success = None
def execute(self):
generic_queue.QueueItem.execute(self)
for season, episode in self.segment.iteritems():
epObj = self.show.getEpisode(season, episode)
episodes = []
(release, provider) = failed_history.findRelease(self.show, season, episode)
for epObj in episodes:
(release, provider) = failed_history.findRelease(self.show, epObj.season, epObj.episode)
if release:
logger.log(u"Marking release as bad: " + release)
failed_history.markFailed(self.show, season, episode)
failed_history.markFailed(self.show, epObj.season, epObj.episode)
failed_history.logFailed(release)
history.logFailed(self.show.indexerid, season, episode, epObj.status, release, provider)
history.logFailed(self.show.indexerid, epObj.season, epObj.episode, epObj.status, release, provider)
failed_history.revertEpisode(self.show, season, episode)
failed_history.revertEpisode(self.show, epObj.season, epObj.episode)
episodes.append(epObj)
# get search results
results = search.searchProviders(self.show, season, episode)
# get search results
results = search.searchProviders(self.show, episodes[0].season, episodes)
# download whatever we find
for curResult in results:
self.success = search.snatchEpisode(curResult)
time.sleep(5)
# download whatever we find
for curResult in results:
self.success = search.snatchEpisode(curResult)
time.sleep(5)
self.finish()

View file

@ -139,7 +139,7 @@ class TVShow(object):
sql_selection = sql_selection + " FROM tv_episodes tve WHERE showid = " + str(self.indexerid)
if season is not None:
if not self.air_by_date and not self.sports:
if not self.air_by_date:
sql_selection = sql_selection + " AND season = " + str(season)
else:
segment_year, segment_month = map(int, str(season).split('-'))
@ -1128,15 +1128,26 @@ def dirty_setter(attr_name):
class TVEpisode(object):
def __init__(self, show, season, episode, file=""):
# Convert season/episode to XEM scene numbering
scene_season, scene_episode = sickbeard.scene_numbering.get_scene_numbering(show.indexerid, season, episode)
def __init__(self, show, season=None, episode=None, scene_season=None, scene_episode=None, file=""):
# convert from indexer numbering <-> scene numerbing and back again once we have correct season and episode numbers
if season and episode:
self._scene_season, self._scene_episode = sickbeard.scene_numbering.get_scene_numbering(show.indexerid,
show.indexer,
season, episode)
self._season, self._episode = sickbeard.scene_numbering.get_indexer_numbering(show.indexerid, show.indexer,
self._scene_season,
self._scene_episode)
# convert from scene numbering <-> indexer numbering and back again once we have correct season and episode numbers
elif scene_season and scene_episode:
self._season, self._episode = sickbeard.scene_numbering.get_indexer_numbering(show.indexerid, show.indexer,
scene_season,
scene_episode)
self._scene_season, self._scene_episode = sickbeard.scene_numbering.get_scene_numbering(show.indexerid,
show.indexer,
self._season,
self._episode)
self._name = ""
self._season = season
self._episode = episode
self._scene_season = scene_season
self._scene_episode = scene_episode
self._description = ""
self._subtitles = list()
self._subtitles_searchcount = 0
@ -1161,7 +1172,7 @@ class TVEpisode(object):
self.lock = threading.Lock()
self.specifyEpisode(self.season, self.episode)
self.specifyEpisode(self.season, self.episode, self.scene_season, self.scene_episode)
self.relatedEps = []
@ -1299,9 +1310,9 @@ class TVEpisode(object):
# if either setting has changed return true, if not return false
return oldhasnfo != self.hasnfo or oldhastbn != self.hastbn
def specifyEpisode(self, season, episode):
def specifyEpisode(self, season, episode, scene_season, scene_episode):
sqlResult = self.loadFromDB(season, episode)
sqlResult = self.loadFromDB(season, episode, scene_season, scene_episode)
if not sqlResult:
# only load from NFO if we didn't load from DB
@ -1316,7 +1327,7 @@ class TVEpisode(object):
# if we tried loading it from NFO and didn't find the NFO, try the Indexers
if self.hasnfo == False:
try:
result = self.loadFromIndexer(season, episode)
result = self.loadFromIndexer(season, episode, scene_season, scene_episode)
except exceptions.EpisodeDeletedException:
result = False
@ -1325,7 +1336,7 @@ class TVEpisode(object):
raise exceptions.EpisodeNotFoundException(
"Couldn't find episode " + str(season) + "x" + str(episode))
def loadFromDB(self, season, episode):
def loadFromDB(self, season, episode, scene_season, scene_episode):
logger.log(
str(self.show.indexerid) + u": Loading episode details from DB for episode " + str(season) + "x" + str(
@ -1345,9 +1356,11 @@ class TVEpisode(object):
#NAMEIT logger.log(u"AAAAA from" + str(self.season)+"x"+str(self.episode) + " -" + self.name + " to " + str(sqlResults[0]["name"]))
if sqlResults[0]["name"]:
self.name = sqlResults[0]["name"]
self.season = season
self.episode = episode
self.scene_season = scene_season
self.scene_episode = scene_episode
self.description = sqlResults[0]["description"]
if not self.description:
self.description = ""
@ -1379,13 +1392,18 @@ class TVEpisode(object):
self.dirty = False
return True
def loadFromIndexer(self, season=None, episode=None, cache=True, tvapi=None, cachedSeason=None):
def loadFromIndexer(self, season=None, episode=None, scene_season=None, scene_episode=None, cache=True, tvapi=None, cachedSeason=None):
if season is None:
season = self.season
if episode is None:
episode = self.episode
if scene_season is None:
scene_season = self.scene_season
if scene_episode is None:
scene_episode = self.scene_episode
logger.log(str(self.show.indexerid) + u": Loading episode details from " + sickbeard.indexerApi(
self.show.indexer).name + " for episode " + str(season) + "x" + str(episode), logger.DEBUG)
@ -1676,11 +1694,11 @@ class TVEpisode(object):
# use a custom update/insert method to get the data into the DB
return [
"INSERT OR REPLACE INTO tv_episodes (episode_id, indexerid, indexer, name, description, subtitles, subtitles_searchcount, subtitles_lastsearch, airdate, hasnfo, hastbn, status, location, file_size, release_name, is_proper, showid, season, episode) VALUES ((SELECT episode_id FROM tv_episodes WHERE showid = ? AND season = ? AND episode = ?),?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);",
"INSERT OR REPLACE INTO tv_episodes (episode_id, indexerid, indexer, name, description, subtitles, subtitles_searchcount, subtitles_lastsearch, airdate, hasnfo, hastbn, status, location, file_size, release_name, is_proper, showid, season, episode) VALUES ((SELECT episode_id FROM tv_episodes WHERE showid = ? AND season = ? AND episode = ? AND scene_season = ? AND scene_episode = ?),?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);",
[self.show.indexerid, self.season, self.episode, self.indexerid, self.indexer, self.name, self.description,
",".join([sub for sub in self.subtitles]), self.subtitles_searchcount, self.subtitles_lastsearch,
self.airdate.toordinal(), self.hasnfo, self.hastbn, self.status, self.location, self.file_size,
self.release_name, self.is_proper, self.show.indexerid, self.season, self.episode]]
self.release_name, self.is_proper, self.show.indexerid, self.season, self.episode, self.scene_season, self.scene_episode]]
def saveToDB(self, forceSave=False):
"""
@ -1714,7 +1732,9 @@ class TVEpisode(object):
"location": self.location,
"file_size": self.file_size,
"release_name": self.release_name,
"is_proper": self.is_proper}
"is_proper": self.is_proper,
"scene_season": self.scene_season,
"scene_episode": self.scene_episode}
controlValueDict = {"showid": self.show.indexerid,
"season": self.season,
"episode": self.episode}
@ -1748,16 +1768,6 @@ class TVEpisode(object):
return self._format_pattern('%SN - %XMSx%0XME - %EN')
def sports_prettyName(self):
"""
Returns the name of this episode in a "pretty" human-readable format. Used for logging
and notifications and such.
Returns: A string representing the episode's name and season/ep numbers
"""
return self._format_pattern('%SN - %A-D - %EN')
def _ep_name(self):
"""
Returns the name of the episode to use during renaming. Combines the names of related episodes.

View file

@ -56,14 +56,6 @@ class CacheDBConnection(db.DBConnection):
if str(e) != "table lastUpdate already exists":
raise
# Clear out records missing there Indexer IDs
try:
sql = "DELETE FROM [" + providerName + "] WHERE indexerid is NULL or indexerid is 0"
self.connection.execute(sql)
self.connection.commit()
except:
pass
class TVCache():
def __init__(self, provider):
@ -113,15 +105,15 @@ class TVCache():
if self._checkAuth(data):
items = data.entries
cl = []
ql = []
for item in items:
ci = self._parseItem(item)
if ci is not None:
cl.append(ci)
qi = self._parseItem(item)
if qi is not None:
ql.append(qi)
if len(cl) > 0:
if len(ql):
myDB = self._getDB()
myDB.mass_action(cl)
myDB.mass_action(ql)
else:
raise AuthException(
@ -192,14 +184,13 @@ class TVCache():
def _addCacheEntry(self, name, url, quality=None):
cacheDB = self._getDB()
season = None
episodes = None
# if we don't have complete info then parse the filename to get it
try:
myParser = NameParser()
parse_result = myParser.parse(name).convert()
parse_result = myParser.parse(name)
except InvalidNameException:
logger.log(u"Unable to parse the filename " + name + " into a valid episode", logger.DEBUG)
return None
@ -212,42 +203,41 @@ class TVCache():
logger.log(u"No series name retrieved from " + name + ", unable to cache it", logger.DEBUG)
return None
if not parse_result.show:
logger.log(u"Couldn't find a show in our databases matching " + name + ", unable to cache it", logger.DEBUG)
if not helpers.get_show_by_name(parse_result.series_name):
logger.log(u"Could not find a show matching " + parse_result.series_name + " in the database, skipping ...", logger.DEBUG)
return None
try:
if parse_result.air_by_date:
myDB = db.DBConnection()
if parse_result.show.air_by_date:
airdate = parse_result.sports_event_date.toordinal() if parse_result.show.sports else parse_result.air_date.toordinal()
sql_results = myDB.select("SELECT season, episode FROM tv_episodes WHERE showid = ? AND airdate = ?",
[parse_result.show.indexerid, airdate])
if sql_results > 0:
season = int(sql_results[0]["season"])
episodes = [int(sql_results[0]["episode"])]
else:
season = parse_result.season_number
episodes = parse_result.episode_numbers
if season and episodes:
# store episodes as a seperated string
episodeText = "|" + "|".join(map(str, episodes)) + "|"
airdate = parse_result.air_date.toordinal()
sql_results = myDB.select("SELECT season, episode FROM tv_episodes WHERE showid = ? AND indexer = ? AND airdate = ?",
[parse_result.show.indexerid, parse_result.show.indexer, airdate])
if sql_results > 0:
season = int(sql_results[0]["season"])
episodes = [int(sql_results[0]["episode"])]
else:
season = parse_result.season_number
episodes = parse_result.episode_numbers
# get the current timestamp
curTimestamp = int(time.mktime(datetime.datetime.today().timetuple()))
if season and episodes:
# store episodes as a seperated string
episodeText = "|" + "|".join(map(str, episodes)) + "|"
# get quality of release
if quality is None:
quality = Quality.sceneQuality(name)
# get the current timestamp
curTimestamp = int(time.mktime(datetime.datetime.today().timetuple()))
if not isinstance(name, unicode):
name = unicode(name, 'utf-8')
# get quality of release
if quality is None:
quality = Quality.sceneQuality(name)
cacheDB.action(
"INSERT INTO [" + self.providerID + "] (name, season, episodes, indexerid, url, time, quality) VALUES (?,?,?,?,?,?,?)",
[name, season, episodeText, parse_result.show.indexerid, url, curTimestamp, quality])
except:
return
if not isinstance(name, unicode):
name = unicode(name, 'utf-8')
logger.log(u"Added RSS item: [" + name + "] to cache: [" + self.providerID + "]", logger.DEBUG)
return ["INSERT INTO [" + self.providerID + "] (name, season, episodes, indexerid, url, time, quality) VALUES (?,?,?,?,?,?,?)",
[name, season, episodeText, parse_result.show.indexerid, url, curTimestamp, quality]]
def searchCache(self, episode, manualSearch=False):
neededEps = self.findNeededEpisodes(episode, manualSearch)
@ -275,7 +265,7 @@ class TVCache():
else:
sqlResults = myDB.select(
"SELECT * FROM [" + self.providerID + "] WHERE indexerid = ? AND season = ? AND episodes LIKE ?",
[episode.show.indexerid, episode.season, "%|" + str(episode.episode) + "|%"])
[episode.show.indexerid, episode.scene_season, "%|" + str(episode.scene_episode) + "|%"])
# for each cache entry
for curResult in sqlResults:

View file

@ -2833,8 +2833,8 @@ class Home:
#t.all_scene_exceptions = list(set((get_scene_exceptions(showObj.indexerid) or []) + (get_custom_exceptions(showObj.indexerid) or [])))
t.all_scene_exceptions = get_scene_exceptions(showObj.indexerid)
t.scene_numbering = get_scene_numbering_for_show(showObj.indexerid)
t.xem_numbering = get_xem_numbering_for_show(showObj.indexerid)
t.scene_numbering = get_scene_numbering_for_show(showObj.indexerid, showObj.indexer)
t.xem_numbering = get_xem_numbering_for_show(showObj.indexerid, showObj.indexer)
return _munge(t)
@ -3404,7 +3404,7 @@ class Home:
set_scene_numbering(show, forSeason, forEpisode, sceneSeason, sceneEpisode)
sn = get_scene_numbering(show, forSeason, forEpisode)
sn = get_scene_numbering(show, ep_obj.indexer, forSeason, forEpisode)
if sn:
(result['sceneSeason'], result['sceneEpisode']) = sn
else:
@ -3421,7 +3421,7 @@ class Home:
return json.dumps({'result': 'failure'})
# make a queue item for it and put it on the queue
ep_queue_item = search_queue.FailedQueueItem(ep_obj.show, {ep_obj.season: ep_obj.episode})
ep_queue_item = search_queue.FailedQueueItem(ep_obj.show, [ep_obj])
sickbeard.searchQueueScheduler.action.add_item(ep_queue_item) # @UndefinedVariable
# wait until the queue item tells us whether it worked or not

View file

@ -33,6 +33,21 @@ from sickbeard.name_parser.parser import NameParser
from sickbeard.tv import TVShow
class XEMBasicTests(test.SickbeardTestDBCase):
def loadShowsFromDB(self):
"""
Populates the showList with shows from the database
"""
myDB = test.db.DBConnection()
sqlResults = myDB.select("SELECT * FROM tv_shows")
for sqlShow in sqlResults:
try:
curShow = TVShow(int(sqlShow["indexer"]), int(sqlShow["indexer_id"]))
sickbeard.showList.append(curShow)
except Exception:
pass
def loadFromDB(self):
"""
Populates the showList with shows from the database
@ -49,9 +64,7 @@ class XEMBasicTests(test.SickbeardTestDBCase):
print "There was an error creating the show"
def test_formating(self):
self.loadFromDB()
release = "d:\\Downloads\\newdownload\\2.Broke.Girls.S03E10.And.the.First.Day.of.School.720p.WEB-DL.DD5.1.H.264-BS.mkv"
release = "UFC.172.26th.April.2014.HDTV.x264.720p-Sir.Paul[rartv]"
# parse the name to break it into show name, season, and episode
np = NameParser(file)
parse_result = np.parse(release).convert()