def test_FULLHDBLURAY(self): self.assertEqual( Quality.FULLHDBLURAY, Quality.nameQuality("Test.Show.S01E02.1080p.BluRay.x264-GROUP")) self.assertEqual( Quality.FULLHDBLURAY, Quality.nameQuality("Test.Show.S01E02.1080p.HDDVD.x264-GROUP"))
def test_HDTV(self): self.assertEqual( Quality.HDTV, Quality.nameQuality("Test.Show.S01E02.720p.HDTV.x264-GROUP")) self.assertEqual( Quality.HDTV, Quality.nameQuality("Test.Show.S01E02.HR.WS.PDTV.x264-GROUP"))
def test_RAWHDTV(self): self.assertEqual(Quality.RAWHDTV, Quality.nameQuality("Test.Show.S01E02.720p.HDTV.DD5.1.MPEG2-GROUP")) self.assertEqual(Quality.RAWHDTV, Quality.nameQuality("Test.Show.S01E02.1080i.HDTV.DD2.0.MPEG2-GROUP")) self.assertEqual(Quality.RAWHDTV, Quality.nameQuality("Test.Show.S01E02.1080i.HDTV.H.264.DD2.0-GROUP")) self.assertEqual(Quality.RAWHDTV, Quality.nameQuality("Test Show - S01E02 - 1080i HDTV MPA1.0 H.264 - GROUP")) self.assertEqual(Quality.RAWHDTV, Quality.nameQuality("Test.Show.S01E02.1080i.HDTV.DD.5.1.h264-GROUP"))
def generate_sample_ep(multi=None, abd=False, sports=False, anime_type=None): # make a fake episode object ep = Episode(2, 3, 3, "Ep Name") ep._status = Quality.compositeStatus(DOWNLOADED, Quality.HDTV) ep._airdate = date(2011, 3, 9) if abd: ep._release_name = 'Show.Name.2011.03.09.HDTV.XviD-RLSGROUP' ep.show.air_by_date = 1 elif sports: ep._release_name = 'Show.Name.2011.03.09.HDTV.XviD-RLSGROUP' ep.show.sports = 1 else: if anime_type != 3: ep.show.anime = 1 ep._release_name = 'Show.Name.003.HDTV.XviD-RLSGROUP' else: ep._release_name = 'Show.Name.S02E03.HDTV.XviD-RLSGROUP' if multi is not None: ep._name = "Ep Name (1)" if anime_type != 3: ep.show.anime = 1 ep._release_name = 'Show.Name.003-004.HDTV.XviD-RLSGROUP' second_ep = Episode(2, 4, 4, "Ep Name (2)") second_ep._status = Quality.compositeStatus( DOWNLOADED, Quality.HDTV) second_ep._release_name = ep.release_name ep.relatedEps.append(second_ep) else: ep._release_name = 'Show.Name.S02E03E04E05.HDTV.XviD-RLSGROUP' second_ep = Episode(2, 4, 4, "Ep Name (2)") second_ep._status = Quality.compositeStatus( DOWNLOADED, Quality.HDTV) second_ep._release_name = ep.release_name third_ep = Episode(2, 5, 5, "Ep Name (3)") third_ep._status = Quality.compositeStatus(DOWNLOADED, Quality.HDTV) third_ep._release_name = ep.release_name ep.relatedEps.append(second_ep) ep.relatedEps.append(third_ep) return ep
def test_HDWEBDL(self): self.assertEqual( Quality.HDWEBDL, Quality.nameQuality("Test.Show.S01E02.720p.WEB-DL-GROUP")) self.assertEqual( Quality.HDWEBDL, Quality.nameQuality("Test.Show.S01E02.720p.WEBRip-GROUP")) self.assertEqual( Quality.HDWEBDL, Quality.nameQuality( "Test.Show.S01E02.WEBRip.720p.H.264.AAC.2.0-GROUP")) self.assertEqual( Quality.HDWEBDL, Quality.nameQuality( "Test.Show.S01E02.720p.WEB-DL.AAC2.0.H.264-GROUP")) self.assertEqual( Quality.HDWEBDL, Quality.nameQuality( "Test Show S01E02 720p WEB-DL AAC2 0 H 264-GROUP")) self.assertEqual( Quality.HDWEBDL, Quality.nameQuality( "Test_Show.S01E02_720p_WEB-DL_AAC2.0_H264-GROUP")) self.assertEqual( Quality.HDWEBDL, Quality.nameQuality( "Test.Show.S01E02.720p.WEB-DL.AAC2.0.H264-GROUP")) self.assertEqual( Quality.HDWEBDL, Quality.nameQuality( "Test.Show.S01E02.720p.iTunes.Rip.H264.AAC-GROUP"))
def logFailed(epObj, release, provider=None): """ Log a failed download :param epObj: Episode object :param release: Release group :param provider: Provider used for snatch """ showid = int(epObj.show.indexerid) season = int(epObj.season) epNum = int(epObj.episode) status, quality = Quality.splitCompositeStatus(epObj.status) action = Quality.compositeStatus(FAILED, quality) History._logHistoryItem(action, showid, season, epNum, quality, release, provider)
def generate_sample_ep(multi=None, abd=False, sports=False, anime_type=None): # make a fake episode object ep = Episode(2, 3, 3, "Ep Name") ep._status = Quality.compositeStatus(DOWNLOADED, Quality.HDTV) ep._airdate = date(2011, 3, 9) if abd: ep._release_name = "Show.Name.2011.03.09.HDTV.XviD-RLSGROUP" ep.show.air_by_date = 1 elif sports: ep._release_name = "Show.Name.2011.03.09.HDTV.XviD-RLSGROUP" ep.show.sports = 1 else: if anime_type != 3: ep.show.anime = 1 ep._release_name = "Show.Name.003.HDTV.XviD-RLSGROUP" else: ep._release_name = "Show.Name.S02E03.HDTV.XviD-RLSGROUP" if multi is not None: ep._name = "Ep Name (1)" if anime_type != 3: ep.show.anime = 1 ep._release_name = "Show.Name.003-004.HDTV.XviD-RLSGROUP" second_ep = Episode(2, 4, 4, "Ep Name (2)") second_ep._status = Quality.compositeStatus(DOWNLOADED, Quality.HDTV) second_ep._release_name = ep.release_name ep.relatedEps.append(second_ep) else: ep._release_name = "Show.Name.S02E03E04E05.HDTV.XviD-RLSGROUP" second_ep = Episode(2, 4, 4, "Ep Name (2)") second_ep._status = Quality.compositeStatus(DOWNLOADED, Quality.HDTV) second_ep._release_name = ep.release_name third_ep = Episode(2, 5, 5, "Ep Name (3)") third_ep._status = Quality.compositeStatus(DOWNLOADED, Quality.HDTV) third_ep._release_name = ep.release_name ep.relatedEps.append(second_ep) ep.relatedEps.append(third_ep) return ep
def logSnatch(searchResult): """ Log history of snatch :param searchResult: search result object """ for curEpObj in searchResult.episodes: showid = int(curEpObj.show.indexerid) season = int(curEpObj.season) episode = int(curEpObj.episode) quality = searchResult.quality version = searchResult.version providerClass = searchResult.provider if providerClass is not None: provider = providerClass.name else: provider = "unknown" action = Quality.compositeStatus(SNATCHED, searchResult.quality) resource = searchResult.name History._logHistoryItem(action, showid, season, episode, quality, resource, provider, version)
def isFinalResult(result): """ Checks if the given result is good enough quality that we can stop searching for other ones. If the result is the highest quality in both the any/best quality lists then this function returns True, if not then it's False """ sickrage.srLogger.debug("Checking if we should keep searching after we've found " + result.name) show_obj = result.episodes[0].show any_qualities, best_qualities = Quality.splitQuality(show_obj.quality) # if there is a redownload that's higher than this then we definitely need to keep looking if best_qualities and result.quality < max(best_qualities): return False # if it does not match the shows black and white list its no good elif show_obj.is_anime and show_obj.release_groups.is_valid(result): return False # if there's no redownload that's higher (above) and this is the highest initial download then we're good elif any_qualities and result.quality in any_qualities: return True elif best_qualities and result.quality == max(best_qualities): return True # if we got here than it's either not on the lists, they're empty, or it's lower than the highest required else: return False
def _get_segments(self, show, fromDate): if show.paused: sickrage.srLogger.debug( "Skipping backlog for {show_name} because the show is paused". format(show_name=show.name)) return {} anyQualities, bestQualities = Quality.splitQuality( show.quality) # @UnusedVariable sickrage.srLogger.debug( "Seeing if we need anything from {show_name}".format( show_name=show.name)) sqlResults = main_db.MainDB().select( "SELECT status, season, episode FROM tv_episodes WHERE season > 0 AND airdate > ? AND showid = ?", [fromDate.toordinal(), show.indexerid]) # check through the list of statuses to see if we want any wanted = {} for result in sqlResults: curCompositeStatus = int(result[b"status"] or -1) curStatus, curQuality = Quality.splitCompositeStatus( curCompositeStatus) if bestQualities: highestBestQuality = max(bestQualities) lowestBestQuality = min(bestQualities) else: highestBestQuality = 0 lowestBestQuality = 0 # if we need a better one then say yes if (curStatus in (DOWNLOADED, SNATCHED, SNATCHED_PROPER) and curQuality < highestBestQuality) or curStatus == WANTED: epObj = show.getEpisode(int(result[b"season"]), int(result[b"episode"])) # only fetch if not archive on first match, or if show is lowest than the lower expected quality if (epObj.show.archive_firstmatch == 0 or curQuality < lowestBestQuality): if epObj.season not in wanted: wanted[epObj.season] = [epObj] else: wanted[epObj.season].append(epObj) return wanted
def logSubtitle(showid, season, episode, status, subtitleResult): """ Log download of subtitle :param showid: Showid of download :param season: Show season :param episode: Show episode :param status: Status of download :param subtitleResult: Result object """ resource = subtitleResult.language.opensubtitles provider = subtitleResult.provider_name status, quality = Quality.splitCompositeStatus(status) action = Quality.compositeStatus(SUBTITLED, quality) History._logHistoryItem(action, showid, season, episode, quality, resource, provider)
def test_FULLHDWEBDL(self): self.assertEqual( Quality.FULLHDWEBDL, Quality.nameQuality("Test.Show.S01E02.1080p.WEB-DL-GROUP")) self.assertEqual( Quality.FULLHDWEBDL, Quality.nameQuality("Test.Show.S01E02.1080p.WEBRip-GROUP")) self.assertEqual( Quality.FULLHDWEBDL, Quality.nameQuality( "Test.Show.S01E02.WEBRip.1080p.H.264.AAC.2.0-GROUP")) self.assertEqual( Quality.FULLHDWEBDL, Quality.nameQuality( "Test.Show.S01E02.WEBRip.1080p.H264.AAC.2.0-GROUP")) self.assertEqual( Quality.FULLHDWEBDL, Quality.nameQuality( "Test.Show.S01E02.1080p.iTunes.H.264.AAC-GROUP")) self.assertEqual( Quality.FULLHDWEBDL, Quality.nameQuality( "Test Show S01E02 1080p iTunes H 264 AAC-GROUP")) self.assertEqual( Quality.FULLHDWEBDL, Quality.nameQuality( "Test_Show_S01E02_1080p_iTunes_H_264_AAC-GROUP"))
def markFailed(epObj): """ Mark an episode as failed :param epObj: Episode object to mark as failed :return: empty string """ log_str = "" try: with epObj.lock: quality = Quality.splitCompositeStatus(epObj.status)[1] epObj.status = Quality.compositeStatus(FAILED, quality) epObj.saveToDB() except EpisodeNotFoundException as e: sickrage.srLogger.warning("Unable to get episode, please set its status manually: {}".format(e.message)) return log_str
def getQuality(self, item, anime=False): """ Figures out the quality of the given RSS item node item: An elementtree.ElementTree element representing the <item> tag of the RSS feed Returns a Quality value obtained from the node's data """ (title, url) = self._get_title_and_url(item) quality = Quality.sceneQuality(title, anime) return quality
def test_RAWHDTV(self): self.assertEqual( Quality.RAWHDTV, Quality.nameQuality( "Test.Show.S01E02.720p.HDTV.DD5.1.MPEG2-GROUP")) self.assertEqual( Quality.RAWHDTV, Quality.nameQuality( "Test.Show.S01E02.1080i.HDTV.DD2.0.MPEG2-GROUP")) self.assertEqual( Quality.RAWHDTV, Quality.nameQuality( "Test.Show.S01E02.1080i.HDTV.H.264.DD2.0-GROUP")) self.assertEqual( Quality.RAWHDTV, Quality.nameQuality( "Test Show - S01E02 - 1080i HDTV MPA1.0 H.264 - GROUP")) self.assertEqual( Quality.RAWHDTV, Quality.nameQuality( "Test.Show.S01E02.1080i.HDTV.DD.5.1.h264-GROUP"))
def markFailed(epObj): """ Mark an episode as failed :param epObj: Episode object to mark as failed :return: empty string """ log_str = "" try: with epObj.lock: quality = Quality.splitCompositeStatus(epObj.status)[1] epObj.status = Quality.compositeStatus(FAILED, quality) epObj.saveToDB() except EpisodeNotFoundException as e: sickrage.srLogger.warning( "Unable to get episode, please set its status manually: {}". format(e.message)) return log_str
def _get_segments(self, show, fromDate): if show.paused: sickrage.srLogger.debug("Skipping backlog for {show_name} because the show is paused".format(show_name=show.name)) return {} anyQualities, bestQualities = Quality.splitQuality(show.quality) # @UnusedVariable sickrage.srLogger.debug("Seeing if we need anything from {show_name}".format(show_name=show.name)) sqlResults = main_db.MainDB().select( "SELECT status, season, episode FROM tv_episodes WHERE season > 0 AND airdate > ? AND showid = ?", [fromDate.toordinal(), show.indexerid]) # check through the list of statuses to see if we want any wanted = {} for result in sqlResults: curCompositeStatus = int(result[b"status"] or -1) curStatus, curQuality = Quality.splitCompositeStatus(curCompositeStatus) if bestQualities: highestBestQuality = max(bestQualities) lowestBestQuality = min(bestQualities) else: highestBestQuality = 0 lowestBestQuality = 0 # if we need a better one then say yes if (curStatus in (DOWNLOADED, SNATCHED, SNATCHED_PROPER) and curQuality < highestBestQuality) or curStatus == WANTED: epObj = show.getEpisode(int(result[b"season"]), int(result[b"episode"])) # only fetch if not archive on first match, or if show is lowest than the lower expected quality if (epObj.show.archive_firstmatch == 0 or curQuality < lowestBestQuality): if epObj.season not in wanted: wanted[epObj.season] = [epObj] else: wanted[epObj.season].append(epObj) return wanted
def test_HDWEBDL(self): self.assertEqual(Quality.HDWEBDL, Quality.nameQuality("Test.Show.S01E02.720p.WEB-DL-GROUP")) self.assertEqual(Quality.HDWEBDL, Quality.nameQuality("Test.Show.S01E02.720p.WEBRip-GROUP")) self.assertEqual(Quality.HDWEBDL, Quality.nameQuality("Test.Show.S01E02.WEBRip.720p.H.264.AAC.2.0-GROUP")) self.assertEqual(Quality.HDWEBDL, Quality.nameQuality("Test.Show.S01E02.720p.WEB-DL.AAC2.0.H.264-GROUP")) self.assertEqual(Quality.HDWEBDL, Quality.nameQuality("Test Show S01E02 720p WEB-DL AAC2 0 H 264-GROUP")) self.assertEqual(Quality.HDWEBDL, Quality.nameQuality("Test_Show.S01E02_720p_WEB-DL_AAC2.0_H264-GROUP")) self.assertEqual(Quality.HDWEBDL, Quality.nameQuality("Test.Show.S01E02.720p.WEB-DL.AAC2.0.H264-GROUP")) self.assertEqual(Quality.HDWEBDL, Quality.nameQuality("Test.Show.S01E02.720p.iTunes.Rip.H264.AAC-GROUP"))
def test_FULLHDWEBDL(self): self.assertEqual(Quality.FULLHDWEBDL, Quality.nameQuality("Test.Show.S01E02.1080p.WEB-DL-GROUP")) self.assertEqual(Quality.FULLHDWEBDL, Quality.nameQuality("Test.Show.S01E02.1080p.WEBRip-GROUP")) self.assertEqual(Quality.FULLHDWEBDL, Quality.nameQuality("Test.Show.S01E02.WEBRip.1080p.H.264.AAC.2.0-GROUP")) self.assertEqual(Quality.FULLHDWEBDL, Quality.nameQuality("Test.Show.S01E02.WEBRip.1080p.H264.AAC.2.0-GROUP")) self.assertEqual(Quality.FULLHDWEBDL, Quality.nameQuality("Test.Show.S01E02.1080p.iTunes.H.264.AAC-GROUP")) self.assertEqual(Quality.FULLHDWEBDL, Quality.nameQuality("Test Show S01E02 1080p iTunes H 264 AAC-GROUP")) self.assertEqual(Quality.FULLHDWEBDL, Quality.nameQuality("Test_Show_S01E02_1080p_iTunes_H_264_AAC-GROUP"))
def wantedEpisodes(show, fromDate): """ Get a list of episodes that we want to download :param show: Show these episodes are from :param fromDate: Search from a certain date :return: list of wanted episodes """ anyQualities, bestQualities = Quality.splitQuality(show.quality) # @UnusedVariable allQualities = list(set(anyQualities + bestQualities)) sickrage.srLogger.debug("Seeing if we need anything from " + show.name) sqlResults = main_db.MainDB().select( "SELECT status, season, episode FROM tv_episodes WHERE showid = ? AND season > 0 AND airdate > ?", [show.indexerid, fromDate.toordinal()]) # check through the list of statuses to see if we want any wanted = [] for result in sqlResults: curCompositeStatus = int(result[b"status"] or -1) curStatus, curQuality = Quality.splitCompositeStatus(curCompositeStatus) if bestQualities: highestBestQuality = max(allQualities) else: highestBestQuality = 0 # if we need a better one then say yes if (curStatus in (DOWNLOADED, SNATCHED, SNATCHED_PROPER) and curQuality < highestBestQuality) or curStatus == WANTED: epObj = show.getEpisode(int(result[b"season"]), int(result[b"episode"])) epObj.wantedQuality = [i for i in allQualities if (i > curQuality and i != Quality.UNKNOWN)] wanted.append(epObj) return wanted
def __init__(self, season, episode, absolute_number, name): self._name = name self._season = season self._episode = episode self._absolute_number = absolute_number self._airdate = date(2010, 3, 9) self._status = Quality.compositeStatus(DOWNLOADED, Quality.SDTV) self._release_name = 'Show.Name.S02E03.HDTV.XviD-RLSGROUP' self._release_group = 'RLSGROUP' self._is_proper = True self.show = Show() self.scene_season = season self.scene_episode = episode self.scene_absolute_number = absolute_number self.relatedEps = []
def isFirstBestMatch(result): """ Checks if the given result is a best quality match and if we want to archive the episode on first match. """ sickrage.srLogger.debug("Checking if we should archive our first best quality match for for episode " + result.name) show_obj = result.episodes[0].show any_qualities, best_qualities = Quality.splitQuality(show_obj.quality) # if there is a redownload that's a match to one of our best qualities and we want to archive the episode then we are done if best_qualities and show_obj.archive_firstmatch and result.quality in best_qualities: return True return False
def _parse_string(self, name): if not name: return matches = [] bestResult = None for (cur_regex_num, cur_regex_name, cur_regex) in self.compiled_regexes: match = cur_regex.match(name) if not match: continue result = ParseResult(name) result.which_regex = [cur_regex_name] result.score = 0 - cur_regex_num named_groups = match.groupdict().keys() if 'series_name' in named_groups: result.series_name = match.group('series_name') if result.series_name: result.series_name = self.clean_series_name(result.series_name) result.score += 1 if 'series_num' in named_groups and match.group('series_num'): result.score += 1 if 'season_num' in named_groups: tmp_season = int(match.group('season_num')) if cur_regex_name == 'bare' and tmp_season in (19, 20): continue result.season_number = tmp_season result.score += 1 if 'ep_num' in named_groups: ep_num = self._convert_number(match.group('ep_num')) if 'extra_ep_num' in named_groups and match.group('extra_ep_num'): result.episode_numbers = range(ep_num, self._convert_number(match.group('extra_ep_num')) + 1) result.score += 1 else: result.episode_numbers = [ep_num] result.score += 1 if 'ep_ab_num' in named_groups: ep_ab_num = self._convert_number(match.group('ep_ab_num')) if 'extra_ab_ep_num' in named_groups and match.group('extra_ab_ep_num'): result.ab_episode_numbers = range(ep_ab_num, self._convert_number(match.group('extra_ab_ep_num')) + 1) result.score += 1 else: result.ab_episode_numbers = [ep_ab_num] result.score += 1 if 'air_date' in named_groups: air_date = match.group('air_date') try: result.air_date = parser.parse(air_date, fuzzy=True).date() result.score += 1 except Exception: continue if 'extra_info' in named_groups: tmp_extra_info = match.group('extra_info') # Show.S04.Special or Show.S05.Part.2.Extras is almost certainly not every episode in the season if tmp_extra_info and cur_regex_name == 'season_only' and re.search( r'([. _-]|^)(special|extra)s?\w*([. _-]|$)', tmp_extra_info, re.I): continue result.extra_info = tmp_extra_info result.score += 1 if 'release_group' in named_groups: result.release_group = match.group('release_group') result.score += 1 if 'version' in named_groups: # assigns version to anime file if detected using anime regex. Non-anime regex receives -1 version = match.group('version') if version: result.version = version else: result.version = 1 else: result.version = -1 matches.append(result) if len(matches): # pick best match with highest score based on placement bestResult = max(sorted(matches, reverse=True, key=lambda x: x.which_regex), key=lambda x: x.score) show = None if not self.naming_pattern: # try and create a show object for this result show = self.get_show(bestResult.series_name, self.tryIndexers) # confirm passed in show object indexer id matches result show object indexer id if show: if self.showObj and show.indexerid != self.showObj.indexerid: show = None bestResult.show = show elif not show and self.showObj: bestResult.show = self.showObj # if this is a naming pattern test or result doesn't have a show object then return best result if not bestResult.show or self.naming_pattern: return bestResult # get quality bestResult.quality = Quality.nameQuality(name, bestResult.show.is_anime) new_episode_numbers = [] new_season_numbers = [] new_absolute_numbers = [] # if we have an air-by-date show then get the real season/episode numbers if bestResult.is_air_by_date: from core.databases import main_db airdate = bestResult.air_date.toordinal() sql_result = main_db.MainDB().select( "SELECT season, episode FROM tv_episodes WHERE showid = ? AND indexer = ? AND airdate = ?", [bestResult.show.indexerid, bestResult.show.indexer, airdate]) season_number = None episode_numbers = [] if sql_result: season_number = int(sql_result[0][0]) episode_numbers = [int(sql_result[0][1])] if not season_number or not len(episode_numbers): try: lINDEXER_API_PARMS = sickrage.srCore.INDEXER_API(bestResult.show.indexer).api_params.copy() if bestResult.show.lang: lINDEXER_API_PARMS[b'language'] = bestResult.show.lang t = sickrage.srCore.INDEXER_API(bestResult.show.indexer).indexer(**lINDEXER_API_PARMS) epObj = t[bestResult.show.indexerid].airedOn(bestResult.air_date)[0] season_number = int(epObj[b"seasonnumber"]) episode_numbers = [int(epObj[b"episodenumber"])] except indexer_episodenotfound: sickrage.srLogger.warning( "Unable to find episode with date " + bestResult.air_date + " for show " + bestResult.show.name + ", skipping") episode_numbers = [] except indexer_error as e: sickrage.srLogger.warning( "Unable to contact " + sickrage.srCore.INDEXER_API(bestResult.show.indexer).name + ": {}".format( e)) episode_numbers = [] for epNo in episode_numbers: s = season_number e = epNo if bestResult.show.is_scene: (s, e) = get_indexer_numbering(bestResult.show.indexerid, bestResult.show.indexer, season_number, epNo) new_episode_numbers.append(e) new_season_numbers.append(s) elif bestResult.show.is_anime and len(bestResult.ab_episode_numbers): scene_season = get_scene_exception_by_name(bestResult.series_name)[1] for epAbsNo in bestResult.ab_episode_numbers: a = epAbsNo if bestResult.show.is_scene: a = get_indexer_absolute_numbering(bestResult.show.indexerid, bestResult.show.indexer, epAbsNo, True, scene_season) (s, e) = get_all_episodes_from_absolute_number(bestResult.show, [a]) new_absolute_numbers.append(a) new_episode_numbers.extend(e) new_season_numbers.append(s) elif bestResult.season_number and len(bestResult.episode_numbers): for epNo in bestResult.episode_numbers: s = bestResult.season_number e = epNo if bestResult.show.is_scene: (s, e) = get_indexer_numbering(bestResult.show.indexerid, bestResult.show.indexer, bestResult.season_number, epNo) if bestResult.show.is_anime: a = get_absolute_number_from_season_and_episode(bestResult.show, s, e) if a: new_absolute_numbers.append(a) new_episode_numbers.append(e) new_season_numbers.append(s) # need to do a quick sanity check heregex. It's possible that we now have episodes # from more than one season (by tvdb numbering), and this is just too much # for sickrage, so we'd need to flag it. new_season_numbers = list(set(new_season_numbers)) # remove duplicates if len(new_season_numbers) > 1: raise InvalidNameException("Scene numbering results episodes from " "seasons %s, (i.e. more than one) and " "sickrage does not support this. " "Sorry." % (new_season_numbers)) # I guess it's possible that we'd have duplicate episodes too, so lets # eliminate them new_episode_numbers = list(set(new_episode_numbers)) new_episode_numbers.sort() # maybe even duplicate absolute numbers so why not do them as well new_absolute_numbers = list(set(new_absolute_numbers)) new_absolute_numbers.sort() if len(new_absolute_numbers): bestResult.ab_episode_numbers = new_absolute_numbers if len(new_season_numbers) and len(new_episode_numbers): bestResult.episode_numbers = new_episode_numbers bestResult.season_number = new_season_numbers[0] if bestResult.show.is_scene: sickrage.srLogger.debug("Converted parsed result {} into {}".format(bestResult.original_name, bestResult)) # CPU sleep time.sleep(1) return bestResult
def pickBestResult(results, show): """ Find the best result out of a list of search results for a show :param results: list of result objects :param show: Shows we check for :return: best result object """ results = results if isinstance(results, list) else [results] sickrage.srLogger.debug("Picking the best result out of " + str([x.name for x in results])) bestResult = None # find the best result for the current episode for cur_result in results: if show and cur_result.show is not show: continue # build the black And white list if show.is_anime: if not show.release_groups.is_valid(cur_result): continue sickrage.srLogger.info("Quality of " + cur_result.name + " is " + Quality.qualityStrings[cur_result.quality]) anyQualities, bestQualities = Quality.splitQuality(show.quality) if cur_result.quality not in anyQualities + bestQualities: sickrage.srLogger.debug(cur_result.name + " is a quality we know we don't want, rejecting it") continue if show.rls_ignore_words and show_names.containsAtLeastOneWord(cur_result.name, cur_result.show.rls_ignore_words): sickrage.srLogger.info( "Ignoring " + cur_result.name + " based on ignored words filter: " + show.rls_ignore_words) continue if show.rls_require_words and not show_names.containsAtLeastOneWord(cur_result.name, cur_result.show.rls_require_words): sickrage.srLogger.info( "Ignoring " + cur_result.name + " based on required words filter: " + show.rls_require_words) continue if not show_names.filterBadReleases(cur_result.name, parse=False): sickrage.srLogger.info( "Ignoring " + cur_result.name + " because its not a valid scene release that we want, ignoring it") continue if hasattr(cur_result, 'size'): if sickrage.srConfig.USE_FAILED_DOWNLOADS and FailedHistory.hasFailed(cur_result.name, cur_result.size, cur_result.provider.name): sickrage.srLogger.info(cur_result.name + " has previously failed, rejecting it") continue if not bestResult: bestResult = cur_result elif cur_result.quality in bestQualities and ( bestResult.quality < cur_result.quality or bestResult.quality not in bestQualities): bestResult = cur_result elif cur_result.quality in anyQualities and bestResult.quality not in bestQualities and bestResult.quality < cur_result.quality: bestResult = cur_result elif bestResult.quality == cur_result.quality: if "proper" in cur_result.name.lower() or "repack" in cur_result.name.lower(): bestResult = cur_result elif "internal" in bestResult.name.lower() and "internal" not in cur_result.name.lower(): bestResult = cur_result elif "xvid" in bestResult.name.lower() and "x264" in cur_result.name.lower(): sickrage.srLogger.info("Preferring " + cur_result.name + " (x264 over xvid)") bestResult = cur_result if bestResult: sickrage.srLogger.debug("Picked " + bestResult.name + " as the best") else: sickrage.srLogger.debug("No result picked.") return bestResult
def test_SDTV(self): self.assertEqual( Quality.SDTV, Quality.nameQuality("Test.Show.S01E02.PDTV.XViD-GROUP")) self.assertEqual( Quality.SDTV, Quality.nameQuality("Test.Show.S01E02.PDTV.x264-GROUP")) self.assertEqual( Quality.SDTV, Quality.nameQuality("Test.Show.S01E02.HDTV.XViD-GROUP")) self.assertEqual( Quality.SDTV, Quality.nameQuality("Test.Show.S01E02.HDTV.x264-GROUP")) self.assertEqual( Quality.SDTV, Quality.nameQuality("Test.Show.S01E02.DSR.XViD-GROUP")) self.assertEqual( Quality.SDTV, Quality.nameQuality("Test.Show.S01E02.DSR.x264-GROUP")) self.assertEqual( Quality.SDTV, Quality.nameQuality("Test.Show.S01E02.TVRip.XViD-GROUP")) self.assertEqual( Quality.SDTV, Quality.nameQuality("Test.Show.S01E02.TVRip.x264-GROUP")) self.assertEqual( Quality.SDTV, Quality.nameQuality("Test.Show.S01E02.WEBRip.XViD-GROUP")) self.assertEqual( Quality.SDTV, Quality.nameQuality("Test.Show.S01E02.WEBRip.x264-GROUP")) self.assertEqual( Quality.SDTV, Quality.nameQuality("Test.Show.S01E02.WEB-DL.x264-GROUP")) self.assertEqual( Quality.SDTV, Quality.nameQuality("Test.Show.S01E02.WEB-DL.AAC2.0.H.264-GROUP")) self.assertEqual( Quality.SDTV, Quality.nameQuality("Test.Show.S01E02 WEB-DL H 264-GROUP")) self.assertEqual( Quality.SDTV, Quality.nameQuality("Test.Show.S01E02_WEB-DL_H_264-GROUP")) self.assertEqual( Quality.SDTV, Quality.nameQuality("Test.Show.S01E02.WEB-DL.AAC2.0.H264-GROUP"))
def test_SDDVD(self): self.assertEqual( Quality.SDDVD, Quality.nameQuality("Test.Show.S01E02.DVDRiP.XViD-GROUP")) self.assertEqual( Quality.SDDVD, Quality.nameQuality("Test.Show.S01E02.DVDRiP.DiVX-GROUP")) self.assertEqual( Quality.SDDVD, Quality.nameQuality("Test.Show.S01E02.DVDRiP.x264-GROUP")) self.assertEqual( Quality.SDDVD, Quality.nameQuality("Test.Show.S01E02.DVDRip.WS.XViD-GROUP")) self.assertEqual( Quality.SDDVD, Quality.nameQuality("Test.Show.S01E02.DVDRip.WS.DiVX-GROUP")) self.assertEqual( Quality.SDDVD, Quality.nameQuality("Test.Show.S01E02.DVDRip.WS.x264-GROUP")) self.assertEqual( Quality.SDDVD, Quality.nameQuality("Test.Show.S01E02.BDRIP.XViD-GROUP")) self.assertEqual( Quality.SDDVD, Quality.nameQuality("Test.Show.S01E02.BDRIP.DiVX-GROUP")) self.assertEqual( Quality.SDDVD, Quality.nameQuality("Test.Show.S01E02.BDRIP.x264-GROUP")) self.assertEqual( Quality.SDDVD, Quality.nameQuality("Test.Show.S01E02.BDRIP.WS.XViD-GROUP")) self.assertEqual( Quality.SDDVD, Quality.nameQuality("Test.Show.S01E02.BDRIP.WS.DiVX-GROUP")) self.assertEqual( Quality.SDDVD, Quality.nameQuality("Test.Show.S01E02.BDRIP.WS.x264-GROUP"))
def _doSearch(self, search_params, search_mode='eponly', epcount=0, age=0, epObj=None): results = [] items = {'Season': [], 'Episode': [], 'RSS': []} self.categories = "cat=" + str(self.cat) if not self._doLogin(): return results for mode in search_params.keys(): sickrage.srLogger.debug("Search Mode: %s" % mode) for search_string in search_params[mode]: if mode is 'RSS': self.page = 2 last_page = 0 y = int(self.page) if search_string == '': continue search_string = str(search_string).replace('.', ' ') for x in range(0, y): z = x * 20 if last_page: break if mode is not 'RSS': searchURL = (self.urls['search_page'] + '&filter={2}').format( z, self.categories, search_string) else: searchURL = self.urls['search_page'].format( z, self.categories) if mode is not 'RSS': sickrage.srLogger.debug("Search string: %s " % search_string) sickrage.srLogger.debug("Search URL: %s" % searchURL) data = self.getURL(searchURL) if not data: sickrage.srLogger.debug( "No data returned from provider") continue try: with bs4_parser(data) as html: torrent_table = html.find( 'table', attrs={'class': 'copyright'}) torrent_rows = torrent_table.find_all( 'tr') if torrent_table else [] # Continue only if one Release is found if len(torrent_rows) < 3: sickrage.srLogger.debug( "Data returned from provider does not contain any torrents" ) last_page = 1 continue if len(torrent_rows) < 42: last_page = 1 for result in torrent_table.find_all('tr')[2:]: try: link = result.find('td').find('a') title = link.string download_url = self.urls[ 'download'] % result.find_all( 'td')[8].find('a')['href'][-8:] leechers = result.find_all( 'td')[3].find_all('td')[1].text leechers = int(leechers.strip('[]')) seeders = result.find_all( 'td')[3].find_all('td')[2].text seeders = int(seeders.strip('[]')) # FIXME size = -1 except (AttributeError, TypeError): continue filename_qt = self._reverseQuality( self._episodeQuality(result)) for text in self.hdtext: title1 = title title = title.replace(text, filename_qt) if title != title1: break if Quality.nameQuality( title) == Quality.UNKNOWN: title += filename_qt if not self._is_italian( result) and not self.subtitle: sickrage.srLogger.debug( "Torrent is subtitled, skipping: %s " % title) continue if self.engrelease and not self._is_english( result): sickrage.srLogger.debug( "Torrent isnt english audio/subtitled , skipping: %s " % title) continue search_show = re.split(r'([Ss][\d{1,2}]+)', search_string)[0] show_title = search_show rindex = re.search(r'([Ss][\d{1,2}]+)', title) if rindex: show_title = title[:rindex.start()] ep_params = title[rindex.start():] if show_title.lower() != search_show.lower() \ and search_show.lower() in show_title.lower() and ep_params: title = search_show + ep_params if not all([title, download_url]): continue if self._is_season_pack(title): title = re.sub(r'([Ee][\d{1,2}\-?]+)', '', title) # Filter unseeded torrent if seeders < self.minseed or leechers < self.minleech: if mode is not 'RSS': sickrage.srLogger.debug( "Discarding torrent because it doesn't meet the minimum seeders or leechers: {0} (S:{1} L:{2})" .format(title, seeders, leechers)) continue item = title, download_url, size, seeders, leechers if mode is not 'RSS': sickrage.srLogger.debug( "Found result: %s " % title) items[mode].append(item) except Exception: sickrage.srLogger.error( "Failed parsing provider. Traceback: %s" % traceback.format_exc()) # For each search mode sort all the items by seeders if available if available items[mode].sort(key=lambda tup: tup[3], reverse=True) results += items[mode] return results
def test_UNKNOWN(self): self.assertEqual(Quality.UNKNOWN, Quality.nameQuality("Test.Show.S01E02-SiCKBEARD"))
def makeSceneSeasonSearchString(show, ep_obj, extraSearchType=None): numseasons = 0 if show.air_by_date or show.sports: # the search string for air by date shows is just seasonStrings = [str(ep_obj.airdate).split('-')[0]] elif show.is_anime: seasonEps = show.getAllEpisodes(ep_obj.season) # get show qualities anyQualities, bestQualities = Quality.splitQuality(show.quality) # compile a list of all the episode numbers we need in this 'season' seasonStrings = [] for episode in seasonEps: # get quality of the episode curCompositeStatus = episode.status curStatus, curQuality = Quality.splitCompositeStatus( curCompositeStatus) if bestQualities: highestBestQuality = max(bestQualities) else: highestBestQuality = 0 # if we need a better one then add it to the list of episodes to fetch if (curStatus in (DOWNLOADED, SNATCHED) and curQuality < highestBestQuality) or curStatus == WANTED: ab_number = episode.scene_absolute_number if ab_number > 0: seasonStrings.append("%02d" % ab_number) else: numseasonsSQlResult = main_db.MainDB().select( "SELECT COUNT(DISTINCT season) as numseasons FROM tv_episodes WHERE showid = ? and season != 0", [show.indexerid]) if numseasonsSQlResult: numseasons = int(numseasonsSQlResult[0][0]) seasonStrings = ["S%02d" % int(ep_obj.scene_season)] showNames = set(makeSceneShowSearchStrings(show, ep_obj.scene_season)) toReturn = [] # search each show name for curShow in showNames: # most providers all work the same way if not extraSearchType: # if there's only one season then we can just use the show name straight up if numseasons == 1: toReturn.append(curShow) # for providers that don't allow multiple searches in one request we only search for Sxx style stuff else: for cur_season in seasonStrings: if ep_obj.show.is_anime: if ep_obj.show.release_groups is not None: if len(show.release_groups.whitelist) > 0: for keyword in show.release_groups.whitelist: toReturn.append(keyword + '.' + curShow + "." + cur_season) else: toReturn.append(curShow + "." + cur_season) return toReturn
def test_SDTV(self): self.assertEqual(Quality.SDTV, Quality.nameQuality("Test.Show.S01E02.PDTV.XViD-GROUP")) self.assertEqual(Quality.SDTV, Quality.nameQuality("Test.Show.S01E02.PDTV.x264-GROUP")) self.assertEqual(Quality.SDTV, Quality.nameQuality("Test.Show.S01E02.HDTV.XViD-GROUP")) self.assertEqual(Quality.SDTV, Quality.nameQuality("Test.Show.S01E02.HDTV.x264-GROUP")) self.assertEqual(Quality.SDTV, Quality.nameQuality("Test.Show.S01E02.DSR.XViD-GROUP")) self.assertEqual(Quality.SDTV, Quality.nameQuality("Test.Show.S01E02.DSR.x264-GROUP")) self.assertEqual(Quality.SDTV, Quality.nameQuality("Test.Show.S01E02.TVRip.XViD-GROUP")) self.assertEqual(Quality.SDTV, Quality.nameQuality("Test.Show.S01E02.TVRip.x264-GROUP")) self.assertEqual(Quality.SDTV, Quality.nameQuality("Test.Show.S01E02.WEBRip.XViD-GROUP")) self.assertEqual(Quality.SDTV, Quality.nameQuality("Test.Show.S01E02.WEBRip.x264-GROUP")) self.assertEqual(Quality.SDTV, Quality.nameQuality("Test.Show.S01E02.WEB-DL.x264-GROUP")) self.assertEqual(Quality.SDTV, Quality.nameQuality("Test.Show.S01E02.WEB-DL.AAC2.0.H.264-GROUP")) self.assertEqual(Quality.SDTV, Quality.nameQuality("Test.Show.S01E02 WEB-DL H 264-GROUP")) self.assertEqual(Quality.SDTV, Quality.nameQuality("Test.Show.S01E02_WEB-DL_H_264-GROUP")) self.assertEqual(Quality.SDTV, Quality.nameQuality("Test.Show.S01E02.WEB-DL.AAC2.0.H264-GROUP"))
def test_FULLHDTV(self): self.assertEqual( Quality.FULLHDTV, Quality.nameQuality("Test.Show.S01E02.1080p.HDTV.x264-GROUP"))
def test_SDDVD(self): self.assertEqual(Quality.SDDVD, Quality.nameQuality("Test.Show.S01E02.DVDRiP.XViD-GROUP")) self.assertEqual(Quality.SDDVD, Quality.nameQuality("Test.Show.S01E02.DVDRiP.DiVX-GROUP")) self.assertEqual(Quality.SDDVD, Quality.nameQuality("Test.Show.S01E02.DVDRiP.x264-GROUP")) self.assertEqual(Quality.SDDVD, Quality.nameQuality("Test.Show.S01E02.DVDRip.WS.XViD-GROUP")) self.assertEqual(Quality.SDDVD, Quality.nameQuality("Test.Show.S01E02.DVDRip.WS.DiVX-GROUP")) self.assertEqual(Quality.SDDVD, Quality.nameQuality("Test.Show.S01E02.DVDRip.WS.x264-GROUP")) self.assertEqual(Quality.SDDVD, Quality.nameQuality("Test.Show.S01E02.BDRIP.XViD-GROUP")) self.assertEqual(Quality.SDDVD, Quality.nameQuality("Test.Show.S01E02.BDRIP.DiVX-GROUP")) self.assertEqual(Quality.SDDVD, Quality.nameQuality("Test.Show.S01E02.BDRIP.x264-GROUP")) self.assertEqual(Quality.SDDVD, Quality.nameQuality("Test.Show.S01E02.BDRIP.WS.XViD-GROUP")) self.assertEqual(Quality.SDDVD, Quality.nameQuality("Test.Show.S01E02.BDRIP.WS.DiVX-GROUP")) self.assertEqual(Quality.SDDVD, Quality.nameQuality("Test.Show.S01E02.BDRIP.WS.x264-GROUP"))
def _doSearch(self, search_params, search_mode='eponly', epcount=0, age=0, epObj=None): results = [] items = {'Season': [], 'Episode': [], 'RSS': []} self.categories = "cat=" + str(self.cat) if not self._doLogin(): return results for mode in search_params.keys(): sickrage.srLogger.debug("Search Mode: %s" % mode) for search_string in search_params[mode]: if mode is 'RSS': self.page = 2 last_page = 0 y = int(self.page) if search_string == '': continue search_string = str(search_string).replace('.', ' ') for x in range(0, y): z = x * 20 if last_page: break if mode is not 'RSS': searchURL = (self.urls['search_page'] + '&filter={2}').format(z, self.categories, search_string) else: searchURL = self.urls['search_page'].format(z, self.categories) if mode is not 'RSS': sickrage.srLogger.debug("Search string: %s " % search_string) sickrage.srLogger.debug("Search URL: %s" % searchURL) data = self.getURL(searchURL) if not data: sickrage.srLogger.debug("No data returned from provider") continue try: with bs4_parser(data) as html: torrent_table = html.find('table', attrs={'class': 'copyright'}) torrent_rows = torrent_table.find_all('tr') if torrent_table else [] # Continue only if one Release is found if len(torrent_rows) < 3: sickrage.srLogger.debug("Data returned from provider does not contain any torrents") last_page = 1 continue if len(torrent_rows) < 42: last_page = 1 for result in torrent_table.find_all('tr')[2:]: try: link = result.find('td').find('a') title = link.string download_url = self.urls['download'] % result.find_all('td')[8].find('a')['href'][ -8:] leechers = result.find_all('td')[3].find_all('td')[1].text leechers = int(leechers.strip('[]')) seeders = result.find_all('td')[3].find_all('td')[2].text seeders = int(seeders.strip('[]')) # FIXME size = -1 except (AttributeError, TypeError): continue filename_qt = self._reverseQuality(self._episodeQuality(result)) for text in self.hdtext: title1 = title title = title.replace(text, filename_qt) if title != title1: break if Quality.nameQuality(title) == Quality.UNKNOWN: title += filename_qt if not self._is_italian(result) and not self.subtitle: sickrage.srLogger.debug("Torrent is subtitled, skipping: %s " % title) continue if self.engrelease and not self._is_english(result): sickrage.srLogger.debug("Torrent isnt english audio/subtitled , skipping: %s " % title) continue search_show = re.split(r'([Ss][\d{1,2}]+)', search_string)[0] show_title = search_show rindex = re.search(r'([Ss][\d{1,2}]+)', title) if rindex: show_title = title[:rindex.start()] ep_params = title[rindex.start():] if show_title.lower() != search_show.lower() \ and search_show.lower() in show_title.lower() and ep_params: title = search_show + ep_params if not all([title, download_url]): continue if self._is_season_pack(title): title = re.sub(r'([Ee][\d{1,2}\-?]+)', '', title) # Filter unseeded torrent if seeders < self.minseed or leechers < self.minleech: if mode is not 'RSS': sickrage.srLogger.debug( "Discarding torrent because it doesn't meet the minimum seeders or leechers: {0} (S:{1} L:{2})".format( title, seeders, leechers)) continue item = title, download_url, size, seeders, leechers if mode is not 'RSS': sickrage.srLogger.debug("Found result: %s " % title) items[mode].append(item) except Exception: sickrage.srLogger.error("Failed parsing provider. Traceback: %s" % traceback.format_exc()) # For each search mode sort all the items by seeders if available if available items[mode].sort(key=lambda tup: tup[3], reverse=True) results += items[mode] return results
def _getProperList(self): """ Walk providers for propers """ propers = {} search_date = datetime.today() - timedelta(days=2) origThreadName = threading.currentThread().getName() # for each provider get a list of the for providerID, providerObj in {k: v for k, v in sortedProviderDict( sickrage.srConfig.RANDOMIZE_PROVIDERS).items() if v.isActive}.items(): threading.currentThread().setName(origThreadName + " :: [" + providerObj.name + "]") sickrage.srLogger.info("Searching for any new PROPER releases from " + providerObj.name) try: curPropers = providerObj.findPropers(search_date) except AuthException as e: sickrage.srLogger.debug("Authentication error: {}".format(e.message)) continue except Exception as e: sickrage.srLogger.debug("Error while searching " + providerObj.name + ", skipping: {}".format(e.message)) sickrage.srLogger.debug(traceback.format_exc()) continue # if they haven't been added by a different provider than add the proper to the list for x in curPropers: if not re.search(r'(^|[\. _-])(proper|repack)([\. _-]|$)', x.name, re.I): sickrage.srLogger.debug('findPropers returned a non-proper, we have caught and skipped it.') continue name = self._genericName(x.name) if not name in propers: sickrage.srLogger.debug("Found new proper: " + x.name) x.provider = providerObj propers[name] = x threading.currentThread().setName(origThreadName) # 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 = NameParser(False) parse_result = myParser.parse(curProper.name) except InvalidNameException: sickrage.srLogger.debug("Unable to parse the filename " + curProper.name + " into a valid episode") continue except InvalidShowException: sickrage.srLogger.debug("Unable to parse the filename " + curProper.name + " into a valid show") continue if not parse_result.series_name: continue if not parse_result.episode_numbers: sickrage.srLogger.debug( "Ignoring " + curProper.name + " because it's for a full season rather than specific episode") continue sickrage.srLogger.debug( "Successful match! Result " + parse_result.original_name + " matched to show " + parse_result.show.name) # set the indexerid in the db to the show's indexerid curProper.indexerid = parse_result.show.indexerid # set the indexer in the db to the show's indexer curProper.indexer = parse_result.show.indexer # populate our Proper instance curProper.show = parse_result.show curProper.season = parse_result.season_number if parse_result.season_number is not None else 1 curProper.episode = parse_result.episode_numbers[0] curProper.release_group = parse_result.release_group curProper.version = parse_result.version curProper.quality = Quality.nameQuality(curProper.name, parse_result.is_anime) curProper.content = None # filter release bestResult = pickBestResult(curProper, parse_result.show) if not bestResult: sickrage.srLogger.debug("Proper " + curProper.name + " were rejected by our release filters.") continue # only get anime proper if it has release group and version if bestResult.show.is_anime: if not bestResult.release_group and bestResult.version == -1: sickrage.srLogger.debug("Proper " + bestResult.name + " doesn't have a release group and version, ignoring it") continue # check if we actually want this proper (if it's the right quality) sqlResults = main_db.MainDB().select( "SELECT status FROM tv_episodes WHERE showid = ? AND season = ? AND episode = ?", [bestResult.indexerid, bestResult.season, bestResult.episode]) if not sqlResults: continue # only keep the proper if we have already retrieved the same quality ep (don't get better/worse ones) oldStatus, oldQuality = Quality.splitCompositeStatus(int(sqlResults[0][b"status"])) if oldStatus not in (DOWNLOADED, SNATCHED) or oldQuality != bestResult.quality: continue # check if we actually want this proper (if it's the right release group and a higher version) if bestResult.show.is_anime: sqlResults = main_db.MainDB().select( "SELECT release_group, version FROM tv_episodes WHERE showid = ? AND season = ? AND episode = ?", [bestResult.indexerid, bestResult.season, bestResult.episode]) oldVersion = int(sqlResults[0][b"version"]) oldRelease_group = (sqlResults[0][b"release_group"]) if oldVersion > -1 and oldVersion < bestResult.version: sickrage.srLogger.info( "Found new anime v" + str(bestResult.version) + " to replace existing v" + str(oldVersion)) else: continue if oldRelease_group != bestResult.release_group: sickrage.srLogger.info( "Skipping proper from release group: " + bestResult.release_group + ", does not match existing release group: " + oldRelease_group) 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 bestResult.indexerid != -1 and (bestResult.indexerid, bestResult.season, bestResult.episode) not in map( operator.attrgetter('indexerid', 'season', 'episode'), finalPropers): sickrage.srLogger.info("Found a proper that we need: " + str(bestResult.name)) finalPropers.append(bestResult) return finalPropers
def makeSceneSeasonSearchString(show, ep_obj, extraSearchType=None): numseasons = 0 if show.air_by_date or show.sports: # the search string for air by date shows is just seasonStrings = [str(ep_obj.airdate).split('-')[0]] elif show.is_anime: seasonEps = show.getAllEpisodes(ep_obj.season) # get show qualities anyQualities, bestQualities = Quality.splitQuality(show.quality) # compile a list of all the episode numbers we need in this 'season' seasonStrings = [] for episode in seasonEps: # get quality of the episode curCompositeStatus = episode.status curStatus, curQuality = Quality.splitCompositeStatus(curCompositeStatus) if bestQualities: highestBestQuality = max(bestQualities) else: highestBestQuality = 0 # if we need a better one then add it to the list of episodes to fetch if (curStatus in ( DOWNLOADED, SNATCHED) and curQuality < highestBestQuality) or curStatus == WANTED: ab_number = episode.scene_absolute_number if ab_number > 0: seasonStrings.append("%02d" % ab_number) else: numseasonsSQlResult = main_db.MainDB().select( "SELECT COUNT(DISTINCT season) as numseasons FROM tv_episodes WHERE showid = ? and season != 0", [show.indexerid]) if numseasonsSQlResult: numseasons = int(numseasonsSQlResult[0][0]) seasonStrings = ["S%02d" % int(ep_obj.scene_season)] showNames = set(makeSceneShowSearchStrings(show, ep_obj.scene_season)) toReturn = [] # search each show name for curShow in showNames: # most providers all work the same way if not extraSearchType: # if there's only one season then we can just use the show name straight up if numseasons == 1: toReturn.append(curShow) # for providers that don't allow multiple searches in one request we only search for Sxx style stuff else: for cur_season in seasonStrings: if ep_obj.show.is_anime: if ep_obj.show.release_groups is not None: if len(show.release_groups.whitelist) > 0: for keyword in show.release_groups.whitelist: toReturn.append(keyword + '.' + curShow + "." + cur_season) else: toReturn.append(curShow + "." + cur_season) return toReturn
def test_FULLHDBLURAY(self): self.assertEqual(Quality.FULLHDBLURAY, Quality.nameQuality("Test.Show.S01E02.1080p.BluRay.x264-GROUP")) self.assertEqual(Quality.FULLHDBLURAY, Quality.nameQuality("Test.Show.S01E02.1080p.HDDVD.x264-GROUP"))
def test_FULLHDTV(self): self.assertEqual(Quality.FULLHDTV, Quality.nameQuality("Test.Show.S01E02.1080p.HDTV.x264-GROUP"))
def test_HDTV(self): self.assertEqual(Quality.HDTV, Quality.nameQuality("Test.Show.S01E02.720p.HDTV.x264-GROUP")) self.assertEqual(Quality.HDTV, Quality.nameQuality("Test.Show.S01E02.HR.WS.PDTV.x264-GROUP"))
def snatchEpisode(result, endStatus=SNATCHED): """ Contains the internal logic necessary to actually "snatch" a result that has been found. :param result: SearchResult instance to be snatched. :param endStatus: the episode status that should be used for the episode object once it's snatched. :return: boolean, True on success """ if result is None: return False result.priority = 0 # -1 = low, 0 = normal, 1 = high if sickrage.srConfig.ALLOW_HIGH_PRIORITY: # if it aired recently make it high priority for curEp in result.episodes: if date.today() - curEp.airdate <= timedelta(days=7): result.priority = 1 if re.search(r'(^|[\. _-])(proper|repack)([\. _-]|$)', result.name, re.I) is not None: endStatus = SNATCHED_PROPER if result.url.startswith('magnet') or result.url.endswith('torrent'): result.resultType = 'torrent' # NZBs can be sent straight to SAB or saved to disk if result.resultType in ("nzb", "nzbdata"): if sickrage.srConfig.NZB_METHOD == "blackhole": dlResult = _downloadResult(result) elif sickrage.srConfig.NZB_METHOD == "sabnzbd": dlResult = SabNZBd.sendNZB(result) elif sickrage.srConfig.NZB_METHOD == "nzbget": is_proper = True if endStatus == SNATCHED_PROPER else False dlResult = NZBGet.sendNZB(result, is_proper) else: sickrage.srLogger.error("Unknown NZB action specified in config: " + sickrage.srConfig.NZB_METHOD) dlResult = False # TORRENTs can be sent to clients or saved to disk elif result.resultType == "torrent": # torrents are saved to disk when blackhole mode if sickrage.srConfig.TORRENT_METHOD == "blackhole": dlResult = _downloadResult(result) else: if not result.content and not result.url.startswith('magnet'): result.content = result.provider.getURL(result.url, needBytes=True) if result.content or result.url.startswith('magnet'): client = getClientIstance(sickrage.srConfig.TORRENT_METHOD)() dlResult = client.sendTORRENT(result) else: sickrage.srLogger.warning("Torrent file content is empty") dlResult = False else: sickrage.srLogger.error("Unknown result type, unable to download it (%r)" % result.resultType) dlResult = False if not dlResult: return False if sickrage.srConfig.USE_FAILED_DOWNLOADS: FailedHistory.logSnatch(result) notifications.message('Episode snatched', result.name) History.logSnatch(result) # don't notify when we re-download an episode sql_l = [] trakt_data = [] for curEpObj in result.episodes: with curEpObj.lock: if isFirstBestMatch(result): curEpObj.status = Quality.compositeStatus(SNATCHED_BEST, result.quality) else: curEpObj.status = Quality.compositeStatus(endStatus, result.quality) sql_q = curEpObj.saveToDB(False) if sql_q: sql_l.append(sql_q) del sql_q # cleanup if curEpObj.status not in Quality.DOWNLOADED: try: srNotifiers.notify_snatch( curEpObj._format_pattern('%SN - %Sx%0E - %EN - %QN') + " from " + result.provider.name) except: sickrage.srLogger.debug("Failed to send snatch notification") trakt_data.append((curEpObj.season, curEpObj.episode)) data = sickrage.srCore.NOTIFIERS.trakt_notifier.trakt_episode_data_generate(trakt_data) if sickrage.srConfig.USE_TRAKT and sickrage.srConfig.TRAKT_SYNC_WATCHLIST: sickrage.srLogger.debug("Add episodes, showid: indexerid " + str(result.show.indexerid) + ", Title " + str( result.show.name) + " to Traktv Watchlist") if data: sickrage.srCore.NOTIFIERS.trakt_notifier.update_watchlist(result.show, data_episode=data, update="add") if len(sql_l) > 0: main_db.MainDB().mass_upsert(sql_l) del sql_l # cleanup return True
def _getProperList(self): """ Walk providers for propers """ propers = {} search_date = datetime.today() - timedelta(days=2) origThreadName = threading.currentThread().getName() # for each provider get a list of the for providerID, providerObj in { k: v for k, v in sortedProviderDict( sickrage.srConfig.RANDOMIZE_PROVIDERS).items() if v.isActive }.items(): threading.currentThread().setName(origThreadName + " :: [" + providerObj.name + "]") sickrage.srLogger.info( "Searching for any new PROPER releases from " + providerObj.name) try: curPropers = providerObj.findPropers(search_date) except AuthException as e: sickrage.srLogger.debug("Authentication error: {}".format( e.message)) continue except Exception as e: sickrage.srLogger.debug("Error while searching " + providerObj.name + ", skipping: {}".format(e.message)) sickrage.srLogger.debug(traceback.format_exc()) continue # if they haven't been added by a different provider than add the proper to the list for x in curPropers: if not re.search(r'(^|[\. _-])(proper|repack)([\. _-]|$)', x.name, re.I): sickrage.srLogger.debug( 'findPropers returned a non-proper, we have caught and skipped it.' ) continue name = self._genericName(x.name) if not name in propers: sickrage.srLogger.debug("Found new proper: " + x.name) x.provider = providerObj propers[name] = x threading.currentThread().setName(origThreadName) # 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 = NameParser(False) parse_result = myParser.parse(curProper.name) except InvalidNameException: sickrage.srLogger.debug("Unable to parse the filename " + curProper.name + " into a valid episode") continue except InvalidShowException: sickrage.srLogger.debug("Unable to parse the filename " + curProper.name + " into a valid show") continue if not parse_result.series_name: continue if not parse_result.episode_numbers: sickrage.srLogger.debug( "Ignoring " + curProper.name + " because it's for a full season rather than specific episode" ) continue sickrage.srLogger.debug("Successful match! Result " + parse_result.original_name + " matched to show " + parse_result.show.name) # set the indexerid in the db to the show's indexerid curProper.indexerid = parse_result.show.indexerid # set the indexer in the db to the show's indexer curProper.indexer = parse_result.show.indexer # populate our Proper instance curProper.show = parse_result.show curProper.season = parse_result.season_number if parse_result.season_number is not None else 1 curProper.episode = parse_result.episode_numbers[0] curProper.release_group = parse_result.release_group curProper.version = parse_result.version curProper.quality = Quality.nameQuality(curProper.name, parse_result.is_anime) curProper.content = None # filter release bestResult = pickBestResult(curProper, parse_result.show) if not bestResult: sickrage.srLogger.debug( "Proper " + curProper.name + " were rejected by our release filters.") continue # only get anime proper if it has release group and version if bestResult.show.is_anime: if not bestResult.release_group and bestResult.version == -1: sickrage.srLogger.debug( "Proper " + bestResult.name + " doesn't have a release group and version, ignoring it" ) continue # check if we actually want this proper (if it's the right quality) sqlResults = main_db.MainDB().select( "SELECT status FROM tv_episodes WHERE showid = ? AND season = ? AND episode = ?", [bestResult.indexerid, bestResult.season, bestResult.episode]) if not sqlResults: continue # only keep the proper if we have already retrieved the same quality ep (don't get better/worse ones) oldStatus, oldQuality = Quality.splitCompositeStatus( int(sqlResults[0][b"status"])) if oldStatus not in (DOWNLOADED, SNATCHED) or oldQuality != bestResult.quality: continue # check if we actually want this proper (if it's the right release group and a higher version) if bestResult.show.is_anime: sqlResults = main_db.MainDB().select( "SELECT release_group, version FROM tv_episodes WHERE showid = ? AND season = ? AND episode = ?", [ bestResult.indexerid, bestResult.season, bestResult.episode ]) oldVersion = int(sqlResults[0][b"version"]) oldRelease_group = (sqlResults[0][b"release_group"]) if oldVersion > -1 and oldVersion < bestResult.version: sickrage.srLogger.info("Found new anime v" + str(bestResult.version) + " to replace existing v" + str(oldVersion)) else: continue if oldRelease_group != bestResult.release_group: sickrage.srLogger.info( "Skipping proper from release group: " + bestResult.release_group + ", does not match existing release group: " + oldRelease_group) 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 bestResult.indexerid != -1 and ( bestResult.indexerid, bestResult.season, bestResult.episode) not in map( operator.attrgetter('indexerid', 'season', 'episode'), finalPropers): sickrage.srLogger.info("Found a proper that we need: " + str(bestResult.name)) finalPropers.append(bestResult) return finalPropers