Пример #1
0
    def _get_release_name(self):
        """Try to find a valid-looking release name"""

        if self.nzb_name is not None:
            self._log(u"Using self.nzb_name for release name.")
            return re.sub(r'\.nzb$', '', self.nzb_name, flags=re.IGNORECASE)

        # try to get the release name from nzb/nfo
        self._log(u"No self.nzb_name given. Trying to guess release name.")
        file_types = ["*.nzb", "*.nfo"]
        for search in file_types:
            search_path = ek.ek(os.path.join, self.dir_name, search)
            results = ek.ek(glob, search_path)
            if len(results) == 1:
                found_file = ek.ek(os.path.basename, results[0])
                found_file = re.sub(r'\.nzb$', '', found_file, flags=re.IGNORECASE)
                if show_name_helpers.filterBadReleases(found_file, self._show_obj):
                    self._log(u"Release name (" + found_file + ") found from file (" + results[0] + ")")
                    return found_file

        # If that fails, we try the folder
        folder = ek.ek(os.path.basename, self.dir_name)
        if show_name_helpers.filterBadReleases(folder, self._show_obj):
            # NOTE: Multiple failed downloads will change the folder name.
            # (e.g., appending #s)
            # Should we handle that?
            self._log(u"Folder name (" + folder + ") appears to be a valid release name. Using it.")
            return folder

        return None
Пример #2
0
def findSeason(show, season):

    logger.log(u"Searching for stuff we need from " + show.name + " season " + str(season))

    foundResults = {}

    didSearch = False

    for curProvider in providers.sortedProviderList():

        if not curProvider.isActive():
            continue

        try:
            curResults = curProvider.findSeasonResults(show, season)

            # make a list of all the results for this provider
            for curEp in curResults:

                # skip non-tv crap
                curResults[curEp] = filter(lambda x: show_name_helpers.filterBadReleases(x.name) and show_name_helpers.isGoodResult(x.name, show), curResults[curEp])

                if curEp in foundResults:
                    foundResults[curEp] += curResults[curEp]
                else:
                    foundResults[curEp] = curResults[curEp]

        except exceptions.AuthException, e:
            logger.log(u"Authentication error: " + ex(e), logger.ERROR)
            continue
        except Exception, e:
            logger.log(u"Error while searching " + curProvider.name + ", skipping: " + ex(e), logger.ERROR)
            logger.log(traceback.format_exc(), logger.DEBUG)
            continue
Пример #3
0
def findSeason(show, season):

    myDB = db.DBConnection()
    allEps = [int(x["episode"]) for x in myDB.select("SELECT episode FROM tv_episodes WHERE showid = ? AND season = ?", [show.tvdbid, season])]
    logger.log(u"Episode list: "+str(allEps), logger.DEBUG)

    
    reallywanted=[]
    notwanted=[]
    finalResults = []
    for curEpNum in allEps:
        sqlResults = myDB.select("SELECT status FROM tv_episodes WHERE showid = ? AND season = ? AND episode = ?", [show.tvdbid, season, curEpNum])
        epStatus = int(sqlResults[0]["status"])
        if epStatus ==3:
            reallywanted.append(curEpNum)
        else:
            notwanted.append(curEpNum)
    if notwanted != []:
        for EpNum in reallywanted:
            showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, show.tvdbid)
            episode = showObj.getEpisode(season, EpNum)
            res=findEpisode(episode, manualSearch=True)
            snatchEpisode(res)
        return
    else:
        logger.log(u"Searching for stuff we need from "+show.name+" season "+str(season))
    
        foundResults = {}
    
        didSearch = False
    
        for curProvider in providers.sortedProviderList():
    
            if not curProvider.isActive():
                continue
    
            try:
                curResults = curProvider.findSeasonResults(show, season)
    
                # make a list of all the results for this provider
                for curEp in curResults:
    
                    # skip non-tv crap
                    curResults[curEp] = filter(lambda x:  show_name_helpers.filterBadReleases(x.name) and show_name_helpers.isGoodResult(x.name, show), curResults[curEp])
    
                    if curEp in foundResults:
                        foundResults[curEp] += curResults[curEp]
                    else:
                        foundResults[curEp] = curResults[curEp]
    
            except exceptions.AuthException, e:
                logger.log(u"Authentication error: "+ex(e), logger.ERROR)
                continue
            except Exception, e:
                logger.log(u"Error while searching "+curProvider.name+", skipping: "+ex(e), logger.DEBUG)
                logger.log(traceback.format_exc(), logger.DEBUG)
                continue
    
            didSearch = True
    def _doSearch(self, search_params, show=None):
    
        results = []
        items = {'Season': [], 'Episode': []}
        
        if not self._doLogin():
            return 
        
        for mode in search_params.keys():
            for search_string in search_params[mode]:
                
                searchURL = self.urls['search'] % (search_string, self.categories)

                logger.log(u"Search string: " + searchURL, logger.DEBUG)
        
                data = self.getURL(searchURL)
                if not data:
                    return []

                html = BeautifulSoup(data)
                
                try:
                    torrent_table = html.find('table', attrs = {'id' : 'torrenttable'})
                    
                    if not torrent_table:
                        logger.log(u"No results found for: " + search_string + "(" + searchURL + ")", logger.DEBUG)
                        return []

                    for result in torrent_table.find_all('tr')[1:]:

                        link = result.find('td', attrs = {'class' : 'name'}).find('a')
                        url = result.find('td', attrs = {'class' : 'quickdownload'}).find('a')

                        title = link.string
                        download_url = self.urls['download'] % url['href']
                        id = int(link['href'].replace('/torrent/', ''))
                        seeders = int(result.find('td', attrs = {'class' : 'seeders'}).string)
                        leechers = int(result.find('td', attrs = {'class' : 'leechers'}).string)

                        #Filter unseeded torrent
                        if seeders == 0 or not title \
                        or not show_name_helpers.filterBadReleases(title):
                            continue 

                        item = title, download_url, id, seeders, leechers
                        logger.log(u"Found result: " + title + "(" + searchURL + ")", logger.DEBUG)

                        items[mode].append(item)

                except:
                    logger.log(u"Failed to parsing " + self.name + " page url: " + searchURL, logger.ERROR)

            #For each search mode sort all the items by seeders
            items[mode].sort(key=lambda tup: tup[3], reverse=True)        

            results += items[mode]  
                
        return results
Пример #5
0
    def _test_filter_bad_releases(self, name, expected):
        """
        Test filter of bad releases

        :param name:
        :param expected:
        :return:
        """
        result = show_name_helpers.filterBadReleases(name)
        self.assertEqual(result, expected)
    def _doSearch(self, search_params, show=None):
    
        results = []
        items = {'Season': [], 'Episode': []}

        for mode in search_params.keys():
            for search_string in search_params[mode]:

                searchURL = self.proxy._buildURL(self.searchurl %(urllib.quote(search_string)))    
        
                logger.log(u"Search string: " + searchURL, logger.DEBUG)
        
                data = self.getURL(searchURL)
                if not data:
                    return []
        
                re_title_url = self.proxy._buildRE(self.re_title_url)
                
                #Extracting torrent information from data returned by searchURL                   
                match = re.compile(re_title_url, re.DOTALL ).finditer(urllib.unquote(data))
                for torrent in match:

                    title = torrent.group('title').replace('_','.')#Do not know why but SickBeard skip release with '_' in name
                    url = torrent.group('url')
                    id = int(torrent.group('id'))
                    seeders = int(torrent.group('seeders'))
                    leechers = int(torrent.group('leechers'))

                    #Filter unseeded torrent
                    if seeders == 0 or not title \
                    or not show_name_helpers.filterBadReleases(title):
                        continue 
                   
                    #Accept Torrent only from Good People for every Episode Search
                    if sickbeard.THEPIRATEBAY_TRUSTED and re.search('(VIP|Trusted|Helper)',torrent.group(0))== None:
                        logger.log(u"ThePirateBay Provider found result "+torrent.group('title')+" but that doesn't seem like a trusted result so I'm ignoring it",logger.DEBUG)
                        continue

                    #Try to find the real Quality for full season torrent analyzing files in torrent 
                    if mode == 'Season' and Quality.nameQuality(title) == Quality.UNKNOWN:     
                        if not self._find_season_quality(title,id): continue
                        
                    item = title, url, id, seeders, leechers
                    
                    items[mode].append(item)    

            #For each search mode sort all the items by seeders
            items[mode].sort(key=lambda tup: tup[3], reverse=True)        

            results += items[mode]  
                
        return results
Пример #7
0
def filterSearchResults(show, season, results):
    foundResults = {}

    # make a list of all the results for this provider
    for curEp in results:
        # skip non-tv crap
        results[curEp] = filter(
            lambda x: show_name_helpers.filterBadReleases(x.name) and x.show == show,results[curEp])

        if curEp in foundResults:
            foundResults[curEp] += results[curEp]
        else:
            foundResults[curEp] = results[curEp]

    return foundResults
Пример #8
0
def searchProviders(show, season, episode=None, manualSearch=False):
    logger.log(u"Searching for stuff we need from " + show.name + " season " + str(season))

    foundResults = {}

    didSearch = False
    seasonSearch = False

    # gather all episodes for season and then pick out the wanted episodes and compare to determin if we want whole season or just a few episodes
    if episode is None:
        seasonEps = show.getAllEpisodes(season)
        wantedEps = [x for x in seasonEps if show.getOverview(x.status) in (Overview.WANTED, Overview.QUAL)]
        if len(seasonEps) == len(wantedEps):
            seasonSearch = True
    else:
        ep_obj = show.getEpisode(season, episode)
        wantedEps = [ep_obj]

    for curProvider in providers.sortedProviderList():

        if not curProvider.isActive():
            continue

        try:
            curResults = curProvider.getSearchResults(show, season, wantedEps, seasonSearch, manualSearch)

            # make a list of all the results for this provider
            for curEp in curResults:

                # skip non-tv crap
                curResults[curEp] = filter(
                    lambda x: show_name_helpers.filterBadReleases(x.name) and show_name_helpers.isGoodResult(x.name,
                                                                                                             show),
                    curResults[curEp])

                if curEp in foundResults:
                    foundResults[curEp] += curResults[curEp]
                else:
                    foundResults[curEp] = curResults[curEp]

        except exceptions.AuthException, e:
            logger.log(u"Authentication error: " + ex(e), logger.ERROR)
            continue
        except Exception, e:
            logger.log(u"Error while searching " + curProvider.name + ", skipping: " + ex(e), logger.ERROR)
            logger.log(traceback.format_exc(), logger.DEBUG)
            continue
Пример #9
0
def filterSearchResults(show, results):
    foundResults = {}

    # make a list of all the results for this provider
    for curEp in results.keys():
        # skip non-tv crap
        results[curEp] = filter(
            lambda x: show_name_helpers.filterBadReleases(x.name) and show_name_helpers.isGoodResult(x.name, show),
            results[curEp])

        if len(results[curEp]):
            if curEp in foundResults:
                foundResults[curEp] += results[curEp]
            else:
                foundResults[curEp] = results[curEp]

    return foundResults
Пример #10
0
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]

    logger.log(u"Picking the best result out of " + str([x.name for x in results]), logger.DEBUG)

    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

        logger.log(u"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:
            logger.log(cur_result.name + " is a quality we know we don't want, rejecting it", logger.DEBUG)
            continue

        if show.rls_ignore_words and show_name_helpers.containsAtLeastOneWord(cur_result.name, cur_result.show.rls_ignore_words):
            logger.log(u"Ignoring " + cur_result.name + " based on ignored words filter: " + show.rls_ignore_words,
                       logger.INFO)
            continue

        if show.rls_require_words and not show_name_helpers.containsAtLeastOneWord(cur_result.name, cur_result.show.rls_require_words):
            logger.log(u"Ignoring " + cur_result.name + " based on required words filter: " + show.rls_require_words,
                       logger.INFO)
            continue

        if not show_name_helpers.filterBadReleases(cur_result.name, parse=False):
            logger.log(u"Ignoring " + cur_result.name + " because its not a valid scene release that we want, ignoring it",
                       logger.INFO)
            continue

        if hasattr(cur_result, 'size'):
            if sickbeard.USE_FAILED_DOWNLOADS and failed_history.hasFailed(cur_result.name, cur_result.size,
                                                                           cur_result.provider.name):
                logger.log(cur_result.name + u" 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():
                logger.log(u"Preferring " + cur_result.name + " (x264 over xvid)")
                bestResult = cur_result

    if bestResult:
        logger.log(u"Picked " + bestResult.name + " as the best", logger.DEBUG)
    else:
        logger.log(u"No result picked.", logger.DEBUG)

    return bestResult
Пример #11
0
def pickBestResult(results, show):  # pylint: disable=too-many-branches
    """
    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]

    logger.log(u"Picking the best result out of " + str([x.name for x in results]), logger.DEBUG)

    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

        logger.log(u"Quality of " + cur_result.name + u" is " + Quality.qualityStrings[cur_result.quality])

        anyQualities, bestQualities = Quality.splitQuality(show.quality)

        if cur_result.quality not in anyQualities + bestQualities:
            logger.log(cur_result.name + u" is a quality we know we don't want, rejecting it", logger.DEBUG)
            continue

        # If doesnt have min seeders OR min leechers then discard it
        if cur_result.seeders not in (-1, None) and cur_result.leechers not in (-1, None) \
            and hasattr(cur_result.provider, 'minseed') and hasattr(cur_result.provider, 'minleech') \
            and (int(cur_result.seeders) < int(cur_result.provider.minseed) or
                 int(cur_result.leechers) < int(cur_result.provider.minleech)):
            logger.log(u"Discarding torrent because it doesn't meet the minimum provider setting "
                       u"S:{0} L:{1}. Result has S:{2} L:{3}".format
                       (cur_result.provider.minseed, cur_result.provider.minleech,
                        cur_result.seeders, cur_result.leechers))
            continue

        show_words = show_name_helpers.show_words(cur_result.show)
        ignore_words = show_words.ignore_words
        require_words = show_words.require_words
        found_ignore_word = show_name_helpers.containsAtLeastOneWord(cur_result.name, ignore_words)
        found_require_word = show_name_helpers.containsAtLeastOneWord(cur_result.name, require_words)

        if ignore_words and found_ignore_word:
            logger.log(u"Ignoring " + cur_result.name + u" based on ignored words filter: " + found_ignore_word,
                       logger.INFO)
            continue

        if require_words and not found_require_word:
            logger.log(u"Ignoring " + cur_result.name + u" based on required words filter: " + require_words,
                       logger.INFO)
            continue

        if not show_name_helpers.filterBadReleases(cur_result.name, parse=False):
            continue

        if hasattr(cur_result, 'size'):
            if sickbeard.USE_FAILED_DOWNLOADS and failed_history.hasFailed(cur_result.name, cur_result.size,
                                                                           cur_result.provider.name):
                logger.log(cur_result.name + u" has previously failed, rejecting it")
                continue
        preferred_words = ''
        if sickbeard.PREFERRED_WORDS:
            preferred_words = sickbeard.PREFERRED_WORDS.lower().split(',')
        undesired_words = ''
        if sickbeard.UNDESIRED_WORDS:
            undesired_words = sickbeard.UNDESIRED_WORDS.lower().split(',')

        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 any(ext in cur_result.name.lower() for ext in preferred_words):
                logger.log(u"Preferring " + cur_result.name + u" (preferred words)")
                bestResult = cur_result
            if cur_result.proper_tags:
                logger.log(u"Preferring " + cur_result.name + u" (repack/proper/real/rerip over nuked)")
                bestResult = cur_result
            elif "internal" in bestResult.name.lower() and "internal" not in cur_result.name.lower():
                logger.log(u"Preferring " + cur_result.name + u" (normal instead of internal)")
                bestResult = cur_result
            elif "xvid" in bestResult.name.lower() and "x264" in cur_result.name.lower():
                logger.log(u"Preferring " + cur_result.name + u" (x264 over xvid)")
                bestResult = cur_result
            if any(ext in bestResult.name.lower() and ext not in cur_result.name.lower() for ext in undesired_words):
                logger.log(u"Dont want this release " + cur_result.name + u" (contains undesired word(s))")
                bestResult = cur_result

    if bestResult:
        logger.log(u"Picked " + bestResult.name + u" as the best", logger.DEBUG)
    else:
        logger.log(u"No result picked.", logger.DEBUG)

    return bestResult
Пример #12
0
    def findNeededEpisodes(self, episode=None, manualSearch=False):
        neededEps = {}

        if episode:
            neededEps[episode] = []

        myDB = self._getDB()

        if not episode:
            sqlResults = myDB.select("SELECT * FROM " + self.providerID)
        else:
            sqlResults = myDB.select(
                "SELECT * FROM " + self.providerID +
                " WHERE tvdbid = ? AND season = ? AND episodes LIKE ?", [
                    episode.show.tvdbid, episode.season,
                    "|" + str(episode.episode) + "|"
                ])

        # for each cache entry
        for curResult in sqlResults:

            # skip non-tv crap (but allow them for Newzbin cause we assume it's filtered well)
            if self.providerID != 'newzbin' and not show_name_helpers.filterBadReleases(
                    curResult["name"]):
                continue

            # get the show object, or if it's not one of our shows then ignore it
            showObj = helpers.findCertainShow(sickbeard.showList,
                                              int(curResult["tvdbid"]))
            if not showObj:
                continue

            # get season and ep data (ignoring multi-eps for now)
            curSeason = int(curResult["season"])
            if curSeason == -1:
                continue
            curEp = curResult["episodes"].split("|")[1]
            if not curEp:
                continue
            curEp = int(curEp)
            curQuality = int(curResult["quality"])

            # if the show says we want that episode then add it to the list
            if not showObj.wantEpisode(curSeason, curEp, curQuality,
                                       manualSearch):
                logger.log(
                    u"Skipping " + curResult["name"] +
                    " because we don't want an episode that's " +
                    Quality.qualityStrings[curQuality], logger.DEBUG)

            else:

                if episode:
                    epObj = episode
                else:
                    epObj = showObj.getEpisode(curSeason, curEp)

                # build a result object
                title = curResult["name"]
                url = curResult["url"]

                logger.log(u"Found result " + title + " at " + url)

                result = self.provider.getResult([epObj])
                result.url = url
                result.name = title
                result.quality = curQuality

                # add it to the list
                if epObj not in neededEps:
                    neededEps[epObj] = [result]
                else:
                    neededEps[epObj].append(result)

        return neededEps
Пример #13
0
    def _getProperList(self):

        propers = {}

        # for each provider get a list of the propers
        for curProvider in providers.sortedProviderList():

            if not curProvider.isActive():
                continue

            date = datetime.datetime.today() - datetime.timedelta(days=2)

            logger.log(u"Searching for any new PROPER releases from "+curProvider.name)
            curPropers = curProvider.findPropers(date)

            # if they haven't been added by a different provider than add the proper to the list
            for x in curPropers:
                name = self._genericName(x.name)
                
                if not name in propers:
                    logger.log(u"Found new proper: "+x.name, logger.DEBUG)
                    x.provider = curProvider
                    propers[name] = x

        # take the list of unique propers and get it sorted by
        sortedPropers = sorted(propers.values(), key=operator.attrgetter('date'), reverse=True)
        finalPropers = []

        for curProper in sortedPropers:

            # parse the file name
            try:
                myParser = NameParser(False)
                parse_result = myParser.parse(curProper.name)
            except InvalidNameException:
                logger.log(u"Unable to parse the filename "+curProper.name+" into a valid episode", logger.DEBUG)
                continue

            if not parse_result.episode_numbers:
                logger.log(u"Ignoring "+curProper.name+" because it's for a full season rather than specific episode", logger.DEBUG)
                continue

            # populate our Proper instance
            if parse_result.air_by_date:
                curProper.season = -1
                curProper.episode = parse_result.air_date
            else:
                curProper.season = parse_result.season_number if parse_result.season_number != None else 1
                curProper.episode = parse_result.episode_numbers[0]
            curProper.quality = Quality.nameQuality(curProper.name)

            # for each show in our list
            for curShow in sickbeard.showList:

                genericName = self._genericName(parse_result.series_name)

                # get the scene name masks
                sceneNames = set(show_name_helpers.makeSceneShowSearchStrings(curShow))

                # for each scene name mask
                for curSceneName in sceneNames:

                    # if it matches
                    if genericName == self._genericName(curSceneName):
                        logger.log(u"Successful match! Result "+parse_result.series_name+" matched to show "+curShow.name, logger.DEBUG)

                        # set the tvdbid in the db to the show's tvdbid
                        curProper.tvdbid = curShow.tvdbid

                        # since we found it, break out
                        break

                # if we found something in the inner for loop break out of this one
                if curProper.tvdbid != -1:
                    break

            if curProper.tvdbid == -1:
                continue
            
            if not show_name_helpers.filterBadReleases(curProper.name):
                logger.log(u"Proper "+curProper.name+" isn't a valid scene release that we want, igoring it", logger.DEBUG)
                continue

            # if we have an air-by-date show then get the real season/episode numbers
            if curProper.season == -1 and curProper.tvdbid:
                showObj = helpers.findCertainShow(sickbeard.showList, curProper.tvdbid)
                if not showObj:
                    logger.log(u"This should never have happened, post a bug about this!", logger.ERROR)
                    raise Exception("BAD STUFF HAPPENED")

                tvdb_lang = showObj.lang
                # There's gotta be a better way of doing this but we don't wanna
                # change the language value elsewhere
                ltvdb_api_parms = sickbeard.TVDB_API_PARMS.copy()

                if tvdb_lang and not tvdb_lang == 'en':
                    ltvdb_api_parms['language'] = tvdb_lang

                try:
                    t = tvdb_api.Tvdb(**ltvdb_api_parms)
                    epObj = t[curProper.tvdbid].airedOn(curProper.episode)[0]
                    curProper.season = int(epObj["seasonnumber"])
                    curProper.episodes = [int(epObj["episodenumber"])]
                except tvdb_exceptions.tvdb_episodenotfound:
                    logger.log(u"Unable to find episode with date "+str(curProper.episode)+" for show "+parse_result.series_name+", skipping", logger.WARNING)
                    continue

            # check if we actually want this proper (if it's the right quality)
            sqlResults = db.DBConnection().select("SELECT status FROM tv_episodes WHERE showid = ? AND season = ? AND episode = ?", [curProper.tvdbid, curProper.season, curProper.episode])
            if not sqlResults:
                continue
            oldStatus, oldQuality = Quality.splitCompositeStatus(int(sqlResults[0]["status"]))

            # only keep the proper if we have already retrieved the same quality ep (don't get better/worse ones)
            if oldStatus not in (DOWNLOADED, SNATCHED) or oldQuality != curProper.quality:
                continue

            # if the show is in our list and there hasn't been a proper already added for that particular episode then add it to our list of propers
            if curProper.tvdbid != -1 and (curProper.tvdbid, curProper.season, curProper.episode) not in map(operator.attrgetter('tvdbid', 'season', 'episode'), finalPropers):
                logger.log(u"Found a proper that we need: "+str(curProper.name))
                finalPropers.append(curProper)

        return finalPropers
Пример #14
0
        try:
            curFoundResults = curProvider.findEpisode(episode, manualSearch=manualSearch)
        except exceptions.AuthException, e:
            logger.log(u"Authentication error: " + ex(e), logger.ERROR)
            continue
        except Exception, e:
            logger.log(u"Error while searching " + curProvider.name + ", skipping: " + ex(e), logger.ERROR)
            logger.log(traceback.format_exc(), logger.DEBUG)
            continue

        didSearch = True

        # skip non-tv crap
        curFoundResults = filter(
            lambda x: show_name_helpers.filterBadReleases(x.name)
            and show_name_helpers.isGoodResult(x.name, episode.show),
            curFoundResults,
        )

        # loop all results and see if any of them are good enough that we can stop searching
        done_searching = False
        for cur_result in curFoundResults:
            done_searching = isFinalResult(cur_result)
            logger.log(
                u"Should we stop searching after finding " + cur_result.name + ": " + str(done_searching), logger.DEBUG
            )
            if done_searching:
                break

        foundResults += curFoundResults
Пример #15
0
    def _doSearch(self, search_params, show=None):

        results = []
        items = {'Season': [], 'Episode': []}

        if not self._doLogin():
            return

        for mode in search_params.keys():
            for search_string in search_params[mode]:

                searchURL = self.urls['search'] % (search_string,
                                                   self.categories)

                logger.log(u"Search string: " + searchURL, logger.DEBUG)

                data = self.getURL(searchURL)
                if not data:
                    return []

                html = BeautifulSoup(data)

                try:
                    torrent_table = html.find('table',
                                              attrs={'id': 'torrenttable'})

                    if not torrent_table:
                        logger.log(
                            u"No results found for: " + search_string + "(" +
                            searchURL + ")", logger.DEBUG)
                        return []

                    for result in torrent_table.find_all('tr')[1:]:

                        link = result.find('td', attrs={
                            'class': 'name'
                        }).find('a')
                        url = result.find('td',
                                          attrs={
                                              'class': 'quickdownload'
                                          }).find('a')

                        title = link.string
                        download_url = self.urls['download'] % url['href']
                        id = int(link['href'].replace('/torrent/', ''))
                        seeders = int(
                            result.find('td', attrs={
                                'class': 'seeders'
                            }).string)
                        leechers = int(
                            result.find('td', attrs={
                                'class': 'leechers'
                            }).string)

                        #Filter unseeded torrent
                        if seeders == 0 or not title \
                        or not show_name_helpers.filterBadReleases(title):
                            continue

                        item = title, download_url, id, seeders, leechers
                        logger.log(
                            u"Found result: " + title + "(" + searchURL + ")",
                            logger.DEBUG)

                        items[mode].append(item)

                except:
                    logger.log(
                        u"Failed to parsing " + self.name + " page url: " +
                        searchURL, logger.ERROR)

            #For each search mode sort all the items by seeders
            items[mode].sort(key=lambda tup: tup[3], reverse=True)

            results += items[mode]

        return results
Пример #16
0
                epObjs.append(show.getEpisode(season, curEpNum))
            bestSeasonNZB.episodes = epObjs
            return [bestSeasonNZB]

        elif not anyWanted:
            logger.log(u"No eps from this season are wanted at this quality, ignoring the result of "+bestSeasonNZB.name, logger.DEBUG)

        else:
            
            if bestSeasonNZB.provider.providerType == GenericProvider.NZB:
                logger.log(u"Breaking apart the NZB and adding the individual ones to our results", logger.DEBUG)
                
                # if not, break it apart and add them as the lowest priority results
                individualResults = nzbSplitter.splitResult(bestSeasonNZB)

                individualResults = filter(lambda x:  show_name_helpers.filterBadReleases(x.name) and show_name_helpers.isGoodResult(x.name, show, season=season), individualResults)

                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:
                        foundResults[epNum].append(curResult)
                    else:
                        foundResults[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:
                
Пример #17
0
    def findNeededEpisodes(self, epObj=None, manualSearch=False):
        neededEps = {}

        cacheDB = self._getDB()

        if not epObj:
            sqlResults = cacheDB.select("SELECT * FROM [" + self.providerID + "]")
        else:
            sqlResults = cacheDB.select(
                "SELECT * FROM [" + self.providerID + "] WHERE indexerid = ? AND season = ? AND episodes LIKE ?",
                [epObj.show.indexerid, epObj.season, "%|" + str(epObj.episode) + "|%"])

        # for each cache entry
        for curResult in sqlResults:
            # skip non-tv crap (but allow them for Newzbin cause we assume it's filtered well)
            if self.providerID != 'newzbin' and not show_name_helpers.filterBadReleases(curResult["name"]):
                continue

            # get the show object, or if it's not one of our shows then ignore it
            try:
                showObj = helpers.findCertainShow(sickbeard.showList, int(curResult["indexerid"]))
            except MultipleShowObjectsException:
                showObj = None

            if not showObj:
                continue

            # get season and ep data (ignoring multi-eps for now)
            curSeason = int(curResult["season"])
            if curSeason == -1:
                continue
            curEp = curResult["episodes"].split("|")[1]
            if not curEp:
                continue
            curEp = int(curEp)
            curQuality = int(curResult["quality"])

            # if the show says we want that episode then add it to the list
            if not showObj.wantEpisode(curSeason, curEp, curQuality, manualSearch):
                logger.log(u"Skipping " + curResult["name"] + " because we don't want an episode that's " +
                           Quality.qualityStrings[curQuality], logger.DEBUG)
            else:

                if not epObj:
                    epObj = showObj.getEpisode(curSeason, curEp)

                # build a result object
                title = curResult["name"]
                url = curResult["url"]

                logger.log(u"Found result " + title + " at " + url)

                result = self.provider.getResult([epObj])
                result.url = url
                result.name = title
                result.quality = curQuality
                result.content = self.provider.getURL(url) \
                    if self.provider.providerType == sickbeard.providers.generic.GenericProvider.TORRENT \
                    and not url.startswith('magnet') else None

                # add it to the list
                if epObj not in neededEps:
                    neededEps[epObj.episode] = [result]
                else:
                    neededEps[epObj.episode].append(result)

        return neededEps
Пример #18
0
    def findNeededEpisodes(self, episodes, manualSearch=False):
        neededEps = {}

        for epObj in episodes:
            myDB = self._getDB()
            sqlResults = myDB.select(
                "SELECT * FROM [" + self.providerID +
                "] WHERE indexerid = ? AND season = ? AND episodes LIKE ?", [
                    epObj.show.indexerid, epObj.season,
                    "%|" + str(epObj.episode) + "|%"
                ])

            # for each cache entry
            for curResult in sqlResults:

                # skip non-tv crap (but allow them for Newzbin cause we assume it's filtered well)
                if self.providerID != 'newzbin' and not show_name_helpers.filterBadReleases(
                        curResult["name"]):
                    continue

                # get the show object, or if it's not one of our shows then ignore it
                try:
                    showObj = helpers.findCertainShow(
                        sickbeard.showList, int(curResult["indexerid"]))
                except MultipleShowObjectsException:
                    showObj = None

                if not showObj:
                    continue

                # get season and ep data (ignoring multi-eps for now)
                curSeason = int(curResult["season"])
                if curSeason == -1:
                    continue
                curEp = curResult["episodes"].split("|")[1]
                if not curEp:
                    continue
                curEp = int(curEp)
                curQuality = int(curResult["quality"])
                curReleaseGroup = curResult["release_group"]
                curVersion = curResult["version"]

                # if the show says we want that episode then add it to the list
                if not showObj.wantEpisode(curSeason, curEp, curQuality,
                                           manualSearch):
                    logger.log(
                        u"Skipping " + curResult["name"] +
                        " because we don't want an episode that's " +
                        Quality.qualityStrings[curQuality], logger.DEBUG)
                    continue

                # build a result object
                title = curResult["name"]
                url = curResult["url"]

                logger.log(u"Found result " + title + " at " + url)

                result = self.provider.getResult([epObj])
                result.show = showObj
                result.url = url
                result.name = title
                result.quality = curQuality
                result.release_group = curReleaseGroup
                result.version = curVersion
                result.content = None

                # validate torrent file if not magnet link to avoid invalid torrent links
                if self.provider.providerType == sickbeard.providers.generic.GenericProvider.TORRENT:
                    if sickbeard.TORRENT_METHOD != "blackhole":
                        client = clients.getClientIstance(
                            sickbeard.TORRENT_METHOD)()
                        result = client._get_torrent_hash(result)
                        if not result.hash:
                            logger.log(
                                u'Unable to get torrent hash for ' + title +
                                ', skipping it', logger.DEBUG)
                            continue

                # add it to the list
                if epObj not in neededEps:
                    neededEps[epObj] = [result]
                else:
                    neededEps[epObj].append(result)

        # datetime stamp this search so cache gets cleared
        self.setLastSearch()

        return neededEps
Пример #19
0
class ProperFinder():
    def __init__(self):
        self.amActive = False
        self.updateInterval = datetime.timedelta(hours=1)

        check_propers_interval = {'15m': 15, '45m': 45, '90m': 90, '4h': 4*60, 'daily': 24*60}
        for curInterval in ('15m', '45m', '90m', '4h', 'daily'):
            if sickbeard.CHECK_PROPERS_INTERVAL == curInterval:
                self.updateInterval = datetime.timedelta(minutes = check_propers_interval[curInterval])

    def run(self, force=False):

        if not sickbeard.DOWNLOAD_PROPERS:
            return

        # look for propers every night at 1 AM
        updateTime = datetime.time(hour=1)

        logger.log(u"Checking proper time", logger.DEBUG)

        hourDiff = datetime.datetime.today().time().hour - updateTime.hour
        dayDiff = (datetime.date.today() - self._get_lastProperSearch()).days

        if sickbeard.CHECK_PROPERS_INTERVAL == "daily" and not force:
            # if it's less than an interval after the update time then do an update
            if not (hourDiff >= 0 and hourDiff < self.updateInterval.seconds / 3600 or dayDiff >= 1):
                return

        logger.log(u"Beginning the search for new propers")

        self.amActive = True

        propers = self._getProperList()

        if propers:
            self._downloadPropers(propers)

        self._set_lastProperSearch(datetime.datetime.today().toordinal())

        msg = u"Completed the search for new propers, next check "
        if sickbeard.CHECK_PROPERS_INTERVAL == "daily":
            logger.log(u"%sat 1am tomorrow" % msg)
        else:
            logger.log(u"%sin ~%s" % (msg, sickbeard.CHECK_PROPERS_INTERVAL))

        self.amActive = False

    def _getProperList(self):
        propers = {}

        # for each provider get a list of the
        origThreadName = threading.currentThread().name
        providers = [x for x in sickbeard.providers.sortedProviderList() if x.isActive()]
        for curProvider in providers:
            threading.currentThread().name = origThreadName + " :: [" + curProvider.name + "]"

            search_date = datetime.datetime.today() - datetime.timedelta(days=2)

            logger.log(u"Searching for any new PROPER releases from " + curProvider.name)
            try:
                curPropers = curProvider.findPropers(search_date)
            except exceptions.AuthException, e:
                logger.log(u"Authentication error: " + ex(e), logger.ERROR)
                continue

            # if they haven't been added by a different provider than add the proper to the list
            for x in curPropers:
                name = self._genericName(x.name)
                if not name in propers:
                    logger.log(u"Found new proper: " + x.name, logger.DEBUG)
                    x.provider = curProvider
                    propers[name] = x

        # reset thread name back to original
        threading.currentThread().name = 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:
            in_cache = False

            try:
                myParser = NameParser(False)
                parse_result = myParser.parse(curProper.name)
            except InvalidNameException:
                logger.log(u"Unable to parse the filename " + curProper.name + " into a valid episode", logger.DEBUG)
                continue

            if not parse_result.series_name:
                continue

            cacheResult = sickbeard.name_cache.retrieveNameFromCache(parse_result.series_name)
            if cacheResult:
                in_cache = True
                curProper.indexerid = int(cacheResult)
            elif cacheResult == 0:
                return None

            if not curProper.indexerid:
                showResult = helpers.searchDBForShow(parse_result.series_name)
                if showResult:
                    curProper.indexerid = int(showResult[0])

            if not curProper.indexerid:
                for curShow in sickbeard.showList:
                    if show_name_helpers.isGoodResult(curProper.name, curShow, False):
                        curProper.indexerid = curShow.indexerid
                        break

            showObj = None
            if curProper.indexerid:
                showObj = helpers.findCertainShow(sickbeard.showList, curProper.indexerid)

            if not showObj:
                sickbeard.name_cache.addNameToCache(parse_result.series_name, 0)
                continue

            if not in_cache:
                sickbeard.name_cache.addNameToCache(parse_result.series_name, curProper.indexerid)

            # scene numbering -> indexer numbering
            parse_result = parse_result.convert(showObj)

            if not parse_result.episode_numbers:
                logger.log(
                    u"Ignoring " + curProper.name + " because it's for a full season rather than specific episode",
                    logger.DEBUG)
                continue

            # populate our Proper instance
            if parse_result.air_by_date or parse_result.sports:
                curProper.season = -1
                curProper.episode = parse_result.air_date or parse_result.sports_event_date
            else:
                curProper.season = parse_result.season_number if parse_result.season_number != None else 1
                curProper.episode = parse_result.episode_numbers[0]

            curProper.quality = Quality.nameQuality(curProper.name)

            # for each show in our list
            for curShow in sickbeard.showList:

                genericName = self._genericName(parse_result.series_name)

                # get the scene name masks
                sceneNames = set(show_name_helpers.makeSceneShowSearchStrings(curShow))

                # for each scene name mask
                for curSceneName in sceneNames:

                    # if it matches
                    if genericName == self._genericName(curSceneName):
                        logger.log(
                            u"Successful match! Result " + parse_result.series_name + " matched to show " + curShow.name,
                            logger.DEBUG)

                        # set the indexerid in the db to the show's indexerid
                        curProper.indexerid = curShow.indexerid

                        # set the indexer in the db to the show's indexer
                        curProper.indexer = curShow.indexer

                        # since we found it, break out
                        break

                # if we found something in the inner for loop break out of this one
                if curProper.indexerid != -1:
                    break

            if not show_name_helpers.filterBadReleases(curProper.name):
                logger.log(u"Proper " + curProper.name + " isn't a valid scene release that we want, igoring it",
                           logger.DEBUG)
                continue

            showObj = helpers.findCertainShow(sickbeard.showList, curProper.indexerid)
            if not showObj:
                logger.log(u"Unable to find the show with indexerID " + str(curProper.indexerid), logger.ERROR)
                continue

            if showObj.rls_ignore_words and search.filter_release_name(curProper.name, showObj.rls_ignore_words):
                logger.log(u"Ignoring " + curProper.name + " based on ignored words filter: " + showObj.rls_ignore_words,
                           logger.MESSAGE)
                continue

            if showObj.rls_require_words and not search.filter_release_name(curProper.name, showObj.rls_require_words):
                logger.log(u"Ignoring " + curProper.name + " based on required words filter: " + showObj.rls_require_words,
                           logger.MESSAGE)
                continue

            # if we have an air-by-date show then get the real season/episode numbers
            if (parse_result.air_by_date or parse_result.sports_event_date) and curProper.indexerid:
                logger.log(
                    u"Looks like this is an air-by-date or sports show, attempting to convert the date to season/episode",
                    logger.DEBUG)
                airdate = curProper.episode.toordinal()
                myDB = db.DBConnection()
                sql_result = myDB.select(
                    "SELECT season, episode FROM tv_episodes WHERE showid = ? and indexer = ? and airdate = ?",
                    [curProper.indexerid, curProper.indexer, airdate])

                if sql_result:
                    curProper.season = int(sql_result[0][0])
                    curProper.episodes = [int(sql_result[0][1])]
                else:
                    logger.log(u"Unable to find episode with date " + str(
                        curProper.episode) + " for show " + parse_result.series_name + ", skipping", logger.WARNING)
                    continue

            # check if we actually want this proper (if it's the right quality)
            sqlResults = db.DBConnection().select(
                "SELECT status FROM tv_episodes WHERE showid = ? AND season = ? AND episode = ?",
                [curProper.indexerid, curProper.season, curProper.episode])
            if not sqlResults:
                continue
            oldStatus, oldQuality = Quality.splitCompositeStatus(int(sqlResults[0]["status"]))

            # only keep the proper if we have already retrieved the same quality ep (don't get better/worse ones)
            if oldStatus not in (DOWNLOADED, SNATCHED) or oldQuality != curProper.quality:
                continue

            # if the show is in our list and there hasn't been a proper already added for that particular episode then add it to our list of propers
            if curProper.indexerid != -1 and (curProper.indexerid, curProper.season, curProper.episode) not in map(
                    operator.attrgetter('indexerid', 'season', 'episode'), finalPropers):
                logger.log(u"Found a proper that we need: " + str(curProper.name))
                finalPropers.append(curProper)

        return finalPropers
Пример #20
0
        elif not anyWanted:
            logger.log(
                u"No eps from this season are wanted at this quality, ignoring the result of " + bestSeasonNZB.name,
                logger.DEBUG)

        else:

            if bestSeasonNZB.provider.providerType == GenericProvider.NZB:
                logger.log(u"Breaking apart the NZB and adding the individual ones to our results", logger.DEBUG)

                # if not, break it apart and add them as the lowest priority results
                individualResults = nzbSplitter.splitResult(bestSeasonNZB)

                individualResults = filter(
                    lambda x: show_name_helpers.filterBadReleases(x.name) and show_name_helpers.isGoodResult(x.name,
                                                                                                             show),
                    individualResults)

                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:
                        foundResults[epNum].append(curResult)
                    else:
                        foundResults[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
Пример #21
0
def pickBestResult(results, show):
    results = results if isinstance(results, list) else [results]

    logger.log(u"Picking the best result out of " + str([x.name for x in results]), logger.DEBUG)

    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

        logger.log("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:
            logger.log(cur_result.name + " is a quality we know we don't want, rejecting it", logger.DEBUG)
            continue

        if show.rls_ignore_words and show_name_helpers.containsAtLeastOneWord(cur_result.name, cur_result.show.rls_ignore_words):
            logger.log(u"Ignoring " + cur_result.name + " based on ignored words filter: " + show.rls_ignore_words,
                       logger.INFO)
            continue

        if show.rls_require_words and not show_name_helpers.containsAtLeastOneWord(cur_result.name, cur_result.show.rls_require_words):
            logger.log(u"Ignoring " + cur_result.name + " based on required words filter: " + show.rls_require_words,
                       logger.INFO)
            continue

        if not show_name_helpers.filterBadReleases(cur_result.name, parse=False):
            logger.log(u"Ignoring " + cur_result.name + " because its not a valid scene release that we want, ignoring it",
                       logger.INFO)
            continue

        if hasattr(cur_result, 'size'):
            if sickbeard.USE_FAILED_DOWNLOADS and failed_history.hasFailed(cur_result.name, cur_result.size,
                                                                           cur_result.provider.name):
                logger.log(cur_result.name + u" has previously failed, rejecting it")
                continue

        # Download the torrent file contents only if it has passed all other checks!
        # Must be done before setting bestResult
        if cur_result.resultType == "torrent" and sickbeard.TORRENT_METHOD != "blackhole":
            if len(cur_result.url) and  not cur_result.url.startswith('magnet'):
                cur_result.content = cur_result.provider.getURL(cur_result.url)
                if not cur_result.content:
                    continue

        if cur_result.quality in bestQualities and (not bestResult or bestResult.quality < cur_result.quality or bestResult not in bestQualities):
            bestResult = cur_result
        elif cur_result.quality in anyQualities and (not bestResult or bestResult not in bestQualities) and (not bestResult or bestResult.quality < cur_result.quality):
            bestResult = cur_result
        elif bestResult and 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():
                logger.log(u"Preferring " + cur_result.name + " (x264 over xvid)")
                bestResult = cur_result

    if bestResult:
        logger.log(u"Picked " + bestResult.name + " as the best", logger.DEBUG)
    else:
        logger.log(u"No result picked.", logger.DEBUG)

    return bestResult
Пример #22
0
def findSeason(show, season):

    myDB = db.DBConnection()
    allEps = [
        int(x["episode"]) for x in myDB.select(
            "SELECT episode FROM tv_episodes WHERE showid = ? AND season = ?",
            [show.tvdbid, season])
    ]
    logger.log(u"Episode list: " + str(allEps), logger.DEBUG)

    reallywanted = []
    notwanted = []
    finalResults = []
    for curEpNum in allEps:
        sqlResults = myDB.select(
            "SELECT status FROM tv_episodes WHERE showid = ? AND season = ? AND episode = ?",
            [show.tvdbid, season, curEpNum])
        epStatus = int(sqlResults[0]["status"])
        if epStatus == 3:
            reallywanted.append(curEpNum)
        else:
            notwanted.append(curEpNum)
    if notwanted != []:
        for EpNum in reallywanted:
            showObj = sickbeard.helpers.findCertainShow(
                sickbeard.showList, show.tvdbid)
            episode = showObj.getEpisode(season, EpNum)
            finalResults.append(findEpisode(episode, manualSearch=True))
        return finalResults
    else:
        logger.log(u"Searching for stuff we need from " + show.name +
                   " season " + str(season))

        foundResults = {}

        didSearch = False

        for curProvider in providers.sortedProviderList():

            if not curProvider.isActive():
                continue

            try:
                curResults = curProvider.findSeasonResults(show, season)

                # make a list of all the results for this provider
                for curEp in curResults:

                    # skip non-tv crap
                    curResults[curEp] = filter(
                        lambda x: show_name_helpers.filterBadReleases(x.name)
                        and show_name_helpers.isGoodResult(x.name, show),
                        curResults[curEp])

                    if curEp in foundResults:
                        foundResults[curEp] += curResults[curEp]
                    else:
                        foundResults[curEp] = curResults[curEp]

            except exceptions.AuthException, e:
                logger.log(u"Authentication error: " + ex(e), logger.ERROR)
                continue
            except Exception, e:
                logger.log(
                    u"Error while searching " + curProvider.name +
                    ", skipping: " + ex(e), logger.DEBUG)
                logger.log(traceback.format_exc(), logger.DEBUG)
                continue

            didSearch = True
Пример #23
0
            # populate our Proper instance
            curProper.season = parse_result.season_number if parse_result.season_number != None else 1
            curProper.episode = parse_result.episode_numbers[0]

            # only get anime proper if it has release group and version
            if parse_result.is_anime:
                if parse_result.release_group and parse_result.version:
                    curProper.release_group = parse_result.release_group
                    curProper.version = parse_result.version
                else:
                    continue

            curProper.quality = Quality.nameQuality(curProper.name, parse_result.is_anime)

            if not show_name_helpers.filterBadReleases(curProper.name):
                logger.log(u"Proper " + curProper.name + " isn't a valid scene release that we want, ignoring it",
                           logger.DEBUG)
                continue

            if parse_result.show.rls_ignore_words and search.filter_release_name(curProper.name,
                                                                                 parse_result.show.rls_ignore_words):
                logger.log(
                    u"Ignoring " + curProper.name + " based on ignored words filter: " + parse_result.show.rls_ignore_words,
                    logger.MESSAGE)
                continue

            if parse_result.show.rls_require_words and not search.filter_release_name(curProper.name,
                                                                                      parse_result.show.rls_require_words):
                logger.log(
                    u"Ignoring " + curProper.name + " based on required words filter: " + parse_result.show.rls_require_words,
Пример #24
0
def findEpisode(episode, manualSearch=False):

    logger.log(u"Searching for " + episode.prettyName(True))

    foundResults = []

    didSearch = False

    for curProvider in providers.sortedProviderList():

        if not curProvider.isActive():
            continue

        # we check our results after every search string
        # this is done because in the future we will have a ordered list of all show aliases and release_group aliases
        # ordered by success rate ...

        # lets get all search strings
        # we use the method from the curProvider to accommodate for the internal join functions
        # this way we do not break the special abilities of the providers e.g. nzbmatrix
        searchStrings = curProvider.get_episode_search_strings(episode)
        logger.log("All search string permutations (" + curProvider.name + "):" + str(searchStrings))
        """
        try:
            searchStrings = list(set(searchStrings))
        except TypeError:
            pass
        """
        done_searching = False
        for searchString in searchStrings:
            try:
                curFoundResults = curProvider.findEpisode(episode, manualSearch=manualSearch, searchString=searchString)
            except exceptions.AuthException, e:
                logger.log(u"Authentication error: "+ex(e), logger.ERROR)
                break # break the while loop
            except Exception, e:
                logger.log(u"Error while searching "+curProvider.name+", skipping: "+ex(e), logger.ERROR)
                logger.log(traceback.format_exc(), logger.DEBUG)
                break # break the while loop

            didSearch = True

            # skip non-tv crap
            curFoundResults = filter(lambda x: show_name_helpers.filterBadReleases(x.name) and show_name_helpers.isGoodResult(x.name, episode.show, season=episode.season), curFoundResults)

            # loop all results and see if any of them are good enough that we can stop searching
            for cur_result in curFoundResults:
                done_searching = isFinalResult(cur_result)
                logger.log(u"Should we stop searching after finding "+cur_result.name+": "+str(done_searching), logger.DEBUG)
                if done_searching:
                    break

            # if we are searching an anime we are a little more loose
            # this means we check every turn for a possible result
            # in contrast the isFinalResultlooks function looks for a perfect result (best quality)
            # but this will accept any result that would have been picked in the end -> pickBestResult
            # and then stop and use that
            if episode.show.is_anime:
                logger.log(u"We are searching an anime. i am checking if we got a good result with search provider "+curProvider.name, logger.DEBUG)
                bestResult = pickBestResult(curFoundResults, show=episode.show)
                if bestResult:
                    return bestResult

            foundResults += curFoundResults
            # if we did find a result that's good enough to stop then don't continue
            # this breaks the turn loop
            if done_searching:
                break
Пример #25
0
    def findNeededEpisodes(self, episodes, manualSearch=False):
        neededEps = {}

        for epObj in episodes:
            myDB = self._getDB()
            sqlResults = myDB.select(
                "SELECT * FROM [" + self.providerID + "] WHERE indexerid = ? AND season = ? AND episodes LIKE ?",
                [epObj.show.indexerid, epObj.season, "%|" + str(epObj.episode) + "|%"])

            # for each cache entry
            for curResult in sqlResults:

                # skip non-tv crap (but allow them for Newzbin cause we assume it's filtered well)
                if self.providerID != 'newzbin' and not show_name_helpers.filterBadReleases(curResult["name"]):
                    continue

                # get the show object, or if it's not one of our shows then ignore it
                try:
                    showObj = helpers.findCertainShow(sickbeard.showList, int(curResult["indexerid"]))
                except MultipleShowObjectsException:
                    showObj = None

                if not showObj:
                    continue

                # get season and ep data (ignoring multi-eps for now)
                curSeason = int(curResult["season"])
                if curSeason == -1:
                    continue
                curEp = curResult["episodes"].split("|")[1]
                if not curEp:
                    continue
                curEp = int(curEp)
                curQuality = int(curResult["quality"])
                curReleaseGroup = curResult["release_group"]
                curVersion = curResult["version"]

                # if the show says we want that episode then add it to the list
                if not showObj.wantEpisode(curSeason, curEp, curQuality, manualSearch):
                    logger.log(u"Skipping " + curResult["name"] + " because we don't want an episode that's " +
                               Quality.qualityStrings[curQuality], logger.DEBUG)
                    continue

                # build a result object
                title = curResult["name"]
                url = curResult["url"]

                logger.log(u"Found result " + title + " at " + url)

                result = self.provider.getResult([epObj])
                result.show = showObj
                result.url = url
                result.name = title
                result.quality = curQuality
                result.release_group = curReleaseGroup
                result.version = curVersion
                result.content = None

                # add it to the list
                if epObj not in neededEps:
                    neededEps[epObj] = [result]
                else:
                    neededEps[epObj].append(result)

        # datetime stamp this search so cache gets cleared
        self.setLastSearch()

        return neededEps
Пример #26
0
                episode, manualSearch=manualSearch)
        except exceptions.AuthException, e:
            logger.log(u"Authentication error: " + ex(e), logger.ERROR)
            continue
        except Exception, e:
            logger.log(
                u"Error while searching " + curProvider.name + ", skipping: " +
                ex(e), logger.ERROR)
            logger.log(traceback.format_exc(), logger.DEBUG)
            continue

        didSearch = True

        # skip non-tv crap
        curFoundResults = filter(
            lambda x: show_name_helpers.filterBadReleases(
                x.name, episode.show) and show_name_helpers.isGoodResult(
                    x.name, episode.show), curFoundResults)

        # loop all results and see if any of them are good enough that we can stop searching
        done_searching = False
        for cur_result in curFoundResults:
            done_searching = isFinalResult(cur_result)
            logger.log(
                u"Should we stop searching after finding " + cur_result.name +
                ": " + str(done_searching), logger.DEBUG)
            if done_searching:
                break

        foundResults += curFoundResults

        # if we did find a result that's good enough to stop then don't continue
Пример #27
0
    def findNeededEpisodes(self, episode=None, manualSearch=False):
        neededEps = {}

        if episode:
            neededEps[episode] = []

        myDB = self._getDB()

        if not episode:
            sqlResults = myDB.select("SELECT * FROM " + self.providerID)
        else:
            sqlResults = myDB.select(
                "SELECT * FROM " + self.providerID +
                " WHERE tvdbid = ? AND season = ? AND episodes LIKE ?", [
                    episode.show.tvdbid, episode.season,
                    "%|" + str(episode.episode) + "|%"
                ])
            #print episode.show + " aaaa"

        sbDB = db.DBConnection()
        # for each cache entry
        for curResult in sqlResults:

            curID = str(curResult["tvdbid"])
            if str(curResult["tvdbid"]) != "0":
                #logger.log(u"tvdb id: "+str(curResult["tvdbid"]), logger.ERROR)
                #logger.log("hahaha1", logger.ERROR)
                sqlResults2 = sbDB.select(
                    "SELECT * FROM tv_shows WHERE tvdb_id = " + curID + "")
                for show in sqlResults2:
                    #logger.log(u"SHOWNAME: "+str(show["show_name"]), logger.ERROR)
                    #logger.log(u"LANGUAGE: "+str(show["lang"]), logger.ERROR)
                    class myShow(object):
                        pass

                    setattr(myShow, "lang", show["lang"])
                    setattr(myShow, "name", show["show_name"])

                    # skip non-tv crap (but allow them for Newzbin cause we assume it's filtered well)
                    if self.providerID != 'newzbin':
                        continue
            # get the show object, or if it's not one of our shows then ignore it
            showObj = helpers.findCertainShow(sickbeard.showList,
                                              int(curResult["tvdbid"]))
            if not showObj:
                continue

            # get season and ep data (ignoring multi-eps for now)
            curSeason = int(curResult["season"])
            if curSeason == -1:
                continue
            curEp = curResult["episodes"].split("|")[1]
            if not curEp:
                continue
            curEp = int(curEp)
            curQuality = int(curResult["quality"])

            # if the show says we want that episode then add it to the list
            if not showObj.wantEpisode(curSeason, curEp, curQuality,
                                       manualSearch):
                logger.log(
                    u"Skipping " + curResult["name"] +
                    " because we don't want an episode that's " +
                    Quality.qualityStrings[curQuality], logger.DEBUG)

            elif not show_name_helpers.filterBadReleases(
                    curResult["name"], myShow):
                #logger.log(u"Skipping it because of bad release name", logger.ERROR)
                continue
            else:

                if episode:
                    epObj = episode
                else:
                    epObj = showObj.getEpisode(curSeason, curEp)

                # build a result object
                title = curResult["name"]
                url = curResult["url"]

                logger.log(u"Found result " + title + " at " + url)

                result = self.provider.getResult([epObj])
                result.url = url
                result.name = title
                result.quality = curQuality

                # add it to the list
                if epObj not in neededEps:
                    neededEps[epObj] = [result]
                else:
                    neededEps[epObj].append(result)

        return neededEps
Пример #28
0
            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)

            # only get anime proper if it has release group and version
            if parse_result.is_anime:
                if not curProper.release_group and curProper.version == -1:
                    logger.log(
                        u"Proper " + curProper.name +
                        " doesn't have a release group and version, ignoring it",
                        logger.DEBUG)
                    continue

            if not show_name_helpers.filterBadReleases(curProper.name,
                                                       parse=False):
                logger.log(
                    u"Proper " + curProper.name +
                    " isn't a valid scene release that we want, ignoring it",
                    logger.DEBUG)
                continue

            if parse_result.show.rls_ignore_words and search.filter_release_name(
                    curProper.name, parse_result.show.rls_ignore_words):
                logger.log(
                    u"Ignoring " + curProper.name +
                    " based on ignored words filter: " +
                    parse_result.show.rls_ignore_words, logger.MESSAGE)
                continue

            if parse_result.show.rls_require_words and not search.filter_release_name(
Пример #29
0
    def findNeededEpisodes(self, episode, manualSearch=False, downCurQuality=False):
        neededEps = {}
        cl = []

        myDB = self._getDB()
        if not episode:
            sqlResults = myDB.select("SELECT * FROM [" + self.providerID + "]")
        elif type(episode) != list:
            sqlResults = myDB.select(
                "SELECT * FROM [" + self.providerID + "] WHERE indexerid = ? AND season = ? AND episodes LIKE ?",
                [episode.show.indexerid, episode.season, "%|" + str(episode.episode) + "|%"])
        else:
            for epObj in episode:
                cl.append([
                    "SELECT * FROM [" + self.providerID + "] WHERE indexerid = ? AND season = ? AND episodes LIKE ? AND quality IN (" + ",".join(
                        [str(x) for x in epObj.wantedQuality]) + ")",
                    [epObj.show.indexerid, epObj.season, "%|" + str(epObj.episode) + "|%"]])

            sqlResults = myDB.mass_action(cl, fetchall=True)
            sqlResults = list(itertools.chain(*sqlResults))

        # for each cache entry
        for curResult in sqlResults:
            # ignored/required words, and non-tv junk
            if not show_name_helpers.filterBadReleases(curResult["name"]):
                continue

            # get the show object, or if it's not one of our shows then ignore it
            showObj = Show.find(sickbeard.showList, int(curResult["indexerid"]))
            if not showObj:
                continue

            # skip if provider is anime only and show is not anime
            if self.provider.anime_only and not showObj.is_anime:
                logger.log(u"" + str(showObj.name) + " is not an anime, skiping", logger.DEBUG)
                continue

            # get season and ep data (ignoring multi-eps for now)
            curSeason = int(curResult["season"])
            if curSeason == -1:
                continue

            curEp = curResult["episodes"].split("|")[1]
            if not curEp:
                continue

            curEp = int(curEp)

            curQuality = int(curResult["quality"])
            curReleaseGroup = curResult["release_group"]
            curVersion = curResult["version"]

            # if the show says we want that episode then add it to the list
            if not showObj.wantEpisode(curSeason, curEp, curQuality, manualSearch, downCurQuality):
                logger.log(u"Skipping " + curResult["name"], logger.DEBUG)
                continue

            epObj = showObj.getEpisode(curSeason, curEp)

            # build a result object
            title = curResult["name"]
            url = curResult["url"]

            logger.log(u"Found result " + title + " at " + url)

            result = self.provider.get_result([epObj])
            result.show = showObj
            result.url = url
            result.name = title
            result.quality = curQuality
            result.release_group = curReleaseGroup
            result.version = curVersion
            result.content = None

            # add it to the list
            if epObj not in neededEps:
                neededEps[epObj] = [result]
            else:
                neededEps[epObj].append(result)

        # datetime stamp this search so cache gets cleared
        self.setLastSearch()

        return neededEps
Пример #30
0
def searchProviders(show, episodes, manual_search=False):
    foundResults = {}
    finalResults = []

    didSearch = False

    origThreadName = threading.currentThread().name

    providers = [x for x in sickbeard.providers.sortedProviderList() if x.is_active() and x.enable_backlog]
    for providerNum, curProvider in enumerate(providers):
        if curProvider.anime_only and not show.is_anime:
            logger.log(u"" + str(show.name) + " is not an anime, skipping", logger.DEBUG)
            continue

        threading.currentThread().name = origThreadName + " :: [" + curProvider.name + "]"

        foundResults[curProvider.name] = {}

        searchCount = 0
        search_mode = curProvider.search_mode

        while(True):
            searchCount += 1

            if search_mode == 'eponly':
                logger.log(u"Performing episode search for " + show.name)
            else:
                logger.log(u"Performing season pack search for " + show.name)

            try:
                curProvider.cache._clearCache()
                searchResults = curProvider.find_search_results(show, episodes, search_mode, manual_search)
            except exceptions.AuthException as e:
                logger.log(u"Authentication error: " + ex(e), logger.ERROR)
                break
            except Exception as e:
                logger.log(u"Error while searching " + curProvider.name + ", skipping: " + ex(e), logger.ERROR)
                logger.log(traceback.format_exc(), logger.DEBUG)
                break
            finally:
                threading.currentThread().name = origThreadName

            didSearch = True

            if len(searchResults):
                # make a list of all the results for this provider
                for curEp in searchResults:
                    # skip non-tv crap
                    searchResults[curEp] = filter(
                        lambda x: show_name_helpers.filterBadReleases(x.name, parse=False) and x.show == show, searchResults[curEp])

                    if curEp in foundResults:
                        foundResults[curProvider.name][curEp] += searchResults[curEp]
                    else:
                        foundResults[curProvider.name][curEp] = searchResults[curEp]

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

            if search_mode == 'sponly':
                logger.log(u"FALLBACK EPISODE SEARCH INITIATED ...")
                search_mode = 'eponly'
            else:
                logger.log(u"FALLBACK SEASON PACK SEARCH INITIATED ...")
                search_mode = 'sponly'

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

        anyQualities, bestQualities = Quality.splitQuality(show.quality)

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

        highest_quality_overall = 0
        for cur_episode in foundResults[curProvider.name]:
            for cur_result in foundResults[curProvider.name][cur_episode]:
                if cur_result.quality != Quality.UNKNOWN and cur_result.quality > highest_quality_overall:
                    highest_quality_overall = cur_result.quality
        logger.log(u"The highest quality of any match is " + Quality.qualityStrings[highest_quality_overall],
                   logger.DEBUG)

        # see if every episode is wanted
        if bestSeasonResult:
            searchedSeasons = []
            searchedSeasons = [str(x.season) for x in episodes]
            # get the quality of the season nzb
            seasonQual = bestSeasonResult.quality
            logger.log(
                u"The quality of the season " + bestSeasonResult.provider.providerType + " is " + Quality.qualityStrings[
                    seasonQual], logger.DEBUG)

            myDB = db.DBConnection()
            allEps = [int(x["episode"]) 
                      for x in myDB.select("SELECT episode FROM tv_episodes WHERE showid = ? AND ( season IN ( " + ','.join(searchedSeasons) + " ) )", 
                                           [show.indexerid])]
            
            logger.log(u"Executed query: [SELECT episode FROM tv_episodes WHERE showid = %s AND season in  %s]" % (show.indexerid, ','.join(searchedSeasons)))
            logger.log(u"Episode list: " + str(allEps), logger.DEBUG)

            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):
                        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:
                logger.log(
                    u"Every episode in this season is needed, downloading the whole " + bestSeasonResult.provider.providerType + " " + bestSeasonResult.name)
                epObjs = []
                for curEpNum in allEps:
                    epObjs.append(show.getEpisode(season, curEpNum))
                bestSeasonResult.episodes = epObjs

                return [bestSeasonResult]

            elif not anyWanted:
                logger.log(
                    u"No episodes from this season are wanted at this quality, ignoring the result of " + bestSeasonResult.name,
                    logger.DEBUG)

            else:

                if bestSeasonResult.provider.providerType == GenericProvider.NZB:
                    logger.log(u"Breaking apart the NZB and adding the individual ones to our results", logger.DEBUG)

                    # if not, break it apart and add them as the lowest priority results
                    individualResults = nzbSplitter.splitResult(bestSeasonResult)

                    individualResults = filter(
                        lambda x: show_name_helpers.filterBadReleases(x.name, parse=False) and x.show == show, individualResults)

                    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[curProvider.name]:
                            foundResults[curProvider.name][epNum].append(curResult)
                        else:
                            foundResults[curProvider.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.
                    logger.log(
                        u"Adding multi episode 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:
                        epObjs.append(show.getEpisode(season, curEpNum))
                    bestSeasonResult.episodes = epObjs

                    epNum = MULTI_EP_RESULT
                    if epNum in foundResults[curProvider.name]:
                        foundResults[curProvider.name][epNum].append(bestSeasonResult)
                    else:
                        foundResults[curProvider.name][epNum] = [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[curProvider.name]:
            for multiResult in foundResults[curProvider.name][MULTI_EP_RESULT]:

                logger.log(u"Seeing if we want to bother with multi episode result " + multiResult.name, logger.DEBUG)

                if sickbeard.USE_FAILED_DOWNLOADS and failed_history.hasFailed(multiResult.name, multiResult.size,
                                                                               multiResult.provider.name):
                    logger.log(multiResult.name + u" has previously failed, rejecting this multi episode result")
                    continue

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

                logger.log(
                    u"Single episode check result is needed episodes: " + str(neededEps) + ", not needed episodes: " + str(notNeededEps),
                    logger.DEBUG)

                if not notNeededEps:
                    logger.log(u"All of these episodes were covered by single episode results, ignoring this multi episode result", logger.DEBUG)
                    continue

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

                logger.log(
                    u"Multi episode check result is multi needed episodes: " + str(multiNeededEps) + ", multi not needed episodes: " + str(
                        multiNotNeededEps), logger.DEBUG)

                if not multiNeededEps:
                    logger.log(
                        u"All of these episodes were covered by another multi episode nzb, ignoring this multi episode result",
                        logger.DEBUG)
                    continue

                # if we're keeping this multi-result then remember it
                for epObj in multiResult.episodes:
                    multiResults[epObj.episode] = multiResult

                # don't bother with the single result if we're going to get it with a multi result
                for epObj in multiResult.episodes:
                    epNum = epObj.episode
                    if epNum in foundResults[curProvider.name]:
                        logger.log(
                            u"A needed multi episode result overlaps with a single episode result for episode #" + str(
                                epNum) + ", removing the single episode results from the list", logger.DEBUG)
                        del foundResults[curProvider.name][epNum]

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

            if len(foundResults[curProvider.name][curEp]) == 0:
                continue

            bestResult = pickBestResult(foundResults[curProvider.name][curEp], show)

            # if all results were rejected move on to the next episode
            if not bestResult:
                continue

            # filter out possible bad torrents from providers
            if bestResult.resultType == "torrent" and sickbeard.TORRENT_METHOD != "blackhole":
                bestResult.content = None
                if not bestResult.url.startswith('magnet'):
                    bestResult.content = bestResult.provider.get_url(bestResult.url)
                    if not bestResult.content:
                        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:
        logger.log(u"No NZB/Torrent providers found or enabled in the SickGear config for backlog searches. Please check your settings.",
                   logger.ERROR)

    return finalResults
Пример #31
0
 def _test_filterBadReleases(self, name, expected):
     result = show_name_helpers.filterBadReleases(name)
     self.assertEqual(result, expected)
Пример #32
0
                break
            except Exception, e:
                logger.log(u"Error while searching " + curProvider.name + ", skipping: " + ex(e), logger.ERROR)
                logger.log(traceback.format_exc(), logger.DEBUG)
                break
            finally:
                threading.currentThread().name = origThreadName

            didSearch = True

            if len(searchResults):
                # make a list of all the results for this provider
                for curEp in searchResults:
                    # skip non-tv crap
                    searchResults[curEp] = filter(
                        lambda x: show_name_helpers.filterBadReleases(x.name, parse=False) and x.show == show, searchResults[curEp])

                    if curEp in foundResults:
                        foundResults[curProvider.name][curEp] += searchResults[curEp]
                    else:
                        foundResults[curProvider.name][curEp] = searchResults[curEp]

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

            if search_mode == 'sponly':
                logger.log(u"FALLBACK EPISODE SEARCH INITIATED ...")
                search_mode = 'eponly'
            else:
                logger.log(u"FALLBACK SEASON PACK SEARCH INITIATED ...")
                episode, manualSearch=manualSearch)
        except exceptions.AuthException, e:
            logger.log(u"Authentication error: " + ex(e), logger.ERROR)
            continue
        except Exception, e:
            logger.log(
                u"Error while searching " + curProvider.name + ", skipping: " +
                ex(e), logger.ERROR)
            logger.log(traceback.format_exc(), logger.DEBUG)
            continue

        didSearch = True

        # skip non-tv crap
        curFoundResults = filter(
            lambda x: show_name_helpers.filterBadReleases(x.name) and
            show_name_helpers.isGoodResult(x.name, episode.show),
            curFoundResults)

        # loop all results and see if any of them are good enough that we can stop searching
        done_searching = False
        for cur_result in curFoundResults:
            done_searching = isFinalResult(cur_result)
            logger.log(
                u"Should we stop searching after finding " + cur_result.name +
                ": " + str(done_searching), logger.DEBUG)
            if done_searching:
                break

        foundResults += curFoundResults
Пример #34
0
                logger.log(
                    u"Error while searching " + curProvider.name +
                    ", skipping: " + ex(e), logger.ERROR)
                logger.log(traceback.format_exc(), logger.DEBUG)
                break
            finally:
                threading.currentThread().name = origThreadName

            didSearch = True

            if len(searchResults):
                # make a list of all the results for this provider
                for curEp in searchResults:
                    # skip non-tv crap
                    searchResults[curEp] = filter(
                        lambda x: show_name_helpers.filterBadReleases(
                            x.name, parse=False) and x.show == show,
                        searchResults[curEp])

                    if curEp in foundResults:
                        foundResults[
                            curProvider.name][curEp] += searchResults[curEp]
                    else:
                        foundResults[
                            curProvider.name][curEp] = searchResults[curEp]

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

            if search_mode == 'sponly':
                logger.log(u"FALLBACK EPISODE SEARCH INITIATED ...")
Пример #35
0
    def findNeededEpisodes(self, episode, manualSearch=False):
        res = {}
        neededEps = {}
        cl = []

        myDB = self._getDB()
        if type(episode) != list:
            sqlResults = myDB.select(
                "SELECT * FROM [" + self.providerID + "] WHERE indexerid = ? AND season = ? AND episodes LIKE ?",
                [episode.show.indexerid, episode.season, "%|" + str(episode.episode) + "|%"])
            res[episode] = [sqlResults]
        else:
            for epObj in episode:
                sqlResults = myDB.select(
                    "SELECT * FROM [" + self.providerID + "] WHERE indexerid = ? AND season = ? AND episodes LIKE ? "
                    "AND quality IN (" + ",".join([str(x) for x in epObj.wantedQuality]) + ")",
                    [epObj.show.indexerid, epObj.season, "%|" + str(epObj.episode) + "|%"])
                res[epObj] = [sqlResults]


        # for each cache entry
        for ep in res:
            for curResult in sqlResults:

                # skip non-tv crap
                if not show_name_helpers.filterBadReleases(curResult["name"], parse=False):
                    continue
    
                # get the show object, or if it's not one of our shows then ignore it
                showObj = helpers.findCertainShow(sickbeard.showList, int(curResult["indexerid"]))
                if not showObj:
                    continue

                # skip if provider is anime only and show is not anime
                if self.provider.anime_only and not showObj.is_anime:
                    logger.log(u"" + str(showObj.name) + " is not an anime, skiping", logger.DEBUG)
                    continue

                # get season and ep data (ignoring multi-eps for now)
                curSeason = int(curResult["season"])
                if curSeason == -1:
                    continue

                curEp = int(ep.episode)

                curQuality = int(curResult["quality"])
                curReleaseGroup = curResult["release_group"]
                curVersion = curResult["version"]

                # if the show says we want that episode then add it to the list
                if not showObj.wantEpisode(curSeason, curEp, curQuality, manualSearch) and not showObj.lookIfDownloadable(curSeason, curEp, curQuality, manualSearch):
                    logger.log(u"Skipping " + curResult["name"] + " because we don't want an episode that's " +
                               Quality.qualityStrings[curQuality], logger.DEBUG)
                    continue

                # build a result object
                title = curResult["name"]
                url = curResult["url"]

                logger.log(u"Found result " + title + " at " + url)

                result = self.provider.getResult([ep])
                result.show = showObj
                result.url = url
                result.name = title
                result.quality = curQuality
                result.release_group = curReleaseGroup
                result.version = curVersion
                result.content = None

                # add it to the list
                if ep not in neededEps:
                    neededEps[ep] = [result]
                else:
                    neededEps[ep].append(result)

        # datetime stamp this search so cache gets cleared
        self.setLastSearch()

        return neededEps
Пример #36
0
            # populate our Proper instance
            curProper.season = parse_result.season_number if parse_result.season_number != None else 1
            curProper.episode = parse_result.episode_numbers[0]

            # only get anime proper if it has release group and version
            if parse_result.is_anime:
                if parse_result.release_group and parse_result.version:
                    curProper.release_group = parse_result.release_group
                    curProper.version = parse_result.version
                else:
                    continue

            curProper.quality = Quality.nameQuality(curProper.name,
                                                    parse_result.is_anime)

            if not show_name_helpers.filterBadReleases(curProper.name):
                logger.log(
                    u"Proper " + curProper.name +
                    " isn't a valid scene release that we want, ignoring it",
                    logger.DEBUG)
                continue

            if parse_result.show.rls_ignore_words and search.filter_release_name(
                    curProper.name, parse_result.show.rls_ignore_words):
                logger.log(
                    u"Ignoring " + curProper.name +
                    " based on ignored words filter: " +
                    parse_result.show.rls_ignore_words, logger.MESSAGE)
                continue

            if parse_result.show.rls_require_words and not search.filter_release_name(
Пример #37
0
    def findNeededEpisodes(self,
                           episode,
                           manualSearch=False,
                           downCurQuality=False):  # pylint:disable=too-many-locals, too-many-branches
        neededEps = {}
        cl = []

        cache_db_con = self._getDB()
        if not episode:
            sql_results = cache_db_con.select("SELECT * FROM [" +
                                              self.providerID + "]")
        elif not isinstance(episode, list):
            sql_results = cache_db_con.select(
                "SELECT * FROM [" + self.providerID +
                "] WHERE indexerid = ? AND season = ? AND episodes LIKE ?", [
                    episode.show.indexerid, episode.season,
                    "%|" + str(episode.episode) + "|%"
                ])
        else:
            for epObj in episode:
                cl.append([
                    "SELECT * FROM [" + self.providerID +
                    "] WHERE indexerid = ? AND season = ? AND episodes LIKE ? AND quality IN ("
                    + ",".join([str(x) for x in epObj.wantedQuality]) + ")",
                    [
                        epObj.show.indexerid, epObj.season,
                        "%|" + str(epObj.episode) + "|%"
                    ]
                ])

            sql_results = cache_db_con.mass_action(cl, fetchall=True)
            sql_results = list(itertools.chain(*sql_results))

        # for each cache entry
        for curResult in sql_results:
            # ignored/required words, and non-tv junk
            if not show_name_helpers.filterBadReleases(curResult["name"]):
                continue

            # get the show object, or if it's not one of our shows then ignore it
            showObj = Show.find(sickbeard.showList,
                                int(curResult["indexerid"]))
            if not showObj:
                continue

            # skip if provider is anime only and show is not anime
            if self.provider.anime_only and not showObj.is_anime:
                logger.log(
                    u"" + str(showObj.name) + " is not an anime, skiping",
                    logger.DEBUG)
                continue

            # get season and ep data (ignoring multi-eps for now)
            curSeason = int(curResult["season"])
            if curSeason == -1:
                continue

            curEp = curResult["episodes"].split("|")[1]
            if not curEp:
                continue

            curEp = int(curEp)

            curQuality = int(curResult["quality"])
            curReleaseGroup = curResult["release_group"]
            curVersion = curResult["version"]

            # if the show says we want that episode then add it to the list
            if not showObj.wantEpisode(curSeason, curEp, curQuality,
                                       manualSearch, downCurQuality):
                logger.log(u"Ignoring " + curResult["name"], logger.DEBUG)
                continue

            epObj = showObj.getEpisode(curSeason, curEp)

            # build a result object
            title = curResult["name"]
            url = curResult["url"]

            logger.log(u"Found result " + title + " at " + url)

            result = self.provider.get_result([epObj])
            result.show = showObj
            result.url = url
            result.name = title
            result.quality = curQuality
            result.release_group = curReleaseGroup
            result.version = curVersion
            result.content = None

            # add it to the list
            if epObj not in neededEps:
                neededEps[epObj] = [result]
            else:
                neededEps[epObj].append(result)

        # datetime stamp this search so cache gets cleared
        self.setLastSearch()

        return neededEps
Пример #38
0
    def _doSearch(self, search_params, show=None):

        results = []
        items = {'Season': [], 'Episode': []}

        for mode in search_params.keys():
            for search_string in search_params[mode]:

                searchURL = self.proxy._buildURL(self.searchurl %
                                                 (urllib.quote(search_string)))

                logger.log(u"Search string: " + searchURL, logger.DEBUG)

                data = self.getURL(searchURL)
                if not data:
                    return []

                re_title_url = self.proxy._buildRE(self.re_title_url)

                #Extracting torrent information from data returned by searchURL
                match = re.compile(re_title_url,
                                   re.DOTALL).finditer(urllib.unquote(data))
                for torrent in match:

                    title = torrent.group('title').replace(
                        '_', '.'
                    )  #Do not know why but SickBeard skip release with '_' in name
                    url = torrent.group('url')
                    id = int(torrent.group('id'))
                    seeders = int(torrent.group('seeders'))
                    leechers = int(torrent.group('leechers'))

                    #Filter unseeded torrent
                    if seeders == 0 or not title \
                    or not show_name_helpers.filterBadReleases(title):
                        continue

                    #Accept Torrent only from Good People for every Episode Search
                    if sickbeard.THEPIRATEBAY_TRUSTED and re.search(
                            '(VIP|Trusted|Helper)', torrent.group(0)) == None:
                        logger.log(
                            u"ThePirateBay Provider found result " +
                            torrent.group('title') +
                            " but that doesn't seem like a trusted result so I'm ignoring it",
                            logger.DEBUG)
                        continue

                    #Try to find the real Quality for full season torrent analyzing files in torrent
                    if mode == 'Season' and Quality.nameQuality(
                            title) == Quality.UNKNOWN:
                        if not self._find_season_quality(title, id): continue

                    item = title, url, id, seeders, leechers

                    items[mode].append(item)

            #For each search mode sort all the items by seeders
            items[mode].sort(key=lambda tup: tup[3], reverse=True)

            results += items[mode]

        return results
Пример #39
0
def _getProperList():
    propers = {}

    search_date = datetime.datetime.today() - datetime.timedelta(days=2)

    # for each provider get a list of the
    origThreadName = threading.currentThread().name
    providers = [
        x for x in sickbeard.providers.sortedProviderList() if x.is_active()
    ]
    for curProvider in providers:
        threading.currentThread(
        ).name = origThreadName + ' :: [' + curProvider.name + ']'

        logger.log(u'Searching for any new PROPER releases from ' +
                   curProvider.name)

        try:
            curPropers = curProvider.find_propers(search_date)
        except exceptions.AuthException as e:
            logger.log(u'Authentication error: ' + ex(e), logger.ERROR)
            continue
        except Exception as e:
            logger.log(
                u'Error while searching ' + curProvider.name + ', skipping: ' +
                ex(e), logger.ERROR)
            logger.log(traceback.format_exc(), logger.DEBUG)
            continue
        finally:
            threading.currentThread().name = origThreadName

        # if they haven't been added by a different provider than add the proper to the list
        for x in curPropers:
            name = _genericName(x.name)
            if not name in propers:
                logger.log(u'Found new proper: ' + x.name, logger.DEBUG)
                x.provider = curProvider
                propers[name] = x

    # take the list of unique propers and get it sorted by
    sortedPropers = sorted(propers.values(),
                           key=operator.attrgetter('date'),
                           reverse=True)
    finalPropers = []

    for curProper in sortedPropers:

        try:
            myParser = NameParser(False)
            parse_result = myParser.parse(curProper.name)
        except InvalidNameException:
            logger.log(
                u'Unable to parse the filename ' + curProper.name +
                ' into a valid episode', logger.DEBUG)
            continue
        except InvalidShowException:
            logger.log(
                u'Unable to parse the filename ' + curProper.name +
                ' into a valid show', logger.DEBUG)
            continue

        if not parse_result.series_name:
            continue

        if not parse_result.episode_numbers:
            logger.log(
                u'Ignoring ' + curProper.name +
                ' because it\'s for a full season rather than specific episode',
                logger.DEBUG)
            continue

        logger.log(
            u'Successful match! Result ' + parse_result.original_name +
            ' matched to show ' + parse_result.show.name, logger.DEBUG)

        # 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.season = parse_result.season_number if parse_result.season_number != 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)

        # only get anime proper if it has release group and version
        if parse_result.is_anime:
            if not curProper.release_group and curProper.version == -1:
                logger.log(
                    u'Proper ' + curProper.name +
                    ' doesn\'t have a release group and version, ignoring it',
                    logger.DEBUG)
                continue

        if not show_name_helpers.filterBadReleases(curProper.name,
                                                   parse=False):
            logger.log(
                u'Proper ' + curProper.name +
                ' isn\'t a valid scene release that we want, ignoring it',
                logger.DEBUG)
            continue

        if parse_result.show.rls_ignore_words and search.filter_release_name(
                curProper.name, parse_result.show.rls_ignore_words):
            logger.log(
                u'Ignoring ' + curProper.name +
                ' based on ignored words filter: ' +
                parse_result.show.rls_ignore_words, logger.MESSAGE)
            continue

        if parse_result.show.rls_require_words and not search.filter_release_name(
                curProper.name, parse_result.show.rls_require_words):
            logger.log(
                u'Ignoring ' + curProper.name +
                ' based on required words filter: ' +
                parse_result.show.rls_require_words, logger.MESSAGE)
            continue

        # check if we actually want this proper (if it's the right quality)
        myDB = db.DBConnection()
        sqlResults = myDB.select(
            'SELECT status FROM tv_episodes WHERE showid = ? AND season = ? AND episode = ?',
            [curProper.indexerid, curProper.season, curProper.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]['status']))
        if oldStatus not in (DOWNLOADED,
                             SNATCHED) or oldQuality != curProper.quality:
            continue

        # check if we actually want this proper (if it's the right release group and a higher version)
        if parse_result.is_anime:
            myDB = db.DBConnection()
            sqlResults = myDB.select(
                'SELECT release_group, version FROM tv_episodes WHERE showid = ? AND season = ? AND episode = ?',
                [curProper.indexerid, curProper.season, curProper.episode])

            oldVersion = int(sqlResults[0]['version'])
            oldRelease_group = (sqlResults[0]['release_group'])

            if oldVersion > -1 and oldVersion < curProper.version:
                logger.log('Found new anime v' + str(curProper.version) +
                           ' to replace existing v' + str(oldVersion))
            else:
                continue

            if oldRelease_group != curProper.release_group:
                logger.log('Skipping proper from release group: ' +
                           curProper.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 curProper.indexerid != -1 and (curProper.indexerid,
                                          curProper.season,
                                          curProper.episode) not in map(
                                              operator.attrgetter(
                                                  'indexerid', 'season',
                                                  'episode'), finalPropers):
            logger.log(u'Found a proper that we need: ' + str(curProper.name))
            finalPropers.append(curProper)

    return finalPropers
Пример #40
0
    def __init__(self, force=None, show=None):

        #TODOif not sickbeard.DOWNLOAD_FRENCH:
        #    return
        if sickbeard.showList==None:
            return
        logger.log(u"Beginning the search for french episodes older than "+ str(sickbeard.FRENCH_DELAY) +" days")
       
        frenchlist=[]
        #get list of english episodes that we want to search in french
        myDB = db.DBConnection()
        today = datetime.date.today().toordinal()
        if show:
            frenchsql=myDB.select("SELECT showid, season, episode from tv_episodes where audio_langs='en' and tv_episodes.showid =? and (? - tv_episodes.airdate) > ? order by showid, airdate asc",[show,today,sickbeard.FRENCH_DELAY]) 
            count=myDB.select("SELECT count(*) from tv_episodes where audio_langs='en' and tv_episodes.showid =? and (? - tv_episodes.airdate) > ?",[show,today,sickbeard.FRENCH_DELAY]) 
        else:
            frenchsql=myDB.select("SELECT showid, season, episode from tv_episodes, tv_shows where audio_langs='en' and tv_episodes.showid = tv_shows.tvdb_id and tv_shows.frenchsearch = 1 and (? - tv_episodes.airdate) > ? order by showid, airdate asc",[today,sickbeard.FRENCH_DELAY])
            count=myDB.select("SELECT count(*) from tv_episodes, tv_shows where audio_langs='en' and tv_episodes.showid = tv_shows.tvdb_id and tv_shows.frenchsearch = 1 and (? - tv_episodes.airdate) > ?",[today,sickbeard.FRENCH_DELAY])
        #make the episodes objects
        logger.log(u"Searching for "+str(count[0][0]) +" episodes in french")
        for episode in frenchsql:
            showObj = helpers.findCertainShow(sickbeard.showList, episode[0])
            epObj = showObj.getEpisode(episode[1], episode[2])
            frenchlist.append(epObj)
        
        #for each episode in frenchlist fire a search in french
        delay=[]
        rest=count[0][0]
        for frepisode in frenchlist:
            rest=rest-1    
            if frepisode.show.tvdbid in delay:
                logger.log(u"Previous episode for show "+str(frepisode.show.tvdbid)+" not found in french so skipping this search", logger.DEBUG)
                continue
            result=[]
            for curProvider in providers.sortedProviderList():

                if not curProvider.isActive():
                    continue

                logger.log(u"Searching for french episode on "+curProvider.name +" for " +frepisode.show.name +" season "+str(frepisode.season)+" episode "+str(frepisode.episode))
                try:
                    curfrench = curProvider.findFrench(frepisode, manualSearch=True)
                except:
                    logger.log(u"Exception", logger.DEBUG)
                    pass
                test=0
                if curfrench:
                    for x in curfrench:
                        if not show_name_helpers.filterBadReleases(x.name):
                            logger.log(u"French "+x.name+" isn't a valid scene release that we want, ignoring it", logger.DEBUG)
                            test+=1
                            continue
                        if sickbeard.IGNORE_WORDS == "":
                            ignore_words="ztreyfgut"
                        else:
                            ignore_words=str(sickbeard.IGNORE_WORDS)
                        for fil in resultFilters + ignore_words.split(','):
                            if fil == showLanguages.get(u"fr"):
                                continue
                            if re.search('(^|[\W_])'+fil+'($|[\W_])', x.url, re.I) or re.search('(^|[\W_])'+fil+'($|[\W_])', x.name, re.I) :
                                logger.log(u"Invalid scene release: "+x.url+" contains "+fil+", ignoring it", logger.DEBUG)
                                test+=1
                    if test==0:
                        result.append(x)
            best=None
            try:
                epi={}
                epi[1]=frepisode
                best = search.pickBestResult(result, episode = epi)
            except:
                pass
            if best:
                best.name=best.name + ' snatchedfr'
                logger.log(u"Found french episode for " +frepisode.show.name +" season "+str(frepisode.season)+" episode "+str(frepisode.episode))
                try:
                    search.snatchEpisode(best, SNATCHED_FRENCH)
                except:
                    logger.log(u"Exception", logger.DEBUG)
                    pass
            else:
                delay.append(frepisode.show.tvdbid)
                logger.log(u"No french episode found for " +frepisode.show.name +" season "+str(frepisode.season)+" episode "+str(frepisode.episode))
            logger.log(str(rest) + u" episodes left")
Пример #41
0
                break
            except Exception, e:
                logger.log(u"Error while searching " + curProvider.name + ", skipping: " + ex(e), logger.ERROR)
                logger.log(traceback.format_exc(), logger.DEBUG)
                break
            finally:
                threading.currentThread().name = origThreadName

            didSearch = True

            if len(searchResults):
                # make a list of all the results for this provider
                for curEp in searchResults:
                    # skip non-tv crap
                    searchResults[curEp] = filter(
                        lambda x: show_name_helpers.filterBadReleases(x.name, parse=False) and x.show == show, searchResults[curEp])

                    if curEp in foundResults:
                        foundResults[curProvider.name][curEp] += searchResults[curEp]
                    else:
                        foundResults[curProvider.name][curEp] = searchResults[curEp]

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

            if search_mode == 'sponly':
                logger.log(u"FALLBACK EPISODE SEARCH INITIATED ...")
                search_mode = 'eponly'
            else:
                logger.log(u"FALLBACK SEASON PACK SEARCH INITIATED ...")
Пример #42
0
def pickBestResult(results, show):  # pylint: disable=too-many-branches
    """
    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]

    logger.log(u"Picking the best result out of " + str([x.name for x in results]), logger.DEBUG)

    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

        logger.log(u"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:
            logger.log(cur_result.name + " is a quality we know we don't want, rejecting it", logger.DEBUG)
            continue

        if show.rls_ignore_words and show_name_helpers.containsAtLeastOneWord(cur_result.name, cur_result.show.rls_ignore_words):
            logger.log(u"Ignoring " + cur_result.name + " based on ignored words filter: " + show.rls_ignore_words,
                       logger.INFO)
            continue

        if show.rls_require_words and not show_name_helpers.containsAtLeastOneWord(cur_result.name, cur_result.show.rls_require_words):
            logger.log(u"Ignoring " + cur_result.name + " based on required words filter: " + show.rls_require_words,
                       logger.INFO)
            continue

        if not show_name_helpers.filterBadReleases(cur_result.name, parse=False):
            logger.log(u"Ignoring " + cur_result.name + " because its not a valid scene release that we want, ignoring it",
                       logger.INFO)
            continue

        if hasattr(cur_result, 'size'):
            if sickbeard.USE_FAILED_DOWNLOADS and failed_history.hasFailed(cur_result.name, cur_result.size,
                                                                           cur_result.provider.name):
                logger.log(cur_result.name + u" 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 "real" in cur_result.name.lower() or "repack" in cur_result.name.lower():
                logger.log(u"Preferring " + cur_result.name + " (repack/proper/real over nuked)")
                bestResult = cur_result
            elif "internal" in bestResult.name.lower() and "internal" not in cur_result.name.lower():
                logger.log(u"Preferring " + cur_result.name + " (normal instead of internal)")
                bestResult = cur_result
            elif "xvid" in bestResult.name.lower() and "x264" in cur_result.name.lower():
                logger.log(u"Preferring " + cur_result.name + " (x264 over xvid)")
                bestResult = cur_result

    if bestResult:
        logger.log(u"Picked " + bestResult.name + " as the best", logger.DEBUG)
    else:
        logger.log(u"No result picked.", logger.DEBUG)

    return bestResult
Пример #43
0
def pickBestResult(results, show=None, quality_list=None):
    results = results if isinstance(results, list) else [results]

    logger.log(u"Picking the best result out of " + str([x.name for x in results]), logger.DEBUG)

    bwl = None
    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 not bwl and cur_result.show.is_anime:
            bwl = BlackAndWhiteList(cur_result.show.indexerid)
            if not bwl.is_valid(cur_result):
                logger.log(cur_result.name+" does not match the blacklist or the whitelist, rejecting it. Result: " + bwl.get_last_result_msg(), logger.INFO)
                continue

        logger.log("Quality of " + cur_result.name + " is " + Quality.qualityStrings[cur_result.quality])

        if quality_list and cur_result.quality not in quality_list:
            logger.log(cur_result.name + " is a quality we know we don't want, rejecting it", logger.DEBUG)
            continue

        if show.rls_ignore_words and filter_release_name(cur_result.name, cur_result.show.rls_ignore_words):
            logger.log(u"Ignoring " + cur_result.name + " based on ignored words filter: " + show.rls_ignore_words,
                       logger.INFO)
            continue

        if show.rls_require_words and not filter_release_name(cur_result.name, cur_result.show.rls_require_words):
            logger.log(u"Ignoring " + cur_result.name + " based on required words filter: " + show.rls_require_words,
                       logger.INFO)
            continue

        if not show_name_helpers.filterBadReleases(cur_result.name, parse=False):
            logger.log(u"Ignoring " + cur_result.name + " because its not a valid scene release that we want, ignoring it",
                       logger.INFO)
            continue

        if sickbeard.USE_FAILED_DOWNLOADS and failed_history.hasFailed(cur_result.name, cur_result.size,
                                                                       cur_result.provider.name):
            logger.log(cur_result.name + u" has previously failed, rejecting it")
            continue

        if not bestResult or bestResult.quality < cur_result.quality and cur_result.quality != Quality.UNKNOWN:
            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():
                logger.log(u"Preferring " + cur_result.name + " (x264 over xvid)")
                bestResult = cur_result

    if bestResult:
        logger.log(u"Picked " + bestResult.name + " as the best", logger.DEBUG)
    else:
        logger.log(u"No result picked.", logger.DEBUG)

    return bestResult
Пример #44
0
            # 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)

            # only get anime proper if it has release group and version
            if parse_result.is_anime:
                if not curProper.release_group and curProper.version == -1:
                    logger.log(u"Proper " + curProper.name + " doesn't have a release group and version, ignoring it",
                               logger.DEBUG)
                    continue

            if not show_name_helpers.filterBadReleases(curProper.name, parse=False):
                logger.log(u"Proper " + curProper.name + " isn't a valid scene release that we want, ignoring it",
                           logger.DEBUG)
                continue

            if parse_result.show.rls_ignore_words and search.filter_release_name(curProper.name,
                                                                                 parse_result.show.rls_ignore_words):
                logger.log(
                    u"Ignoring " + curProper.name + " based on ignored words filter: " + parse_result.show.rls_ignore_words,
                    logger.INFO)
                continue

            if parse_result.show.rls_require_words and not search.filter_release_name(curProper.name,
                                                                                      parse_result.show.rls_require_words):
                logger.log(
                    u"Ignoring " + curProper.name + " based on required words filter: " + parse_result.show.rls_require_words,
Пример #45
0
    def __init__(self, force=None, show=None):

        #TODOif not sickbeard.DOWNLOAD_FRENCH:
        #    return
        if sickbeard.showList==None:
            return
        logger.log(u"Beginning the search for french episodes older than "+ str(sickbeard.FRENCH_DELAY) +" days")
       
        frenchlist=[]
        #get list of english episodes that we want to search in french
        myDB = db.DBConnection()
        today = datetime.date.today().toordinal()
        if show:
            frenchsql=myDB.select("SELECT showid, season, episode from tv_episodes where audio_langs='en' and tv_episodes.showid =? and (? - tv_episodes.airdate) > ? order by showid, airdate asc",[show,today,sickbeard.FRENCH_DELAY]) 
            count=myDB.select("SELECT count(*) from tv_episodes where audio_langs='en' and tv_episodes.showid =? and (? - tv_episodes.airdate) > ?",[show,today,sickbeard.FRENCH_DELAY]) 
        else:
            frenchsql=myDB.select("SELECT showid, season, episode from tv_episodes, tv_shows where audio_langs='en' and tv_episodes.showid = tv_shows.tvdb_id and tv_shows.frenchsearch = 1 and (? - tv_episodes.airdate) > ? order by showid, airdate asc",[today,sickbeard.FRENCH_DELAY])
            count=myDB.select("SELECT count(*) from tv_episodes, tv_shows where audio_langs='en' and tv_episodes.showid = tv_shows.tvdb_id and tv_shows.frenchsearch = 1 and (? - tv_episodes.airdate) > ?",[today,sickbeard.FRENCH_DELAY])
        #make the episodes objects
        logger.log(u"Searching for "+str(count[0][0]) +" episodes in french")
        for episode in frenchsql:
            showObj = helpers.findCertainShow(sickbeard.showList, episode[0])
            epObj = showObj.getEpisode(episode[1], episode[2])
            frenchlist.append(epObj)
        
        #for each episode in frenchlist fire a search in french
        delay=[]
        for frepisode in frenchlist:
            if frepisode.show.tvdbid in delay:
                logger.log(u"Previous episode for show "+str(frepisode.show.tvdbid)+" not found in french so skipping this search", logger.DEBUG)
                continue
            result=[]
            for curProvider in providers.sortedProviderList():

                if not curProvider.isActive():
                    continue

                logger.log(u"Searching for french episodes on "+curProvider.name +" for " +frepisode.show.name +" season "+str(frepisode.season)+" episode "+str(frepisode.episode))
                try:
                    curfrench = curProvider.findFrench(frepisode, manualSearch=True)
                except:
                    logger.log(u"Exception", logger.DEBUG)
                    pass
                test=0
                if curfrench:
                    for x in curfrench:
                        if not show_name_helpers.filterBadReleases(x.name):
                            logger.log(u"French "+x.name+" isn't a valid scene release that we want, ignoring it", logger.DEBUG)
                            test+=1
                            continue
                        if sickbeard.IGNORE_WORDS == "":
                            ignore_words="ztreyfgut"
                        else:
                            ignore_words=str(sickbeard.IGNORE_WORDS)
                        for fil in resultFilters + ignore_words.split(','):
                            if fil == showLanguages.get(u"fr"):
                                continue
                            if re.search('(^|[\W_])'+fil+'($|[\W_])', x.url, re.I):
                                logger.log(u"Invalid scene release: "+x.url+" contains "+fil+", ignoring it", logger.DEBUG)
                                test+=1
                    if test==0:
                        result.append(x)
            best=None
            try:
                epi={}
                epi[1]=frepisode
                best = search.pickBestResult(result, episode = epi)
            except:
                pass
            if best:
                best.name=best.name + ' snatchedfr'
                logger.log(u"Found french episode for " +frepisode.show.name +" season "+str(frepisode.season)+" episode "+str(frepisode.episode))
                try:
                    search.snatchEpisode(best, SNATCHED_FRENCH)
                except:
                    logger.log(u"Exception", logger.DEBUG)
                    pass
            else:
                delay.append(frepisode.show.tvdbid)
                logger.log(u"No french episodes found for " +frepisode.show.name +" season "+str(frepisode.season)+" episode "+str(frepisode.episode))
Пример #46
0
        elif not anyWanted:
            logger.log(
                u"No eps from this season are wanted at this quality, ignoring the result of " + bestSeasonNZB.name,
                logger.DEBUG)

        else:

            if bestSeasonNZB.provider.providerType == GenericProvider.NZB:
                logger.log(u"Breaking apart the NZB and adding the individual ones to our results", logger.DEBUG)

                # if not, break it apart and add them as the lowest priority results
                individualResults = nzbSplitter.splitResult(bestSeasonNZB)

                individualResults = filter(
                    lambda x: show_name_helpers.filterBadReleases(x.name) and show_name_helpers.isGoodResult(x.name,
                                                                                                             show),
                    individualResults)

                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:
                        foundResults[epNum].append(curResult)
                    else:
                        foundResults[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
Пример #47
0
def searchProviders(show, season, episodes, manualSearch=False):
    foundResults = {}
    finalResults = []

    # check if we want to search for season packs instead of just season/episode
    seasonSearch = False
    if not manualSearch:
        seasonEps = show.getAllEpisodes(season)
        if len(seasonEps) == len(episodes):
            seasonSearch = True

    providers = [x for x in sickbeard.providers.sortedProviderList() if x.isActive()]

    if not len(providers):
        logger.log(
            u"No NZB/Torrent providers found or enabled in the sickrage config. Please check your settings.",
            logger.ERROR,
        )
        return

    origThreadName = threading.currentThread().name
    for providerNum, provider in enumerate(providers):
        if provider.anime_only and not show.is_anime:
            logger.log(u"" + str(show.name) + " is not an anime skiping ...")
            continue

        threading.currentThread().name = origThreadName + " :: [" + provider.name + "]"
        foundResults.setdefault(provider.name, {})
        searchCount = 0

        search_mode = "eponly"
        if seasonSearch and provider.search_mode == "sponly":
            search_mode = provider.search_mode

        while True:
            searchCount += 1

            if search_mode == "sponly":
                logger.log(u"Searching for " + show.name + " Season " + str(season) + " pack")
            else:
                logger.log(u"Searching for episodes we need from " + show.name + " Season " + str(season))

            try:
                searchResults = provider.findSearchResults(show, season, episodes, search_mode, manualSearch)
            except exceptions.AuthException, e:
                logger.log(u"Authentication error: " + ex(e), logger.ERROR)
                break
            except Exception, e:
                logger.log(u"Error while searching " + provider.name + ", skipping: " + ex(e), logger.ERROR)
                break

            if len(searchResults):
                # make a list of all the results for this provider
                for curEp in searchResults:
                    # skip non-tv crap
                    searchResults[curEp] = filter(
                        lambda x: show_name_helpers.filterBadReleases(x.name)
                        and show_name_helpers.isGoodResult(x.name, show, season=season),
                        searchResults[curEp],
                    )

                    if curEp in foundResults:
                        foundResults[provider.name][curEp] += searchResults[curEp]
                    else:
                        foundResults[provider.name][curEp] = searchResults[curEp]

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

            if search_mode == "sponly":
                logger.log(u"FALLBACK EPISODE SEARCH INITIATED ...")
                search_mode = "eponly"
            else:
                logger.log(u"FALLBACK SEASON PACK SEARCH INITIATED ...")
                search_mode = "sponly"
    def findNeededEpisodes(self, episode=None, manualSearch=False):
        neededEps = {}

        myDB = self._getDB()

        if not episode:
            sqlResults = myDB.select("SELECT * FROM [" + self.providerID + "]")
        else:
            sqlResults = myDB.select(
                "SELECT * FROM [" + self.providerID + "] WHERE indexerid = ? AND season = ? AND episodes LIKE ?",
                [episode.show.indexerid, episode.season, "%|" + str(episode.episode) + "|%"])

        # for each cache entry
        for curResult in sqlResults:
            # skip if we don't have a indexerid
            indexerid = int(curResult["indexerid"])
            if not indexerid:
                continue

            # skip non-tv crap (but allow them for Newzbin cause we assume it's filtered well)
            if self.providerID != 'newzbin' and not show_name_helpers.filterBadReleases(curResult["name"]):
                continue

            # get the show object, or if it's not one of our shows then ignore it
            try:
                showObj = helpers.findCertainShow(sickbeard.showList, int(curResult["indexerid"]))
            except (MultipleShowObjectsException):
                showObj = None

            if not showObj:
                continue

            # get season and ep data (ignoring multi-eps for now)
            curSeason = int(curResult["season"])
            if curSeason == -1:
                continue
            curEp = curResult["episodes"].split("|")[1]
            if not curEp:
                continue
            curEp = int(curEp)
            curQuality = int(curResult["quality"])

            # if the show says we want that episode then add it to the list
            if not showObj.wantEpisode(curSeason, curEp, curQuality, manualSearch):
                logger.log(u"Skipping " + curResult["name"] + " because we don't want an episode that's " +
                           Quality.qualityStrings[curQuality], logger.DEBUG)
            else:
                epObj = None
                if episode:
                    epObj = episode

                if epObj:
                    # build a result object
                    title = curResult["name"]
                    url = curResult["url"]

                    logger.log(u"Found result " + title + " at " + url)

                    result = self.provider.getResult([epObj])
                    result.url = url
                    result.name = title
                    result.quality = curQuality
                    result.content = self.provider.getURL(url) \
                        if self.provider.providerType == sickbeard.providers.generic.GenericProvider.TORRENT \
                        and not url.startswith('magnet') else None

                    # add it to the list
                    if epObj not in neededEps:
                        neededEps[epObj] = [result]
                    else:
                        neededEps[epObj].append(result)

        return neededEps
Пример #49
0
    def findNeededEpisodes(self, episode = None, manualSearch=False):
        neededEps = {}

        if episode:
            neededEps[episode] = []

        myDB = self._getDB()

        if not episode:
            sqlResults = myDB.select("SELECT * FROM "+self.providerID)
        else:
            sqlResults = myDB.select("SELECT * FROM "+self.providerID+" WHERE tvdbid = ? AND season = ? AND episodes LIKE ?", [episode.show.tvdbid, episode.season, "|"+str(episode.episode)+"|"])

        # for each cache entry
        for curResult in sqlResults:

            # skip non-tv crap (but allow them for Newzbin cause we assume it's filtered well)
            if self.providerID != 'newzbin' and not show_name_helpers.filterBadReleases(curResult["name"]):
                continue

            # get the show object, or if it's not one of our shows then ignore it
            showObj = helpers.findCertainShow(sickbeard.showList, int(curResult["tvdbid"]))
            if not showObj:
                continue

            # get season and ep data (ignoring multi-eps for now)
            curSeason = int(curResult["season"])
            if curSeason == -1:
                continue
            curEp = curResult["episodes"].split("|")[1]
            if not curEp:
                continue
            curEp = int(curEp)
            curQuality = int(curResult["quality"])

            # if the show says we want that episode then add it to the list
            if not showObj.wantEpisode(curSeason, curEp, curQuality, manualSearch):
                logger.log(u"Skipping "+curResult["name"]+" because we don't want an episode that's "+Quality.qualityStrings[curQuality], logger.DEBUG)

            else:

                if episode:
                    epObj = episode
                else:
                    epObj = showObj.getEpisode(curSeason, curEp)

                # build a result object
                title = curResult["name"]
                url = curResult["url"]

                logger.log(u"Found result " + title + " at " + url)

                result = self.provider.getResult([epObj])
                result.url = url
                result.name = title
                result.quality = curQuality

                # add it to the list
                if epObj not in neededEps:
                    neededEps[epObj] = [result]
                else:
                    neededEps[epObj].append(result)

        return neededEps
Пример #50
0
def findEpisode(episode, manualSearch=False):

    logger.log(u"Searching for " + episode.prettyName())

    foundResults = []

    didSearch = False

    for curProvider in providers.sortedProviderList():

        if not curProvider.isActive():
            continue

        # we check our results after every search string
        # this is done because in the future we will have a ordered list of all show aliases and release_group aliases
        # ordered by success rate ...

        # lets get all search strings
        # we use the method from the curProvider to accommodate for the internal join functions
        # this way we do not break the special abilities of the providers e.g. nzbmatrix
        searchStrings = curProvider.get_episode_search_strings(episode)
        logger.log("All search string permutations (" + curProvider.name +
                   "):" + str(searchStrings))
        """
        try:
            searchStrings = list(set(searchStrings))
        except TypeError:
            pass
        """
        done_searching = False
        for searchString in searchStrings:
            try:
                curFoundResults = curProvider.findEpisode(
                    episode,
                    manualSearch=manualSearch,
                    searchString=searchString)
            except exceptions.AuthException, e:
                logger.log(u"Authentication error: " + ex(e), logger.ERROR)
                break  # break the while loop
            except Exception, e:
                logger.log(
                    u"Error while searching " + curProvider.name +
                    ", skipping: " + ex(e), logger.ERROR)
                logger.log(traceback.format_exc(), logger.DEBUG)
                break  # break the while loop

            didSearch = True

            # skip non-tv crap
            curFoundResults = filter(
                lambda x: show_name_helpers.filterBadReleases(
                    x.name) and show_name_helpers.isGoodResult(
                        x.name, episode.show, season=episode.season),
                curFoundResults)

            # loop all results and see if any of them are good enough that we can stop searching
            for cur_result in curFoundResults:
                done_searching = isFinalResult(cur_result)
                logger.log(
                    u"Should we stop searching after finding " +
                    cur_result.name + ": " + str(done_searching), logger.DEBUG)
                if done_searching:
                    break

            # if we are searching an anime we are a little more loose
            # this means we check every turn for a possible result
            # in contrast the isFinalResultlooks function looks for a perfect result (best quality)
            # but this will accept any result that would have been picked in the end -> pickBestResult
            # and then stop and use that
            if episode.show.is_anime:
                logger.log(
                    u"We are searching an anime. i am checking if we got a good result with search provider "
                    + curProvider.name, logger.DEBUG)
                bestResult = pickBestResult(curFoundResults, show=episode.show)
                if bestResult:
                    return bestResult

            foundResults += curFoundResults
            # if we did find a result that's good enough to stop then don't continue
            # this breaks the turn loop
            if done_searching:
                break
Пример #51
0
def searchProviders(show, season, episode=None, manualSearch=False):
    logger.log(u"Searching for stuff we need from " + show.name + " season " +
               str(season))
    curResults = {}
    foundResults = {}

    didSearch = False
    seasonSearch = False

    # gather all episodes for season and then pick out the wanted episodes and compare to determin if we want whole season or just a few episodes
    if episode is None:
        seasonEps = show.getAllEpisodes(season)
        wantedEps = [
            x for x in seasonEps
            if show.getOverview(x.status) in (Overview.WANTED, Overview.QUAL)
        ]
        if len(seasonEps) == len(wantedEps):
            seasonSearch = True
    else:
        ep_obj = show.getEpisode(season, episode)
        wantedEps = [ep_obj]

    for curProvider in providers.sortedProviderList():
        if not curProvider.isActive():
            continue

        # update cache
        if manualSearch:
            curProvider.cache.updateCache()

        # search cache first for wanted episodes
        for ep_obj in wantedEps:
            curResults.update(
                curProvider.cache.searchCache(ep_obj, manualSearch))

        # did we find our results ?
        if curResults:
            logger.log(u"Cache results: " + str(curResults), logger.DEBUG)
            didSearch = True
            break

    if not curResults:
        for curProvider in providers.sortedProviderList():
            if not curProvider.isActive():
                continue

            try:
                if not curResults:
                    curResults = curProvider.getSearchResults(
                        show, season, wantedEps, seasonSearch, manualSearch)

                # make a list of all the results for this provider
                for curEp in curResults:

                    # skip non-tv crap
                    curResults[curEp] = filter(
                        lambda x: show_name_helpers.filterBadReleases(x.name)
                        and show_name_helpers.isGoodResult(x.name, show),
                        curResults[curEp])

                    if curEp in foundResults:
                        foundResults[curEp] += curResults[curEp]
                    else:
                        foundResults[curEp] = curResults[curEp]

            except exceptions.AuthException, e:
                logger.log(u"Authentication error: " + ex(e), logger.ERROR)
                continue
            except Exception, e:
                logger.log(
                    u"Error while searching " + curProvider.name +
                    ", skipping: " + ex(e), logger.ERROR)
                logger.log(traceback.format_exc(), logger.DEBUG)
                continue

            didSearch = True
Пример #52
0
def pickBestResult(results, show):
    results = results if isinstance(results, list) else [results]

    logger.log(
        u"Picking the best result out of " + str([x.name for x in results]),
        logger.DEBUG)

    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

        logger.log("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:
            logger.log(
                cur_result.name +
                " is a quality we know we don't want, rejecting it",
                logger.DEBUG)
            continue

        if show.rls_ignore_words and show_name_helpers.containsAtLeastOneWord(
                cur_result.name, cur_result.show.rls_ignore_words):
            logger.log(
                u"Ignoring " + cur_result.name +
                " based on ignored words filter: " + show.rls_ignore_words,
                logger.INFO)
            continue

        if show.rls_require_words and not show_name_helpers.containsAtLeastOneWord(
                cur_result.name, cur_result.show.rls_require_words):
            logger.log(
                u"Ignoring " + cur_result.name +
                " based on required words filter: " + show.rls_require_words,
                logger.INFO)
            continue

        if not show_name_helpers.filterBadReleases(cur_result.name,
                                                   parse=False):
            logger.log(
                u"Ignoring " + cur_result.name +
                " because its not a valid scene release that we want, ignoring it",
                logger.INFO)
            continue

        if hasattr(cur_result, 'size'):
            if sickbeard.USE_FAILED_DOWNLOADS and failed_history.hasFailed(
                    cur_result.name, cur_result.size,
                    cur_result.provider.name):
                logger.log(cur_result.name +
                           u" has previously failed, rejecting it")
                continue

        # Only request HEAD instead of downloading content here, and only after all other checks but before bestresult!
        # Otherwise we are spamming providers even when searching with cache only. We can validate now, and download later
        if len(cur_result.url) and cur_result.provider:
            cur_result.url = cur_result.provider.headURL(cur_result)
            if not len(cur_result.url):
                continue

        if cur_result.quality in bestQualities and (
                not bestResult or bestResult.quality < cur_result.quality
                or bestResult not in bestQualities):
            bestResult = cur_result
        elif cur_result.quality in anyQualities and (
                not bestResult or bestResult not in bestQualities) and (
                    not bestResult or bestResult.quality < cur_result.quality):
            bestResult = cur_result
        elif bestResult and 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():
                logger.log(u"Preferring " + cur_result.name +
                           " (x264 over xvid)")
                bestResult = cur_result

    if bestResult:
        logger.log(u"Picked " + bestResult.name + " as the best", logger.DEBUG)
    else:
        logger.log(u"No result picked.", logger.DEBUG)

    return bestResult
Пример #53
0
    def findNeededEpisodes(self, episode, manualSearch=False):
        neededEps = {}
        cl = []

        myDB = self._getDB()
        if type(episode) != list:
            sqlResults = myDB.select(
                'SELECT * FROM provider_cache WHERE provider = ? AND indexerid = ? AND season = ? AND episodes LIKE ?',
                [self.providerID, episode.show.indexerid, episode.season, '%|' + str(episode.episode) + '|%'])
        else:
            for epObj in episode:
                cl.append([
                    'SELECT * FROM provider_cache WHERE provider = ? AND indexerid = ? AND season = ? AND episodes LIKE ? '
                    'AND quality IN (' + ','.join([str(x) for x in epObj.wantedQuality]) + ')',
                    [self.providerID, epObj.show.indexerid, epObj.season, '%|' + str(epObj.episode) + '|%']])
            sqlResults = myDB.mass_action(cl)
            if sqlResults:
                sqlResults = list(itertools.chain(*sqlResults))

        if not sqlResults:
            self.setLastSearch()
            return neededEps

        # for each cache entry
        for curResult in sqlResults:

            # skip non-tv crap
            if not show_name_helpers.filterBadReleases(curResult['name'], parse=False):
                continue

            # get the show object, or if it's not one of our shows then ignore it
            showObj = helpers.findCertainShow(sickbeard.showList, int(curResult['indexerid']))
            if not showObj:
                continue

            # skip if provider is anime only and show is not anime
            if self.provider.anime_only and not showObj.is_anime:
                logger.log(u'' + str(showObj.name) + ' is not an anime, skiping', logger.DEBUG)
                continue

            # get season and ep data (ignoring multi-eps for now)
            curSeason = int(curResult['season'])
            if curSeason == -1:
                continue
            curEp = curResult['episodes'].split('|')[1]
            if not curEp:
                continue
            curEp = int(curEp)

            curQuality = int(curResult['quality'])
            curReleaseGroup = curResult['release_group']
            curVersion = curResult['version']

            # if the show says we want that episode then add it to the list
            if not showObj.wantEpisode(curSeason, curEp, curQuality, manualSearch):
                logger.log(u'Skipping ' + curResult['name'] + ' because we don\'t want an episode that\'s ' +
                           Quality.qualityStrings[curQuality], logger.DEBUG)
                continue

            epObj = showObj.getEpisode(curSeason, curEp)

            # build a result object
            title = curResult['name']
            url = curResult['url']

            logger.log(u'Found result ' + title + ' at ' + url)

            result = self.provider.getResult([epObj])
            result.show = showObj
            result.url = url
            result.name = title
            result.quality = curQuality
            result.release_group = curReleaseGroup
            result.version = curVersion
            result.content = None

            # add it to the list
            if epObj not in neededEps:
                neededEps[epObj] = [result]
            else:
                neededEps[epObj].append(result)

        # datetime stamp this search so cache gets cleared
        self.setLastSearch()

        return neededEps
Пример #54
0
            continue

        try:
            curFoundResults = curProvider.findEpisode(episode, manualSearch=manualSearch)
        except exceptions.AuthException, e:
            logger.log(u"Authentication error: "+ex(e), logger.ERROR)
            continue
        except Exception, e:
            logger.log(u"Error while searching "+curProvider.name+", skipping: "+ex(e), logger.ERROR)
            logger.log(traceback.format_exc(), logger.DEBUG)
            continue

        didSearch = True

        # skip non-tv crap
        curFoundResults = filter(lambda x: show_name_helpers.filterBadReleases(x.name) and show_name_helpers.isGoodResult(x.name, episode.show), curFoundResults)

        # loop all results and see if any of them are good enough that we can stop searching
        done_searching = False
        for cur_result in curFoundResults:
            done_searching = isFinalResult(cur_result)
            logger.log(u"Should we stop searching after finding "+cur_result.name+": "+str(done_searching), logger.DEBUG)
            if done_searching:
                break
        
        foundResults += curFoundResults

        # if we did find a result that's good enough to stop then don't continue
        if done_searching:
            break
Пример #55
0
 def _test_filterBadReleases(self, name, expected):
     result = show_name_helpers.filterBadReleases(name)
     self.assertEqual(result, expected)
Пример #56
0
    def _getProperList(self):

        propers = {}

        # for each provider get a list of the propers
        for curProvider in providers.sortedProviderList():

            if not curProvider.isActive():
                continue

            date = datetime.datetime.today() - datetime.timedelta(days=2)

            logger.log(u"Searching for any new PROPER releases from "+curProvider.name)
            curPropers = curProvider.findPropers(date)

            # if they haven't been added by a different provider than add the proper to the list
            for x in curPropers:
                name = self._genericName(x.name)
                
                if not name in propers:
                    logger.log(u"Found new proper: "+x.name, logger.DEBUG)
                    x.provider = curProvider
                    propers[name] = x

        # take the list of unique propers and get it sorted by
        sortedPropers = sorted(propers.values(), key=operator.attrgetter('date'), reverse=True)
        finalPropers = []

        for curProper in sortedPropers:

            # parse the file name
            cp = CompleteParser()
            cpr = cp.parse(curProper.name)
            parse_result = cpr.parse_result

            if not parse_result.episode_numbers and not parse_result.is_anime:
                logger.log(u"Ignoring "+curProper.name+" because it's for a full season rather than specific episode", logger.DEBUG)
                continue

            # populate our Proper instance
            if parse_result.air_by_date:
                curProper.season = -1
                curProper.episode = parse_result.air_date
            else:
                curProper.season = parse_result.season_number if parse_result.season_number != None else 1
                if parse_result.is_anime:
                    logger.log(u"I am sorry '"+curProper.name+"' seams to be an anime proper seach is not yet suported", logger.DEBUG)
                    continue
                    curProper.episode = parse_result.ab_episode_numbers[0]
                else:
                    curProper.episode = parse_result.episode_numbers[0]
            
            curProper.quality = Quality.nameQuality(curProper.name,parse_result.is_anime)

            # for each show in our list
            for curShow in sickbeard.showList:

                genericName = self._genericName(parse_result.series_name)

                # get the scene name masks
                sceneNames = set(show_name_helpers.makeSceneShowSearchStrings(curShow))

                # for each scene name mask
                for curSceneName in sceneNames:

                    # if it matches
                    if genericName == self._genericName(curSceneName):
                        logger.log(u"Successful match! Result "+parse_result.series_name+" matched to show "+curShow.name, logger.DEBUG)

                        # set the tvdbid in the db to the show's tvdbid
                        curProper.tvdbid = curShow.tvdbid

                        # since we found it, break out
                        break

                # if we found something in the inner for loop break out of this one
                if curProper.tvdbid != -1:
                    break

            if curProper.tvdbid == -1:
                continue
            
            if not show_name_helpers.filterBadReleases(curProper.name):
                logger.log(u"Proper "+curProper.name+" isn't a valid scene release that we want, igoring it", logger.DEBUG)
                continue

            # if we have an air-by-date show then get the real season/episode numbers
            if curProper.season == -1 and curProper.tvdbid:
                showObj = helpers.findCertainShow(sickbeard.showList, curProper.tvdbid)
                if not showObj:
                    logger.log(u"This should never have happened, post a bug about this!", logger.ERROR)
                    raise Exception("BAD STUFF HAPPENED")

                tvdb_lang = showObj.lang
                # There's gotta be a better way of doing this but we don't wanna
                # change the language value elsewhere
                ltvdb_api_parms = sickbeard.TVDB_API_PARMS.copy()

                if tvdb_lang and not tvdb_lang == 'en':
                    ltvdb_api_parms['language'] = tvdb_lang

                try:
                    t = tvdb_api.Tvdb(**ltvdb_api_parms)
                    epObj = t[curProper.tvdbid].airedOn(curProper.episode)[0]
                    curProper.season = int(epObj["seasonnumber"])
                    curProper.episodes = [int(epObj["episodenumber"])]
                except tvdb_exceptions.tvdb_episodenotfound:
                    logger.log(u"Unable to find episode with date "+str(curProper.episode)+" for show "+parse_result.series_name+", skipping", logger.WARNING)
                    continue

            # check if we actually want this proper (if it's the right quality)
            sqlResults = db.DBConnection().select("SELECT status FROM tv_episodes WHERE showid = ? AND season = ? AND episode = ?", [curProper.tvdbid, curProper.season, curProper.episode])
            if not sqlResults:
                continue
            oldStatus, oldQuality = Quality.splitCompositeStatus(int(sqlResults[0]["status"]))

            # only keep the proper if we have already retrieved the same quality ep (don't get better/worse ones)
            if oldStatus not in (DOWNLOADED, SNATCHED) or oldQuality != curProper.quality:
                continue

            # if the show is in our list and there hasn't been a proper already added for that particular episode then add it to our list of propers
            if curProper.tvdbid != -1 and (curProper.tvdbid, curProper.season, curProper.episode) not in map(operator.attrgetter('tvdbid', 'season', 'episode'), finalPropers):
                logger.log(u"Found a proper that we need: "+str(curProper.name))
                finalPropers.append(curProper)

        return finalPropers
Пример #57
0
            continue

        try:
            curFoundResults = curProvider.findEpisode(episode, manualSearch=manualSearch)
        except exceptions.AuthException, e:
            logger.log(u"Authentication error: " + ex(e), logger.ERROR)
            continue
        except Exception, e:
            logger.log(u"Error while searching " + curProvider.name + ", skipping: " + ex(e), logger.ERROR)
            logger.log(traceback.format_exc(), logger.DEBUG)
            continue

        didSearch = True

        # skip non-tv crap
        curFoundResults = filter(lambda x: show_name_helpers.filterBadReleases(x.name) and show_name_helpers.isGoodResult(x.name, episode.show), curFoundResults)

        # loop all results and see if any of them are good enough that we can stop searching
        done_searching = False
        for cur_result in curFoundResults:
            done_searching = isFinalResult(cur_result)
            logger.log(u"Should we stop searching after finding " + cur_result.name + ": " + str(done_searching), logger.DEBUG)
            if done_searching:
                break

        foundResults += curFoundResults

        # if we did find a result that's good enough to stop then don't continue
        if done_searching:
            break
Пример #58
0
class ProperFinder():
    def __init__(self):
        self.updateInterval = datetime.timedelta(hours=1)

    def run(self):

        if not sickbeard.DOWNLOAD_PROPERS:
            return

        # look for propers every night at 1 AM
        updateTime = datetime.time(hour=1)

        logger.log(u"Checking proper time", logger.DEBUG)

        hourDiff = datetime.datetime.today().time().hour - updateTime.hour

        # if it's less than an interval after the update time then do an update
        if hourDiff >= 0 and hourDiff < self.updateInterval.seconds / 3600:
            logger.log(u"Beginning the search for new propers")
        else:
            return

        propers = self._getProperList()

        self._downloadPropers(propers)

    def _getProperList(self):

        propers = {}

        # for each provider get a list of the propers
        for curProvider in providers.sortedProviderList():

            if not curProvider.isActive():
                continue

            search_date = datetime.datetime.today() - datetime.timedelta(
                days=2)

            logger.log(u"Searching for any new PROPER releases from " +
                       curProvider.name)
            try:
                curPropers = curProvider.findPropers(search_date)
            except exceptions.AuthException, e:
                logger.log(u"Authentication error: " + ex(e), logger.ERROR)
                continue

            # if they haven't been added by a different provider than add the proper to the list
            for x in curPropers:
                name = self._genericName(x.name)

                if not name in propers:
                    logger.log(u"Found new proper: " + x.name, logger.DEBUG)
                    x.provider = curProvider
                    propers[name] = x

        # take the list of unique propers and get it sorted by
        sortedPropers = sorted(propers.values(),
                               key=operator.attrgetter('date'),
                               reverse=True)
        finalPropers = []

        for curProper in sortedPropers:

            # parse the file name
            try:
                myParser = NameParser(False)
                parse_result = myParser.parse(curProper.name)
            except InvalidNameException:
                logger.log(
                    u"Unable to parse the filename " + curProper.name +
                    " into a valid episode", logger.DEBUG)
                continue

            if not parse_result.episode_numbers:
                logger.log(
                    u"Ignoring " + curProper.name +
                    " because it's for a full season rather than specific episode",
                    logger.DEBUG)
                continue

            # populate our Proper instance
            if parse_result.air_by_date:
                curProper.season = -1
                curProper.episode = parse_result.air_date
            else:
                curProper.season = parse_result.season_number if parse_result.season_number != None else 1
                curProper.episode = parse_result.episode_numbers[0]
            curProper.quality = Quality.nameQuality(curProper.name)

            # for each show in our list
            for curShow in sickbeard.showList:

                if not parse_result.series_name:
                    continue

                genericName = self._genericName(parse_result.series_name)

                # get the scene name masks
                sceneNames = set(
                    show_name_helpers.makeSceneShowSearchStrings(curShow))

                # for each scene name mask
                for curSceneName in sceneNames:

                    # if it matches
                    if genericName == self._genericName(curSceneName):
                        logger.log(
                            u"Successful match! Result " +
                            parse_result.series_name + " matched to show " +
                            curShow.name, logger.DEBUG)

                        # set the tvdbid in the db to the show's tvdbid
                        curProper.tvdbid = curShow.tvdbid

                        # since we found it, break out
                        break

                # if we found something in the inner for loop break out of this one
                if curProper.tvdbid != -1:
                    break

            if curProper.tvdbid == -1:
                continue

            if not show_name_helpers.filterBadReleases(curProper.name):
                logger.log(
                    u"Proper " + curProper.name +
                    " isn't a valid scene release that we want, ignoring it",
                    logger.DEBUG)
                continue

            show = helpers.findCertainShow(sickbeard.showList,
                                           curProper.tvdbid)
            if not show:
                logger.log(
                    u"Unable to find the show with tvdbid " +
                    str(curProper.tvdbid), logger.ERROR)
                continue

            if show.rls_ignore_words and search.filter_release_name(
                    curProper.name, show.rls_ignore_words):
                logger.log(
                    u"Ignoring " + curProper.name +
                    " based on ignored words filter: " + show.rls_ignore_words,
                    logger.MESSAGE)
                continue

            if show.rls_require_words and not search.filter_release_name(
                    curProper.name, show.rls_require_words):
                logger.log(
                    u"Ignoring " + curProper.name +
                    " based on required words filter: " +
                    show.rls_require_words, logger.MESSAGE)
                continue

            # if we have an air-by-date show then get the real season/episode numbers
            if curProper.season == -1 and curProper.tvdbid:

                tvdb_lang = show.lang
                # There's gotta be a better way of doing this but we don't wanna
                # change the language value elsewhere
                ltvdb_api_parms = sickbeard.TVDB_API_PARMS.copy()

                if tvdb_lang and not tvdb_lang == 'en':
                    ltvdb_api_parms['language'] = tvdb_lang

                try:
                    t = tvdb_api.Tvdb(**ltvdb_api_parms)
                    epObj = t[curProper.tvdbid].airedOn(curProper.episode)[0]
                    curProper.season = int(epObj["seasonnumber"])
                    curProper.episodes = [int(epObj["episodenumber"])]
                except tvdb_exceptions.tvdb_episodenotfound:
                    logger.log(
                        u"Unable to find episode with date " +
                        str(curProper.episode) + " for show " +
                        parse_result.series_name + ", skipping",
                        logger.WARNING)
                    continue

            # check if we actually want this proper (if it's the right quality)
            sqlResults = db.DBConnection().select(
                "SELECT status FROM tv_episodes WHERE showid = ? AND season = ? AND episode = ?",
                [curProper.tvdbid, curProper.season, curProper.episode])
            if not sqlResults:
                continue
            oldStatus, oldQuality = Quality.splitCompositeStatus(
                int(sqlResults[0]["status"]))

            # only keep the proper if we have already retrieved the same quality ep (don't get better/worse ones)
            if oldStatus not in (DOWNLOADED,
                                 SNATCHED) or oldQuality != curProper.quality:
                continue

            # if the show is in our list and there hasn't been a proper already added for that particular episode then add it to our list of propers
            if curProper.tvdbid != -1 and (curProper.tvdbid, curProper.season,
                                           curProper.episode) not in map(
                                               operator.attrgetter(
                                                   'tvdbid', 'season',
                                                   'episode'), finalPropers):
                logger.log(u"Found a proper that we need: " +
                           str(curProper.name))
                finalPropers.append(curProper)

        return finalPropers
Пример #59
0
def pickBestResult(results, show, quality_list=None):
    results = results if isinstance(results, list) else [results]

    logger.log(u"Picking the best result out of " + str([x.name for x in results]), logger.DEBUG)

    bwl = None
    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

        # filter out possible bad torrents from providers such as ezrss
        if isinstance(cur_result, sickbeard.classes.SearchResult):
            if cur_result.resultType == "torrent" and sickbeard.TORRENT_METHOD != "blackhole":
                if not cur_result.url.startswith('magnet'):
                    cur_result.content = cur_result.provider.getURL(cur_result.url)
                    if not cur_result.content:
                        continue
        else:
            if not cur_result.url.startswith('magnet'):
                cur_result.content = cur_result.provider.getURL(cur_result.url)
                if not cur_result.content:
                    continue

        # build the black And white list
        if cur_result.show.is_anime:
            if not bwl:
                bwl = BlackAndWhiteList(cur_result.show.indexerid)
            if not bwl.is_valid(cur_result):
                logger.log(cur_result.name+" does not match the blacklist or the whitelist, rejecting it. Result: " + bwl.get_last_result_msg(), logger.INFO)
                continue

        logger.log("Quality of " + cur_result.name + " is " + Quality.qualityStrings[cur_result.quality])

        if quality_list and cur_result.quality not in quality_list:
            logger.log(cur_result.name + " is a quality we know we don't want, rejecting it", logger.DEBUG)
            continue

        if show.rls_ignore_words and show_name_helpers.containsAtLeastOneWord(cur_result.name, cur_result.show.rls_ignore_words):
            logger.log(u"Ignoring " + cur_result.name + " based on ignored words filter: " + show.rls_ignore_words,
                       logger.INFO)
            continue

        if show.rls_require_words and not show_name_helpers.containsAtLeastOneWord(cur_result.name, cur_result.show.rls_require_words):
            logger.log(u"Ignoring " + cur_result.name + " based on required words filter: " + show.rls_require_words,
                       logger.INFO)
            continue

        if not show_name_helpers.filterBadReleases(cur_result.name, parse=False):
            logger.log(u"Ignoring " + cur_result.name + " because its not a valid scene release that we want, ignoring it",
                       logger.INFO)
            continue

        if hasattr(cur_result, 'size'):
            if sickbeard.USE_FAILED_DOWNLOADS and failed_history.hasFailed(cur_result.name, cur_result.size,
                                                                           cur_result.provider.name):
                logger.log(cur_result.name + u" has previously failed, rejecting it")
                continue

        if not bestResult or bestResult.quality < cur_result.quality and cur_result.quality != Quality.UNKNOWN:
            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():
                logger.log(u"Preferring " + cur_result.name + " (x264 over xvid)")
                bestResult = cur_result

    if bestResult:
        logger.log(u"Picked " + bestResult.name + " as the best", logger.DEBUG)
    else:
        logger.log(u"No result picked.", logger.DEBUG)

    return bestResult
Пример #60
0
def pickBestResult(results, show, quality_list=None):
    results = results if isinstance(results, list) else [results]

    logger.log(
        u"Picking the best result out of " + str([x.name for x in results]),
        logger.DEBUG)

    bwl = None
    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

        # filter out possible bad torrents from providers such as ezrss
        if isinstance(cur_result, sickbeard.classes.SearchResult):
            if cur_result.resultType == "torrent" and sickbeard.TORRENT_METHOD != "blackhole":
                if not cur_result.url.startswith('magnet'):
                    cur_result.content = cur_result.provider.getURL(
                        cur_result.url)
                    if not cur_result.content:
                        continue
        else:
            if not cur_result.url.startswith('magnet'):
                cur_result.content = cur_result.provider.getURL(cur_result.url)
                if not cur_result.content:
                    continue

        # build the black And white list
        if cur_result.show.is_anime:
            if not bwl:
                bwl = BlackAndWhiteList(cur_result.show.indexerid)
            if not bwl.is_valid(cur_result):
                logger.log(
                    cur_result.name +
                    " does not match the blacklist or the whitelist, rejecting it. Result: "
                    + bwl.get_last_result_msg(), logger.INFO)
                continue

        logger.log("Quality of " + cur_result.name + " is " +
                   Quality.qualityStrings[cur_result.quality])

        if quality_list and cur_result.quality not in quality_list:
            logger.log(
                cur_result.name +
                " is a quality we know we don't want, rejecting it",
                logger.DEBUG)
            continue

        if show.lang == "de" and not filter_release_name(
                cur_result.name, "german|videoman"):
            logger.log(
                u"Ignoring " + cur_result.name +
                " based on ignored words filter: show language 'de'",
                logger.INFO)
            continue

        if show.lang != "de" and filter_release_name(cur_result.name,
                                                     "german|videoman"):
            logger.log(
                u"Ignoring " + cur_result.name +
                " based on ignored words filter: show language '%s'" %
                show.lang, logger.INFO)
            continue

        if show.rls_ignore_words and filter_release_name(
                cur_result.name, cur_result.show.rls_ignore_words):
            logger.log(
                u"Ignoring " + cur_result.name +
                " based on ignored words filter: " + show.rls_ignore_words,
                logger.INFO)
            continue

        if show.rls_require_words and not filter_release_name(
                cur_result.name, cur_result.show.rls_require_words):
            logger.log(
                u"Ignoring " + cur_result.name +
                " based on required words filter: " + show.rls_require_words,
                logger.INFO)
            continue

        if not show_name_helpers.filterBadReleases(cur_result.name,
                                                   parse=False):
            logger.log(
                u"Ignoring " + cur_result.name +
                " because its not a valid scene release that we want, ignoring it",
                logger.INFO)
            continue

        if hasattr(cur_result, 'size'):
            if sickbeard.USE_FAILED_DOWNLOADS and failed_history.hasFailed(
                    cur_result.name, cur_result.size,
                    cur_result.provider.name):
                logger.log(cur_result.name +
                           u" has previously failed, rejecting it")
                continue

        if not bestResult or bestResult.quality < cur_result.quality and cur_result.quality != Quality.UNKNOWN:
            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():
                logger.log(u"Preferring " + cur_result.name +
                           " (x264 over xvid)")
                bestResult = cur_result

    if bestResult:
        logger.log(u"Picked " + bestResult.name + " as the best", logger.DEBUG)
    else:
        logger.log(u"No result picked.", logger.DEBUG)

    return bestResult