def findEpisode (self, episode, manualSearch=False): self._checkAuth() logger.log(u"Searching "+self.name+" for " + episode.prettyName(True)) self.cache.updateCache() results = self.cache.searchCache(episode, manualSearch) logger.log(u"Cache results: "+str(results), logger.DEBUG) # if we got some results then use them no matter what. # OR # return anyway unless we're doing a manual search if results or not manualSearch: return results itemList = [] for cur_search_string in self._get_episode_search_strings(episode): itemList += self._doSearch(cur_search_string) for item in itemList: title = item.findtext('title') url = item.findtext('link').replace('&','&') # parse the file name try: myParser = FileParser(title) epInfo = myParser.parse() except tvnamer_exceptions.InvalidFilename: logger.log(u"Unable to parse the filename "+title+" into a valid episode", logger.WARNING) continue if episode.show.is_air_by_date: if epInfo.episodenumbers[0] != episode.airdate: logger.log("Episode "+title+" didn't air on "+str(episode.airdate)+", skipping it", logger.DEBUG) continue elif epInfo.seasonnumber != episode.season or episode.episode not in epInfo.episodenumbers: logger.log("Episode "+title+" isn't "+str(episode.season)+"x"+str(episode.episode)+", skipping it", logger.DEBUG) continue quality = self.getQuality(item) if not episode.show.wantEpisode(episode.season, episode.episode, quality, manualSearch): logger.log(u"Ignoring result "+title+" because we don't want an episode that is "+Quality.qualityStrings[quality], logger.DEBUG) continue logger.log(u"Found result " + title + " at " + url, logger.DEBUG) result = self.getResult([episode]) result.url = url result.name = title result.quality = quality results.append(result) return results
def processFile(fileName, downloadDir=None, nzbName=None): returnStr = '' folderName = None if downloadDir != None: folderName = downloadDir.split(os.path.sep)[-1] returnStr += logHelper("Processing file "+fileName+" (with folder name "+str(folderName)+" and NZB name "+str(nzbName)+")", logger.DEBUG) finalNameList = [] for curName in (fileName, folderName, nzbName): if curName != None: for curSceneName in helpers.sceneToNormalShowNames(curName): if curSceneName not in finalNameList: finalNameList.append(curSceneName) showResults = None result = None for curName in finalNameList: try: returnStr += logHelper("Attempting to parse name "+curName, logger.DEBUG) myParser = FileParser(curName) result = myParser.parse() except tvnamer_exceptions.InvalidFilename: returnStr += logHelper("Unable to parse the filename "+curName+" into a valid episode", logger.DEBUG) continue if not result.seriesname: returnStr += logHelper("Filename "+curName+" has no series name, unable to use this name for processing", logger.DEBUG) continue try: t = tvdb_api.Tvdb(custom_ui=classes.ShowListUI, **sickbeard.TVDB_API_PARMS) showObj = t[result.seriesname] showInfo = (int(showObj["id"]), showObj["seriesname"]) except (tvdb_exceptions.tvdb_exception, IOError), e: returnStr += logHelper("TVDB didn't respond, trying to look up the show in the DB instead: "+str(e), logger.DEBUG) showInfo = helpers.searchDBForShow(result.seriesname) # if we didn't get anything from TVDB or the DB then try the next option if showInfo == None: continue # find the show in the showlist try: showResults = helpers.findCertainShow(sickbeard.showList, showInfo[0]) except exceptions.MultipleShowObjectsException: raise #TODO: later I'll just log this, for now I want to know about it ASAP if showResults != None: returnStr += logHelper("Found the show in our list, continuing", logger.DEBUG) break
def makeEpFromFile(self, file): if not os.path.isfile(file): logger.log(str(self.tvdbid) + ": That isn't even a real file dude... " + file) return None logger.log(str(self.tvdbid) + ": Creating episode object from " + file, logger.DEBUG) try: myParser = FileParser(file) epInfo = myParser.parse() except tvnamer_exceptions.InvalidFilename: logger.log("Unable to parse the filename "+file+" into a valid episode", logger.ERROR) return None # for now lets assume that any episode in the show dir belongs to that show season = epInfo.seasonnumber rootEp = None for curEp in epInfo.episodenumber: episode = int(curEp) logger.log(str(self.tvdbid) + ": " + file + " parsed to " + self.name + " " + str(season) + "x" + str(episode), logger.DEBUG) curEp = self.getEpisode(season, episode) if curEp == None: try: curEp = self.getEpisode(season, episode, file) except exceptions.EpisodeNotFoundException: logger.log(str(self.tvdbid) + ": Unable to figure out what this file is, skipping", logger.ERROR) continue else: with curEp.lock: curEp.location = file curEp.checkForMetaFiles() if rootEp == None: rootEp = curEp else: rootEp.relatedEps.append(curEp) if sickbeard.helpers.isMediaFile(file): with curEp.lock: curEp.status = DOWNLOADED logger.log("STATUS: we have an associated file, so setting the status to DOWNLOADED/" + str(DOWNLOADED), logger.DEBUG) with curEp.lock: curEp.saveToDB() # creating metafiles on the root should be good enough if rootEp != None: with rootEp.lock: rootEp.createMetaFiles() return None
def findSeasonResults(show, season): itemList = [] results = {} for curString in helpers.makeSceneSeasonSearchString(show, season, "nzbmatrix"): itemList += _doSearch(curString) for item in itemList: title = item.findtext('title') url = item.findtext('link') quality = Quality.nameQuality(title) # parse the file name try: myParser = FileParser(title) epInfo = myParser.parse() except tvnamer_exceptions.InvalidFilename: logger.log("Unable to parse the filename "+title+" into a valid episode", logger.ERROR) continue if epInfo.seasonnumber != season: logger.log("The result "+title+" doesn't seem to be a valid episode for season "+str(season)+", ignoring") continue # make sure we want the episode wantEp = True for epNo in epInfo.episodenumbers: if not show.wantEpisode(season, epNo, quality): logger.log("Ignoring result "+title+" because we don't want an episode that is "+Quality.qualityStrings[quality], logger.DEBUG) wantEp = False break if not wantEp: continue logger.log("Found result " + title + " at " + url, logger.DEBUG) # make a result object epNum = epInfo.episodenumbers[0] epObj = show.getEpisode(season, epNum) result = classes.NZBSearchResult(epObj) result.provider = providerName.lower() result.url = url result.extraInfo = [title] result.quality = quality if epNum in results: results[epNum].append(result) else: results[epNum] = [result] return results
def findEpisode(self, episode, manualSearch=False): nzbResults = generic.NZBProvider.findEpisode(self, episode, manualSearch) # if we got some results then use them no matter what. # OR # return anyway unless we're doing a manual search if nzbResults or not manualSearch: return nzbResults sceneSearchStrings = set(sceneHelpers.makeSceneSearchString(episode)) results = [] # search for all show names and episode numbers like ("a","b","c") in a single search nzbMatrixSearchString = '("' + '","'.join(sceneSearchStrings) + '")' itemList = self._doSearch(nzbMatrixSearchString) for item in itemList: title = item.findtext("title") url = item.findtext("link").replace("&", "&") # parse the file name try: myParser = FileParser(title) epInfo = myParser.parse() except tvnamer_exceptions.InvalidFilename: logger.log(u"Unable to parse the name " + title + " into a valid episode", logger.WARNING) continue quality = self.getQuality(item) season = epInfo.seasonnumber if epInfo.seasonnumber != None else 1 if not episode.show.wantEpisode(season, episode.episode, quality, manualSearch): logger.log( u"Ignoring result " + title + " because we don't want an episode that is " + Quality.qualityStrings[quality], logger.DEBUG, ) continue logger.log(u"Found result " + title + " at " + url, logger.DEBUG) result = self.getResult([episode]) result.url = url result.name = title result.quality = quality results.append(result) return results
def findEpisode (episode, manualSearch=False): logger.log("Searching NZBMatrix for " + episode.prettyName(True)) myCache = NZBMatrixCache() myCache.updateCache() nzbResults = myCache.searchCache(episode) logger.log("Cache results: "+str(nzbResults), logger.DEBUG) # if we got some results then use them no matter what. # OR # return anyway unless we're doing a manual search if nzbResults or not manualSearch: return nzbResults sceneSearchStrings = set(sceneHelpers.makeSceneSearchString(episode)) results = [] # search for all show names and episode numbers like ("a","b","c") in a single search nzbMatrixSearchString = '("' + '","'.join(sceneSearchStrings) + '")' itemList = _doSearch(nzbMatrixSearchString) for item in itemList: title = item.findtext('title') url = item.findtext('link').replace('&','&') # parse the file name try: myParser = FileParser(title) epInfo = myParser.parse() except tvnamer_exceptions.InvalidFilename: logger.log("Unable to parse the filename "+title+" into a valid episode", logger.ERROR) continue quality = Quality.nameQuality(title) if not episode.show.wantEpisode(episode.season, episode.episode, quality, manualSearch): logger.log("Ignoring result "+title+" because we don't want an episode that is "+Quality.qualityStrings[quality], logger.DEBUG) continue logger.log("Found result " + title + " at " + url, logger.DEBUG) result = classes.NZBSearchResult([episode]) result.provider = providerName.lower() result.url = url result.name = title result.quality = quality results.append(result) return results
def filterBadReleases(name): try: fp = FileParser(name) epInfo = fp.parse() except tvnamer_exceptions.InvalidFilename: logger.log("Unable to parse the filename "+name+" into a valid episode", logger.WARNING) return False # if there's no info after the season info then assume it's fine if not epInfo.episodename: return True # if any of the bad strings are in the name then say no for x in resultFilters: if re.search('(^|[\W_])'+x+'($|[\W_])', epInfo.episodename, re.I): logger.log("Invalid scene release: "+name+" contains "+x+", ignoring it", logger.DEBUG) return False return True
def splitResult(result): fileObj = urllib.urlopen(result.url) # parse the season ep name try: fp = FileParser(result.name) epInfo = fp.parse() except tvnamer_exceptions.InvalidFilename: logger.log("Unable to parse the filename "+result.name+" into a valid episode", logger.WARNING) return False # bust it up season = epInfo.seasonnumber separateNZBs, xmlns = getSeasonNZBs(result.name, fileObj, season) resultList = [] for newNZB in separateNZBs: logger.log("Split out "+newNZB+" from "+result.name, logger.DEBUG) # parse the name try: fp = FileParser(newNZB) epInfo = fp.parse() except tvnamer_exceptions.InvalidFilename: logger.log("Unable to parse the filename "+newNZB+" into a valid episode", logger.WARNING) return False # make sure the result is sane if epInfo.seasonnumber != season: logger.log("Found "+newNZB+" inside "+result.name+" but it doesn't seem to belong to the same season, ignoring it", logger.WARNING) continue elif len(epInfo.episodenumbers) == 0: logger.log("Found "+newNZB+" inside "+result.name+" but it doesn't seem to be a valid episode NZB, ignoring it", logger.WARNING) continue wantEp = True for epNo in epInfo.episodenumbers: if epNo == -1: continue if not result.extraInfo[0].wantEpisode(season, epNo, result.quality): logger.log("Ignoring result "+newNZB+" because we don't want an episode that is "+Quality.qualityStrings[result.quality], logger.DEBUG) wantEp = False break if not wantEp: continue # get all the associated episode objects epObjList = [] for curEp in epInfo.episodenumbers: epObjList.append(result.extraInfo[0].getEpisode(season, curEp)) # make a result curResult = classes.NZBDataSearchResult(epObjList) curResult.name = newNZB curResult.provider = result.provider curResult.quality = result.quality curResult.extraInfo = [createNZBString(separateNZBs[newNZB], xmlns)] resultList.append(curResult) return resultList
def _addCacheEntry(self, name, url, season=None, episodes=None, tvdb_id=0, tvrage_id=0, quality=None, extraNames=[]): myDB = self._getDB() epInfo = None # if we don't have complete info then parse the filename to get it for curName in [name] + extraNames: try: myParser = FileParser(curName) epInfo = myParser.parse() except tvnamer_exceptions.InvalidFilename: logger.log("Unable to parse the filename "+curName+" into a valid episode", logger.DEBUG) continue if not epInfo: logger.log("Giving up because I'm unable to figure out what show/etc this is: "+name, logger.DEBUG) return False if not epInfo.seriesname: logger.log("No series name retrieved from "+name+", unable to cache it", logger.DEBUG) return False # if we need tvdb_id or tvrage_id then search the DB for them if not tvdb_id or not tvrage_id: # if we have only the tvdb_id, use the database if tvdb_id: showObj = helpers.findCertainShow(sickbeard.showList, tvdb_id) if showObj: tvrage_id = showObj.tvrid else: logger.log("We were given a TVDB id "+str(tvdb_id)+" but it doesn't match a show we have in our list, so leaving tvrage_id empty", logger.DEBUG) tvrage_id = 0 # if we have only a tvrage_id then use the database elif tvrage_id: showObj = helpers.findCertainTVRageShow(sickbeard.showList, tvrage_id) if showObj: tvdb_id = showObj.tvdbid else: logger.log("We were given a TVRage id "+str(tvrage_id)+" but it doesn't match a show we have in our list, so leaving tvdb_id empty", logger.DEBUG) tvdb_id = 0 # if they're both empty then fill out as much info as possible by searching the show name else: showResult = helpers.searchDBForShow(epInfo.seriesname) if showResult: logger.log(epInfo.seriesname+" was found to be show "+showResult[1]+" ("+str(showResult[0])+") in our DB.", logger.DEBUG) tvdb_id = showResult[0] showObj = helpers.findCertainShow(sickbeard.showList, tvdb_id) if not showObj: logger.log("This should never have happened, post a bug about this!", logger.ERROR) raise Exception("BAD STUFF HAPPENED") tvrage_id = showObj.tvrid if not season: season = epInfo.seasonnumber if not episodes: episodes = epInfo.episodenumbers # if we have an air-by-date show then get the real season/episode numbers if season == -1 and tvdb_id: try: t = tvdb_api.Tvdb(**sickbeard.TVDB_API_PARMS) epObj = t[tvdb_id].airedOn(episodes[0])[0] season = int(epObj["seasonnumber"]) episodes = [int(epObj["episodenumber"])] except tvdb_exceptions.tvdb_episodenotfound, e: logger.log("Unable to find episode with date "+str(episodes[0])+" for show "+epInfo.seriesname+", skipping", logger.WARNING) return False
def _getProperList(self): propers = {} # for each provider get a list of the propers for curProvider in providers.sortedProviderList(): if not curProvider.isActive(): continue date = datetime.datetime.today() - datetime.timedelta(days=2) logger.log("Searching for any new PROPER releases from "+curProvider.name) curPropers = curProvider.findPropers(date) # if they haven't been added by a different provider than add the proper to the list for x in curPropers: name = self._genericName(x.name) if not name in propers: logger.log("Found new proper: "+x.name, logger.DEBUG) x.provider = curProvider propers[name] = x # take the list of unique propers and get it sorted by sortedPropers = sorted(propers.values(), key=operator.attrgetter('date'), reverse=True) finalPropers = [] for curProper in sortedPropers: # parse the file name try: myParser = FileParser(curProper.name) epInfo = myParser.parse() except tvnamer_exceptions.InvalidFilename: logger.log("Unable to parse the filename "+curProper.name+" into a valid episode", logger.ERROR) continue if not epInfo.episodenumbers: logger.log("Ignoring "+curProper.name+" because it's for a full season rather than specific episode", logger.DEBUG) continue # populate our Proper instance curProper.season = epInfo.seasonnumber curProper.episode = epInfo.episodenumbers[0] curProper.quality = Quality.nameQuality(curProper.name) # for each show in our list for curShow in sickbeard.showList: genericName = self._genericName(epInfo.seriesname) # get the scene name masks sceneNames = set(sceneHelpers.makeSceneShowSearchStrings(curShow)) # for each scene name mask for curSceneName in sceneNames: # if it matches if genericName == self._genericName(curSceneName): logger.log("Successful match! Result "+epInfo.seriesname+" matched to show "+curShow.name, logger.DEBUG) # set the tvdbid in the db to the show's tvdbid curProper.tvdbid = curShow.tvdbid # since we found it, break out break # if we found something in the inner for loop break out of this one if curProper.tvdbid != -1: break if curProper.tvdbid == -1: continue # if we have an air-by-date show then get the real season/episode numbers if curProper.season == -1 and curProper.tvdbid: try: t = tvdb_api.Tvdb(**sickbeard.TVDB_API_PARMS) epObj = t[curProper.tvdbid].airedOn(curProper.episode)[0] season = int(epObj["seasonnumber"]) episodes = [int(epObj["episodenumber"])] except tvdb_exceptions.tvdb_episodenotfound, e: logger.log("Unable to find episode with date "+str(curProper.episode)+" for show "+epInfo.seriesname+", skipping", logger.WARNING) continue # check if we actually want this proper (if it's the right quality) sqlResults = db.DBConnection().select("SELECT status FROM tv_episodes WHERE showid = ? AND season = ? AND episode = ?", [curProper.tvdbid, curProper.season, curProper.episode]) if not sqlResults: continue oldStatus, oldQuality = Quality.splitCompositeStatus(int(sqlResults[0]["status"])) # only keep the proper if we have already retrieved the same quality ep (don't get better/worse ones) if oldStatus not in (DOWNLOADED, SNATCHED) or oldQuality != curProper.quality: continue # if the show is in our list and there hasn't been a proper already added for that particular episode then add it to our list of propers if curProper.tvdbid != -1 and (curProper.tvdbid, curProper.season, curProper.episode) not in map(operator.attrgetter('tvdbid', 'season', 'episode'), finalPropers): logger.log("Found a proper that we need: "+str(curProper.name)) finalPropers.append(curProper)
def processFile(fileName, downloadDir=None, nzbName=None, multi_file=False): returnStr = '' folderName = None if downloadDir != None: folderName = downloadDir.split(os.path.sep)[-1] returnStr += logHelper(u"Processing file "+fileName+" (with folder name "+str(folderName)+" and NZB name "+str(nzbName)+")", logger.DEBUG) finalNameList = [] for curName in (fileName, folderName, nzbName): if curName != None: for curSceneName in sceneHelpers.sceneToNormalShowNames(curName): if curSceneName not in finalNameList: finalNameList.append(curSceneName) showResults = None result = None tvdb_id = None season = None episodes = [] # first try looking up every name in our history for curName in finalNameList: historyResult = findInHistory(curName) if historyResult: returnStr += logHelper(u"Result from history: "+str(historyResult)+" from "+curName, logger.DEBUG) (tvdb_id, season, episodes) = historyResult showResults = helpers.findCertainShow(sickbeard.showList, tvdb_id) break # if we're parsing a multi-file folder then the folder name doesn't reflect the correct episode so ignore it if multi_file and episodes: returnStr += logHelper(u"Multi-file dir "+downloadDir+" doesn't reflect all episode names, only using name & season", logger.DEBUG) episodes = [] # if that didn't work then try manually parsing and searching them on TVDB for curName in finalNameList: # if we already have the info from the history then don't bother with this if tvdb_id != None and season != None and episodes != []: break # if we're doing a multi-file dir and we already got the tvdb_id/season but no episodes then assume it's right and carry it forward # otherwise, reset it every time if not (tvdb_id and season and not episodes and multi_file): tvdb_id = None season = None episodes = [] try: returnStr += logHelper(u"Attempting to parse name "+curName, logger.DEBUG) myParser = FileParser(curName) result = myParser.parse() season = result.seasonnumber if result.seasonnumber != None else 1 episodes = result.episodenumbers returnStr += logHelper(u"Ended up with season "+str(season)+" and episodes "+str(episodes), logger.DEBUG) except tvnamer_exceptions.InvalidFilename: returnStr += logHelper(u"Unable to parse the filename "+curName+" into a valid episode", logger.DEBUG) continue if not result.seriesname: returnStr += logHelper(u"Filename "+curName+" has no series name, unable to use this name for processing", logger.DEBUG) continue if not episodes: returnStr += logHelper(u"Unable to find an episode number in the filename "+curName+", skipping", logger.DEBUG) continue # reverse-lookup the scene exceptions returnStr += logHelper(u"Checking scene exceptions for "+result.seriesname, logger.DEBUG) sceneID = None for exceptionID in sceneExceptions: for curException in sceneExceptions[exceptionID]: if result.seriesname == curException: sceneID = exceptionID break if sceneID: returnStr += logHelper(u"Scene exception lookup got tvdb id "+str(sceneID)+", using that", logger.DEBUG) break if sceneID: tvdb_id = sceneID showObj = None try: t = tvdb_api.Tvdb(custom_ui=classes.ShowListUI, **sickbeard.TVDB_API_PARMS) # get the tvdb object from either the scene exception ID or the series name if tvdb_id: returnStr += logHelper(u"Looking up ID "+str(tvdb_id)+" on TVDB", logger.DEBUG) showObj = t[tvdb_id] else: returnStr += logHelper(u"Looking up name "+result.seriesname+" on TVDB", logger.DEBUG) showObj = t[result.seriesname] returnStr += logHelper(u"Got tvdb_id "+str(showObj["id"])+" and series name "+showObj["seriesname"].decode('utf-8')+" from TVDB", logger.DEBUG) showInfo = (int(showObj["id"]), showObj["seriesname"]) except (tvdb_exceptions.tvdb_exception, IOError), e: returnStr += logHelper(u"Unable to look up show on TVDB: "+str(e).decode('utf-8'), logger.DEBUG) returnStr += logHelper(u"Looking up show in DB instead", logger.DEBUG) showInfo = helpers.searchDBForShow(result.seriesname) if showInfo: tvdb_id = showInfo[0] if showInfo and season == None: myDB = db.DBConnection() numseasonsSQlResult = myDB.select("SELECT COUNT(DISTINCT season) as numseasons FROM tv_episodes WHERE showid = ? and season != 0", [tvdb_id]) numseasons = numseasonsSQlResult[0][0] if numseasons == 1 and season == None: returnStr += logHelper(u"Don't have a season number, but this show appears to only have 1 season, setting seasonnumber to 1...", logger.DEBUG) season = 1 # if it is an air-by-date show and we successfully found it on TVDB, convert the date into a season/episode if season == -1 and showObj: returnStr += logHelper(u"Looks like this is an air-by-date show, attempting to parse...", logger.DEBUG) try: epObj = showObj.airedOn(episodes[0])[0] season = int(epObj["seasonnumber"]) episodes = [int(epObj["episodenumber"])] except tvdb_exceptions.tvdb_episodenotfound, e: returnStr += logHelper(u"Unable to find episode with date "+str(episodes[0])+" for show "+showObj["seriesname"]+", skipping", logger.DEBUG) continue
def processFile(fileName, downloadDir=None, nzbName=None): returnStr = '' folderName = None if downloadDir != None: folderName = downloadDir.split(os.path.sep)[-1] returnStr += logHelper("Processing file "+fileName+" (with folder name "+str(folderName)+" and NZB name "+str(nzbName)+")", logger.DEBUG) finalNameList = [] for curName in (fileName, folderName, nzbName): if curName != None: for curSceneName in sceneHelpers.sceneToNormalShowNames(curName): if curSceneName not in finalNameList: finalNameList.append(curSceneName) showResults = None result = None tvdb_id = None season = None episodes = [] # first try looking up every name in our history for curName in finalNameList: historyResult = findInHistory(curName) if historyResult: returnStr += logHelper("Result from history: "+str(historyResult)+" from "+curName, logger.DEBUG) (tvdb_id, season, episode) = historyResult episodes = [episode] showResults = helpers.findCertainShow(sickbeard.showList, tvdb_id) break # if that didn't work then try manually parsing and searching them on TVDB for curName in finalNameList: # if we already have the info from the history then don't bother with this if tvdb_id != None and season != None and episodes != []: break # set all search stuff to defaults so we don't carry results over from the last iteration tvdb_id = None season = None episodes = [] try: returnStr += logHelper("Attempting to parse name "+curName, logger.DEBUG) myParser = FileParser(curName) result = myParser.parse() season = result.seasonnumber episodes = result.episodenumbers except tvnamer_exceptions.InvalidFilename: returnStr += logHelper("Unable to parse the filename "+curName+" into a valid episode", logger.DEBUG) continue if not result.seriesname: returnStr += logHelper("Filename "+curName+" has no series name, unable to use this name for processing", logger.DEBUG) continue if not episodes: returnStr += logHelper("Unable to find an episode number in the filename "+curName+", skipping", logger.DEBUG) continue # reverse-lookup the scene exceptions sceneID = None for exceptionID in sceneExceptions: if curName == sceneExceptions[exceptionID]: sceneID = exceptionID break try: returnStr += logHelper("Looking up name "+result.seriesname+" on TVDB", logger.DEBUG) t = tvdb_api.Tvdb(custom_ui=classes.ShowListUI, **sickbeard.TVDB_API_PARMS) # get the tvdb object from either the scene exception ID or the series name if sceneID: showObj = t[sceneID] else: showObj = t[result.seriesname] showInfo = (int(showObj["id"]), showObj["seriesname"]) except (tvdb_exceptions.tvdb_exception, IOError), e: returnStr += logHelper("Unable to look up show on TVDB: "+str(e), logger.DEBUG) returnStr += logHelper("Looking up show in DB instead", logger.DEBUG) showInfo = helpers.searchDBForShow(result.seriesname) if showInfo: tvdb_id = showInfo[0] # if it is an air-by-date show and we successfully found it on TVDB, convert the date into a season/episode if season == -1 and showObj: try: epObj = showObj.airedOn(episodes[0])[0] season = int(epObj["seasonnumber"]) episodes = [int(epObj["episodenumber"])] except tvdb_exceptions.tvdb_episodenotfound, e: returnStr += logHelper("Unable to find episode with date "+str(episodes[0])+" for show "+showObj["seriesname"]+", skipping", logger.DEBUG) continue
def findSeasonResults(self, show, season): itemList = [] results = {} for curString in self._get_season_search_strings(show, season): itemList += self._doSearch(curString) for item in itemList: title = item.findtext("title") url = item.findtext("link") quality = self.getQuality(item) # parse the file name try: myParser = FileParser(title) epInfo = myParser.parse() except tvnamer_exceptions.InvalidFilename: logger.log(u"Unable to parse the filename " + title + " into a valid episode", logger.WARNING) continue if not show.is_air_by_date: # this check is meaningless for non-season searches if (epInfo.seasonnumber != None and epInfo.seasonnumber != season) or ( epInfo.seasonnumber == None and season != 1 ): logger.log( u"The result " + title + " doesn't seem to be a valid episode for season " + str(season) + ", ignoring" ) continue # we just use the existing info for normal searches actual_season = season actual_episodes = epInfo.episodenumbers else: if epInfo.seasonnumber != -1 or len(epInfo.episodenumbers) != 1: logger.log( u"This is supposed to be an air-by-date search but the result " + title + " didn't parse as one, skipping it", logger.DEBUG, ) continue myDB = db.DBConnection() sql_results = myDB.select( "SELECT season, episode FROM tv_episodes WHERE showid = ? AND airdate = ?", [show.tvdbid, epInfo.episodenumbers[0].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.ERROR, ) continue actual_season = int(sql_results[0]["season"]) actual_episodes = [int(sql_results[0]["episode"])] # make sure we want the episode wantEp = True for epNo in actual_episodes: if not show.wantEpisode(actual_season, epNo, quality): wantEp = False break if not wantEp: logger.log( u"Ignoring result " + title + " because we don't want an episode that is " + Quality.qualityStrings[quality], logger.DEBUG, ) continue logger.log(u"Found result " + title + " at " + url, logger.DEBUG) # make a result object epObj = [] for curEp in actual_episodes: epObj.append(show.getEpisode(actual_season, curEp)) result = self.getResult(epObj) result.url = url result.name = title result.quality = quality if len(epObj) == 1: epNum = epObj[0].episode elif len(epObj) > 1: epNum = MULTI_EP_RESULT logger.log( u"Separating multi-episode result to check for later - result contains episodes: " + str(epInfo.episodenumbers), logger.DEBUG, ) elif len(epObj) == 0: epNum = SEASON_RESULT result.extraInfo = [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
def findSeasonResults(self, show, season): itemList = [] results = {} for curString in sceneHelpers.makeSceneSeasonSearchString(show, season, "nzbmatrix"): itemList += self._doSearch(curString) for item in itemList: title = item.findtext('title') url = item.findtext('link') quality = Quality.nameQuality(title) # parse the file name try: myParser = FileParser(title) epInfo = myParser.parse() except tvnamer_exceptions.InvalidFilename: logger.log(u"Unable to parse the name "+title+" into a valid episode", logger.WARNING) continue if (epInfo.seasonnumber != None and epInfo.seasonnumber != season) or (epInfo.seasonnumber == None and season != 1): logger.log(u"The result "+title+" doesn't seem to be a valid episode for season "+str(season)+", ignoring") continue # make sure we want the episode wantEp = True for epNo in epInfo.episodenumbers: if not show.wantEpisode(season, epNo, quality): logger.log(u"Ignoring result "+title+" because we don't want an episode that is "+Quality.qualityStrings[quality], logger.DEBUG) wantEp = False break if not wantEp: continue logger.log(u"Found result " + title + " at " + url, logger.DEBUG) # make a result object epObj = [] for curEp in epInfo.episodenumbers: epObj.append(show.getEpisode(season, curEp)) result = self.getResult(epObj) result.url = url result.name = title result.quality = quality if len(epObj) == 1: epNum = epObj[0].episode elif len(epObj) > 1: epNum = MULTI_EP_RESULT logger.log(u"Separating multi-episode result to check for later - result contains episodes: "+str(epInfo.episodenumbers), logger.DEBUG) elif len(epObj) == 0: epNum = SEASON_RESULT result.extraInfo = [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
def doIt(downloaderDir, nzbName=None): returnStr = "" downloadDir = '' # if they passed us a real dir then assume it's the one we want if os.path.isdir(downloaderDir): downloadDir = os.path.abspath(downloaderDir) # if they've got a download dir configured then use it elif sickbeard.TV_DOWNLOAD_DIR != '' and os.path.isdir(sickbeard.TV_DOWNLOAD_DIR): downloadDir = os.path.join(sickbeard.TV_DOWNLOAD_DIR, os.path.abspath(downloaderDir).split(os.path.sep)[-1]) returnStr += logHelper("Trying to use folder "+downloadDir, logger.DEBUG) # if we didn't find a real dir then quit if not os.path.isdir(downloadDir): returnStr += logHelper("Unable to figure out what folder to process. If your downloader and Sick Beard aren't on the same PC make sure you fill out your TV download dir in the config.", logger.DEBUG) return returnStr myDB = db.DBConnection() sqlResults = myDB.select("SELECT * FROM tv_shows") for sqlShow in sqlResults: if downloadDir.startswith(os.path.abspath(sqlShow["location"])+os.sep): returnStr += logHelper("You're trying to post process a show that's already been moved to its show dir", logger.ERROR) return returnStr returnStr += logHelper("Final folder name is " + downloadDir, logger.DEBUG) # TODO: check if it's failed and deal with it if it is if downloadDir.startswith('_FAILED_'): returnStr += logHelper("The directory name indicates it failed to extract, cancelling", logger.DEBUG) return returnStr # find the file we're dealing with biggest_file = findMainFile(downloadDir) if biggest_file == None: returnStr += logHelper("Unable to find the biggest file - is this really a TV download?", logger.DEBUG) return returnStr returnStr += logHelper("The biggest file in the dir is: " + biggest_file, logger.DEBUG) # use file name, folder name, and NZB name (in that order) to try to figure out the episode info result = None nameList = [downloadDir.split(os.path.sep)[-1], biggest_file] if nzbName != None: nameList.append(nzbName) showResults = None for curName in nameList: try: myParser = FileParser(curName) result = myParser.parse() except tvnamer_exceptions.InvalidFilename: returnStr += logHelper("Unable to parse the filename "+curName+" into a valid episode", logger.DEBUG) continue try: t = tvdb_api.Tvdb(custom_ui=classes.ShowListUI, lastTimeout=sickbeard.LAST_TVDB_TIMEOUT, **sickbeard.TVDB_API_PARMS) showObj = t[result.seriesname] showInfo = (int(showObj["id"]), showObj["seriesname"]) except (tvdb_exceptions.tvdb_exception, IOError), e: returnStr += logHelper("TVDB didn't respond, trying to look up the show in the DB instead", logger.DEBUG) showInfo = helpers.searchDBForShow(result.seriesname) # if we didn't get anything from TVDB or the DB then try the next option if showInfo == None: continue # find the show in the showlist try: showResults = helpers.findCertainShow(sickbeard.showList, showInfo[0]) except exceptions.MultipleShowObjectsException: raise #TODO: later I'll just log this, for now I want to know about it ASAP if showResults != None: returnStr += logHelper("Found the show in our list, continuing", logger.DEBUG) break
def _getProperList(self): propers = {} # for each provider get a list of the propers for curProvider in providers.getAllModules(): if not curProvider.isActive(): continue date = datetime.datetime.today() - datetime.timedelta(days=2) logger.log("Searching for any new PROPER releases from "+curProvider.providerName) curPropers = curProvider.findPropers(date) # if they haven't been added by a different provider than add the proper to the list for x in curPropers: name = self._genericName(x.name) if not name in propers: logger.log("Found new proper: "+x.name, logger.DEBUG) x.provider = curProvider propers[name] = x # take the list of unique propers and get it sorted by sortedPropers = sorted(propers.values(), key=operator.attrgetter('date'), reverse=True) finalPropers = [] for curProper in sortedPropers: try: myParser = FileParser(curProper.name) epInfo = myParser.parse() except tvnamer_exceptions.InvalidFilename: logger.log("Unable to parse the filename "+curProper.name+" into a valid episode", logger.ERROR) continue curProper.season = epInfo.seasonnumber curProper.episode = epInfo.episodenumbers[0] curProper.quality = helpers.guessSceneEpisodeQuality(curProper.name) # for each show in our list for curShow in sickbeard.showList: genericName = self._genericName(epInfo.seriesname) # get the scene name masks sceneNames = set(helpers.makeSceneShowSearchStrings(curShow)) # for each scene name mask for curSceneName in sceneNames: # if it matches if genericName == self._genericName(curSceneName): logger.log("Successful match! Result "+epInfo.seriesname+" matched to show "+curShow.name, logger.DEBUG) # set the tvdbid in the db to the show's tvdbid curProper.tvdbid = curShow.tvdbid # since we found it, break out break # if we found something in the inner for loop break out of this one if curProper.tvdbid != -1: break # if the show is in our list and there hasn't been a proper already added for that particular episode then add it to our list of propers if curProper.tvdbid != -1 and (curProper.tvdbid, curProper.season, curProper.episode) not in map(operator.attrgetter('tvdbid', 'season', 'episode'), finalPropers): logger.log("Found a proper that we need: "+str(curProper.name)) finalPropers.append(curProper) return finalPropers
stripNS(curChild, ns) return element def splitResult(result): try: urlData = helpers.getURL(result.url) except urllib2.URLError, e: logger.log(u"Unable to load url "+result.url+", can't download season NZB", logger.ERROR) return False # parse the season ep name try: fp = FileParser(result.name) epInfo = fp.parse() except tvnamer_exceptions.InvalidFilename: logger.log(u"Unable to parse the filename "+result.name+" into a valid episode", logger.WARNING) return False # bust it up season = epInfo.seasonnumber if epInfo.seasonnumber != None else 1 separateNZBs, xmlns = getSeasonNZBs(result.name, urlData, season) resultList = [] for newNZB in separateNZBs: logger.log(u"Split out "+newNZB+" from "+result.name, logger.DEBUG)
try: responseSoup = etree.ElementTree(etree.XML(data)) items = responseSoup.getiterator('item') except Exception, e: logger.log("Error trying to load Newzbin RSS feed: "+str(e), logger.ERROR) return results for item in items: title = item.findtext('title') url = item.findtext('link').replace('&','&') # parse the file name try: myParser = FileParser(title) epInfo = myParser.parse() except tvnamer_exceptions.InvalidFilename: logger.log("Unable to parse the name "+title+" into a valid episode", logger.WARNING) continue quality = self.getQuality(item) season = epInfo.seasonnumber if epInfo.seasonnumber != None else 1 if not episode.show.wantEpisode(season, episode.episode, quality, manualSearch): logger.log("Ignoring result "+title+" because we don't want an episode that is "+Quality.qualityStrings[quality], logger.DEBUG) continue logger.log("Found result " + title + " at " + url, logger.DEBUG)
def processFile(fileName, downloadDir=None, nzbName=None): returnStr = '' folderName = None if downloadDir != None: folderName = downloadDir.split(os.path.sep)[-1] returnStr += logHelper("Processing file "+fileName+" (with folder name "+str(folderName)+" and NZB name "+str(nzbName)+")", logger.DEBUG) finalNameList = [] for curName in (fileName, folderName, nzbName): if curName != None: for curSceneName in helpers.sceneToNormalShowNames(curName): if curSceneName not in finalNameList: finalNameList.append(curSceneName) showResults = None result = None tvdb_id = None season = None episodes = [] # first try looking up every name in our history for curName in finalNameList: historyResult = findInHistory(curName) if historyResult: returnStr += logHelper("Result from history: "+str(historyResult)+" from "+curName, logger.DEBUG) (tvdb_id, season, episode) = historyResult episodes = [episode] showResults = helpers.findCertainShow(sickbeard.showList, tvdb_id) break # if that didn't work then try manually parsing and searching them on TVDB for curName in finalNameList: # if we already have the info from the history then don't bother with this if tvdb_id != None and season != None and episodes != []: break # set all search stuff to defaults so we don't carry results over from the last iteration tvdb_id = None season = None episodes = [] try: returnStr += logHelper("Attempting to parse name "+curName, logger.DEBUG) myParser = FileParser(curName) result = myParser.parse() season = result.seasonnumber episodes = result.episodenumbers except tvnamer_exceptions.InvalidFilename: returnStr += logHelper("Unable to parse the filename "+curName+" into a valid episode", logger.DEBUG) continue if not result.seriesname: returnStr += logHelper("Filename "+curName+" has no series name, unable to use this name for processing", logger.DEBUG) continue # reverse-lookup the scene exceptions sceneID = None for exceptionID in sceneExceptions: if curName == sceneExceptions[exceptionID]: sceneID = exceptionID break try: if result.seriesname == "CSI": result.seriesname = "CSI: Crime Scene Investigation" returnStr += logHelper("Override CSI to CSI: Crime Scene Investigation", logger.DEBUG) returnStr += logHelper("Looking up name "+result.seriesname+" on TVDB", logger.DEBUG) t = tvdb_api.Tvdb(custom_ui=classes.ShowListUI, **sickbeard.TVDB_API_PARMS) # get the tvdb object from either the scene exception ID or the series name if sceneID: showObj = t[sceneID] else: showObj = t[result.seriesname] showInfo = (int(showObj["id"]), showObj["seriesname"]) except (tvdb_exceptions.tvdb_exception, IOError), e: returnStr += logHelper("Unable to look up show on TVDB: "+str(e), logger.DEBUG) returnStr += logHelper("Looking up show in DB instead", logger.DEBUG) showInfo = helpers.searchDBForShow(result.seriesname) if showInfo: tvdb_id = showInfo[0] # if we couldn't get the necessary info from either of the above methods, try the next name if tvdb_id == None or season == None or episodes == []: continue # find the show in the showlist try: showResults = helpers.findCertainShow(sickbeard.showList, showInfo[0]) except exceptions.MultipleShowObjectsException: raise #TODO: later I'll just log this, for now I want to know about it ASAP if showResults != None: returnStr += logHelper("Found the show in our list, continuing", logger.DEBUG) break
def _addCacheEntry(self, name, url, season=None, episodes=None, tvdb_id=0, tvrage_id=0, quality=None, extraNames=[]): myDB = self._getDB() epInfo = None # if we don't have complete info then parse the filename to get it for curName in [name] + extraNames: try: myParser = FileParser(curName) epInfo = myParser.parse() except tvnamer_exceptions.InvalidFilename: logger.log("Unable to parse the filename "+curName+" into a valid episode", logger.DEBUG) continue if not epInfo: logger.log("Giving up because I'm unable to figure out what show/etc this is: "+name, logger.DEBUG) return False if not epInfo.seriesname: logger.log("No series name retrieved from "+name+", unable to cache it", logger.DEBUG) return False # if we need tvdb_id or tvrage_id then search the DB for them if not tvdb_id or not tvrage_id: # if we have only the tvdb_id, use the database if tvdb_id: showObj = helpers.findCertainShow(sickbeard.showList, tvdb_id) if showObj: tvrage_id = showObj.tvrid else: logger.log("We were given a TVDB id "+str(tvdb_id)+" but it doesn't match a show we have in our list, so leaving tvrage_id empty", logger.DEBUG) tvrage_id = 0 # if we have only a tvrage_id then use the database elif tvrage_id: showObj = helpers.findCertainTVRageShow(sickbeard.showList, tvrage_id) if showObj: tvdb_id = showObj.tvdbid else: logger.log("We were given a TVRage id "+str(tvrage_id)+" but it doesn't match a show we have in our list, so leaving tvdb_id empty", logger.DEBUG) tvdb_id = 0 # if they're both empty then fill out as much info as possible by searching the show name else: showResult = helpers.searchDBForShow(epInfo.seriesname) if showResult: logger.log(epInfo.seriesname+" was found to be show "+showResult[1]+" ("+str(showResult[0])+") in our DB.", logger.DEBUG) tvdb_id = showResult[0] showObj = helpers.findCertainShow(sickbeard.showList, tvdb_id) if not showObj: logger.log("This should never have happened, post a bug about this!", logger.ERROR) raise Exception("BAD STUFF HAPPENED") tvrage_id = showObj.tvrid if not season: season = epInfo.seasonnumber if not episodes: episodes = epInfo.episodenumbers episodeText = "|"+"|".join(map(str, episodes))+"|" # get the current timestamp curTimestamp = int(time.mktime(datetime.datetime.today().timetuple())) if not quality: # if we don't know what quality it is and it looks like itouch quality, skip it if "itouch" in name.lower(): return False elif any(x in name.lower() for x in ("720p", "1080p", "x264")): quality = HD elif any(x in name.lower() for x in ("xvid", "divx")): quality = SD else: logger.log("Unable to figure out the quality of "+name+", assuming SD", logger.DEBUG) quality = SD myDB.action("INSERT INTO "+self.providerName+" (name, season, episodes, tvrid, tvdbid, url, time, quality) VALUES (?,?,?,?,?,?,?,?)", [name, season, episodeText, tvrage_id, tvdb_id, url, curTimestamp, quality])