Exemplo n.º 1
0
    def __init__(self, something):
        for provider in sortedProviderDict().values():
            provider.getURL = self._fake_getURL
            # provider.isActive = self._fake_isActive

        super(SearchTest, self).__init__(something)
        super(SearchTest, self).setUp()
Exemplo n.º 2
0
    def __init__(self, something):
        for provider in sortedProviderDict().values():
            provider.getURL = self._fake_getURL
            # provider.isActive = self._fake_isActive

        super(SearchTest, self).__init__(something)
        super(SearchTest, self).setUp()
Exemplo n.º 3
0
            quality = provider.getQuality(items[0])
            size = provider._get_size(items[0])
            if not show.quality & quality:
                print("Quality not in ANY, %r" % quality)
                continue

    return test


# create the test methods
for forceSearch in (True, False):
    for name, curData in tests.items():
        fname = name.replace(' ', '_')

        for provider in sortedProviderDict().values():
            if provider.type == GenericProvider.TORRENT:
                if forceSearch:
                    test_name = 'test_manual_%s_%s_%s' % (
                        fname, curData[b"tvdbid"], provider.name)
                else:
                    test_name = 'test_%s_%s_%s' % (fname, curData[b"tvdbid"],
                                                   provider.name)
                test = test_generator(curData, name, provider, forceSearch)
                setattr(SearchTest, test_name, test)

if __name__ == '__main__':
    print("==================")
    print("STARTING - SEARCH TESTS")
    print("==================")
    print(
Exemplo n.º 4
0
from __future__ import print_function, unicode_literals

import unittest

from sickrage.providers import sortedProviderDict
from tests import SiCKRAGETestCase


class RSSTest(SiCKRAGETestCase): pass

def test_get_rss(self, provider):
    result = provider.cache.getRSSFeed(provider.url)
    if result:
        self.assertTrue(isinstance(result[b'feed'], dict))
        self.assertTrue(isinstance(result[b'entries'], list))
        for item in result[b'entries']:
            title, url = provider._get_title_and_url(item)
            self.assertTrue(title and url, "Failed to get title and url from RSS feed for %s" % provider.name)


for provider in sortedProviderDict().values():
    setattr(RSSTest, 'test_rss_%s' % provider.name, lambda self, x=provider: test_get_rss(self, x))

if __name__ == "__main__":
    print("==================")
    print("STARTING - RSS TESTS")
    print("==================")
    print("######################################################################")
    unittest.main()
Exemplo n.º 5
0
class SNI_Tests(SiCKRAGETestCase):
    pass


def test_sni(self, provider):
    try:
        requests.head(provider.url, verify=certifi.where(), timeout=5)
    except requests.exceptions.Timeout:
        pass
    except requests.exceptions.SSLError as error:
        if 'SSL3_GET_SERVER_CERTIFICATE' not in error:
            print(error)
    except Exception:
        pass


for providerID, providerObj in sortedProviderDict().items():
    setattr(SNI_Tests,
            'test_%s' % providerObj.name,
            lambda self, x=providerObj: test_sni(self, x))

if __name__ == "__main__":
    print("==================")
    print("STARTING - SSL TESTS")
    print("==================")
    print(
        "######################################################################"
    )
    unittest.main()
Exemplo n.º 6
0
def searchProviders(show, episodes, manualSearch=False, downCurQuality=False):
    """
    Walk providers for information on shows

    :param show: Show we are looking for
    :param episodes: Episodes we hope to find
    :param manualSearch: Boolean, is this a manual search?
    :param downCurQuality: Boolean, should we redownload currently avaialble quality file
    :return: results for search
    """
    foundResults = {}

    # build name cache for show
    sickrage.NAMECACHE.buildNameCache(show)

    origThreadName = threading.currentThread().getName()

    providers = {
        k: v
        for k, v in sortedProviderDict(sickrage.RANDOMIZE_PROVIDERS).items()
        if v.isActive
    }

    def perform_searches():

        finalResults = []
        didSearch = False

        for providerID, providerObj in providers.items():
            if providerObj.anime_only and not show.is_anime:
                sickrage.LOGGER.debug("" + str(show.name) +
                                      " is not an anime, skiping")
                continue

            threading.currentThread().setName(origThreadName + "::[" +
                                              providerObj.name + "]")

            foundResults[providerObj.name] = {}

            searchCount = 0
            search_mode = providerObj.search_mode

            # Always search for episode when manually searching when in sponly
            if search_mode == 'sponly' and manualSearch == True:
                search_mode = 'eponly'

            while True:
                searchCount += 1

                if search_mode == 'eponly':
                    sickrage.LOGGER.info("Performing episode search for " +
                                         show.name)
                else:
                    sickrage.LOGGER.info("Performing season pack search for " +
                                         show.name)

                try:
                    providerObj.cache.updateCache()
                    searchResults = providerObj.findSearchResults(
                        show, episodes, search_mode, manualSearch,
                        downCurQuality)
                except AuthException as e:
                    sickrage.LOGGER.error("Authentication error: {}".format(e))
                    break
                except Exception as e:
                    sickrage.LOGGER.error("Error while searching " +
                                          providerObj.name +
                                          ", skipping: {}".format(e))
                    sickrage.LOGGER.debug(traceback.format_exc())
                    break

                didSearch = True

                if len(searchResults):
                    # make a list of all the results for this provider
                    for curEp in searchResults:
                        if curEp in foundResults:
                            foundResults[providerObj.
                                         name][curEp] += searchResults[curEp]
                        else:
                            foundResults[
                                providerObj.name][curEp] = searchResults[curEp]

                    break
                elif not providerObj.search_fallback or searchCount == 2:
                    break

                if search_mode == 'sponly':
                    sickrage.LOGGER.debug("Fallback episode search initiated")
                    search_mode = 'eponly'
                else:
                    sickrage.LOGGER.debug(
                        "Fallback season pack search initiate")
                    search_mode = 'sponly'

            # skip to next provider if we have no results to process
            if not len(foundResults[providerObj.name]):
                continue

            # pick the best season NZB
            bestSeasonResult = None
            if SEASON_RESULT in foundResults[providerObj.name]:
                bestSeasonResult = pickBestResult(
                    foundResults[providerObj.name][SEASON_RESULT], show)

            highest_quality_overall = 0
            for cur_episode in foundResults[providerObj.name]:
                for cur_result in foundResults[providerObj.name][cur_episode]:
                    if cur_result.quality != Quality.UNKNOWN and cur_result.quality > highest_quality_overall:
                        highest_quality_overall = cur_result.quality
            sickrage.LOGGER.debug(
                "The highest quality of any match is " +
                Quality.qualityStrings[highest_quality_overall])

            # see if every episode is wanted
            if bestSeasonResult:
                searchedSeasons = [str(x.season) for x in episodes]

                # get the quality of the season nzb
                seasonQual = bestSeasonResult.quality
                sickrage.LOGGER.debug("The quality of the season " +
                                      bestSeasonResult.provider.type + " is " +
                                      Quality.qualityStrings[seasonQual])

                allEps = [
                    int(x[b"episode"]) for x in main_db.MainDB().select(
                        "SELECT episode FROM tv_episodes WHERE showid = ? AND ( season IN ( "
                        + ','.join(searchedSeasons) + " ) )", [show.indexerid])
                ]

                sickrage.LOGGER.info(
                    "Executed query: [SELECT episode FROM tv_episodes WHERE showid = %s AND season in  %s]"
                    % (show.indexerid, ','.join(searchedSeasons)))
                sickrage.LOGGER.debug("Episode list: " + str(allEps))

                allWanted = True
                anyWanted = False
                for curEpNum in allEps:
                    for season in set([x.season for x in episodes]):
                        if not show.wantEpisode(season, curEpNum, seasonQual,
                                                downCurQuality):
                            allWanted = False
                        else:
                            anyWanted = True

                # if we need every ep in the season and there's nothing better then just download this and be done with it (unless single episodes are preferred)
                if allWanted and bestSeasonResult.quality == highest_quality_overall:
                    sickrage.LOGGER.info(
                        "Every ep in this season is needed, downloading the whole "
                        + bestSeasonResult.provider.type + " " +
                        bestSeasonResult.name)
                    epObjs = []
                    for curEpNum in allEps:
                        for season in set([x.season for x in episodes]):
                            epObjs.append(show.getEpisode(season, curEpNum))
                    bestSeasonResult.episodes = epObjs

                    return [bestSeasonResult]

                elif not anyWanted:
                    sickrage.LOGGER.debug(
                        "No eps from this season are wanted at this quality, ignoring the result of "
                        + bestSeasonResult.name)

                else:

                    if bestSeasonResult.provider.type == GenericProvider.NZB:
                        sickrage.LOGGER.debug(
                            "Breaking apart the NZB and adding the individual ones to our results"
                        )

                        # if not, break it apart and add them as the lowest priority results
                        individualResults = splitNZBResult(bestSeasonResult)
                        for curResult in individualResults:
                            if len(curResult.episodes) == 1:
                                epNum = curResult.episodes[0].episode
                            elif len(curResult.episodes) > 1:
                                epNum = MULTI_EP_RESULT

                            if epNum in foundResults[providerObj.name]:
                                foundResults[providerObj.name][epNum].append(
                                    curResult)
                            else:
                                foundResults[providerObj.name][epNum] = [
                                    curResult
                                ]

                    # If this is a torrent all we can do is leech the entire torrent, user will have to select which eps not do download in his torrent client
                    else:

                        # Season result from Torrent Provider must be a full-season torrent, creating multi-ep result for it.
                        sickrage.LOGGER.info(
                            "Adding multi-ep result for full-season torrent. Set the episodes you don't want to 'don't download' in your torrent client if desired!"
                        )
                        epObjs = []
                        for curEpNum in allEps:
                            for season in set([x.season for x in episodes]):
                                epObjs.append(show.getEpisode(
                                    season, curEpNum))
                        bestSeasonResult.episodes = epObjs

                        if MULTI_EP_RESULT in foundResults[providerObj.name]:
                            foundResults[providerObj.name][
                                MULTI_EP_RESULT].append(bestSeasonResult)
                        else:
                            foundResults[providerObj.name][MULTI_EP_RESULT] = [
                                bestSeasonResult
                            ]

            # go through multi-ep results and see if we really want them or not, get rid of the rest
            multiResults = {}
            if MULTI_EP_RESULT in foundResults[providerObj.name]:
                for _multiResult in foundResults[
                        providerObj.name][MULTI_EP_RESULT]:

                    sickrage.LOGGER.debug(
                        "Seeing if we want to bother with multi-episode result "
                        + _multiResult.name)

                    # Filter result by ignore/required/whitelist/blacklist/quality, etc
                    multiResult = pickBestResult(_multiResult, show)
                    if not multiResult:
                        continue

                    # see how many of the eps that this result covers aren't covered by single results
                    neededEps = []
                    notNeededEps = []
                    for epObj in multiResult.episodes:
                        # if we have results for the episode
                        if epObj.episode in foundResults[
                                providerObj.name] and len(foundResults[
                                    providerObj.name][epObj.episode]) > 0:
                            notNeededEps.append(epObj.episode)
                        else:
                            neededEps.append(epObj.episode)

                    sickrage.LOGGER.debug(
                        "Single-ep check result is neededEps: " +
                        str(neededEps) + ", notNeededEps: " +
                        str(notNeededEps))

                    if not neededEps:
                        sickrage.LOGGER.debug(
                            "All of these episodes were covered by single episode results, ignoring this multi-episode result"
                        )
                        continue

                    # check if these eps are already covered by another multi-result
                    multiNeededEps = []
                    multiNotNeededEps = []
                    for epObj in multiResult.episodes:
                        if epObj.episode in multiResults:
                            multiNotNeededEps.append(epObj.episode)
                        else:
                            multiNeededEps.append(epObj.episode)

                    sickrage.LOGGER.debug(
                        "Multi-ep check result is multiNeededEps: " +
                        str(multiNeededEps) + ", multiNotNeededEps: " +
                        str(multiNotNeededEps))

                    if not multiNeededEps:
                        sickrage.LOGGER.debug(
                            "All of these episodes were covered by another multi-episode nzbs, ignoring this multi-ep result"
                        )
                        continue

                    # don't bother with the single result if we're going to get it with a multi result
                    for epObj in multiResult.episodes:
                        multiResults[epObj.episode] = multiResult
                        if epObj.episode in foundResults[providerObj.name]:
                            sickrage.LOGGER.debug(
                                "A needed multi-episode result overlaps with a single-episode result for ep #"
                                + str(epObj.episode) +
                                ", removing the single-episode results from the list"
                            )
                            del foundResults[providerObj.name][epObj.episode]

            # of all the single ep results narrow it down to the best one for each episode
            finalResults += set(multiResults.values())
            for curEp in foundResults[providerObj.name]:
                if curEp in (MULTI_EP_RESULT, SEASON_RESULT):
                    continue

                if not len(foundResults[providerObj.name][curEp]) > 0:
                    continue

                # if all results were rejected move on to the next episode
                bestResult = pickBestResult(
                    foundResults[providerObj.name][curEp], show)
                if not bestResult:
                    continue

                # add result if its not a duplicate and
                found = False
                for i, result in enumerate(finalResults):
                    for bestResultEp in bestResult.episodes:
                        if bestResultEp in result.episodes:
                            if result.quality < bestResult.quality:
                                finalResults.pop(i)
                            else:
                                found = True
                if not found:
                    finalResults += [bestResult]

            # check that we got all the episodes we wanted first before doing a match and snatch
            wantedEpCount = 0
            for wantedEp in episodes:
                for result in finalResults:
                    if wantedEp in result.episodes and isFinalResult(result):
                        wantedEpCount += 1

            # make sure we search every provider for results unless we found everything we wanted
            if wantedEpCount == len(episodes):
                break

        if not didSearch:
            sickrage.LOGGER.warning(
                "No NZB/Torrent providers found or enabled in the sickrage config for backlog searches. Please check your settings."
            )

        return finalResults

    return perform_searches()
Exemplo n.º 7
0
def searchForNeededEpisodes():
    """
    Check providers for details on wanted episodes

    :return: episodes we have a search hit for
    """
    foundResults = {}

    origThreadName = threading.currentThread().getName()

    fromDate = datetime.date.fromordinal(1)
    episodes = []

    with threading.Lock():
        for curShow in sickrage.showList:
            if not curShow.paused:
                episodes.extend(wantedEpisodes(curShow, fromDate))

    # list of providers
    providers = {
        k: v
        for k, v in sortedProviderDict(sickrage.RANDOMIZE_PROVIDERS).items()
        if v.isActive
    }

    # perform provider searchers
    def perform_searches():
        didSearch = False
        for providerID, providerObj in providers.items():
            threading.currentThread().setName(origThreadName + "::[" +
                                              providerObj.name + "]")

            try:
                providerObj.cache.updateCache()
                curFoundResults = dict(providerObj.searchRSS(episodes))
            except AuthException as e:
                sickrage.LOGGER.error("Authentication error: {}".format(e))
                return
            except Exception as e:
                sickrage.LOGGER.error("Error while searching " +
                                      providerObj.name +
                                      ", skipping: {}".format(e))
                sickrage.LOGGER.debug(traceback.format_exc())
                return

            didSearch = True

            # pick a single result for each episode, respecting existing results
            for curEp in curFoundResults:
                if not curEp.show or curEp.show.paused:
                    sickrage.LOGGER.debug(
                        "Skipping %s because the show is paused " %
                        curEp.prettyName())
                    continue

                bestResult = pickBestResult(curFoundResults[curEp], curEp.show)

                # if all results were rejected move on to the next episode
                if not bestResult:
                    sickrage.LOGGER.debug("All found results for " +
                                          curEp.prettyName() +
                                          " were rejected.")
                    continue

                # if it's already in the list (from another provider) and the newly found quality is no better then skip it
                if curEp in foundResults and bestResult.quality <= foundResults[
                        curEp].quality:
                    continue

                foundResults[curEp] = bestResult

        if not didSearch:
            sickrage.LOGGER.warning(
                "No NZB/Torrent providers found or enabled in the sickrage config for daily searches. Please check your settings."
            )

        return foundResults.values()

    return perform_searches()
Exemplo n.º 8
0
    def _getProperList(self):
        """
        Walk providers for propers
        """
        propers = {}

        search_date = datetime.datetime.today() - datetime.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.RANDOMIZE_PROVIDERS).items() if v.isActive
        }.items():

            threading.currentThread().setName(origThreadName + " :: [" +
                                              providerObj.name + "]")

            sickrage.LOGGER.info(
                "Searching for any new PROPER releases from " +
                providerObj.name)

            try:
                curPropers = providerObj.findPropers(search_date)
            except AuthException as e:
                sickrage.LOGGER.debug("Authentication error: {}".format(e))
                continue
            except Exception as e:
                sickrage.LOGGER.debug("Error while searching " +
                                      providerObj.name +
                                      ", skipping: {}".format(e))
                sickrage.LOGGER.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.LOGGER.debug(
                        'findPropers returned a non-proper, we have caught and skipped it.'
                    )
                    continue

                name = self._genericName(x.name)
                if not name in propers:
                    sickrage.LOGGER.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.LOGGER.debug("Unable to parse the filename " +
                                      curProper.name + " into a valid episode")
                continue
            except InvalidShowException:
                sickrage.LOGGER.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.LOGGER.debug(
                    "Ignoring " + curProper.name +
                    " because it's for a full season rather than specific episode"
                )
                continue

            sickrage.LOGGER.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.LOGGER.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.LOGGER.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.LOGGER.info("Found new anime v" +
                                         str(bestResult.version) +
                                         " to replace existing v" +
                                         str(oldVersion))
                else:
                    continue

                if oldRelease_group != bestResult.release_group:
                    sickrage.LOGGER.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.LOGGER.info("Found a proper that we need: " +
                                     str(bestResult.name))
                finalPropers.append(bestResult)

        return finalPropers
Exemplo n.º 9
0
import certifi
import requests

from sickrage.providers import sortedProviderDict
from tests import SiCKRAGETestCase

class SNI_Tests(SiCKRAGETestCase): pass

def test_sni(self, provider):
    try:
        requests.head(provider.url, verify=certifi.where(), timeout=5)
    except requests.exceptions.Timeout:
        pass
    except requests.exceptions.SSLError as error:
        if 'SSL3_GET_SERVER_CERTIFICATE' not in error:
            print(error)
    except Exception:
        pass


for providerID, providerObj in sortedProviderDict().items():
    setattr(SNI_Tests, 'test_%s' % providerObj.name, lambda self, x=providerObj: test_sni(self, x))

if __name__ == "__main__":
    print("==================")
    print("STARTING - SSL TESTS")
    print("==================")
    print("######################################################################")
    unittest.main()
Exemplo n.º 10
0
    def _getProperList(self):
        """
        Walk providers for propers
        """
        propers = {}

        search_date = datetime.datetime.today() - datetime.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.RANDOMIZE_PROVIDERS).items()
                                        if v.isActive}.items():

            threading.currentThread().setName(origThreadName + " :: [" + providerObj.name + "]")

            sickrage.LOGGER.info("Searching for any new PROPER releases from " + providerObj.name)

            try:
                curPropers = providerObj.findPropers(search_date)
            except AuthException as e:
                sickrage.LOGGER.debug("Authentication error: {}".format(e))
                continue
            except Exception as e:
                sickrage.LOGGER.debug("Error while searching " + providerObj.name + ", skipping: {}".format(e))
                sickrage.LOGGER.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.LOGGER.debug('findPropers returned a non-proper, we have caught and skipped it.')
                    continue

                name = self._genericName(x.name)
                if not name in propers:
                    sickrage.LOGGER.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.LOGGER.debug("Unable to parse the filename " + curProper.name + " into a valid episode")
                continue
            except InvalidShowException:
                sickrage.LOGGER.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.LOGGER.debug(
                        "Ignoring " + curProper.name + " because it's for a full season rather than specific episode")
                continue

            sickrage.LOGGER.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.LOGGER.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.LOGGER.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.LOGGER.info(
                        "Found new anime v" + str(bestResult.version) + " to replace existing v" + str(oldVersion))
                else:
                    continue

                if oldRelease_group != bestResult.release_group:
                    sickrage.LOGGER.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.LOGGER.info("Found a proper that we need: " + str(bestResult.name))
                finalPropers.append(bestResult)

        return finalPropers
Exemplo n.º 11
0
def searchProviders(show, episodes, manualSearch=False, downCurQuality=False):
    """
    Walk providers for information on shows

    :param show: Show we are looking for
    :param episodes: Episodes we hope to find
    :param manualSearch: Boolean, is this a manual search?
    :param downCurQuality: Boolean, should we redownload currently avaialble quality file
    :return: results for search
    """
    foundResults = {}

    # build name cache for show
    sickrage.NAMECACHE.buildNameCache(show)

    origThreadName = threading.currentThread().getName()

    providers = {k: v for k, v in sortedProviderDict(sickrage.RANDOMIZE_PROVIDERS).items() if v.isActive}

    def perform_searches():

        finalResults = []
        didSearch = False

        for providerID, providerObj in providers.items():
            if providerObj.anime_only and not show.is_anime:
                sickrage.LOGGER.debug("" + str(show.name) + " is not an anime, skiping")
                continue

            threading.currentThread().setName(origThreadName + "::[" + providerObj.name + "]")

            foundResults[providerObj.name] = {}

            searchCount = 0
            search_mode = providerObj.search_mode

            # Always search for episode when manually searching when in sponly
            if search_mode == "sponly" and manualSearch == True:
                search_mode = "eponly"

            while True:
                searchCount += 1

                if search_mode == "eponly":
                    sickrage.LOGGER.info("Performing episode search for " + show.name)
                else:
                    sickrage.LOGGER.info("Performing season pack search for " + show.name)

                try:
                    providerObj.cache.updateCache()
                    searchResults = providerObj.findSearchResults(
                        show, episodes, search_mode, manualSearch, downCurQuality
                    )
                except AuthException as e:
                    sickrage.LOGGER.error("Authentication error: {}".format(e))
                    break
                except Exception as e:
                    sickrage.LOGGER.error("Error while searching " + providerObj.name + ", skipping: {}".format(e))
                    sickrage.LOGGER.debug(traceback.format_exc())
                    break

                didSearch = True

                if len(searchResults):
                    # make a list of all the results for this provider
                    for curEp in searchResults:
                        if curEp in foundResults:
                            foundResults[providerObj.name][curEp] += searchResults[curEp]
                        else:
                            foundResults[providerObj.name][curEp] = searchResults[curEp]

                    break
                elif not providerObj.search_fallback or searchCount == 2:
                    break

                if search_mode == "sponly":
                    sickrage.LOGGER.debug("Fallback episode search initiated")
                    search_mode = "eponly"
                else:
                    sickrage.LOGGER.debug("Fallback season pack search initiate")
                    search_mode = "sponly"

            # skip to next provider if we have no results to process
            if not len(foundResults[providerObj.name]):
                continue

            # pick the best season NZB
            bestSeasonResult = None
            if SEASON_RESULT in foundResults[providerObj.name]:
                bestSeasonResult = pickBestResult(foundResults[providerObj.name][SEASON_RESULT], show)

            highest_quality_overall = 0
            for cur_episode in foundResults[providerObj.name]:
                for cur_result in foundResults[providerObj.name][cur_episode]:
                    if cur_result.quality != Quality.UNKNOWN and cur_result.quality > highest_quality_overall:
                        highest_quality_overall = cur_result.quality
            sickrage.LOGGER.debug(
                "The highest quality of any match is " + Quality.qualityStrings[highest_quality_overall]
            )

            # see if every episode is wanted
            if bestSeasonResult:
                searchedSeasons = [str(x.season) for x in episodes]

                # get the quality of the season nzb
                seasonQual = bestSeasonResult.quality
                sickrage.LOGGER.debug(
                    "The quality of the season "
                    + bestSeasonResult.provider.type
                    + " is "
                    + Quality.qualityStrings[seasonQual]
                )

                allEps = [
                    int(x[b"episode"])
                    for x in main_db.MainDB().select(
                        "SELECT episode FROM tv_episodes WHERE showid = ? AND ( season IN ( "
                        + ",".join(searchedSeasons)
                        + " ) )",
                        [show.indexerid],
                    )
                ]

                sickrage.LOGGER.info(
                    "Executed query: [SELECT episode FROM tv_episodes WHERE showid = %s AND season in  %s]"
                    % (show.indexerid, ",".join(searchedSeasons))
                )
                sickrage.LOGGER.debug("Episode list: " + str(allEps))

                allWanted = True
                anyWanted = False
                for curEpNum in allEps:
                    for season in set([x.season for x in episodes]):
                        if not show.wantEpisode(season, curEpNum, seasonQual, downCurQuality):
                            allWanted = False
                        else:
                            anyWanted = True

                # if we need every ep in the season and there's nothing better then just download this and be done with it (unless single episodes are preferred)
                if allWanted and bestSeasonResult.quality == highest_quality_overall:
                    sickrage.LOGGER.info(
                        "Every ep in this season is needed, downloading the whole "
                        + bestSeasonResult.provider.type
                        + " "
                        + bestSeasonResult.name
                    )
                    epObjs = []
                    for curEpNum in allEps:
                        for season in set([x.season for x in episodes]):
                            epObjs.append(show.getEpisode(season, curEpNum))
                    bestSeasonResult.episodes = epObjs

                    return [bestSeasonResult]

                elif not anyWanted:
                    sickrage.LOGGER.debug(
                        "No eps from this season are wanted at this quality, ignoring the result of "
                        + bestSeasonResult.name
                    )

                else:

                    if bestSeasonResult.provider.type == GenericProvider.NZB:
                        sickrage.LOGGER.debug("Breaking apart the NZB and adding the individual ones to our results")

                        # if not, break it apart and add them as the lowest priority results
                        individualResults = splitNZBResult(bestSeasonResult)
                        for curResult in individualResults:
                            if len(curResult.episodes) == 1:
                                epNum = curResult.episodes[0].episode
                            elif len(curResult.episodes) > 1:
                                epNum = MULTI_EP_RESULT

                            if epNum in foundResults[providerObj.name]:
                                foundResults[providerObj.name][epNum].append(curResult)
                            else:
                                foundResults[providerObj.name][epNum] = [curResult]

                    # If this is a torrent all we can do is leech the entire torrent, user will have to select which eps not do download in his torrent client
                    else:

                        # Season result from Torrent Provider must be a full-season torrent, creating multi-ep result for it.
                        sickrage.LOGGER.info(
                            "Adding multi-ep result for full-season torrent. Set the episodes you don't want to 'don't download' in your torrent client if desired!"
                        )
                        epObjs = []
                        for curEpNum in allEps:
                            for season in set([x.season for x in episodes]):
                                epObjs.append(show.getEpisode(season, curEpNum))
                        bestSeasonResult.episodes = epObjs

                        if MULTI_EP_RESULT in foundResults[providerObj.name]:
                            foundResults[providerObj.name][MULTI_EP_RESULT].append(bestSeasonResult)
                        else:
                            foundResults[providerObj.name][MULTI_EP_RESULT] = [bestSeasonResult]

            # go through multi-ep results and see if we really want them or not, get rid of the rest
            multiResults = {}
            if MULTI_EP_RESULT in foundResults[providerObj.name]:
                for _multiResult in foundResults[providerObj.name][MULTI_EP_RESULT]:

                    sickrage.LOGGER.debug("Seeing if we want to bother with multi-episode result " + _multiResult.name)

                    # Filter result by ignore/required/whitelist/blacklist/quality, etc
                    multiResult = pickBestResult(_multiResult, show)
                    if not multiResult:
                        continue

                    # see how many of the eps that this result covers aren't covered by single results
                    neededEps = []
                    notNeededEps = []
                    for epObj in multiResult.episodes:
                        # if we have results for the episode
                        if (
                            epObj.episode in foundResults[providerObj.name]
                            and len(foundResults[providerObj.name][epObj.episode]) > 0
                        ):
                            notNeededEps.append(epObj.episode)
                        else:
                            neededEps.append(epObj.episode)

                    sickrage.LOGGER.debug(
                        "Single-ep check result is neededEps: "
                        + str(neededEps)
                        + ", notNeededEps: "
                        + str(notNeededEps)
                    )

                    if not neededEps:
                        sickrage.LOGGER.debug(
                            "All of these episodes were covered by single episode results, ignoring this multi-episode result"
                        )
                        continue

                    # check if these eps are already covered by another multi-result
                    multiNeededEps = []
                    multiNotNeededEps = []
                    for epObj in multiResult.episodes:
                        if epObj.episode in multiResults:
                            multiNotNeededEps.append(epObj.episode)
                        else:
                            multiNeededEps.append(epObj.episode)

                    sickrage.LOGGER.debug(
                        "Multi-ep check result is multiNeededEps: "
                        + str(multiNeededEps)
                        + ", multiNotNeededEps: "
                        + str(multiNotNeededEps)
                    )

                    if not multiNeededEps:
                        sickrage.LOGGER.debug(
                            "All of these episodes were covered by another multi-episode nzbs, ignoring this multi-ep result"
                        )
                        continue

                    # don't bother with the single result if we're going to get it with a multi result
                    for epObj in multiResult.episodes:
                        multiResults[epObj.episode] = multiResult
                        if epObj.episode in foundResults[providerObj.name]:
                            sickrage.LOGGER.debug(
                                "A needed multi-episode result overlaps with a single-episode result for ep #"
                                + str(epObj.episode)
                                + ", removing the single-episode results from the list"
                            )
                            del foundResults[providerObj.name][epObj.episode]

            # of all the single ep results narrow it down to the best one for each episode
            finalResults += set(multiResults.values())
            for curEp in foundResults[providerObj.name]:
                if curEp in (MULTI_EP_RESULT, SEASON_RESULT):
                    continue

                if not len(foundResults[providerObj.name][curEp]) > 0:
                    continue

                # if all results were rejected move on to the next episode
                bestResult = pickBestResult(foundResults[providerObj.name][curEp], show)
                if not bestResult:
                    continue

                # add result if its not a duplicate and
                found = False
                for i, result in enumerate(finalResults):
                    for bestResultEp in bestResult.episodes:
                        if bestResultEp in result.episodes:
                            if result.quality < bestResult.quality:
                                finalResults.pop(i)
                            else:
                                found = True
                if not found:
                    finalResults += [bestResult]

            # check that we got all the episodes we wanted first before doing a match and snatch
            wantedEpCount = 0
            for wantedEp in episodes:
                for result in finalResults:
                    if wantedEp in result.episodes and isFinalResult(result):
                        wantedEpCount += 1

            # make sure we search every provider for results unless we found everything we wanted
            if wantedEpCount == len(episodes):
                break

        if not didSearch:
            sickrage.LOGGER.warning(
                "No NZB/Torrent providers found or enabled in the sickrage config for backlog searches. Please check your settings."
            )

        return finalResults

    return perform_searches()
Exemplo n.º 12
0
def searchForNeededEpisodes():
    """
    Check providers for details on wanted episodes

    :return: episodes we have a search hit for
    """
    foundResults = {}

    origThreadName = threading.currentThread().getName()

    fromDate = datetime.date.fromordinal(1)
    episodes = []

    with threading.Lock():
        for curShow in sickrage.showList:
            if not curShow.paused:
                episodes.extend(wantedEpisodes(curShow, fromDate))

    # list of providers
    providers = {k: v for k, v in sortedProviderDict(sickrage.RANDOMIZE_PROVIDERS).items() if v.isActive}

    # perform provider searchers
    def perform_searches():
        didSearch = False
        for providerID, providerObj in providers.items():
            threading.currentThread().setName(origThreadName + "::[" + providerObj.name + "]")

            try:
                providerObj.cache.updateCache()
                curFoundResults = dict(providerObj.searchRSS(episodes))
            except AuthException as e:
                sickrage.LOGGER.error("Authentication error: {}".format(e))
                return
            except Exception as e:
                sickrage.LOGGER.error("Error while searching " + providerObj.name + ", skipping: {}".format(e))
                sickrage.LOGGER.debug(traceback.format_exc())
                return

            didSearch = True

            # pick a single result for each episode, respecting existing results
            for curEp in curFoundResults:
                if not curEp.show or curEp.show.paused:
                    sickrage.LOGGER.debug("Skipping %s because the show is paused " % curEp.prettyName())
                    continue

                bestResult = pickBestResult(curFoundResults[curEp], curEp.show)

                # if all results were rejected move on to the next episode
                if not bestResult:
                    sickrage.LOGGER.debug("All found results for " + curEp.prettyName() + " were rejected.")
                    continue

                # if it's already in the list (from another provider) and the newly found quality is no better then skip it
                if curEp in foundResults and bestResult.quality <= foundResults[curEp].quality:
                    continue

                foundResults[curEp] = bestResult

        if not didSearch:
            sickrage.LOGGER.warning(
                "No NZB/Torrent providers found or enabled in the sickrage config for daily searches. Please check your settings."
            )

        return foundResults.values()

    return perform_searches()