Ejemplo n.º 1
0
    def run(self, force=False):
        if self.amActive:
            return

        self.amActive = True

        # set thread name
        threading.currentThread().setName(self.name)

        piList = []
        stale_should_update = []

        update_datetime = datetime.datetime.now()
        update_date = update_datetime.date()

        if sickrage.srCore.srConfig.USE_FAILED_DOWNLOADS:
            FailedHistory.trimHistory()

        if sickrage.srCore.srConfig.SHOWUPDATE_STALE:
            # select 10 'Ended' tv_shows updated more than 90 days ago to include in this update
            stale_update_date = (update_date - datetime.timedelta(days=90)).toordinal()

            # last_update_date <= 90 days, sorted ASC because dates are ordinal
            sql_result = main_db.MainDB().select(
                    "SELECT indexer_id FROM tv_shows WHERE status = 'Ended' AND last_update_indexer <= ? ORDER BY last_update_indexer ASC LIMIT 10;",
                    [stale_update_date])

            # list of stale shows
            [stale_should_update.append(int(cur_result['indexer_id'])) for cur_result in sql_result]

        # start update process
        sickrage.srCore.srLogger.info("Performing daily updates for all shows")
        for curShow in sickrage.srCore.SHOWLIST:
            try:
                # get next episode airdate
                curShow.nextEpisode()

                # if should_update returns True (not 'Ended') or show is selected stale 'Ended' then update, otherwise just refresh
                if curShow.should_update(update_date=update_date) or curShow.indexerid in stale_should_update:
                    try:
                        piList.append(
                                sickrage.srCore.SHOWQUEUE.updateShow(curShow, True))
                    except CantUpdateShowException as e:
                        sickrage.srCore.srLogger.debug("Unable to update show: {}".format(e.message))
                else:
                    piList.append(
                            sickrage.srCore.SHOWQUEUE.refreshShow(curShow, True))

            except (CantUpdateShowException, CantRefreshShowException) as e:
                sickrage.srCore.srLogger.error("Daily show update failed: {}".format(e.message))

        ProgressIndicators.setIndicator('dailyShowUpdates', QueueProgressIndicator("Daily Show Updates", piList))

        sickrage.srCore.srLogger.info("Completed daily updates for all shows")

        self.amActive = False
Ejemplo n.º 2
0
    def run(self, force=False):
        if self.amActive:
            return

        self.amActive = True

        update_datetime = datetime.datetime.now()
        update_date = update_datetime.date()

        if sickrage.USE_FAILED_DOWNLOADS:
            FailedHistory.trimHistory()

        sickrage.LOGGER.info("Doing full update on all shows")

        # select 10 'Ended' tv_shows updated more than 90 days ago to include in this update
        stale_should_update = []
        stale_update_date = (update_date - datetime.timedelta(days=90)).toordinal()

        # last_update_date <= 90 days, sorted ASC because dates are ordinal
        sql_result = main_db.MainDB().select(
                "SELECT indexer_id FROM tv_shows WHERE status = 'Ended' AND last_update_indexer <= ? ORDER BY last_update_indexer ASC LIMIT 10;",
                [stale_update_date])

        for cur_result in sql_result:
            stale_should_update.append(int(cur_result[b'indexer_id']))

        # start update process
        piList = []
        for curShow in sickrage.showList:

            try:
                # get next episode airdate
                curShow.nextEpisode()

                # if should_update returns True (not 'Ended') or show is selected stale 'Ended' then update, otherwise just refresh
                if curShow.should_update(update_date=update_date) or curShow.indexerid in stale_should_update:
                    try:
                        piList.append(
                                sickrage.SHOWQUEUE.updateShow(curShow, True))  # @UndefinedVariable
                    except CantUpdateShowException as e:
                        sickrage.LOGGER.debug("Unable to update show: {0}".format(str(e)))
                else:
                    sickrage.LOGGER.debug(
                            "Not updating episodes for show " + curShow.name + " because it's marked as ended and last/next episode is not within the grace period.")
                    piList.append(
                            sickrage.SHOWQUEUE.refreshShow(curShow, True))  # @UndefinedVariable

            except (CantUpdateShowException, CantRefreshShowException) as e:
                sickrage.LOGGER.error("Automatic update failed: {}".format(e))

        ProgressIndicators.setIndicator('dailyUpdate', QueueProgressIndicator("Daily Update", piList))

        sickrage.LOGGER.info("Completed full update on all shows")

        self.amActive = False
Ejemplo n.º 3
0
    def run(self, force=False):
        """
        Runs the failed searcher, queuing selected episodes for search that have failed to snatch
        :param force: Force search
        """
        if self.amActive or (not sickrage.app.config.use_failed_snatcher or sickrage.app.developer) and not force:
            return

        self.amActive = True

        # set thread name
        threading.currentThread().setName(self.name)

        # trim failed download history
        FailedHistory.trimHistory()

        sickrage.app.log.info("Searching for failed snatches")

        show = None
        failed_snatches = False

        snatched_episodes = (x for x in sickrage.app.main_db.all('history')
                             if x['action'] in Quality.SNATCHED + Quality.SNATCHED_BEST + Quality.SNATCHED_PROPER
                             and 24 >= int((datetime.datetime.now() - datetime.datetime.strptime(x['date'],
                                                                                                 History.date_format)).total_seconds() / 3600) >= sickrage.app.config.failed_snatch_age)

        downloaded_releases = ((x['showid'], x['season'], x['episode']) for x in
                               sickrage.app.main_db.all('history')
                               if x['action'] in Quality.DOWNLOADED)

        episodes = [x for x in snatched_episodes if (x['showid'], x['season'], x['episode']) not in downloaded_releases]

        for episode in episodes:
            failed_snatches = True
            if not show or int(episode["showid"]) != show.indexerid:
                show = findCertainShow(int(episode["showid"]))

            # for when there is orphaned series in the database but not loaded into our showlist
            if not show or show.paused:
                continue

            ep_obj = show.get_episode(int(episode['season']), int(episode['episode']))
            if isinstance(ep_obj, TVEpisode):
                curStatus, curQuality = Quality.splitCompositeStatus(ep_obj.status)
                if curStatus not in {SNATCHED, SNATCHED_BEST, SNATCHED_PROPER}:
                    continue

                # put it on the queue
                sickrage.app.search_queue.put(FailedQueueItem(show, [ep_obj], True))

        if not failed_snatches:
            sickrage.app.log.info("No failed snatches found")

        self.amActive = False
Ejemplo n.º 4
0
    def task(self, force=False):
        """
        Runs the failed searcher, queuing selected episodes for search that have failed to snatch
        :param force: Force search
        """
        if self.running or not sickrage.app.config.failed_snatches.enable and not force:
            return

        try:
            self.running = True

            # set thread name
            threading.currentThread().setName(self.name)

            # trim failed download history
            FailedHistory.trim_history()

            sickrage.app.log.info("Searching for failed snatches")

            failed_snatches = False

            for snatched_episode_obj in [
                    x for x in self.snatched_episodes()
                    if (x.series_id, x.season,
                        x.episode) not in self.downloaded_releases()
            ]:
                show_object = find_show(
                    snatched_episode_obj.series_id,
                    snatched_episode_obj.series_provider_id)
                episode_object = show_object.get_episode(
                    snatched_episode_obj.season, snatched_episode_obj.episode)
                if episode_object.show.paused:
                    continue

                cur_status, cur_quality = Quality.split_composite_status(
                    episode_object.status)
                if cur_status not in {
                        EpisodeStatus.SNATCHED, EpisodeStatus.SNATCHED_BEST,
                        EpisodeStatus.SNATCHED_PROPER
                }:
                    continue

                sickrage.app.search_queue.put(
                    FailedSearchTask(show_object.series_id,
                                     show_object.series_provider_id,
                                     episode_object.season,
                                     episode_object.episode, True))

                failed_snatches = True

            if not failed_snatches:
                sickrage.app.log.info("No failed snatches found")
        finally:
            self.running = False
Ejemplo n.º 5
0
    def run(self, force=False, session=None):
        """
        Runs the failed searcher, queuing selected episodes for search that have failed to snatch
        :param force: Force search
        """
        if self.amActive or not sickrage.app.config.use_failed_snatcher and not force:
            return

        self.amActive = True

        # set thread name
        threading.currentThread().setName(self.name)

        # trim failed download history
        FailedHistory.trim_history()

        sickrage.app.log.info("Searching for failed snatches")

        failed_snatches = False

        for snatched_episode_obj in [
                x for x in self.snatched_episodes()
                if (x.showid, x.season,
                    x.episode) not in self.downloaded_releases()
        ]:
            show_object = find_show(snatched_episode_obj.showid,
                                    session=session)
            episode_object = show_object.get_episode(
                snatched_episode_obj.season, snatched_episode_obj.episode)
            if episode_object.show.paused:
                continue

            cur_status, cur_quality = Quality.split_composite_status(
                episode_object.status)
            if cur_status not in {SNATCHED, SNATCHED_BEST, SNATCHED_PROPER}:
                continue

            sickrage.app.io_loop.add_callback(
                sickrage.app.search_queue.put,
                FailedQueueItem(episode_object.showid, episode_object.season,
                                episode_object.episode, True))

            failed_snatches = True

        if not failed_snatches:
            sickrage.app.log.info("No failed snatches found")

        self.amActive = False
Ejemplo n.º 6
0
    def run(self):
        self.started = True

        try:
            sickrage.app.log.info("Starting failed download search for: [" + self.show.name + "]")

            for epObj in self.segment:
                sickrage.app.log.info("Marking episode as bad: [" + epObj.pretty_name() + "]")

                FailedHistory.markFailed(epObj)

                (release, provider) = FailedHistory.findFailedRelease(epObj)
                if release:
                    FailedHistory.logFailed(release)
                    History.logFailed(epObj, release, provider)

                FailedHistory.revertFailedEpisode(epObj)

            search_result = searchProviders(self.show, self.segment, manualSearch=True, downCurQuality=False)
            if search_result:
                for result in search_result:
                    # just use the first result for now
                    sickrage.app.log.info("Downloading " + result.name + " from " + result.provider.name)
                    snatchEpisode(result)

                    # give the CPU a break
                    time.sleep(cpu_presets[sickrage.app.config.cpu_preset])
        except Exception:
            sickrage.app.log.debug(traceback.format_exc())
        finally:
            sickrage.app.log.info("Finished failed download search for: [" + self.show.name + "]")

        # Keep a list with the 100 last executed searches
        fifo(MANUAL_SEARCH_HISTORY, self, MANUAL_SEARCH_HISTORY_SIZE)
Ejemplo n.º 7
0
    def run(self):
        super(FailedQueueItem, self).run()
        self.started = True

        try:
            for epObj in self.segment:
                sickrage.srCore.srLogger.info("Marking episode as bad: [" + epObj.prettyName() + "]")

                FailedHistory.markFailed(epObj)
                (release, provider) = FailedHistory.findFailedRelease(epObj)
                if release:
                    FailedHistory.logFailed(release)
                    History.logFailed(epObj, release, provider)

                FailedHistory.revertFailedEpisode(epObj)
                sickrage.srCore.srLogger.info("Beginning failed download search for: [" + epObj.prettyName() + "]")

            # If it is wanted, self.downCurQuality doesnt matter
            # if it isnt wanted, we need to make sure to not overwrite the existing ep that we reverted to!
            searchResult = searchProviders(self.show, self.segment, True, False)
            if searchResult:
                for result in searchResult:
                    # just use the first result for now
                    sickrage.srCore.srLogger.info("Downloading " + result.name + " from " + result.provider.name)
                    snatchEpisode(result)

                    # give the CPU a break
                    time.sleep(cpu_presets[sickrage.srCore.srConfig.CPU_PRESET])
        except Exception:
            sickrage.srCore.srLogger.debug(traceback.format_exc())

        ### Keep a list with the 100 last executed searches
        fifo(MANUAL_SEARCH_HISTORY, self, MANUAL_SEARCH_HISTORY_SIZE)
Ejemplo n.º 8
0
    def run(self):
        self.started = True

        try:
            sickrage.app.log.info("Starting failed download search for: [" + self.show.name + "]")

            for epObj in self.segment:
                sickrage.app.log.info("Marking episode as bad: [" + epObj.pretty_name() + "]")

                FailedHistory.markFailed(epObj)

                (release, provider) = FailedHistory.findFailedRelease(epObj)
                if release:
                    FailedHistory.logFailed(release)
                    History.logFailed(epObj, release, provider)

                FailedHistory.revertFailedEpisode(epObj)

            search_result = searchProviders(self.show, self.segment, manualSearch=True, downCurQuality=False)
            if search_result:
                for result in search_result:
                    # just use the first result for now
                    sickrage.app.log.info("Downloading " + result.name + " from " + result.provider.name)
                    snatchEpisode(result)

                    # give the CPU a break
                    time.sleep(cpu_presets[sickrage.app.config.cpu_preset])
        except Exception:
            sickrage.app.log.debug(traceback.format_exc())
        finally:
            sickrage.app.log.info("Finished failed download search for: [" + self.show.name + "]")

        # Keep a list with the 100 last executed searches
        fifo(MANUAL_SEARCH_HISTORY, self, MANUAL_SEARCH_HISTORY_SIZE)
Ejemplo n.º 9
0
    def run(self, force=False):
        if self.amActive:
            return

        self.amActive = True

        # set thread name
        threading.currentThread().setName(self.name)

        update_timestamp = time.mktime(datetime.datetime.now().timetuple())

        sqlResult = cache_db.CacheDB().select('SELECT `time` FROM lastUpdate WHERE provider = ?', ['theTVDB'])
        if sqlResult:
            last_update = sqlResult[0]['time']
        else:
            last_update = time.mktime(datetime.datetime.min.timetuple())
            cache_db.CacheDB().action('INSERT INTO lastUpdate (provider, `time`) VALUES (?, ?)',
                                      ['theTVDB', long(last_update)])

        if sickrage.srCore.srConfig.USE_FAILED_DOWNLOADS:
            FailedHistory.trimHistory()

        # get indexer updated show ids
        updated_shows = srIndexerApi(1).indexer(**srIndexerApi(1).api_params.copy()).updated(long(last_update))

        # start update process
        piList = []
        for curShow in sickrage.srCore.SHOWLIST:
            try:
                curShow.nextEpisode()
                if curShow.indexerid in set(d["id"] for d in updated_shows or {}):
                    piList.append(sickrage.srCore.SHOWQUEUE.updateShow(curShow, True))
                else:
                    piList.append(sickrage.srCore.SHOWQUEUE.refreshShow(curShow, False))
            except (CantUpdateShowException, CantRefreshShowException) as e:
                continue

        ProgressIndicators.setIndicator('dailyShowUpdates', QueueProgressIndicator("Daily Show Updates", piList))

        cache_db.CacheDB().action('UPDATE lastUpdate SET `time` = ? WHERE provider=?',
                                  [long(update_timestamp), 'theTVDB'])

        self.amActive = False
Ejemplo n.º 10
0
    def run(self):
        self.started = True

        show_object = find_show(self.show_id)
        episode_object = show_object.get_episode(self.season, self.episode)

        try:
            sickrage.app.log.info("Starting failed download search for: [" +
                                  episode_object.name + "]")

            sickrage.app.log.info("Marking episode as bad: [" +
                                  episode_object.pretty_name() + "]")

            FailedHistory.mark_failed(self.show_id, self.season, self.episode)

            (release, provider) = FailedHistory.find_failed_release(
                self.show_id, self.season, self.episode)
            if release:
                FailedHistory.log_failed(release)
                History.log_failed(self.show_id, self.season, self.episode,
                                   release, provider)

            FailedHistory.revert_failed_episode(self.show_id, self.season,
                                                self.episode)

            search_result = search_providers(self.show_id,
                                             self.season,
                                             self.episode,
                                             manualSearch=True,
                                             downCurQuality=False)
            if search_result:
                snatch = all([(search_result.show_id, search_result.season,
                               episode)
                              not in sickrage.app.search_queue.SNATCH_HISTORY
                              for episode in search_result.episodes])

                if snatch:
                    [
                        sickrage.app.search_queue.fifo(
                            sickrage.app.search_queue.SNATCH_HISTORY,
                            (search_result.show_id, search_result.season,
                             episode),
                            sickrage.app.search_queue.SNATCH_HISTORY_SIZE)
                        for episode in search_result.episodes
                    ]

                    sickrage.app.log.info("Downloading " + search_result.name +
                                          " from " +
                                          search_result.provider.name)
                    snatch_episode(search_result)
        except Exception:
            sickrage.app.log.debug(traceback.format_exc())
        finally:
            sickrage.app.log.info("Finished failed download search for: [" +
                                  show_object.name + "]")
            sickrage.app.search_queue.fifo(
                sickrage.app.search_queue.MANUAL_SEARCH_HISTORY, self,
                sickrage.app.search_queue.MANUAL_SEARCH_HISTORY_SIZE)
Ejemplo n.º 11
0
    def run(self, force=False):
        """
        Runs the daily searcher, queuing selected episodes for search
        :param force: Force search
        """
        if self.amActive or sickrage.DEVELOPER and not force:
            return

        self.amActive = True

        # set thread name
        threading.currentThread().setName(self.name)

        # trim failed download history
        if sickrage.srCore.srConfig.USE_FAILED_DOWNLOADS:
            FailedHistory.trimHistory()

        # queue episode for daily search
        sickrage.srCore.SEARCHQUEUE.put(DailySearchQueueItem())

        self.amActive = False
Ejemplo n.º 12
0
    def run(self, force=False):
        if self.amActive:
            return

        self.amActive = True

        # set thread name
        threading.currentThread().setName(self.name)

        piList = []
        stale_should_update = []

        update_datetime = datetime.datetime.now()
        update_date = update_datetime.date()

        if sickrage.srCore.srConfig.USE_FAILED_DOWNLOADS:
            FailedHistory.trimHistory()

        if sickrage.srCore.srConfig.SHOWUPDATE_STALE:
            # select 10 'Ended' tv_shows updated more than 90 days ago to include in this update
            stale_update_date = (update_date -
                                 datetime.timedelta(days=90)).toordinal()

            # last_update_date <= 90 days, sorted ASC because dates are ordinal
            sql_result = main_db.MainDB().select(
                "SELECT indexer_id FROM tv_shows WHERE status = 'Ended' AND last_update_indexer <= ? ORDER BY last_update_indexer ASC LIMIT 10;",
                [stale_update_date])

            # list of stale shows
            [
                stale_should_update.append(int(cur_result['indexer_id']))
                for cur_result in sql_result
            ]

        # start update process
        sickrage.srCore.srLogger.info("Performing daily updates for all shows")
        for curShow in sickrage.srCore.SHOWLIST:
            try:
                # get next episode airdate
                curShow.nextEpisode()

                # if should_update returns True (not 'Ended') or show is selected stale 'Ended' then update, otherwise just refresh
                if curShow.should_update(
                        update_date=update_date
                ) or curShow.indexerid in stale_should_update:
                    try:
                        piList.append(
                            sickrage.srCore.SHOWQUEUE.updateShow(
                                curShow, True))
                    except CantUpdateShowException as e:
                        sickrage.srCore.srLogger.debug(
                            "Unable to update show: {}".format(e.message))
                else:
                    piList.append(
                        sickrage.srCore.SHOWQUEUE.refreshShow(curShow, True))

            except (CantUpdateShowException, CantRefreshShowException) as e:
                sickrage.srCore.srLogger.error(
                    "Daily show update failed: {}".format(e.message))

        ProgressIndicators.setIndicator(
            'dailyShowUpdates',
            QueueProgressIndicator("Daily Show Updates", piList))

        sickrage.srCore.srLogger.info("Completed daily updates for all shows")

        self.amActive = False
Ejemplo n.º 13
0
    def run(self, force=False):
        """
        Runs the daily searcher, queuing selected episodes for search
        :param force: Force search
        """
        if self.amActive or sickrage.srCore.srConfig.DEVELOPER and not force:
            return

        self.amActive = True

        # set thread name
        threading.currentThread().setName(self.name)

        # trim failed download history
        if sickrage.srCore.srConfig.USE_FAILED_DOWNLOADS:
            FailedHistory.trimHistory()

        sickrage.srCore.srLogger.info("{}: Searching for new released episodes".format(self.name))

        curDate = datetime.date.today()
        curDate += datetime.timedelta(days=2)
        if tz_updater.load_network_dict():
            curDate += datetime.timedelta(days=1)

        curTime = datetime.datetime.now(tz_updater.sr_timezone)

        show = None

        episodes = [x['doc'] for x in sickrage.srCore.mainDB.db.all('tv_episodes', with_doc=True)
                    if x['doc']['status'] == UNAIRED
                    and x['doc']['season'] > 0
                    and curDate.toordinal() >= x['doc']['airdate'] > 1]

        for episode in episodes:
            if not show or int(episode["showid"]) != show.indexerid:
                show = findCertainShow(sickrage.srCore.SHOWLIST, int(episode["showid"]))

            # for when there is orphaned series in the database but not loaded into our showlist
            if not show or show.paused:
                continue

            if show.airs and show.network:
                # This is how you assure it is always converted to local time
                air_time = tz_updater.parse_date_time(
                    episode['airdate'], show.airs, show.network, dateOnly=True
                ).astimezone(tz_updater.sr_timezone)

                # filter out any episodes that haven't started airing yet,
                # but set them to the default status while they are airing
                # so they are snatched faster
                if air_time > curTime: continue

            ep = show.getEpisode(int(episode['season']), int(episode['episode']))
            with ep.lock:
                if ep.season == 0:
                    sickrage.srCore.srLogger.info(
                        "New episode {} airs today, setting status to SKIPPED because is a special season".format(
                            ep.prettyName()))
                    ep.status = SKIPPED
                else:
                    sickrage.srCore.srLogger.info(
                        "New episode {} airs today, setting to default episode status for this show: {}".format(
                            ep.prettyName(), statusStrings[ep.show.default_ep_status]))
                    ep.status = ep.show.default_ep_status

                ep.saveToDB()
        else:
            sickrage.srCore.srLogger.info("{}: No new released episodes found".format(self.name))

        # queue episode for daily search
        sickrage.srCore.SEARCHQUEUE.put(DailySearchQueueItem())

        self.amActive = False
Ejemplo n.º 14
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]

    sickrage.app.log.debug("Picking the best result out of " +
                           str([x.name for x in results]))

    bestResult = None

    # find the best result for the current episode
    for cur_result in results:
        if show and cur_result.show is not show:
            continue

        # build the black And white list
        if show.is_anime:
            if not show.release_groups.is_valid(cur_result):
                continue

        sickrage.app.log.info("Quality of " + cur_result.name + " is " +
                              Quality.qualityStrings[cur_result.quality])

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

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

        # check if seeders and leechers meet out minimum requirements, disgard result if it does not
        if hasattr(cur_result.provider, 'minseed') and hasattr(
                cur_result.provider, 'minleech'):
            if cur_result.seeders not in (
                    -1, None) and cur_result.leechers not in (-1, None):
                if int(cur_result.seeders) < int(
                        cur_result.provider.minseed) or int(
                            cur_result.leechers) < int(
                                cur_result.provider.minleech):
                    sickrage.app.log.info(
                        'Discarding torrent because it does not meet the minimum provider '
                        'setting S:{} L:{}. Result has S:{} L:{}',
                        cur_result.provider.minseed,
                        cur_result.provider.minleech, cur_result.seeders,
                        cur_result.leechers)
                    continue

        if show.rls_ignore_words and show_names.containsAtLeastOneWord(
                cur_result.name, cur_result.show.rls_ignore_words):
            sickrage.app.log.info("Ignoring " + cur_result.name +
                                  " based on ignored words filter: " +
                                  show.rls_ignore_words)
            continue

        if show.rls_require_words and not show_names.containsAtLeastOneWord(
                cur_result.name, cur_result.show.rls_require_words):
            sickrage.app.log.info("Ignoring " + cur_result.name +
                                  " based on required words filter: " +
                                  show.rls_require_words)
            continue

        if not show_names.filterBadReleases(cur_result.name, parse=False):
            sickrage.app.log.info(
                "Ignoring " + cur_result.name +
                " because its not a valid scene release that we want")
            continue

        if hasattr(cur_result, 'size'):
            if sickrage.app.config.use_failed_downloads and FailedHistory.hasFailed(
                    cur_result.name, cur_result.size,
                    cur_result.provider.name):
                sickrage.app.log.info(cur_result.name +
                                      " has previously failed, rejecting it")
                continue

        # quality definition video file size constraints check
        try:
            quality_size = sickrage.app.config.quality_sizes[
                cur_result.quality]
            for file, file_size in cur_result.files.items():
                if not file.decode('utf-8').endswith(tuple(video_exts)):
                    continue

                file_size = float(file_size / 1000000)
                if file_size > quality_size:
                    raise Exception(
                        "Ignoring " + cur_result.name +
                        " with size: {} based on quality size filter: {}".
                        format(file_size, quality_size))
        except Exception as e:
            sickrage.app.log.info(e.message)
            continue

        # verify result content
        cur_result = _verify_result(cur_result)
        if not cur_result.content:
            sickrage.app.log.info(
                "Ignoring " + cur_result.name +
                " because it does not have valid download url")
            continue

        if not bestResult:
            bestResult = cur_result
        elif cur_result.quality in bestQualities and (
                bestResult.quality < cur_result.quality
                or bestResult.quality not in bestQualities):
            bestResult = cur_result
        elif cur_result.quality in anyQualities and bestResult.quality not in bestQualities and bestResult.quality < cur_result.quality:
            bestResult = cur_result
        elif bestResult.quality == cur_result.quality:
            if "proper" in cur_result.name.lower(
            ) or "repack" in cur_result.name.lower():
                bestResult = cur_result
            elif "internal" in bestResult.name.lower(
            ) and "internal" not in cur_result.name.lower():
                bestResult = cur_result
            elif "xvid" in bestResult.name.lower(
            ) and "x264" in cur_result.name.lower():
                sickrage.app.log.info("Preferring " + cur_result.name +
                                      " (x264 over xvid)")
                bestResult = cur_result

    if bestResult:
        sickrage.app.log.debug("Picked " + bestResult.name + " as the best")
    else:
        sickrage.app.log.debug("No result picked.")

    return bestResult
Ejemplo n.º 15
0
    def run(self, force=False):
        """
        Runs the daily searcher, queuing selected episodes for search
        :param force: Force search
        """
        if self.amActive or sickrage.app.developer and not force:
            return

        self.amActive = True

        # set thread name
        threading.currentThread().setName(self.name)

        # trim failed download history
        if sickrage.app.config.use_failed_downloads:
            FailedHistory.trimHistory()

        sickrage.app.log.info("Searching for new released episodes")

        curDate = datetime.date.today()
        curDate += datetime.timedelta(days=2)
        if tz_updater.load_network_dict():
            curDate += datetime.timedelta(days=1)

        curTime = datetime.datetime.now(sickrage.app.tz)

        show = None

        episodes = [
            x['doc']
            for x in sickrage.app.main_db.db.all('tv_episodes', with_doc=True)
            if x['doc']['status'] == common.UNAIRED and x['doc']['season'] > 0
            and curDate.toordinal() >= x['doc']['airdate'] > 1
        ]

        new_episodes = False
        for episode in episodes:
            if not show or int(episode["showid"]) != show.indexerid:
                show = findCertainShow(sickrage.app.showlist,
                                       int(episode["showid"]))

            # for when there is orphaned series in the database but not loaded into our showlist
            if not show or show.paused:
                continue

            if show.airs and show.network:
                # This is how you assure it is always converted to local time
                air_time = tz_updater.parse_date_time(
                    episode['airdate'], show.airs, show.network,
                    dateOnly=True).astimezone(sickrage.app.tz)

                # filter out any episodes that haven't started airing yet,
                # but set them to the default status while they are airing
                # so they are snatched faster
                if air_time > curTime: continue

            ep_obj = show.getEpisode(int(episode['season']),
                                     int(episode['episode']))
            with ep_obj.lock:
                ep_obj.status = show.default_ep_status if ep_obj.season else common.SKIPPED
                sickrage.app.log.info(
                    'Setting status ({status}) for show airing today: {name} {special}'
                    .format(
                        name=ep_obj.pretty_name(),
                        status=common.statusStrings[ep_obj.status],
                        special='(specials are not supported)'
                        if not ep_obj.season else '',
                    ))

                ep_obj.saveToDB()
                new_episodes = True

        if not new_episodes:
            sickrage.app.log.info("No new released episodes found")

        # queue episode for daily search
        sickrage.app.search_queue.put(DailySearchQueueItem())

        self.amActive = False
Ejemplo n.º 16
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]

    sickrage.app.log.debug("Picking the best result out of " + str([x.name for x in results]))

    bestResult = None

    # find the best result for the current episode
    for cur_result in results:
        if show and cur_result.show is not show:
            continue

        # build the black And white list
        if show.is_anime:
            if not show.release_groups.is_valid(cur_result):
                continue

        sickrage.app.log.info(
            "Quality of " + cur_result.name + " is " + Quality.qualityStrings[cur_result.quality])

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

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

        # check if seeders and leechers meet out minimum requirements, disgard result if it does not
        if hasattr(cur_result.provider, 'minseed') and hasattr(cur_result.provider, 'minleech'):
            if cur_result.seeders not in (-1, None) and cur_result.leechers not in (-1, None):
                if int(cur_result.seeders) < int(cur_result.provider.minseed) or int(cur_result.leechers) < int(cur_result.provider.minleech):
                    sickrage.app.log.info('Discarding torrent because it does not meet the minimum provider '
                                                  'setting S:{} L:{}. Result has S:{} L:{}',
                                                  cur_result.provider.minseed,
                                                  cur_result.provider.minleech,
                                                  cur_result.seeders,
                                                  cur_result.leechers)
                    continue

        if show.rls_ignore_words and show_names.containsAtLeastOneWord(cur_result.name,
                                                                       cur_result.show.rls_ignore_words):
            sickrage.app.log.info(
                "Ignoring " + cur_result.name + " based on ignored words filter: " + show.rls_ignore_words)
            continue

        if show.rls_require_words and not show_names.containsAtLeastOneWord(cur_result.name,
                                                                            cur_result.show.rls_require_words):
            sickrage.app.log.info(
                "Ignoring " + cur_result.name + " based on required words filter: " + show.rls_require_words)
            continue

        if not show_names.filterBadReleases(cur_result.name, parse=False):
            sickrage.app.log.info(
                "Ignoring " + cur_result.name + " because its not a valid scene release that we want")
            continue

        if hasattr(cur_result, 'size'):
            if sickrage.app.config.use_failed_downloads and FailedHistory.hasFailed(cur_result.name,
                                                                                         cur_result.size,
                                                                                         cur_result.provider.name):
                sickrage.app.log.info(cur_result.name + " has previously failed, rejecting it")
                continue

        # quality definition video file size constraints check
        try:
            quality_size = sickrage.app.config.quality_sizes[cur_result.quality]
            for file, file_size in cur_result.files.items():
                if not file.decode('utf-8').endswith(tuple(video_exts)):
                    continue

                file_size = float(file_size / 1000000)
                if file_size > quality_size:
                    raise Exception(
                        "Ignoring " + cur_result.name + " with size: {} based on quality size filter: {}".format(
                            file_size, quality_size)
                    )
        except Exception as e:
            sickrage.app.log.info(e.message)
            continue

        # verify result content
        cur_result = _verify_result(cur_result)
        if not cur_result.content:
            sickrage.app.log.info(
                "Ignoring " + cur_result.name + " because it does not have valid download url")
            continue

        if not bestResult:
            bestResult = cur_result
        elif cur_result.quality in bestQualities and (
                        bestResult.quality < cur_result.quality or bestResult.quality not in bestQualities):
            bestResult = cur_result
        elif cur_result.quality in anyQualities and bestResult.quality not in bestQualities and bestResult.quality < cur_result.quality:
            bestResult = cur_result
        elif bestResult.quality == cur_result.quality:
            if "proper" in cur_result.name.lower() or "repack" in cur_result.name.lower():
                bestResult = cur_result
            elif "internal" in bestResult.name.lower() and "internal" not in cur_result.name.lower():
                bestResult = cur_result
            elif "xvid" in bestResult.name.lower() and "x264" in cur_result.name.lower():
                sickrage.app.log.info("Preferring " + cur_result.name + " (x264 over xvid)")
                bestResult = cur_result

    if bestResult:
        sickrage.app.log.debug("Picked " + bestResult.name + " as the best")
    else:
        sickrage.app.log.debug("No result picked.")

    return bestResult
Ejemplo n.º 17
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]

    sickrage.app.log.debug("Picking the best result out of " +
                           str([x.name for x in results]))

    bestResult = None

    # find the best result for the current episode
    for cur_result in results:
        if show and cur_result.show is not show:
            continue

        # build the black And white list
        if show.is_anime:
            if not show.release_groups.is_valid(cur_result):
                continue

        sickrage.app.log.info("Quality of " + cur_result.name + " is " +
                              Quality.qualityStrings[cur_result.quality])

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

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

        # check if seeders meet out minimum requirements, disgard result if it does not
        if hasattr(cur_result.provider,
                   'minseed') and cur_result.seeders not in (-1, None):
            if int(cur_result.seeders) < int(cur_result.provider.minseed):
                sickrage.app.log.info(
                    "Discarding torrent because it doesn't meet the minimum seeders: {}. Seeders:  "
                    "{}".format(cur_result.name, cur_result.seeders))
                continue

        # check if leechers meet out minimum requirements, disgard result if it does not
        if hasattr(cur_result.provider,
                   'minleech') and cur_result.leechers not in (-1, None):
            if int(cur_result.leechers) < int(cur_result.provider.minleech):
                sickrage.app.log.info(
                    "Discarding torrent because it doesn't meet the minimum leechers: {}. Leechers:  "
                    "{}".format(cur_result.name, cur_result.leechers))
                continue

        if show.rls_ignore_words and show_names.containsAtLeastOneWord(
                cur_result.name, cur_result.show.rls_ignore_words):
            sickrage.app.log.info("Ignoring " + cur_result.name +
                                  " based on ignored words filter: " +
                                  show.rls_ignore_words)
            continue

        if show.rls_require_words and not show_names.containsAtLeastOneWord(
                cur_result.name, cur_result.show.rls_require_words):
            sickrage.app.log.info("Ignoring " + cur_result.name +
                                  " based on required words filter: " +
                                  show.rls_require_words)
            continue

        if not show_names.filterBadReleases(cur_result.name, parse=False):
            sickrage.app.log.info(
                "Ignoring " + cur_result.name +
                " because its not a valid scene release that we want")
            continue

        if hasattr(cur_result, 'size'):
            if FailedHistory.hasFailed(cur_result.name, cur_result.size,
                                       cur_result.provider.name):
                sickrage.app.log.info(cur_result.name +
                                      " has previously failed, rejecting it")
                continue

            # quality definition video file size constraints check
            try:
                if cur_result.size:
                    quality_size = sickrage.app.config.quality_sizes[
                        cur_result.quality]
                    file_size = float(cur_result.size / 1000000)
                    if file_size > quality_size:
                        raise Exception(
                            "Ignoring " + cur_result.name +
                            " with size: {} based on quality size filter: {}".
                            format(file_size, quality_size))
            except Exception as e:
                sickrage.app.log.info(str(e))
                continue

        # verify result content
        if not cur_result.provider.private:
            if cur_result.resultType in [
                    "nzb", "torrent"
            ] and not cur_result.provider.get_content(cur_result.url):
                if sickrage.app.config.download_unverified_magnet_link and cur_result.url.startswith(
                        'magnet'):
                    # Attempt downloading unverified torrent magnet link
                    pass
                else:
                    sickrage.app.log.info(
                        "Ignoring {} because we are unable to verify the download url"
                        .format(cur_result.name))
                    continue

        if not bestResult:
            bestResult = cur_result
        elif cur_result.quality in bestQualities and (
                bestResult.quality < cur_result.quality
                or bestResult.quality not in bestQualities):
            bestResult = cur_result
        elif cur_result.quality in anyQualities and bestResult.quality not in bestQualities and bestResult.quality < cur_result.quality:
            bestResult = cur_result
        elif bestResult.quality == cur_result.quality:
            if "proper" in cur_result.name.lower(
            ) or "repack" in cur_result.name.lower():
                bestResult = cur_result
            elif "internal" in bestResult.name.lower(
            ) and "internal" not in cur_result.name.lower():
                bestResult = cur_result
            elif "xvid" in bestResult.name.lower(
            ) and "x264" in cur_result.name.lower():
                sickrage.app.log.info("Preferring " + cur_result.name +
                                      " (x264 over xvid)")
                bestResult = cur_result

    if bestResult:
        sickrage.app.log.debug("Picked " + bestResult.name + " as the best")
    else:
        sickrage.app.log.debug("No result picked.")

    return bestResult
Ejemplo n.º 18
0
def snatchEpisode(result, endStatus=SNATCHED):
    """
    Contains the internal logic necessary to actually "snatch" a result that
    has been found.

    :param result: SearchResult instance to be snatched.
    :param endStatus: the episode status that should be used for the episode object once it's snatched.
    :return: boolean, True on success
    """

    if result is None:
        return False

    result.priority = 0  # -1 = low, 0 = normal, 1 = high
    if sickrage.srCore.srConfig.ALLOW_HIGH_PRIORITY:
        # if it aired recently make it high priority
        for curEp in result.episodes:
            if date.today() - curEp.airdate <= timedelta(days=7):
                result.priority = 1

    if re.search(r'(^|[\. _-])(proper|repack)([\. _-]|$)', result.name, re.I) is not None:
        endStatus = SNATCHED_PROPER

    if result.url.startswith('magnet') or result.url.endswith('torrent'):
        result.resultType = 'torrent'

    dlResult = False
    if result.resultType in ("nzb", "nzbdata"):
        if sickrage.srCore.srConfig.NZB_METHOD == "blackhole":
            dlResult = _downloadResult(result)
        elif sickrage.srCore.srConfig.NZB_METHOD == "sabnzbd":
            dlResult = SabNZBd.sendNZB(result)
        elif sickrage.srCore.srConfig.NZB_METHOD == "nzbget":
            is_proper = True if endStatus == SNATCHED_PROPER else False
            dlResult = NZBGet.sendNZB(result, is_proper)
        else:
            sickrage.srCore.srLogger.error(
                "Unknown NZB action specified in config: " + sickrage.srCore.srConfig.NZB_METHOD)
    elif result.resultType == "torrent":
        if sickrage.srCore.srConfig.TORRENT_METHOD == "blackhole":
            dlResult = _downloadResult(result)
        else:
            if all([not result.content, not result.url.startswith('magnet:')]):
                result.content = sickrage.srCore.srWebSession.get(result.url).content

            if any([result.content, result.url.startswith('magnet:')]):
                # add public trackers to magnet url for non-private torrent providers
                if not result.provider.private and result.url.startswith('magnet:'):
                    result.url += '&tr='.join(
                        [x.strip() for x in sickrage.srCore.srConfig.TORRENT_TRACKERS.split(',') if x.strip()])

                client = getClientIstance(sickrage.srCore.srConfig.TORRENT_METHOD)()
                dlResult = client.sendTORRENT(result)
            else:
                sickrage.srCore.srLogger.warning("Torrent file content is empty")
    else:
        sickrage.srCore.srLogger.error("Unknown result type, unable to download it (%r)" % result.resultType)

    # no download results found
    if not dlResult:
        return False

    if sickrage.srCore.srConfig.USE_FAILED_DOWNLOADS:
        FailedHistory.logSnatch(result)

    sickrage.srCore.srNotifications.message('Episode snatched', result.name)

    History.logSnatch(result)

    # don't notify when we re-download an episode
    trakt_data = []
    for curEpObj in result.episodes:
        with curEpObj.lock:
            if isFirstBestMatch(result):
                curEpObj.status = Quality.compositeStatus(SNATCHED_BEST, result.quality)
            else:
                curEpObj.status = Quality.compositeStatus(endStatus, result.quality)

            # save episode to DB
            curEpObj.saveToDB()

        if curEpObj.status not in Quality.DOWNLOADED:
            try:
                srNotifiers.notify_snatch(
                    curEpObj._format_pattern('%SN - %Sx%0E - %EN - %QN') + " from " + result.provider.name)
            except:
                sickrage.srCore.srLogger.debug("Failed to send snatch notification")

            trakt_data.append((curEpObj.season, curEpObj.episode))

    data = sickrage.srCore.notifiersDict['trakt'].trakt_episode_data_generate(trakt_data)

    if sickrage.srCore.srConfig.USE_TRAKT and sickrage.srCore.srConfig.TRAKT_SYNC_WATCHLIST:
        sickrage.srCore.srLogger.debug(
            "Add episodes, showid: indexerid " + str(result.show.indexerid) + ", Title " + str(
                result.show.name) + " to Traktv Watchlist")
        if data:
            sickrage.srCore.notifiersDict['trakt'].update_watchlist(result.show, data_episode=data, update="add")

    return True
Ejemplo n.º 19
0
    def run(self, force=False):
        """
        Runs the daily searcher, queuing selected episodes for search
        :param force: Force search
        """
        if self.amActive:
            return

        self.amActive = True

        # set thread name
        threading.currentThread().setName(self.name)

        # trim failed download history
        if sickrage.srCore.srConfig.USE_FAILED_DOWNLOADS:
            FailedHistory.trimHistory()

        sickrage.srCore.srLogger.info("Searching for new released episodes ...")

        curDate = (datetime.date.today() + datetime.timedelta(days=2)).toordinal()
        if tz_updater.load_network_dict():
            curDate = (datetime.date.today() + datetime.timedelta(days=1)).toordinal()

        curTime = datetime.datetime.now(tz_updater.sr_timezone)

        show = None
        for dbData in [x['doc'] for x in sickrage.srCore.mainDB.db.all('tv_episodes', with_doc=True)
                       if x['doc']['status'] in [UNAIRED, WANTED]
                       and x['doc']['season'] > 0
                       and curDate >= x['doc']['airdate'] > 1]:
            try:
                if not show or int(dbData['showid']) != show.indexerid:
                    show = findCertainShow(sickrage.srCore.SHOWLIST, int(dbData['showid']))

                # for when there is orphaned series in the database but not loaded into our showlist
                if not show or show.paused:
                    continue

            except MultipleShowObjectsException:
                sickrage.srCore.srLogger.info("ERROR: expected to find a single show matching " + str(dbData['showid']))
                continue

            if show.airs and show.network:
                # This is how you assure it is always converted to local time
                air_time = tz_updater.parse_date_time(dbData['airdate'], show.airs, show.network,
                                                      dateOnly=True).astimezone(tz_updater.sr_timezone)

                # filter out any episodes that haven't started airing yet,
                # but set them to the default status while they are airing
                # so they are snatched faster
                if air_time > curTime:
                    continue

            ep = show.getEpisode(int(dbData['season']), int(dbData['episode']))
            with ep.lock:
                if ep.season == 0:
                    sickrage.srCore.srLogger.info(
                        "New episode " + ep.prettyName() + " airs today, setting status to SKIPPED because is a special season")
                    ep.status = SKIPPED
                else:
                    sickrage.srCore.srLogger.info(
                        "New episode %s airs today, setting to default episode status for this show: %s" % (
                            ep.prettyName(), statusStrings[ep.show.default_ep_status]))
                    ep.status = ep.show.default_ep_status

                ep.saveToDB()
        else:
            sickrage.srCore.srLogger.info("No new released episodes found ...")

        # queue episode for daily search
        sickrage.srCore.SEARCHQUEUE.put(DailySearchQueueItem())

        self.amActive = False
Ejemplo n.º 20
0
def snatch_episode(result, end_status=EpisodeStatus.SNATCHED):
    """
    Contains the internal logic necessary to actually "snatch" a result that
    has been found.

    :param result: SearchResult instance to be snatched.
    :param end_status: the episode status that should be used for the episode object once it's snatched.
    :return: boolean, True on success
    """

    if result is None:
        return False

    show_object = find_show(result.series_id, result.series_provider_id)

    result.priority = 0  # -1 = low, 0 = normal, 1 = high
    if sickrage.app.config.general.allow_high_priority:
        # if it aired recently make it high priority
        for episode_number in result.episodes:
            if date.today() - show_object.get_episode(result.season, episode_number).airdate <= timedelta(days=7):
                result.priority = 1

    if re.search(r'(^|[. _-])(proper|repack)([. _-]|$)', result.name, re.I) is not None:
        end_status = EpisodeStatus.SNATCHED_PROPER

    # get result content
    result.content = result.provider.get_content(result.url)

    dlResult = False
    if result.provider_type in (SearchProviderType.NZB, SearchProviderType.NZBDATA):
        if sickrage.app.config.general.nzb_method == NzbMethod.BLACKHOLE:
            dlResult = result.provider.download_result(result)
        elif sickrage.app.config.general.nzb_method == NzbMethod.SABNZBD:
            dlResult = SabNZBd.sendNZB(result)
        elif sickrage.app.config.general.nzb_method == NzbMethod.NZBGET:
            is_proper = True if end_status == EpisodeStatus.SNATCHED_PROPER else False
            dlResult = NZBGet.sendNZB(result, is_proper)
        elif sickrage.app.config.general.nzb_method == NzbMethod.DOWNLOAD_STATION:
            client = get_client_instance(sickrage.app.config.general.nzb_method.value, client_type='nzb')()
            dlResult = client.sendNZB(result)
    elif result.provider_type in (SearchProviderType.TORRENT, SearchProviderType.TORZNAB):
        # add public trackers to torrent result
        if not result.provider.private:
            result = result.provider.add_trackers(result)

        if sickrage.app.config.general.torrent_method == TorrentMethod.BLACKHOLE:
            dlResult = result.provider.download_result(result)
        else:
            if any([result.content, result.url.startswith('magnet:')]):
                client = get_client_instance(sickrage.app.config.general.torrent_method.value, client_type='torrent')()
                dlResult = client.send_torrent(result)
            else:
                sickrage.app.log.warning("Torrent file content is empty")
    else:
        sickrage.app.log.error("Unknown result type, unable to download it (%r)" % result.provider_type.display_name)

    # no download results found
    if not dlResult:
        return False

    FailedHistory.log_snatch(result)
    History.log_snatch(result)

    sickrage.app.alerts.message(_('Episode snatched'), result.name)

    trakt_data = []
    for episode_number in result.episodes:
        episode_obj = show_object.get_episode(result.season, episode_number)

        if is_first_best_match(result):
            episode_obj.status = Quality.composite_status(EpisodeStatus.SNATCHED_BEST, result.quality)
        else:
            episode_obj.status = Quality.composite_status(end_status, result.quality)

        episode_obj.save()

        # don't notify when we re-download an episode
        if episode_obj.status not in EpisodeStatus.composites(EpisodeStatus.DOWNLOADED):
            try:
                NotificationProvider.mass_notify_snatch(episode_obj._format_pattern('%SN - %Sx%0E - %EN - %QN') + " from " + result.provider.name)
            except Exception:
                sickrage.app.log.debug("Failed to send snatch notification")

            trakt_data.append((episode_obj.season, episode_obj.episode))

    data = sickrage.app.notification_providers['trakt'].trakt_episode_data_generate(trakt_data)

    if sickrage.app.config.trakt.enable and sickrage.app.config.trakt.sync_watchlist:
        if data:
            sickrage.app.notification_providers['trakt'].update_watchlist(show_object, data_episode=data, update="add")

    return True
Ejemplo n.º 21
0
    def run(self, force=False):
        """
        Runs the daily searcher, queuing selected episodes for search
        :param force: Force search
        """
        if self.amActive or sickrage.app.developer and not force:
            return

        self.amActive = True

        # set thread name
        threading.currentThread().setName(self.name)

        # trim failed download history
        if sickrage.app.config.use_failed_downloads:
            FailedHistory.trimHistory()

        sickrage.app.log.info("Searching for new released episodes")

        curDate = datetime.date.today()
        curDate += datetime.timedelta(days=2)
        if tz_updater.load_network_dict():
            curDate += datetime.timedelta(days=1)

        curTime = datetime.datetime.now(sickrage.app.tz)

        show = None

        episodes = [x['doc'] for x in sickrage.app.main_db.db.all('tv_episodes', with_doc=True)
                    if x['doc']['status'] == common.UNAIRED
                    and x['doc']['season'] > 0
                    and curDate.toordinal() >= x['doc']['airdate'] > 1]

        new_episodes = False
        for episode in episodes:
            if not show or int(episode["showid"]) != show.indexerid:
                show = findCertainShow(sickrage.app.showlist, int(episode["showid"]))

            # for when there is orphaned series in the database but not loaded into our showlist
            if not show or show.paused:
                continue

            if show.airs and show.network:
                # This is how you assure it is always converted to local time
                air_time = tz_updater.parse_date_time(
                    episode['airdate'], show.airs, show.network, dateOnly=True
                ).astimezone(sickrage.app.tz)

                # filter out any episodes that haven't started airing yet,
                # but set them to the default status while they are airing
                # so they are snatched faster
                if air_time > curTime: continue

            ep_obj = show.getEpisode(int(episode['season']), int(episode['episode']))
            with ep_obj.lock:
                ep_obj.status = show.default_ep_status if ep_obj.season else common.SKIPPED
                sickrage.app.log.info('Setting status ({status}) for show airing today: {name} {special}'.format(
                    name=ep_obj.pretty_name(),
                    status=common.statusStrings[ep_obj.status],
                    special='(specials are not supported)' if not ep_obj.season else '',
                ))

                ep_obj.saveToDB()
                new_episodes = True

        if not new_episodes:
            sickrage.app.log.info("No new released episodes found")

        # queue episode for daily search
        sickrage.app.search_queue.put(DailySearchQueueItem())

        self.amActive = False
Ejemplo n.º 22
0
    def run(self):
        self.started = True

        sickrage.app.search_queue.TASK_HISTORY[self.id] = {
            'season': self.season,
            'episode': self.episode
        }

        show_object = find_show(self.series_id, self.series_provider_id)
        if not show_object:
            return

        episode_object = show_object.get_episode(self.season, self.episode)

        try:
            sickrage.app.log.info("Starting failed download search for: [" +
                                  episode_object.name + "]")

            WebSocketMessage(
                'SEARCH_QUEUE_STATUS_UPDATED', {
                    'seriesSlug': show_object.slug,
                    'episodeId': episode_object.episode_id,
                    'searchQueueStatus': episode_object.search_queue_status
                }).push()

            sickrage.app.log.info("Marking episode as bad: [" +
                                  episode_object.pretty_name() + "]")

            FailedHistory.mark_failed(self.series_id, self.series_provider_id,
                                      self.season, self.episode)

            (release, provider) = FailedHistory.find_failed_release(
                self.series_id, self.series_provider_id, self.season,
                self.episode)
            if release:
                FailedHistory.log_failed(release)
                History.log_failed(self.series_id, self.series_provider_id,
                                   self.season, self.episode, release,
                                   provider)

            FailedHistory.revert_failed_episode(self.series_id,
                                                self.series_provider_id,
                                                self.season, self.episode)

            search_result = search_providers(self.series_id,
                                             self.series_provider_id,
                                             self.season,
                                             self.episode,
                                             manualSearch=True,
                                             downCurQuality=False)

            if search_result:
                snatch = all([(search_result.series_id, search_result.season,
                               episode)
                              not in sickrage.app.search_queue.SNATCH_HISTORY
                              for episode in search_result.episodes])

                if snatch:
                    [
                        sickrage.app.search_queue.SNATCH_HISTORY.append(
                            (search_result.series_id, search_result.season,
                             episode)) for episode in search_result.episodes
                    ]

                    sickrage.app.log.info("Downloading " + search_result.name +
                                          " from " +
                                          search_result.provider.name)
                    snatch_episode(search_result)
        except Exception:
            sickrage.app.log.debug(traceback.format_exc())
        finally:
            WebSocketMessage(
                'SEARCH_QUEUE_STATUS_UPDATED', {
                    'seriesSlug': show_object.slug,
                    'episodeId': episode_object.episode_id,
                    'searchQueueStatus': episode_object.search_queue_status
                }).push()

            sickrage.app.log.info("Finished failed download search for: [" +
                                  show_object.name + "]")
Ejemplo n.º 23
0
def snatchEpisode(result, endStatus=SNATCHED):
    """
    Contains the internal logic necessary to actually "snatch" a result that
    has been found.

    :param result: SearchResult instance to be snatched.
    :param endStatus: the episode status that should be used for the episode object once it's snatched.
    :return: boolean, True on success
    """

    if result is None:
        return False

    result.priority = 0  # -1 = low, 0 = normal, 1 = high
    if sickrage.app.config.allow_high_priority:
        # if it aired recently make it high priority
        for curEp in result.episodes:
            if date.today() - curEp.airdate <= timedelta(days=7):
                result.priority = 1

    if re.search(r'(^|[. _-])(proper|repack)([. _-]|$)', result.name, re.I) is not None:
        endStatus = SNATCHED_PROPER

    # get result content
    result.content = result.provider.get_content(result.url)

    dlResult = False
    if result.resultType in ("nzb", "nzbdata"):
        if sickrage.app.config.nzb_method == "blackhole":
            dlResult = result.provider.download_result(result)
        elif sickrage.app.config.nzb_method == "sabnzbd":
            dlResult = SabNZBd.sendNZB(result)
        elif sickrage.app.config.nzb_method == "nzbget":
            is_proper = True if endStatus == SNATCHED_PROPER else False
            dlResult = NZBGet.sendNZB(result, is_proper)
        else:
            sickrage.app.log.error("Unknown NZB action specified in config: " + sickrage.app.config.nzb_method)
    elif result.resultType in ("torrent", "torznab"):
        # add public trackers to torrent result
        if not result.provider.private:
            result = result.provider.add_trackers(result)

        if sickrage.app.config.torrent_method == "blackhole":
            dlResult = result.provider.download_result(result)
        else:
            if any([result.content, result.url.startswith('magnet:')]):
                client = getClientIstance(sickrage.app.config.torrent_method)()
                dlResult = client.send_torrent(result)
            else:
                sickrage.app.log.warning("Torrent file content is empty")
    else:
        sickrage.app.log.error("Unknown result type, unable to download it (%r)" % result.resultType)

    # no download results found
    if not dlResult:
        return False

    FailedHistory.logSnatch(result)

    sickrage.app.alerts.message(_('Episode snatched'), result.name)

    History.logSnatch(result)

    # don't notify when we re-download an episode
    trakt_data = []
    for curEpObj in result.episodes:
        with curEpObj.lock:
            if isFirstBestMatch(result):
                curEpObj.status = Quality.compositeStatus(SNATCHED_BEST, result.quality)
            else:
                curEpObj.status = Quality.compositeStatus(endStatus, result.quality)

            # save episode to DB
            curEpObj.save_to_db()

        if curEpObj.status not in Quality.DOWNLOADED:
            try:
                Notifiers.mass_notify_snatch(
                    curEpObj._format_pattern('%SN - %Sx%0E - %EN - %QN') + " from " + result.provider.name)
            except:
                sickrage.app.log.debug("Failed to send snatch notification")

            trakt_data.append((curEpObj.season, curEpObj.episode))

    data = sickrage.app.notifier_providers['trakt'].trakt_episode_data_generate(trakt_data)

    if sickrage.app.config.use_trakt and sickrage.app.config.trakt_sync_watchlist:
        sickrage.app.log.debug(
            "Add episodes, showid: indexerid " + str(result.show.indexerid) + ", Title " + str(
                result.show.name) + " to Traktv Watchlist")
        if data:
            sickrage.app.notifier_providers['trakt'].update_watchlist(result.show, data_episode=data, update="add")

    return True
Ejemplo n.º 24
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]

    sickrage.app.log.debug("Picking the best result out of " + str([x.name for x in results]))

    bestResult = None

    # find the best result for the current episode
    for cur_result in results:
        if show and cur_result.show is not show:
            continue

        # build the black And white list
        if show.is_anime:
            if not show.release_groups.is_valid(cur_result):
                continue

        sickrage.app.log.info(
            "Quality of " + cur_result.name + " is " + Quality.qualityStrings[cur_result.quality])

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

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

        # check if seeders meet out minimum requirements, disgard result if it does not
        if hasattr(cur_result.provider, 'minseed') and cur_result.seeders not in (-1, None):
            if int(cur_result.seeders) < min(cur_result.provider.minseed, 1):
                sickrage.app.log.info("Discarding torrent because it doesn't meet the minimum seeders: {}. Seeders:  "
                                      "{}".format(cur_result.name, cur_result.seeders))
                continue

        # check if leechers meet out minimum requirements, disgard result if it does not
        if hasattr(cur_result.provider, 'minleech') and cur_result.leechers not in (-1, None):
            if int(cur_result.leechers) < min(cur_result.provider.minleech, 0):
                sickrage.app.log.info("Discarding torrent because it doesn't meet the minimum leechers: {}. Leechers:  "
                                      "{}".format(cur_result.name, cur_result.leechers))
                continue

        if show.rls_ignore_words and show_names.containsAtLeastOneWord(cur_result.name,
                                                                       cur_result.show.rls_ignore_words):
            sickrage.app.log.info(
                "Ignoring " + cur_result.name + " based on ignored words filter: " + show.rls_ignore_words)
            continue

        if show.rls_require_words and not show_names.containsAtLeastOneWord(cur_result.name,
                                                                            cur_result.show.rls_require_words):
            sickrage.app.log.info(
                "Ignoring " + cur_result.name + " based on required words filter: " + show.rls_require_words)
            continue

        if not show_names.filterBadReleases(cur_result.name, parse=False):
            sickrage.app.log.info(
                "Ignoring " + cur_result.name + " because its not a valid scene release that we want")
            continue

        if hasattr(cur_result, 'size'):
            if FailedHistory.hasFailed(cur_result.name, cur_result.size, cur_result.provider.name):
                sickrage.app.log.info(cur_result.name + " has previously failed, rejecting it")
                continue

            # quality definition video file size constraints check
            try:
                if cur_result.size:
                    quality_size = sickrage.app.config.quality_sizes[cur_result.quality]
                    file_size = float(cur_result.size / 1000000)
                    if file_size > quality_size:
                        raise Exception(
                            "Ignoring " + cur_result.name + " with size: {} based on quality size filter: {}".format(
                                file_size, quality_size)
                        )
            except Exception as e:
                sickrage.app.log.info(str(e))
                continue

        # verify result content
        if not cur_result.provider.private:
            if cur_result.resultType in ["nzb", "torrent"] and not cur_result.provider.get_content(cur_result.url):
                if sickrage.app.config.download_unverified_magnet_link and cur_result.url.startswith('magnet'):
                    # Attempt downloading unverified torrent magnet link
                    pass
                else:
                    sickrage.app.log.info(
                        "Ignoring {} because we are unable to verify the download url".format(cur_result.name))
                    continue

        if not bestResult:
            bestResult = cur_result
        elif cur_result.quality in bestQualities and (
                bestResult.quality < cur_result.quality or bestResult.quality not in bestQualities):
            bestResult = cur_result
        elif cur_result.quality in anyQualities and bestResult.quality not in bestQualities and bestResult.quality < cur_result.quality:
            bestResult = cur_result
        elif bestResult.quality == cur_result.quality:
            if "proper" in cur_result.name.lower() or "repack" in cur_result.name.lower():
                bestResult = cur_result
            elif "internal" in bestResult.name.lower() and "internal" not in cur_result.name.lower():
                bestResult = cur_result
            elif "xvid" in bestResult.name.lower() and "x264" in cur_result.name.lower():
                sickrage.app.log.info("Preferring " + cur_result.name + " (x264 over xvid)")
                bestResult = cur_result

    if bestResult:
        sickrage.app.log.debug("Picked " + bestResult.name + " as the best")
    else:
        sickrage.app.log.debug("No result picked.")

    return bestResult
Ejemplo n.º 25
0
    def run(self, force=False):
        """
        Runs the daily searcher, queuing selected episodes for search
        :param force: Force search
        """
        if self.amActive:
            return

        self.amActive = True

        # trim failed download history
        if sickrage.USE_FAILED_DOWNLOADS:
            FailedHistory.trimHistory()

        sickrage.LOGGER.info("Searching for new released episodes ...")

        if tz_updater.network_dict:
            curDate = (datetime.date.today() + datetime.timedelta(days=1)).toordinal()
        else:
            curDate = (datetime.date.today() + datetime.timedelta(days=2)).toordinal()

        curTime = datetime.datetime.now(tz_updater.sr_timezone)

        sqlResults = main_db.MainDB().select(
                "SELECT * FROM tv_episodes WHERE status = ? AND season > 0 AND (airdate <= ? AND airdate > 1)",
                [UNAIRED, curDate])

        sql_l = []
        show = None

        for sqlEp in sqlResults:
            try:
                if not show or int(sqlEp[b"showid"]) != show.indexerid:
                    show = findCertainShow(sickrage.showList, int(sqlEp[b"showid"]))

                # for when there is orphaned series in the database but not loaded into our showlist
                if not show or show.paused:
                    continue

            except MultipleShowObjectsException:
                sickrage.LOGGER.info("ERROR: expected to find a single show matching " + str(sqlEp[b'showid']))
                continue

            if show.airs and show.network:
                # This is how you assure it is always converted to local time
                air_time = tz_updater.parse_date_time(sqlEp[b'airdate'], show.airs, show.network).astimezone(
                        tz_updater.sr_timezone)

                # filter out any episodes that haven't started airing yet,
                # but set them to the default status while they are airing
                # so they are snatched faster
                if air_time > curTime:
                    continue

            ep = show.getEpisode(int(sqlEp[b"season"]), int(sqlEp[b"episode"]))
            with ep.lock:
                if ep.season == 0:
                    sickrage.LOGGER.info(
                            "New episode " + ep.prettyName() + " airs today, setting status to SKIPPED because is a special season")
                    ep.status = SKIPPED
                else:
                    sickrage.LOGGER.info("New episode %s airs today, setting to default episode status for this show: %s" % (
                        ep.prettyName(), statusStrings[ep.show.default_ep_status]))
                    ep.status = ep.show.default_ep_status

                sql_l.append(ep.get_sql())

        if len(sql_l) > 0:
            main_db.MainDB().mass_action(sql_l)
        else:
            sickrage.LOGGER.info("No new released episodes found ...")

        # queue episode for daily search
        dailysearch_queue_item = DailySearchQueueItem()
        sickrage.SEARCHQUEUE.add_item(dailysearch_queue_item)

        self.amActive = False
Ejemplo n.º 26
0
    def run(self, force=False):
        """
        Runs the daily searcher, queuing selected episodes for search
        :param force: Force search
        """
        if self.amActive:
            return

        self.amActive = True

        # trim failed download history
        if sickrage.USE_FAILED_DOWNLOADS:
            FailedHistory.trimHistory()

        sickrage.LOGGER.info("Searching for new released episodes ...")

        if tz_updater.network_dict:
            curDate = (datetime.date.today() +
                       datetime.timedelta(days=1)).toordinal()
        else:
            curDate = (datetime.date.today() +
                       datetime.timedelta(days=2)).toordinal()

        curTime = datetime.datetime.now(tz_updater.sr_timezone)

        sqlResults = main_db.MainDB().select(
            "SELECT * FROM tv_episodes WHERE status = ? AND season > 0 AND (airdate <= ? AND airdate > 1)",
            [UNAIRED, curDate])

        sql_l = []
        show = None

        for sqlEp in sqlResults:
            try:
                if not show or int(sqlEp[b"showid"]) != show.indexerid:
                    show = findCertainShow(sickrage.showList,
                                           int(sqlEp[b"showid"]))

                # for when there is orphaned series in the database but not loaded into our showlist
                if not show or show.paused:
                    continue

            except MultipleShowObjectsException:
                sickrage.LOGGER.info(
                    "ERROR: expected to find a single show matching " +
                    str(sqlEp[b'showid']))
                continue

            if show.airs and show.network:
                # This is how you assure it is always converted to local time
                air_time = tz_updater.parse_date_time(
                    sqlEp[b'airdate'], show.airs,
                    show.network).astimezone(tz_updater.sr_timezone)

                # filter out any episodes that haven't started airing yet,
                # but set them to the default status while they are airing
                # so they are snatched faster
                if air_time > curTime:
                    continue

            ep = show.getEpisode(int(sqlEp[b"season"]), int(sqlEp[b"episode"]))
            with ep.lock:
                if ep.season == 0:
                    sickrage.LOGGER.info(
                        "New episode " + ep.prettyName() +
                        " airs today, setting status to SKIPPED because is a special season"
                    )
                    ep.status = SKIPPED
                else:
                    sickrage.LOGGER.info(
                        "New episode %s airs today, setting to default episode status for this show: %s"
                        % (ep.prettyName(),
                           statusStrings[ep.show.default_ep_status]))
                    ep.status = ep.show.default_ep_status

                sql_l.append(ep.get_sql())

        if len(sql_l) > 0:
            main_db.MainDB().mass_action(sql_l)
        else:
            sickrage.LOGGER.info("No new released episodes found ...")

        # queue episode for daily search
        dailysearch_queue_item = DailySearchQueueItem()
        sickrage.SEARCHQUEUE.add_item(dailysearch_queue_item)

        self.amActive = False
Ejemplo n.º 27
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]

    sickrage.LOGGER.debug("Picking the best result out of " +
                          str([x.name for x in results]))

    bestResult = None

    # find the best result for the current episode
    for cur_result in results:
        if show and cur_result.show is not show:
            continue

        # build the black And white list
        if show.is_anime:
            if not show.release_groups.is_valid(cur_result):
                continue

        sickrage.LOGGER.info("Quality of " + cur_result.name + " is " +
                             Quality.qualityStrings[cur_result.quality])

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

        if cur_result.quality not in anyQualities + bestQualities:
            sickrage.LOGGER.debug(
                cur_result.name +
                " is a quality we know we don't want, rejecting it")
            continue

        if show.rls_ignore_words and show_names.containsAtLeastOneWord(
                cur_result.name, cur_result.show.rls_ignore_words):
            sickrage.LOGGER.info("Ignoring " + cur_result.name +
                                 " based on ignored words filter: " +
                                 show.rls_ignore_words)
            continue

        if show.rls_require_words and not show_names.containsAtLeastOneWord(
                cur_result.name, cur_result.show.rls_require_words):
            sickrage.LOGGER.info("Ignoring " + cur_result.name +
                                 " based on required words filter: " +
                                 show.rls_require_words)
            continue

        if not show_names.filterBadReleases(cur_result.name, parse=False):
            sickrage.LOGGER.info(
                "Ignoring " + cur_result.name +
                " because its not a valid scene release that we want, ignoring it"
            )
            continue

        if hasattr(cur_result, 'size'):
            if sickrage.USE_FAILED_DOWNLOADS and FailedHistory.hasFailed(
                    cur_result.name, cur_result.size,
                    cur_result.provider.name):
                sickrage.LOGGER.info(cur_result.name +
                                     " has previously failed, rejecting it")
                continue

        if not bestResult:
            bestResult = cur_result
        elif cur_result.quality in bestQualities and (
                bestResult.quality < cur_result.quality
                or bestResult.quality not in bestQualities):
            bestResult = cur_result
        elif cur_result.quality in anyQualities and bestResult.quality not in bestQualities and bestResult.quality < cur_result.quality:
            bestResult = cur_result
        elif bestResult.quality == cur_result.quality:
            if "proper" in cur_result.name.lower(
            ) or "repack" in cur_result.name.lower():
                bestResult = cur_result
            elif "internal" in bestResult.name.lower(
            ) and "internal" not in cur_result.name.lower():
                bestResult = cur_result
            elif "xvid" in bestResult.name.lower(
            ) and "x264" in cur_result.name.lower():
                sickrage.LOGGER.info("Preferring " + cur_result.name +
                                     " (x264 over xvid)")
                bestResult = cur_result

    if bestResult:
        sickrage.LOGGER.debug("Picked " + bestResult.name + " as the best")
    else:
        sickrage.LOGGER.debug("No result picked.")

    return bestResult
Ejemplo n.º 28
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]

    sickrage.srCore.srLogger.debug("Picking the best result out of " + str([x.name for x in results]))

    bestResult = None

    # find the best result for the current episode
    for cur_result in results:
        if show and cur_result.show is not show:
            continue

        # build the black And white list
        if show.is_anime:
            if not show.release_groups.is_valid(cur_result):
                continue

        sickrage.srCore.srLogger.info(
            "Quality of " + cur_result.name + " is " + Quality.qualityStrings[cur_result.quality])

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

        if cur_result.quality not in anyQualities + bestQualities:
            sickrage.srCore.srLogger.debug(cur_result.name + " is a quality we know we don't want, rejecting it")
            continue

        if show.rls_ignore_words and show_names.containsAtLeastOneWord(cur_result.name,
                                                                       cur_result.show.rls_ignore_words):
            sickrage.srCore.srLogger.info(
                "Ignoring " + cur_result.name + " based on ignored words filter: " + show.rls_ignore_words)
            continue

        if show.rls_require_words and not show_names.containsAtLeastOneWord(cur_result.name,
                                                                            cur_result.show.rls_require_words):
            sickrage.srCore.srLogger.info(
                "Ignoring " + cur_result.name + " based on required words filter: " + show.rls_require_words)
            continue

        if not show_names.filterBadReleases(cur_result.name, parse=False):
            sickrage.srCore.srLogger.info(
                "Ignoring " + cur_result.name + " because its not a valid scene release that we want, ignoring it")
            continue

        if hasattr(cur_result, 'size'):
            if sickrage.srCore.srConfig.USE_FAILED_DOWNLOADS and FailedHistory.hasFailed(cur_result.name,
                                                                                         cur_result.size,
                                                                                         cur_result.provider.name):
                sickrage.srCore.srLogger.info(cur_result.name + " has previously failed, rejecting it")
                continue

        # quality definition video file size constraints check
        try:
            quality_size = sickrage.srCore.srConfig.QUALITY_SIZES[cur_result.quality]
            for file, file_size in cur_result.files.items():
                if not file.endswith(tuple(video_exts)):
                    continue

                file_size = float(file_size / 1000000)
                if file_size > quality_size:
                    raise Exception(
                        "Ignoring " + cur_result.name + " with size: {} based on quality size filter: {}, ignoring it".format(
                            file_size, quality_size)
                    )
        except Exception as e:
            sickrage.srCore.srLogger.info(e.message)
            continue

        if not bestResult:
            bestResult = cur_result
        elif cur_result.quality in bestQualities and (
                        bestResult.quality < cur_result.quality or bestResult.quality not in bestQualities):
            bestResult = cur_result
        elif cur_result.quality in anyQualities and bestResult.quality not in bestQualities and bestResult.quality < cur_result.quality:
            bestResult = cur_result
        elif bestResult.quality == cur_result.quality:
            if "proper" in cur_result.name.lower() or "repack" in cur_result.name.lower():
                bestResult = cur_result
            elif "internal" in bestResult.name.lower() and "internal" not in cur_result.name.lower():
                bestResult = cur_result
            elif "xvid" in bestResult.name.lower() and "x264" in cur_result.name.lower():
                sickrage.srCore.srLogger.info("Preferring " + cur_result.name + " (x264 over xvid)")
                bestResult = cur_result

    if bestResult:
        sickrage.srCore.srLogger.debug("Picked " + bestResult.name + " as the best")
    else:
        sickrage.srCore.srLogger.debug("No result picked.")

    return bestResult
Ejemplo n.º 29
0
def snatchEpisode(result, endStatus=SNATCHED):
    """
    Contains the internal logic necessary to actually "snatch" a result that
    has been found.

    :param result: SearchResult instance to be snatched.
    :param endStatus: the episode status that should be used for the episode object once it's snatched.
    :return: boolean, True on success
    """

    if result is None:
        return False

    result.priority = 0  # -1 = low, 0 = normal, 1 = high
    if sickrage.ALLOW_HIGH_PRIORITY:
        # if it aired recently make it high priority
        for curEp in result.episodes:
            if datetime.date.today() - curEp.airdate <= datetime.timedelta(
                    days=7):
                result.priority = 1
    if re.search(r'(^|[\. _-])(proper|repack)([\. _-]|$)', result.name,
                 re.I) is not None:
        endStatus = SNATCHED_PROPER

    if result.url.startswith('magnet') or result.url.endswith('torrent'):
        result.resultType = 'torrent'

    # NZBs can be sent straight to SAB or saved to disk
    if result.resultType in ("nzb", "nzbdata"):
        if sickrage.NZB_METHOD == "blackhole":
            dlResult = _downloadResult(result)
        elif sickrage.NZB_METHOD == "sabnzbd":
            dlResult = SabNZBd.sendNZB(result)
        elif sickrage.NZB_METHOD == "nzbget":
            is_proper = True if endStatus == SNATCHED_PROPER else False
            dlResult = NZBGet.sendNZB(result, is_proper)
        else:
            sickrage.LOGGER.error("Unknown NZB action specified in config: " +
                                  sickrage.NZB_METHOD)
            dlResult = False

    # TORRENTs can be sent to clients or saved to disk
    elif result.resultType == "torrent":
        # torrents are saved to disk when blackhole mode
        if sickrage.TORRENT_METHOD == "blackhole":
            dlResult = _downloadResult(result)
        else:
            if not result.content and not result.url.startswith('magnet'):
                result.content = result.provider.getURL(result.url,
                                                        needBytes=True)

            if result.content or result.url.startswith('magnet'):
                client = getClientIstance(sickrage.TORRENT_METHOD)()
                dlResult = client.sendTORRENT(result)
            else:
                sickrage.LOGGER.warning("Torrent file content is empty")
                dlResult = False
    else:
        sickrage.LOGGER.error(
            "Unknown result type, unable to download it (%r)" %
            result.resultType)
        dlResult = False

    if not dlResult:
        return False

    if sickrage.USE_FAILED_DOWNLOADS:
        FailedHistory.logSnatch(result)

    notifications.message('Episode snatched', result.name)

    History.logSnatch(result)

    # don't notify when we re-download an episode
    sql_l = []
    trakt_data = []
    for curEpObj in result.episodes:
        with curEpObj.lock:
            if isFirstBestMatch(result):
                curEpObj.status = Quality.compositeStatus(
                    SNATCHED_BEST, result.quality)
            else:
                curEpObj.status = Quality.compositeStatus(
                    endStatus, result.quality)

            sql_l.append(curEpObj.get_sql())

        if curEpObj.status not in Quality.DOWNLOADED:
            try:
                notify_snatch(
                    curEpObj._format_pattern('%SN - %Sx%0E - %EN - %QN') +
                    " from " + result.provider.name)
            except:
                sickrage.LOGGER.debug("Failed to send snatch notification")

            trakt_data.append((curEpObj.season, curEpObj.episode))

    data = sickrage.NOTIFIERS.trakt_notifier.trakt_episode_data_generate(
        trakt_data)

    if sickrage.USE_TRAKT and sickrage.TRAKT_SYNC_WATCHLIST:
        sickrage.LOGGER.debug("Add episodes, showid: indexerid " +
                              str(result.show.indexerid) + ", Title " +
                              str(result.show.name) + " to Traktv Watchlist")
        if data:
            sickrage.NOTIFIERS.trakt_notifier.update_watchlist(
                result.show, data_episode=data, update="add")

    if len(sql_l) > 0:
        main_db.MainDB().mass_action(sql_l)

    return True
Ejemplo n.º 30
0
def pick_best_result(results, season_pack=False):
    """
    Find the best result out of a list of search results for a show

    :param results: list of result objects
    :param series_id: Show ID we check for
    :return: best result object
    """

    results = results if isinstance(results, list) else [results]

    sickrage.app.log.debug("Picking the best result out of " + str([x.name for x in results]))

    best_result = None

    # find the best result for the current episode
    for cur_result in results:
        show_obj = find_show(cur_result.series_id, cur_result.series_provider_id)

        # build the black And white list
        if show_obj.is_anime:
            if not show_obj.release_groups.is_valid(cur_result):
                continue

        sickrage.app.log.info("Quality of " + cur_result.name + " is " + cur_result.quality.display_name)

        any_qualities, best_qualities = Quality.split_quality(show_obj.quality)
        if cur_result.quality not in any_qualities + best_qualities:
            sickrage.app.log.debug(cur_result.name + " is a quality we know we don't want, rejecting it")
            continue

        # check if seeders meet out minimum requirements, disgard result if it does not
        if cur_result.provider.custom_settings.get('minseed', 0) and cur_result.seeders not in (-1, None):
            if int(cur_result.seeders) < min(cur_result.provider.custom_settings.get('minseed', 0), 1):
                sickrage.app.log.info("Discarding torrent because it doesn't meet the minimum seeders: {}. Seeders:  "
                                      "{}".format(cur_result.name, cur_result.seeders))
                continue

        # check if leechers meet out minimum requirements, disgard result if it does not
        if cur_result.provider.custom_settings.get('minleech', 0) and cur_result.leechers not in (-1, None):
            if int(cur_result.leechers) < min(cur_result.provider.custom_settings.get('minleech', 0), 0):
                sickrage.app.log.info("Discarding torrent because it doesn't meet the minimum leechers: {}. Leechers:  "
                                      "{}".format(cur_result.name, cur_result.leechers))
                continue

        if show_obj.rls_ignore_words and show_names.contains_at_least_one_word(cur_result.name, show_obj.rls_ignore_words):
            sickrage.app.log.info("Ignoring " + cur_result.name + " based on ignored words filter: " + show_obj.rls_ignore_words)
            continue

        if show_obj.rls_require_words and not show_names.contains_at_least_one_word(cur_result.name, show_obj.rls_require_words):
            sickrage.app.log.info("Ignoring " + cur_result.name + " based on required words filter: " + show_obj.rls_require_words)
            continue

        if not show_names.filter_bad_releases(cur_result.name, parse=False):
            sickrage.app.log.info("Ignoring " + cur_result.name + " because its not a valid scene release that we want")
            continue

        if hasattr(cur_result, 'size'):
            if FailedHistory.has_failed(cur_result.name, cur_result.size, cur_result.provider.name):
                sickrage.app.log.info(cur_result.name + " has previously failed, rejecting it")
                continue

            # quality definition video file size constraints check
            try:
                if cur_result.size:
                    quality_size_min = sickrage.app.config.quality_sizes[cur_result.quality.name].min_size
                    quality_size_max = sickrage.app.config.quality_sizes[cur_result.quality.name].max_size

                    if quality_size_min != 0 and quality_size_max != 0:
                        if season_pack and not len(cur_result.episodes):
                            episode_count = len([x for x in show_obj.episodes if x.season == cur_result.season])
                            file_size = float(cur_result.size / episode_count / 1000000)
                        else:
                            file_size = float(cur_result.size / len(cur_result.episodes) / 1000000)

                        if quality_size_min > file_size > quality_size_max:
                            raise Exception("Ignoring " + cur_result.name + " with size {}".format(file_size))
            except Exception as e:
                sickrage.app.log.info(e)
                continue

        # verify result content
        # if not cur_result.provider.private:
        #     if cur_result.provider_type in ["nzb", "torrent"] and not cur_result.provider.get_content(cur_result.url):
        #         if not sickrage.app.config.general.download_unverified_magnet_link and cur_result.url.startswith('magnet'):
        #             sickrage.app.log.info("Ignoring {} because we are unable to verify the download url".format(cur_result.name))
        #             continue

        if not best_result:
            best_result = cur_result
        elif cur_result.quality in best_qualities and (
                best_result.quality < cur_result.quality or best_result.quality not in best_qualities):
            best_result = cur_result
        elif cur_result.quality in any_qualities and best_result.quality not in best_qualities and best_result.quality < cur_result.quality:
            best_result = cur_result
        elif best_result.quality == cur_result.quality:
            if "proper" in cur_result.name.lower() or "repack" in cur_result.name.lower():
                best_result = cur_result
            elif "internal" in best_result.name.lower() and "internal" not in cur_result.name.lower():
                best_result = cur_result
            elif "xvid" in best_result.name.lower() and "x264" in cur_result.name.lower():
                sickrage.app.log.info("Preferring " + cur_result.name + " (x264 over xvid)")
                best_result = cur_result

    if best_result:
        sickrage.app.log.debug("Picked " + best_result.name + " as the best")
    else:
        sickrage.app.log.debug("No result picked.")

    return best_result
Ejemplo n.º 31
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]

    sickrage.srCore.srLogger.debug("Picking the best result out of " + str([x.name for x in results]))

    bestResult = None

    # find the best result for the current episode
    for cur_result in results:
        if show and cur_result.show is not show:
            continue

        # build the black And white list
        if show.is_anime:
            if not show.release_groups.is_valid(cur_result):
                continue

        sickrage.srCore.srLogger.info(
            "Quality of " + cur_result.name + " is " + Quality.qualityStrings[cur_result.quality])

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

        if cur_result.quality not in anyQualities + bestQualities:
            sickrage.srCore.srLogger.debug(cur_result.name + " is a quality we know we don't want, rejecting it")
            continue

        if show.rls_ignore_words and show_names.containsAtLeastOneWord(cur_result.name,
                                                                       cur_result.show.rls_ignore_words):
            sickrage.srCore.srLogger.info(
                "Ignoring " + cur_result.name + " based on ignored words filter: " + show.rls_ignore_words)
            continue

        if show.rls_require_words and not show_names.containsAtLeastOneWord(cur_result.name,
                                                                            cur_result.show.rls_require_words):
            sickrage.srCore.srLogger.info(
                "Ignoring " + cur_result.name + " based on required words filter: " + show.rls_require_words)
            continue

        if not show_names.filterBadReleases(cur_result.name, parse=False):
            sickrage.srCore.srLogger.info(
                "Ignoring " + cur_result.name + " because its not a valid scene release that we want, ignoring it")
            continue

        if hasattr(cur_result, 'size'):
            if sickrage.srCore.srConfig.USE_FAILED_DOWNLOADS and FailedHistory.hasFailed(cur_result.name,
                                                                                         cur_result.size,
                                                                                         cur_result.provider.name):
                sickrage.srCore.srLogger.info(cur_result.name + " has previously failed, rejecting it")
                continue

        if not bestResult:
            bestResult = cur_result
        elif cur_result.quality in bestQualities and (
                        bestResult.quality < cur_result.quality or bestResult.quality not in bestQualities):
            bestResult = cur_result
        elif cur_result.quality in anyQualities and bestResult.quality not in bestQualities and bestResult.quality < cur_result.quality:
            bestResult = cur_result
        elif bestResult.quality == cur_result.quality:
            if "proper" in cur_result.name.lower() or "repack" in cur_result.name.lower():
                bestResult = cur_result
            elif "internal" in bestResult.name.lower() and "internal" not in cur_result.name.lower():
                bestResult = cur_result
            elif "xvid" in bestResult.name.lower() and "x264" in cur_result.name.lower():
                sickrage.srCore.srLogger.info("Preferring " + cur_result.name + " (x264 over xvid)")
                bestResult = cur_result

    if bestResult:
        sickrage.srCore.srLogger.debug("Picked " + bestResult.name + " as the best")
    else:
        sickrage.srCore.srLogger.debug("No result picked.")

    return bestResult
Ejemplo n.º 32
0
    def run(self, force=False):
        """
        Runs the daily searcher, queuing selected episodes for search
        :param force: Force search
        """
        if self.amActive:
            return

        self.amActive = True

        # set thread name
        threading.currentThread().setName(self.name)

        # trim failed download history
        if sickrage.srCore.srConfig.USE_FAILED_DOWNLOADS:
            FailedHistory.trimHistory()

        sickrage.srCore.srLogger.info(
            "Searching for new released episodes ...")

        curDate = (datetime.date.today() +
                   datetime.timedelta(days=2)).toordinal()
        if tz_updater.load_network_dict():
            curDate = (datetime.date.today() +
                       datetime.timedelta(days=1)).toordinal()

        curTime = datetime.datetime.now(tz_updater.sr_timezone)

        show = None
        for dbData in [
                x['doc'] for x in MainDB().db.all('tv_episodes', with_doc=True)
                if x['doc']['status'] in [UNAIRED, WANTED] and
                x['doc']['season'] > 0 and curDate >= x['doc']['airdate'] > 1
        ]:
            try:
                if not show or int(dbData['showid']) != show.indexerid:
                    show = findCertainShow(sickrage.srCore.SHOWLIST,
                                           int(dbData['showid']))

                # for when there is orphaned series in the database but not loaded into our showlist
                if not show or show.paused:
                    continue

            except MultipleShowObjectsException:
                sickrage.srCore.srLogger.info(
                    "ERROR: expected to find a single show matching " +
                    str(dbData['showid']))
                continue

            if show.airs and show.network:
                # This is how you assure it is always converted to local time
                air_time = tz_updater.parse_date_time(
                    dbData['airdate'], show.airs, show.network,
                    dateOnly=True).astimezone(tz_updater.sr_timezone)

                # filter out any episodes that haven't started airing yet,
                # but set them to the default status while they are airing
                # so they are snatched faster
                if air_time > curTime:
                    continue

            ep = show.getEpisode(int(dbData['season']), int(dbData['episode']))
            with ep.lock:
                if ep.season == 0:
                    sickrage.srCore.srLogger.info(
                        "New episode " + ep.prettyName() +
                        " airs today, setting status to SKIPPED because is a special season"
                    )
                    ep.status = SKIPPED
                else:
                    sickrage.srCore.srLogger.info(
                        "New episode %s airs today, setting to default episode status for this show: %s"
                        % (ep.prettyName(),
                           statusStrings[ep.show.default_ep_status]))
                    ep.status = ep.show.default_ep_status

                ep.saveToDB()
        else:
            sickrage.srCore.srLogger.info("No new released episodes found ...")

        # queue episode for daily search
        sickrage.srCore.SEARCHQUEUE.put(DailySearchQueueItem())

        self.amActive = False
Ejemplo n.º 33
0
def snatchEpisode(result, endStatus=SNATCHED):
    """
    Contains the internal logic necessary to actually "snatch" a result that
    has been found.

    :param result: SearchResult instance to be snatched.
    :param endStatus: the episode status that should be used for the episode object once it's snatched.
    :return: boolean, True on success
    """

    if result is None:
        return False

    result.priority = 0  # -1 = low, 0 = normal, 1 = high
    if sickrage.srCore.srConfig.ALLOW_HIGH_PRIORITY:
        # if it aired recently make it high priority
        for curEp in result.episodes:
            if date.today() - curEp.airdate <= timedelta(days=7):
                result.priority = 1

    if re.search(r'(^|[\. _-])(proper|repack)([\. _-]|$)', result.name, re.I) is not None:
        endStatus = SNATCHED_PROPER

    if result.url.startswith('magnet') or result.url.endswith('torrent'):
        result.resultType = 'torrent'

    dlResult = False
    if result.resultType in ("nzb", "nzbdata"):
        if sickrage.srCore.srConfig.NZB_METHOD == "blackhole":
            dlResult = _downloadResult(result)
        elif sickrage.srCore.srConfig.NZB_METHOD == "sabnzbd":
            dlResult = SabNZBd.sendNZB(result)
        elif sickrage.srCore.srConfig.NZB_METHOD == "nzbget":
            is_proper = True if endStatus == SNATCHED_PROPER else False
            dlResult = NZBGet.sendNZB(result, is_proper)
        else:
            sickrage.srCore.srLogger.error(
                "Unknown NZB action specified in config: " + sickrage.srCore.srConfig.NZB_METHOD)
    elif result.resultType == "torrent":
        if sickrage.srCore.srConfig.TORRENT_METHOD == "blackhole":
            dlResult = _downloadResult(result)
        else:
            if all([not result.content, not result.url.startswith('magnet:')]):
                result.content = sickrage.srCore.srWebSession.get(result.url).content

            if any([result.content, result.url.startswith('magnet:')]):
                # add public trackers to magnet url for non-private torrent providers
                if not result.provider.private and result.url.startswith('magnet:'):
                    result.url += '&tr='.join(
                        [x.strip() for x in sickrage.srCore.srConfig.TORRENT_TRACKERS.split(',') if x.strip()])

                client = getClientIstance(sickrage.srCore.srConfig.TORRENT_METHOD)()
                dlResult = client.sendTORRENT(result)
            else:
                sickrage.srCore.srLogger.warning("Torrent file content is empty")
    else:
        sickrage.srCore.srLogger.error("Unknown result type, unable to download it (%r)" % result.resultType)

    # no download results found
    if not dlResult:
        return False

    if sickrage.srCore.srConfig.USE_FAILED_DOWNLOADS:
        FailedHistory.logSnatch(result)

    sickrage.srCore.srNotifications.message('Episode snatched', result.name)

    History.logSnatch(result)

    # don't notify when we re-download an episode
    sql_l = []
    trakt_data = []
    for curEpObj in result.episodes:
        with curEpObj.lock:
            if isFirstBestMatch(result):
                curEpObj.status = Quality.compositeStatus(SNATCHED_BEST, result.quality)
            else:
                curEpObj.status = Quality.compositeStatus(endStatus, result.quality)

            sql_q = curEpObj.saveToDB(False)
            if sql_q:
                sql_l.append(sql_q)

        if curEpObj.status not in Quality.DOWNLOADED:
            try:
                srNotifiers.notify_snatch(
                    curEpObj._format_pattern('%SN - %Sx%0E - %EN - %QN') + " from " + result.provider.name)
            except:
                sickrage.srCore.srLogger.debug("Failed to send snatch notification")

            trakt_data.append((curEpObj.season, curEpObj.episode))

    data = sickrage.srCore.notifiersDict.trakt_notifier.trakt_episode_data_generate(trakt_data)

    if sickrage.srCore.srConfig.USE_TRAKT and sickrage.srCore.srConfig.TRAKT_SYNC_WATCHLIST:
        sickrage.srCore.srLogger.debug(
            "Add episodes, showid: indexerid " + str(result.show.indexerid) + ", Title " + str(
                result.show.name) + " to Traktv Watchlist")
        if data:
            sickrage.srCore.notifiersDict.trakt_notifier.update_watchlist(result.show, data_episode=data, update="add")

    if len(sql_l) > 0:
        main_db.MainDB().mass_upsert(sql_l)
        del sql_l  # cleanup

    return True
Ejemplo n.º 34
0
def snatchEpisode(result, endStatus=SNATCHED):
    """
    Contains the internal logic necessary to actually "snatch" a result that
    has been found.

    :param result: SearchResult instance to be snatched.
    :param endStatus: the episode status that should be used for the episode object once it's snatched.
    :return: boolean, True on success
    """

    if result is None:
        return False

    result.priority = 0  # -1 = low, 0 = normal, 1 = high
    if sickrage.app.config.allow_high_priority:
        # if it aired recently make it high priority
        for curEp in result.episodes:
            if date.today() - curEp.airdate <= timedelta(days=7):
                result.priority = 1

    if re.search(r'(^|[. _-])(proper|repack)([. _-]|$)', result.name,
                 re.I) is not None:
        endStatus = SNATCHED_PROPER

    # get result content
    result.content = result.provider.get_content(result.url)

    dlResult = False
    if result.resultType in ("nzb", "nzbdata"):
        if sickrage.app.config.nzb_method == "blackhole":
            dlResult = result.provider.download_result(result)
        elif sickrage.app.config.nzb_method == "sabnzbd":
            dlResult = SabNZBd.sendNZB(result)
        elif sickrage.app.config.nzb_method == "nzbget":
            is_proper = True if endStatus == SNATCHED_PROPER else False
            dlResult = NZBGet.sendNZB(result, is_proper)
        else:
            sickrage.app.log.error("Unknown NZB action specified in config: " +
                                   sickrage.app.config.nzb_method)
    elif result.resultType in ("torrent", "torznab"):
        # add public trackers to torrent result
        if not result.provider.private:
            result = result.provider.add_trackers(result)

        if sickrage.app.config.torrent_method == "blackhole":
            dlResult = result.provider.download_result(result)
        else:
            if any([result.content, result.url.startswith('magnet:')]):
                client = getClientIstance(sickrage.app.config.torrent_method)()
                dlResult = client.send_torrent(result)
            else:
                sickrage.app.log.warning("Torrent file content is empty")
    else:
        sickrage.app.log.error(
            "Unknown result type, unable to download it (%r)" %
            result.resultType)

    # no download results found
    if not dlResult:
        return False

    FailedHistory.logSnatch(result)

    sickrage.app.alerts.message(_('Episode snatched'), result.name)

    History.logSnatch(result)

    # don't notify when we re-download an episode
    trakt_data = []
    for curEpObj in result.episodes:
        with curEpObj.lock:
            if isFirstBestMatch(result):
                curEpObj.status = Quality.compositeStatus(
                    SNATCHED_BEST, result.quality)
            else:
                curEpObj.status = Quality.compositeStatus(
                    endStatus, result.quality)

            # save episode to DB
            curEpObj.save_to_db()

        if curEpObj.status not in Quality.DOWNLOADED:
            try:
                Notifiers.mass_notify_snatch(
                    curEpObj._format_pattern('%SN - %Sx%0E - %EN - %QN') +
                    " from " + result.provider.name)
            except:
                sickrage.app.log.debug("Failed to send snatch notification")

            trakt_data.append((curEpObj.season, curEpObj.episode))

    data = sickrage.app.notifier_providers[
        'trakt'].trakt_episode_data_generate(trakt_data)

    if sickrage.app.config.use_trakt and sickrage.app.config.trakt_sync_watchlist:
        sickrage.app.log.debug("Add episodes, showid: indexerid " +
                               str(result.show.indexerid) + ", Title " +
                               str(result.show.name) + " to Traktv Watchlist")
        if data:
            sickrage.app.notifier_providers['trakt'].update_watchlist(
                result.show, data_episode=data, update="add")

    return True
Ejemplo n.º 35
0
def snatchEpisode(result, endStatus=SNATCHED):
    """
    Contains the internal logic necessary to actually "snatch" a result that
    has been found.

    :param result: SearchResult instance to be snatched.
    :param endStatus: the episode status that should be used for the episode object once it's snatched.
    :return: boolean, True on success
    """

    if result is None:
        return False

    result.priority = 0  # -1 = low, 0 = normal, 1 = high
    if sickrage.ALLOW_HIGH_PRIORITY:
        # if it aired recently make it high priority
        for curEp in result.episodes:
            if datetime.date.today() - curEp.airdate <= datetime.timedelta(days=7):
                result.priority = 1
    if re.search(r"(^|[\. _-])(proper|repack)([\. _-]|$)", result.name, re.I) is not None:
        endStatus = SNATCHED_PROPER

    if result.url.startswith("magnet") or result.url.endswith("torrent"):
        result.resultType = "torrent"

    # NZBs can be sent straight to SAB or saved to disk
    if result.resultType in ("nzb", "nzbdata"):
        if sickrage.NZB_METHOD == "blackhole":
            dlResult = _downloadResult(result)
        elif sickrage.NZB_METHOD == "sabnzbd":
            dlResult = SabNZBd.sendNZB(result)
        elif sickrage.NZB_METHOD == "nzbget":
            is_proper = True if endStatus == SNATCHED_PROPER else False
            dlResult = NZBGet.sendNZB(result, is_proper)
        else:
            sickrage.LOGGER.error("Unknown NZB action specified in config: " + sickrage.NZB_METHOD)
            dlResult = False

    # TORRENTs can be sent to clients or saved to disk
    elif result.resultType == "torrent":
        # torrents are saved to disk when blackhole mode
        if sickrage.TORRENT_METHOD == "blackhole":
            dlResult = _downloadResult(result)
        else:
            if not result.content and not result.url.startswith("magnet"):
                result.content = result.provider.getURL(result.url, needBytes=True)

            if result.content or result.url.startswith("magnet"):
                client = getClientIstance(sickrage.TORRENT_METHOD)()
                dlResult = client.sendTORRENT(result)
            else:
                sickrage.LOGGER.warning("Torrent file content is empty")
                dlResult = False
    else:
        sickrage.LOGGER.error("Unknown result type, unable to download it (%r)" % result.resultType)
        dlResult = False

    if not dlResult:
        return False

    if sickrage.USE_FAILED_DOWNLOADS:
        FailedHistory.logSnatch(result)

    notifications.message("Episode snatched", result.name)

    History.logSnatch(result)

    # don't notify when we re-download an episode
    sql_l = []
    trakt_data = []
    for curEpObj in result.episodes:
        with curEpObj.lock:
            if isFirstBestMatch(result):
                curEpObj.status = Quality.compositeStatus(SNATCHED_BEST, result.quality)
            else:
                curEpObj.status = Quality.compositeStatus(endStatus, result.quality)

            sql_l.append(curEpObj.get_sql())

        if curEpObj.status not in Quality.DOWNLOADED:
            try:
                notify_snatch(curEpObj._format_pattern("%SN - %Sx%0E - %EN - %QN") + " from " + result.provider.name)
            except:
                sickrage.LOGGER.debug("Failed to send snatch notification")

            trakt_data.append((curEpObj.season, curEpObj.episode))

    data = sickrage.NOTIFIERS.trakt_notifier.trakt_episode_data_generate(trakt_data)

    if sickrage.USE_TRAKT and sickrage.TRAKT_SYNC_WATCHLIST:
        sickrage.LOGGER.debug(
            "Add episodes, showid: indexerid "
            + str(result.show.indexerid)
            + ", Title "
            + str(result.show.name)
            + " to Traktv Watchlist"
        )
        if data:
            sickrage.NOTIFIERS.trakt_notifier.update_watchlist(result.show, data_episode=data, update="add")

    if len(sql_l) > 0:
        main_db.MainDB().mass_action(sql_l)

    return True