Example #1
0
def getEpisodes(search_thread, searchstatus):
    """ Get all episodes located in a search thread with a specific status """

    results = []
    # NOTE!: Show.find called with just indexerid!
    show_obj = Show.find(sickbeard.showList, int(search_thread.show.indexerid))

    if not show_obj:
        if not search_thread.show.is_recently_deleted:
            logger.log(u'No Show Object found for show with indexerID: {0}'.
                       format(search_thread.show.indexerid), logger.ERROR)
        return results

    if not isinstance(search_thread.segment, list):
        search_thread.segment = [search_thread.segment]

    for ep_obj in search_thread.segment:
        ep = show_obj.get_episode(ep_obj.season, ep_obj.episode)
        results.append({
            'show': show_obj.indexerid,
            'episode': ep.episode,
            'episodeindexid': ep.indexerid,
            'season': ep.season,
            'searchstatus': searchstatus,
            'status': statusStrings[ep.status],
            'quality': getQualityClass(ep),
            'overview': Overview.overviewStrings[show_obj.get_overview(ep.status)],
        })

    return results
Example #2
0
def get_scene_absolute_numbering(indexer_id, indexer, absolute_number, fallback_to_xem=True):
    """
    Returns a tuple, (season, episode), with the scene numbering (if there is one),
    otherwise returns the xem numbering (if fallback_to_xem is set), otherwise
    returns the TVDB numbering.
    (so the return values will always be set)

    :param indexer_id: int
    ;param absolute_number: int
    :param fallback_to_xem: bool If set (the default), check xem for matches if there is no local scene numbering
    :return: (int, int) a tuple with (season, episode)
    """
    if indexer_id is None or absolute_number is None:
        return absolute_number

    indexer_id = int(indexer_id)
    indexer = int(indexer)

    showObj = Show.find(sickbeard.showList, indexer_id)
    if showObj and not showObj.is_scene:
        return absolute_number

    result = find_scene_absolute_numbering(indexer_id, indexer, absolute_number)
    if result:
        return result
    else:
        if fallback_to_xem:
            xem_result = find_xem_absolute_numbering(indexer_id, indexer, absolute_number)
            if xem_result:
                return xem_result
        return absolute_number
Example #3
0
    def test_validate_indexer_id(self):
        sickbeard.QUALITY_DEFAULT = Quality.FULLHDTV

        show123 = TestTVShow(0, 123)
        show456 = TestTVShow(0, 456)
        show789 = TestTVShow(0, 789)
        sickbeard.showList = [
            show123,
            show456,
            show789,
        ]

        invalid_show_id = ('Invalid show ID', None)

        indexer_id_list = [
            None, '', u'', '123', u'123', '456', u'456', '789', u'789', 123,
            456, 789, ['123', '456'], [u'123', u'456'], [123, 456]
        ]
        results_list = [
            invalid_show_id, invalid_show_id, invalid_show_id, (None, show123),
            (None, show123), (None, show456), (None, show456), (None, show789),
            (None, show789), (None, show123), (None, show456), (None, show789),
            invalid_show_id, invalid_show_id, invalid_show_id
        ]

        self.assertEqual(
            len(indexer_id_list), len(results_list),
            'Number of parameters (%d) and results (%d) does not match' %
            (len(indexer_id_list), len(results_list)))

        for (index, indexer_id) in enumerate(indexer_id_list):
            self.assertEqual(Show._validate_indexer_id(indexer_id),
                             results_list[index])
Example #4
0
    def find_propers(self, search_date=datetime.datetime.today()):
        """
        Searches providers for PROPER or REPACK releases
        Returns a list of objects of type classes.Proper
        """
        results = []

        myDB = db.DBConnection()
        sqlResults = myDB.select(
            'SELECT s.show_name, e.showid, e.season, e.episode, e.status, e.airdate FROM tv_episodes AS e' +
            ' INNER JOIN tv_shows AS s ON (e.showid = s.indexer_id)' +
            ' WHERE e.airdate >= ' + str(search_date.toordinal()) +
            ' AND (e.status IN (' + ','.join([str(x) for x in Quality.DOWNLOADED]) + ')' +
            ' OR (e.status IN (' + ','.join([str(x) for x in Quality.SNATCHED]) + ')))'
        )

        if not sqlResults:
            return results

        for sqlshow in sqlResults:
            self.show = Show.find(sickbeard.showList, int(sqlshow["showid"]))
            if self.show:
                curEp = self.show.getEpisode(sqlshow["season"], sqlshow["episode"])
                searchStrings = self._get_episode_search_strings(curEp, add_string='PROPER|REPACK')
                for searchString in searchStrings:
                    for item in self.search(searchString):
                        title, url = self._get_title_and_url(item)
                        if re.match(r'.*(REPACK|PROPER).*', title, re.I):
                            results.append(classes.Proper(title, url, datetime.datetime.today(), self.show))

        return results
    def updateShows(self):
        logger.log("SHOW_WATCHLIST::CHECK::START - Trakt Show Watchlist",
                   logger.DEBUG)

        self._getShowWatchlist()
        if not self.ShowWatchlist:
            logger.log(
                "No shows found in your watchlist, aborting watchlist update",
                logger.DEBUG)
            return

        indexer = int(sickbeard.TRAKT_DEFAULT_INDEXER)
        trakt_id = sickbeard.indexerApi(indexer).config['trakt_id']

        for show_el in self.ShowWatchlist[trakt_id]:
            indexer_id = int(str(show_el))
            show = self.ShowWatchlist[trakt_id][show_el]

            # logger.log(u"Checking Show: %s %s %s" % (trakt_id, indexer_id, show['title']),logger.DEBUG)
            if int(sickbeard.TRAKT_METHOD_ADD) != 2:
                self.addDefaultShow(indexer, indexer_id, show['title'],
                                    SKIPPED)
            else:
                self.addDefaultShow(indexer, indexer_id, show['title'], WANTED)

            if int(sickbeard.TRAKT_METHOD_ADD) == 1:
                newShow = Show.find(sickbeard.showList, indexer_id)

                if newShow is not None:
                    setEpisodeToWanted(newShow, 1, 1)
                else:
                    self.todoWanted.append((indexer_id, 1, 1))
        logger.log("SHOW_WATCHLIST::CHECK::FINISH - Trakt Show Watchlist",
                   logger.DEBUG)
Example #6
0
    def add_show(indexer, indexer_id, show_name, status):
        """
        Adds a new show with the default settings
        """
        if not Show.find(sickbeard.showList, int(indexer_id)):
            root_dirs = sickbeard.ROOT_DIRS.split('|')

            location = root_dirs[int(root_dirs[0]) + 1] if root_dirs else None

            if location:
                show_path = ek(os.path.join, location, show_name)
                logger.log(u"Adding show '{}' with ID: '{}' in location: '{}'".format(show_name, indexer_id, show_path))
                dir_exists = helpers.makeDir(show_path)

                if not dir_exists:
                    logger.log(u"Unable to create the folder {}. Unable to add the show {}".format(show_path, show_name), logger.WARNING)
                    return
                else:
                    logger.log(u"Creating the folder '{}'".format(show_path), logger.DEBUG)
                    helpers.chmodAsParent(show_path)

                sickbeard.showQueueScheduler.action.addShow(indexer, indexer_id, show_path,
                                                            default_status=status,
                                                            quality=int(sickbeard.QUALITY_DEFAULT),
                                                            flatten_folders=int(sickbeard.FLATTEN_FOLDERS_DEFAULT),
                                                            paused=sickbeard.TRAKT_START_PAUSED,
                                                            default_status_after=status)
            else:
                logger.log(u"There was an error creating the show, no root directory setting found", logger.WARNING)
                return
Example #7
0
    def find_propers(self, search_date=None):
        results = []
        db = DBConnection()
        placeholder = ','.join([str(x) for x in Quality.DOWNLOADED + Quality.SNATCHED + Quality.SNATCHED_BEST])
        sql_results = db.select(
            'SELECT s.show_name, e.showid, e.season, e.episode, e.status, e.airdate'
            ' FROM tv_episodes AS e'
            ' INNER JOIN tv_shows AS s ON (e.showid = s.indexer_id)'
            ' WHERE e.airdate >= ' + str(search_date.toordinal()) +
            ' AND e.status IN (' + placeholder + ')'
        )

        for result in sql_results or []:
            show = Show.find(sickbeard.showList, int(result['showid']))

            if show:
                episode = show.getEpisode(result['season'], result['episode'])

                for term in self.proper_strings:
                    search_strings = self._get_episode_search_strings(episode, add_string=term)

                    for item in self.search(search_strings[0]):
                        title, url = self._get_title_and_url(item)

                        results.append(Proper(title, url, datetime.today(), show))

        return results
Example #8
0
    def fetch_trakt_shows(self):

        if not self.show_watchlist:
            logger.log(u"No shows found in your watchlist, aborting watchlist update", logger.DEBUG)
        else:
            indexer = int(sickbeard.TRAKT_DEFAULT_INDEXER)
            trakt_id = sickbeard.indexerApi(indexer).config['trakt_id']

            for watchlisted_show in self.show_watchlist[trakt_id]:
                indexer_id = int(watchlisted_show)
                show_obj = self.show_watchlist[trakt_id][watchlisted_show]
                if show_obj['year'] and show_obj['slug'].endswith(str(show_obj['year'])):
                    show_name = '{} ({})'.format(show_obj['title'], show_obj['year'])
                else:
                    show_name = show_obj['title']

                if int(sickbeard.TRAKT_METHOD_ADD) != 2:
                    self.add_show(indexer, indexer_id, show_name, SKIPPED)
                else:
                    self.add_show(indexer, indexer_id, show_name, WANTED)

                if int(sickbeard.TRAKT_METHOD_ADD) == 1:
                    new_show = Show.find(sickbeard.showList, indexer_id)

                    if new_show:
                        setEpisodeToWanted(new_show, 1, 1)
                    else:
                        self.todoWanted.append(indexer_id, 1, 1)
Example #9
0
def set_scene_numbering(indexer_id, indexer, season=None, episode=None,  # pylint:disable=too-many-arguments
                        absolute_number=None, sceneSeason=None,
                        sceneEpisode=None, sceneAbsolute=None):
    """
    Set scene numbering for a season/episode.
    To clear the scene numbering, leave both sceneSeason and sceneEpisode as None.
    """
    if indexer_id is None:
        return

    indexer_id = int(indexer_id)
    indexer = int(indexer)

    main_db_con = db.DBConnection()
    if season and episode:
        main_db_con.action(
            "INSERT OR IGNORE INTO scene_numbering (indexer, indexer_id, season, episode) VALUES (?,?,?,?)",
            [indexer, indexer_id, season, episode])

        main_db_con.action(
            "UPDATE scene_numbering SET scene_season = ?, scene_episode = ? WHERE indexer = ? and indexer_id = ? and season = ? and episode = ?",
            [sceneSeason, sceneEpisode, indexer, indexer_id, season, episode])
    elif absolute_number:
        main_db_con.action(
            "INSERT OR IGNORE INTO scene_numbering (indexer, indexer_id, absolute_number) VALUES (?,?,?)",
            [indexer, indexer_id, absolute_number])

        main_db_con.action(
            "UPDATE scene_numbering SET scene_absolute_number = ? WHERE indexer = ? and indexer_id = ? and absolute_number = ?",
            [sceneAbsolute, indexer, indexer_id, absolute_number])

    # Reload data from DB so that cache and db are in sync
    show = Show.find(sickbeard.showList, indexer_id)
    show.flushEpisodes()
Example #10
0
    def find_propers(self, proper_candidates):
        results = []

        for proper_candidate in proper_candidates:
            show_obj = Show.find(sickbeard.showList, int(proper_candidate[b'showid'])) if proper_candidate[b'showid'] else None

            if show_obj:
                episode_obj = show_obj.get_episode(proper_candidate[b'season'], proper_candidate[b'episode'])

                for term in self.proper_strings:
                    search_strings = self._get_episode_search_strings(episode_obj, add_string=term)

                    for item in self.search(search_strings[0], ep_obj=episode_obj):
                        title, url = self._get_title_and_url(item)
                        seeders, leechers = self._get_result_info(item)
                        size = self._get_size(item)
                        pubdate = self._get_pubdate(item)
                        torrent_hash = self._get_hash(item)

                        # This will be retrived from parser
                        proper_tags = None

                        results.append(Proper(title, url, datetime.today(), show_obj, seeders, leechers, size, pubdate, torrent_hash, proper_tags))

        return results
Example #11
0
    def find_propers(self, search_date=None):
        results = []
        db = DBConnection()
        placeholder = ','.join([
            str(x) for x in Quality.DOWNLOADED + Quality.SNATCHED +
            Quality.SNATCHED_BEST
        ])
        sql_results = db.select(
            'SELECT s.show_name, s.lang, e.showid, e.season, e.episode, e.status, e.airdate'
            ' FROM tv_episodes AS e'
            ' INNER JOIN tv_shows AS s ON (e.showid = s.indexer_id)'
            ' WHERE e.airdate >= ' + str(search_date.toordinal()) +
            ' AND e.status IN (' + placeholder + ')')

        for result in sql_results or []:
            show = Show.find(sickbeard.showList, int(result['showid']))

            if show:
                episode = show.getEpisode(result['season'], result['episode'])

                for term in self.proper_strings:
                    search_strings = self._get_episode_search_strings(
                        episode, add_string=term)

                    for item in self.search(search_strings[0]):
                        title, url = self._get_title_and_url(item)

                        results.append(
                            Proper(title, url, datetime.today(), show))

        return results
Example #12
0
    def find_propers(self, search_date=datetime.datetime.today()):
        """
        Searches providers for PROPER or REPACK releases
        Returns a list of objects of type classes.Proper
        """
        results = []

        myDB = db.DBConnection()
        sqlResults = myDB.select(
            'SELECT s.show_name, e.showid, e.season, e.episode, e.status, e.airdate FROM tv_episodes AS e' +
            ' INNER JOIN tv_shows AS s ON (e.showid = s.indexer_id)' +
            ' WHERE e.airdate >= ' + str(search_date.toordinal()) +
            ' AND (e.status IN (' + ','.join([str(x) for x in Quality.DOWNLOADED]) + ')' +
            ' OR (e.status IN (' + ','.join([str(x) for x in Quality.SNATCHED]) + ')))'
        )

        if not sqlResults:
            return results

        for sqlshow in sqlResults:
            self.show = Show.find(sickbeard.showList, int(sqlshow["showid"]))
            if self.show:
                curEp = self.show.getEpisode(sqlshow["season"], sqlshow["episode"])
                searchStrings = self._get_episode_search_strings(curEp, add_string='PROPER|REPACK')
                for searchString in searchStrings:
                    for item in self.search(searchString):
                        title, url = self._get_title_and_url(item)
                        if re.match(r'.*(REPACK|PROPER).*', title, re.I):
                            results.append(classes.Proper(title, url, datetime.datetime.today(), self.show))

        return results
Example #13
0
    def addDefaultShow(indexer, indexer_id, name, status):
        """
        Adds a new show with the default settings
        """
        if not Show.find(sickbeard.showList, int(indexer_id)):
            logger.log(u"Adding show " + str(indexer_id))
            root_dirs = sickbeard.ROOT_DIRS.split('|')

            try:
                location = root_dirs[int(root_dirs[0]) + 1]
            except Exception:
                location = None

            if location:
                showPath = ek(os.path.join, location, sanitize_filename(name))
                dir_exists = helpers.makeDir(showPath)

                if not dir_exists:
                    logger.log(u"Unable to create the folder {0!s} , can't add the show".format(showPath), logger.WARNING)
                    return
                else:
                    helpers.chmodAsParent(showPath)

                sickbeard.showQueueScheduler.action.addShow(int(indexer), int(indexer_id), showPath,
                                                            default_status=status,
                                                            quality=int(sickbeard.QUALITY_DEFAULT),
                                                            flatten_folders=int(sickbeard.FLATTEN_FOLDERS_DEFAULT),
                                                            paused=sickbeard.TRAKT_START_PAUSED,
                                                            default_status_after=status)
            else:
                logger.log(u"There was an error creating the show, no root directory setting found", logger.WARNING)
                return
Example #14
0
    def backlogShow(self, indexer_id):
        show_obj = Show.find(sickbeard.showList, int(indexer_id))

        if show_obj:
            sickbeard.backlogSearchScheduler.action.searchBacklog([show_obj])

        return self.redirect('/manage/backlogOverview/')
Example #15
0
    def updateShows(self):
        logger.log(u"SHOW_WATCHLIST::CHECK::START - Trakt Show Watchlist", logger.DEBUG)

        if not len(self.ShowWatchlist):
            logger.log(u"No shows found in your watchlist, aborting watchlist update", logger.DEBUG)
            return

        indexer = int(sickbeard.TRAKT_DEFAULT_INDEXER)
        trakt_id = sickbeard.indexerApi(indexer).config['trakt_id']

        for show_el in self.ShowWatchlist[trakt_id]:
            indexer_id = int(str(show_el))
            show = self.ShowWatchlist[trakt_id][show_el]

            # logger.log(u"Checking Show: %s %s %s" % (trakt_id, indexer_id, show['title']),logger.DEBUG)
            if int(sickbeard.TRAKT_METHOD_ADD) != 2:
                self.addDefaultShow(indexer, indexer_id, show['title'], SKIPPED)
            else:
                self.addDefaultShow(indexer, indexer_id, show['title'], WANTED)

            if int(sickbeard.TRAKT_METHOD_ADD) == 1:
                newShow = Show.find(sickbeard.showList, indexer_id)

                if newShow is not None:
                    setEpisodeToWanted(newShow, 1, 1)
                else:
                    self.todoWanted.append((indexer_id, 1, 1))
        logger.log(u"SHOW_WATCHLIST::CHECK::FINISH - Trakt Show Watchlist", logger.DEBUG)
Example #16
0
    def addDefaultShow(indexer, indexer_id, name, status):
        """
        Adds a new show with the default settings
        """
        if not Show.find(sickbeard.showList, int(indexer_id)):
            logger.log(u"Adding show " + str(indexer_id))
            root_dirs = sickbeard.ROOT_DIRS.split('|')

            try:
                location = root_dirs[int(root_dirs[0]) + 1]
            except Exception:
                location = None

            if location:
                showPath = ek(os.path.join, location, sanitize_filename(name))
                dir_exists = helpers.makeDir(showPath)

                if not dir_exists:
                    logger.log(u"Unable to create the folder %s , can't add the show" % showPath, logger.WARNING)
                    return
                else:
                    helpers.chmodAsParent(showPath)

                sickbeard.showQueueScheduler.action.addShow(int(indexer), int(indexer_id), showPath,
                                                            default_status=status,
                                                            quality=int(sickbeard.QUALITY_DEFAULT),
                                                            flatten_folders=int(sickbeard.FLATTEN_FOLDERS_DEFAULT),
                                                            paused=sickbeard.TRAKT_START_PAUSED,
                                                            default_status_after=status)
            else:
                logger.log(u"There was an error creating the show, no root directory setting found", logger.WARNING)
                return
Example #17
0
    def test_validate_indexer_id(self):
        """
        Test validate indexer id
        """
        sickbeard.QUALITY_DEFAULT = Quality.FULLHDTV

        show123 = TestTVShow(0, 123)
        show456 = TestTVShow(0, 456)
        show789 = TestTVShow(0, 789)
        sickbeard.showList = [
            show123,
            show456,
            show789,
        ]

        invalid_show_id = ('Invalid show ID', None)

        indexer_id_list = [
            None, '', u'', '123', u'123', '456', u'456', '789', u'789', 123, 456, 789, ['123', '456'], [u'123', u'456'],
            [123, 456]
        ]
        results_list = [
            invalid_show_id, invalid_show_id, invalid_show_id, (None, show123), (None, show123), (None, show456),
            (None, show456), (None, show789), (None, show789), (None, show123), (None, show456), (None, show789),
            invalid_show_id, invalid_show_id, invalid_show_id
        ]

        self.assertEqual(
            len(indexer_id_list), len(results_list),
            'Number of parameters (%d) and results (%d) does not match' % (len(indexer_id_list), len(results_list))
        )

        for (index, indexer_id) in enumerate(indexer_id_list):
            self.assertEqual(Show._validate_indexer_id(indexer_id), results_list[index])  # pylint: disable=protected-access
Example #18
0
def getEpisode(show, season=None, episode=None, absolute=None):
    """ Get a specific episode object based on show, season and episode number

    :param show: Season number
    :param season: Season number
    :param season: Season number
    :param absolute: Optional if the episode number is a scene absolute number
    :return: episode object
    """
    if show is None:
        return "Invalid show parameters"

    show_obj = Show.find(sickbeard.showList, int(show))

    if show_obj is None:
        return "Invalid show paramaters"

    if absolute:
        ep_obj = show_obj.get_episode(absolute_number=absolute)
    elif season and episode:
        ep_obj = show_obj.get_episode(season, episode)
    else:
        return "Invalid paramaters"

    if ep_obj is None:
        return "Episode couldn't be retrieved"

    return ep_obj
Example #19
0
    def test_find(self):
        """
        Test find
        """
        sickbeard.QUALITY_DEFAULT = Quality.FULLHDTV

        sickbeard.showList = []

        show123 = TestTVShow(0, 123)
        show456 = TestTVShow(0, 456)
        show789 = TestTVShow(0, 789)
        shows = [show123, show456, show789]
        shows_duplicate = shows + shows

        test_cases = {
            (False, None): None,
            (False, ''): None,
            (False, '123'): None,
            (False, 123): None,
            (False, 12.3): None,
            (True, None): None,
            (True, ''): None,
            (True, '123'): None,
            (True, 123): show123,
            (True, 12.3): None,
            (True, 456): show456,
            (True, 789): show789,
        }

        unicode_test_cases = {
            (False, ''): None,
            (False, '123'): None,
            (True, ''): None,
            (True, '123'): None,
        }

        for tests in test_cases, unicode_test_cases:
            for ((use_shows, indexer_id), result) in six.iteritems(tests):
                if use_shows:
                    self.assertEqual(Show.find(shows, indexer_id), result)
                else:
                    self.assertEqual(Show.find(None, indexer_id), result)

        with self.assertRaises(MultipleShowObjectsException):
            Show.find(shows_duplicate, 456)
Example #20
0
    def test_find(self):
        """
        Test find tv shows by indexer_id
        """
        sickbeard.QUALITY_DEFAULT = Quality.FULLHDTV

        sickbeard.showList = []

        show123 = TestTVShow(0, 123)
        show456 = TestTVShow(0, 456)
        show789 = TestTVShow(0, 789)
        shows = [show123, show456, show789]
        shows_duplicate = shows + shows

        test_cases = {
            (False, None): None,
            (False, ''): None,
            (False, '123'): None,
            (False, 123): None,
            (False, 12.3): None,
            (True, None): None,
            (True, ''): None,
            (True, '123'): None,
            (True, 123): show123,
            (True, 12.3): None,
            (True, 456): show456,
            (True, 789): show789,
        }

        unicode_test_cases = {
            (False, ''): None,
            (False, '123'): None,
            (True, ''): None,
            (True, '123'): None,
        }

        for tests in test_cases, unicode_test_cases:
            for ((use_shows, indexer_id), result) in six.iteritems(tests):
                if use_shows:
                    self.assertEqual(Show.find(shows, indexer_id), result)
                else:
                    self.assertEqual(Show.find(None, indexer_id), result)

        with self.assertRaises(MultipleShowObjectsException):
            Show.find(shows_duplicate, 456)
Example #21
0
    def get_show(self):
        """
        :return: The show object associated with ``self.indexer_id`` or ``None``
        """

        try:
            return Show.find(sickbeard.showList, self.indexer_id)
        except MultipleShowObjectsException:
            return None
Example #22
0
    def get_show(self):
        """
        :return: The show object associated with ``self.indexer_id`` or ``None``
        """

        try:
            return Show.find(sickbeard.showList, self.indexer_id)
        except MultipleShowObjectsException:
            return None
Example #23
0
    def _addCacheEntry(self, name, url, parse_result=None, indexer_id=0):

        # check if we passed in a parsed result or should we try and create one
        if not parse_result:

            # create showObj from indexer_id if available
            showObj = None
            if indexer_id:
                showObj = Show.find(sickbeard.showList, indexer_id)

            try:
                parse_result = NameParser(showObj=showObj).parse(name)
            except (InvalidNameException, InvalidShowException) as error:
                logger.log(u"{0}".format(error), logger.DEBUG)
                return None

            if not parse_result or not parse_result.series_name:
                return None

        # if we made it this far then lets add the parsed result to cache for usager later on
        season = parse_result.season_number if parse_result.season_number else 1
        episodes = parse_result.episode_numbers

        if season and episodes:
            # store episodes as a seperated string
            episodeText = "|" + "|".join(
                {str(episode)
                 for episode in episodes if episode}) + "|"

            # get the current timestamp
            curTimestamp = int(
                time.mktime(datetime.datetime.today().timetuple()))

            # get quality of release
            quality = parse_result.quality

            assert isinstance(name, unicode)

            # get release group
            release_group = parse_result.release_group

            # get version
            version = parse_result.version

            logger.log(
                u"Added RSS item: [" + name + "] to cache: [" +
                self.providerID + "]", logger.DEBUG)

            return [
                "INSERT OR IGNORE INTO [" + self.providerID +
                "] (name, season, episodes, indexerid, url, time, quality, release_group, version) VALUES (?,?,?,?,?,?,?,?,?)",
                [
                    name, season, episodeText, parse_result.show.indexerid,
                    url, curTimestamp, quality, release_group, version
                ]
            ]
    def updateEpisodes(self):
        """
        Sets episodes to wanted that are in trakt watchlist
        """
        logger.log("SHOW_WATCHLIST::CHECK::START - Trakt Episode Watchlist",
                   logger.DEBUG)

        self._getEpisodeWatchlist()
        if not self.EpisodeWatchlist:
            logger.log(
                "No episode found in your watchlist, aborting episode update",
                logger.DEBUG)
            return

        managed_show = []

        indexer = int(sickbeard.TRAKT_DEFAULT_INDEXER)
        trakt_id = sickbeard.indexerApi(indexer).config['trakt_id']

        for show_el in self.EpisodeWatchlist[trakt_id]:
            indexer_id = int(show_el)
            show = self.EpisodeWatchlist[trakt_id][show_el]

            newShow = Show.find(sickbeard.showList, indexer_id)

            try:
                if newShow is None:
                    if indexer_id not in managed_show:
                        self.addDefaultShow(indexer, indexer_id, show['title'],
                                            SKIPPED)
                        managed_show.append(indexer_id)

                        for season_el in show['seasons']:
                            season = int(season_el)

                            for episode_el in show['seasons'][season_el][
                                    'episodes']:
                                self.todoWanted.append(
                                    (indexer_id, season, int(episode_el)))
                else:
                    if newShow.indexer == indexer:
                        for season_el in show['seasons']:
                            season = int(season_el)

                            for episode_el in show['seasons'][season_el][
                                    'episodes']:
                                setEpisodeToWanted(newShow, season,
                                                   int(episode_el))
            except TypeError:
                logger.log(
                    "Could not parse the output from trakt for {0} ".format(
                        show["title"]), logger.DEBUG)
        logger.log("SHOW_WATCHLIST::CHECK::FINISH - Trakt Episode Watchlist",
                   logger.DEBUG)
Example #25
0
    def updateWatchedData(self):

        try:
            response = self.trakt_api.traktRequest("users/me/history/episodes")

            changes = dict()
            myDB = db.DBConnection()

            for data in response:
                show_id = None
                if not data['show']['ids']["tvdb"] is None:
                    show_id = data['show']['ids']["tvdb"]
                elif not data['show']['ids']["tvrage"] is None:
                    show_id = data['show']['ids']["tvrage"]
                else:
                    logger.log(u"Could not retrieve show_id from trakt history", logger.WARNING)
                    continue

                show_name = data["show"]["title"]
                season = data["episode"]["season"]
                episode = data["episode"]["number"]
                watched = time.mktime(parser.parse(data["watched_at"]).timetuple())

                cursor = myDB.action("UPDATE tv_episodes SET last_watched=? WHERE showid=? AND season=? AND episode=? AND (last_watched IS NULL OR last_watched < ?)", [watched, show_id, season, episode, watched])
                if cursor.rowcount > 0:
                    changes[show_name] = changes.get(show_name, 0) + 1
                    logger.log("Updated " + show_name + ", episode " + str(season) + "x" + str(episode) + ": Episode was watched at " + str(watched))

                    show = Show.find(sickbeard.showList, int(show_id))
                    show.last_seen = max(show.last_seen, watched)

            message = "Watched episodes synchronization complete: ";
            if (len(changes) == 0):
                message += "No changes detected."
            else:
                message += "Marked as watched "
                first = True;
                for show_name in changes:
                    if (not first):
                        message += ", "

                    message += str(changes[show_name]) + " episodes of " + show_name
                    first = False;

            logger.log(message)

            self._updateAllShowsNextEpisodeData()

        except traktException as e:
            logger.log(u"Could not connect to trakt service, cannot synch Watched Data: %s" % ex(e), logger.ERROR)
Example #26
0
    def _addCacheEntry(self, name, url, parse_result=None, indexer_id=0):

        # check if we passed in a parsed result or should we try and create one
        if not parse_result:

            # create showObj from indexer_id if available
            showObj = None
            if indexer_id:
                showObj = Show.find(sickbeard.showList, indexer_id)

            try:
                myParser = NameParser(showObj=showObj)
                parse_result = myParser.parse(name)
            except InvalidNameException:
                logger.log(u"Unable to parse the filename " + name + " into a valid episode", logger.DEBUG)
                return None
            except InvalidShowException:
                logger.log(u"Unable to parse the filename " + name + " into a valid show", logger.DEBUG)
                return None

            if not parse_result or not parse_result.series_name:
                return None

        # if we made it this far then lets add the parsed result to cache for usager later on
        season = parse_result.season_number if parse_result.season_number else 1
        episodes = parse_result.episode_numbers

        if season and episodes:
            # store episodes as a seperated string
            episodeText = "|" + "|".join(map(str, episodes)) + "|"

            # get the current timestamp
            curTimestamp = int(time.mktime(datetime.datetime.today().timetuple()))

            # get quality of release
            quality = parse_result.quality

            name = ss(name)

            # get release group
            release_group = parse_result.release_group

            # get version
            version = parse_result.version

            logger.log(u"Added RSS item: [" + name + "] to cache: [" + self.providerID + "]", logger.DEBUG)

            return [
                "INSERT OR IGNORE INTO [" + self.providerID + "] (name, season, episodes, indexerid, url, time, quality, release_group, version) VALUES (?,?,?,?,?,?,?,?,?)",
                [name, season, episodeText, parse_result.show.indexerid, url, curTimestamp, quality, release_group, version]]
Example #27
0
    def _add_cache_entry(self, name, url, parse_result=None, indexer_id=0):

        # check if we passed in a parsed result or should we try and create one
        if not parse_result:

            # create show_obj from indexer_id if available
            show_obj = None
            if indexer_id:
                show_obj = Show.find(sickbeard.showList, indexer_id)

            try:
                parse_result = NameParser(showObj=show_obj).parse(name)
            except (InvalidNameException, InvalidShowException) as error:
                logger.log("{0}".format(error), logger.DEBUG)
                return None

            if not parse_result or not parse_result.series_name:
                return None

        # if we made it this far then lets add the parsed result to cache for usager later on
        season = parse_result.season_number if parse_result.season_number else 1
        episodes = parse_result.episode_numbers

        if season and episodes:
            # store episodes as a seperated string
            episode_text = "|" + "|".join({str(episode) for episode in episodes if episode}) + "|"

            # get the current timestamp
            cur_timestamp = int(time.mktime(datetime.datetime.today().timetuple()))

            # get quality of release
            quality = parse_result.quality

            assert isinstance(name, six.text_type)

            # get release group
            release_group = parse_result.release_group

            # get version
            version = parse_result.version

            logger.log("Added RSS item: [" + name + "] to cache: [" + self.provider_id + "]", logger.DEBUG)

            return [
                "INSERT OR IGNORE INTO [" + self.provider_id + "] (name, season, episodes, indexerid, url, time, quality, release_group, version) VALUES (?,?,?,?,?,?,?,?,?)",
                [name, season, episode_text, parse_result.show.indexerid, url, cur_timestamp, quality, release_group, version]]
Example #28
0
    def updateEpisodes(self):
        """
        Sets episodes to wanted that are in trakt watchlist
        """
        logger.log("SHOW_WATCHLIST::CHECK::START - Trakt Episode Watchlist", logger.DEBUG)

        self._getEpisodeWatchlist()
        if not self.EpisodeWatchlist:
            logger.log("No episode found in your watchlist, aborting episode update", logger.DEBUG)
            return

        managed_show = []

        indexer = int(sickbeard.TRAKT_DEFAULT_INDEXER)
        trakt_id = sickbeard.indexerApi(indexer).config['trakt_id']

        for show_el in self.EpisodeWatchlist[trakt_id]:
            indexer_id = int(show_el)
            show = self.EpisodeWatchlist[trakt_id][show_el]

            newShow = Show.find(sickbeard.showList, indexer_id)

            try:
                if newShow is None:
                    if indexer_id not in managed_show:
                        self.addDefaultShow(indexer, indexer_id, show['title'], SKIPPED)
                        managed_show.append(indexer_id)

                        for season_el in show['seasons']:
                            season = int(season_el)

                            for episode_el in show['seasons'][season_el]['episodes']:
                                self.todoWanted.append((indexer_id, season, int(episode_el)))
                else:
                    if newShow.indexer == indexer:
                        for season_el in show['seasons']:
                            season = int(season_el)

                            for episode_el in show['seasons'][season_el]['episodes']:
                                setEpisodeToWanted(newShow, season, int(episode_el))
            except TypeError:
                logger.log("Could not parse the output from trakt for {0} ".format(show["title"]), logger.DEBUG)
        logger.log("SHOW_WATCHLIST::CHECK::FINISH - Trakt Episode Watchlist", logger.DEBUG)
Example #29
0
    def fetch_trakt_episodes(self):
        """
        Sets episodes to wanted that are in trakt watchlist
        """
        logger.log(u"Retrieving episodes to sync with Trakt episode's watchlist", logger.DEBUG)

        if not self.episode_watchlist:
            logger.log(u"No episode found in your watchlist, aborting episode update", logger.DEBUG)
            return

        managed_show = []

        indexer = int(sickbeard.TRAKT_DEFAULT_INDEXER)
        trakt_id = sickbeard.indexerApi(indexer).config['trakt_id']

        for watchlist_item in self.episode_watchlist[trakt_id]:
            indexer_id = int(watchlist_item)
            show = self.episode_watchlist[trakt_id][watchlist_item]

            new_show = Show.find(sickbeard.showList, indexer_id)

            try:
                if not new_show:
                    if indexer_id not in managed_show:
                        self.add_show(indexer, indexer_id, show['title'], SKIPPED)
                        managed_show.append(indexer_id)

                        for season_item in show['seasons']:
                            season = int(season_item)

                            for episode_item in show['seasons'][season_item]['episodes']:
                                self.todoWanted.append((indexer_id, season, int(episode_item)))
                else:
                    if new_show.indexer == indexer:
                        for season_item in show['seasons']:
                            season = int(season_item)

                            for episode_item in show['seasons'][season_item]['episodes']:
                                setEpisodeToWanted(new_show, season, int(episode_item))
            except TypeError:
                logger.log(u"Could not parse the output from trakt for '{}' ".format(show["title"]), logger.DEBUG)
Example #30
0
    def test_validate_indexer_id(self):
        """
        Tests if the indexer_id is valid and if so if it returns the right show
        """
        sickbeard.QUALITY_DEFAULT = Quality.FULLHDTV

        sickbeard.showList = []

        show123 = TestTVShow(0, 123)
        show456 = TestTVShow(0, 456)
        show789 = TestTVShow(0, 789)
        sickbeard.showList = [
            show123,
            show456,
            show789,
        ]

        invalid_show_id = ('Invalid show ID', None)

        indexer_id_list = [
            None, '', '', '123', '123', '456', '456', '789', '789', 123, 456,
            789, ['123', '456'], ['123', '456'], [123, 456]
        ]
        results_list = [
            invalid_show_id, invalid_show_id, invalid_show_id, (None, show123),
            (None, show123), (None, show456), (None, show456), (None, show789),
            (None, show789), (None, show123), (None, show456), (None, show789),
            invalid_show_id, invalid_show_id, invalid_show_id
        ]

        self.assertEqual(
            len(indexer_id_list), len(results_list),
            'Number of parameters ({0:d}) and results ({1:d}) does not match'.
            format(len(indexer_id_list), len(results_list)))

        for (index, indexer_id) in enumerate(indexer_id_list):
            self.assertEqual(Show._validate_indexer_id(indexer_id),
                             results_list[index])  # pylint: disable=protected-access
Example #31
0
    def downloadSubtitleMissed(self, *args, **kwargs):
        to_download = {}

        # make a list of all shows and their associated args
        for arg in kwargs:
            indexer_id, what = arg.split('-')

            # we don't care about unchecked checkboxes
            if kwargs[arg] != 'on':
                continue

            if indexer_id not in to_download:
                to_download[indexer_id] = []

            to_download[indexer_id].append(what)

        for cur_indexer_id in to_download:
            # get a list of all the eps we want to download subtitles if they just said 'all'
            if 'all' in to_download[cur_indexer_id]:
                main_db_con = db.DBConnection()
                all_eps_results = main_db_con.select(
                    b'SELECT season, episode '
                    b'FROM tv_episodes '
                    b'WHERE (status LIKE \'%4\' OR status LIKE \'%6\') '
                    b'AND season != 0 '
                    b'AND showid = ? '
                    b'AND location != \'\'',
                    [cur_indexer_id]
                )
                to_download[cur_indexer_id] = [str(x['season']) + 'x' + str(x['episode']) for x in all_eps_results]

            for epResult in to_download[cur_indexer_id]:
                season, episode = epResult.split('x')

                show = Show.find(sickbeard.showList, int(cur_indexer_id))
                show.getEpisode(season, episode).download_subtitles()

        return self.redirect('/manage/subtitleMissed/')
Example #32
0
    def findPropers(self, search_date=datetime.datetime.today()):

        results = []

        myDB = db.DBConnection()
        sqlResults = myDB.select(
            'SELECT s.show_name, e.showid, e.season, e.episode, e.status, e.airdate FROM tv_episodes AS e' +
            ' INNER JOIN tv_shows AS s ON (e.showid = s.indexer_id)' +
            ' WHERE e.airdate >= ' + str(search_date.toordinal()) +
            ' AND e.status IN (' + ','.join([str(x) for x in Quality.DOWNLOADED + Quality.SNATCHED + Quality.SNATCHED_BEST]) + ')'
        )

        for sqlshow in sqlResults or []:
            show = Show.find(sickbeard.showList, int(sqlshow["showid"]))
            if show:
                curEp = show.getEpisode(int(sqlshow["season"]), int(sqlshow["episode"]))
                for term in self.proper_strings:
                    searchString = self._get_episode_search_strings(curEp, add_string=term)

                    for item in self._doSearch(searchString[0]):
                        title, url = self._get_title_and_url(item)
                        results.append(classes.Proper(title, url, datetime.datetime.today(), show))

        return results
Example #33
0
    def run(self, force=False):  # pylint: disable=too-many-branches, too-many-statements, too-many-locals
        """Check for needed subtitles for users' shows.

        :param force: True if a force search needs to be executed
        :type force: bool
        """
        if self.amActive:
            logger.log(u"Subtitle finder is still running, not starting it again", logger.DEBUG)
            return

        if not sickbeard.USE_SUBTITLES:
            logger.log(u"Subtitle search is disabled. Please enabled it", logger.WARNING)
            return

        if not sickbeard.subtitles.enabled_service_list():
            logger.warning(u'Not enough services selected. At least 1 service is required to search subtitles in the '
                           u'background')
            return

        self.amActive = True

        def dhm(td):
            days = td.days
            hours = td.seconds // 60 ** 2
            minutes = (td.seconds // 60) % 60
            ret = (u'', '{} days, '.format(days))[days > 0] + \
                  (u'', '{} hours, '.format(hours))[hours > 0] + \
                  (u'', '{} minutes'.format(minutes))[minutes > 0]
            if days == 1:
                ret = ret.replace('days', 'day')
            if hours == 1:
                ret = ret.replace('hours', 'hour')
            if minutes == 1:
                ret = ret.replace('minutes', 'minute')
            return ret.rstrip(', ')

        if sickbeard.SUBTITLES_DOWNLOAD_IN_PP:
            self.subtitles_download_in_pp()

        logger.info(u'Checking for missed subtitles')

        database = db.DBConnection()
        # Shows with air date <= 30 days, have a limit of 100 results
        # Shows with air date > 30 days, have a limit of 200 results
        sql_args = [{'age_comparison': '<=', 'limit': 100}, {'age_comparison': '>', 'limit': 200}]
        sql_like_languages = '%' + ','.join(sorted(wanted_languages())) + '%' if sickbeard.SUBTITLES_MULTI else '%und%'
        sql_results = []
        for args in sql_args:
            sql_results += database.select(
                "SELECT "
                "   s.show_name, "
                "   e.showid, "
                "   e.season, "
                "   e.episode,"
                "   e.release_name, "
                "   e.status, "
                "   e.subtitles, "
                "   e.subtitles_searchcount AS searchcount, "
                "   e.subtitles_lastsearch AS lastsearch, "
                "   e.location, (? - e.airdate) as age "
                "FROM "
                "   tv_episodes AS e "
                "INNER JOIN "
                "   tv_shows AS s "
                "ON (e.showid = s.indexer_id) "
                "WHERE"
                "   s.subtitles = 1 "
                "   AND (e.status LIKE '%4' OR e.status LIKE '%6') "
                "   AND e.season > 0 "
                "   AND e.location != '' "
                "   AND age {} 30 "
                "   AND e.subtitles NOT LIKE ? "
                "ORDER BY "
                "   lastsearch ASC "
                "LIMIT {}".format
                (args['age_comparison'], args['limit']), [datetime.datetime.now().toordinal(), sql_like_languages]
            )

        if not sql_results:
            logger.info(u'No subtitles to download')
            self.amActive = False
            return

        for ep_to_sub in sql_results:

            # give the CPU a break
            time.sleep(cpu_presets[sickbeard.CPU_PRESET])

            ep_num = episode_num(ep_to_sub['season'], ep_to_sub['episode']) or \
                     episode_num(ep_to_sub['season'], ep_to_sub['episode'], numbering='absolute')
            subtitle_path = _encode(ep_to_sub['location'], encoding=sickbeard.SYS_ENCODING, fallback='utf-8')
            if not os.path.isfile(subtitle_path):
                logger.debug(u'Episode file does not exist, cannot download subtitles for %s %s',
                             ep_to_sub['show_name'], ep_num)
                continue

            if not needs_subtitles(ep_to_sub['subtitles']):
                logger.debug(u'Episode already has all needed subtitles, skipping %s %s', ep_to_sub['show_name'], ep_num)
                continue

            try:
                lastsearched = datetime.datetime.strptime(ep_to_sub['lastsearch'], dateTimeFormat)
            except ValueError:
                lastsearched = datetime.datetime.min

            try:
                if not force:
                    now = datetime.datetime.now()
                    days = int(ep_to_sub['age'])
                    delay_time = datetime.timedelta(hours=1 if days <= 10 else 8 if days <= 30 else 30 * 24)
                    delay = lastsearched + delay_time - now

                    # Search every hour until 10 days pass
                    # After 10 days, search every 8 hours, after 30 days search once a month
                    # Will always try an episode regardless of age for 3 times
                    # The time resolution is minute
                    # Only delay is the it's bigger than one minute and avoid wrongly skipping the search slot.
                    if delay.total_seconds() > 60 and int(ep_to_sub['searchcount']) > 2:
                        logger.debug(u'Subtitle search for %s %s delayed for %s',
                                     ep_to_sub['show_name'], ep_num, dhm(delay))
                        continue

                show_object = Show.find(sickbeard.showList, int(ep_to_sub['showid']))
                if not show_object:
                    logger.debug(u'Show with ID %s not found in the database', ep_to_sub['showid'])
                    continue

                episode_object = show_object.getEpisode(ep_to_sub['season'], ep_to_sub['episode'])
                if isinstance(episode_object, str):
                    logger.debug(u'%s %s not found in the database', ep_to_sub['show_name'], ep_num)
                    continue

                try:
                    episode_object.download_subtitles()
                except Exception as error:
                    logger.error(u'Unable to find subtitles for %s %s. Error: %s',
                                 ep_to_sub['show_name'], ep_num, ex(error))
                    continue

            except Exception as error:
                logger.warning(u'Error while searching subtitles for %s %s. Error: %s',
                               ep_to_sub['show_name'], ep_num, ex(error))
                continue

        logger.info(u'Finished checking for missed subtitles')
        self.amActive = False
Example #34
0
    def findNeededEpisodes(self, episode, manualSearch=False, downCurQuality=False):
        neededEps = {}
        cl = []

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

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

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

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

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

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

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

            curEp = int(curEp)

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

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

            epObj = showObj.getEpisode(curSeason, curEp)

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

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

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

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

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

        return neededEps
Example #35
0
    def run(self):

        ShowQueueItem.run(self)

        logger.log(u"Starting to add show {0}".format(
            "by ShowDir: {0}".format(self.showDir) if self.
            showDir else "by Indexer Id: {0}".format(self.indexer_id)))
        # make sure the Indexer IDs are valid
        try:

            lINDEXER_API_PARMS = sickbeard.indexerApi(
                self.indexer).api_params.copy()
            if self.lang:
                lINDEXER_API_PARMS['language'] = self.lang

            logger.log(u"" + str(sickbeard.indexerApi(self.indexer).name) +
                       ": " + repr(lINDEXER_API_PARMS))

            t = sickbeard.indexerApi(
                self.indexer).indexer(**lINDEXER_API_PARMS)
            s = t[self.indexer_id]

            # Let's try to create the show Dir if it's not provided. This way we force the show dir to build build using the
            # Indexers provided series name
            if not self.showDir and self.root_dir:
                show_name = get_showname_from_indexer(self.indexer,
                                                      self.indexer_id,
                                                      self.lang)
                if show_name:
                    self.showDir = ek(os.path.join, self.root_dir,
                                      sanitize_filename(show_name))
                    dir_exists = makeDir(self.showDir)
                    if not dir_exists:
                        logger.log(
                            u"Unable to create the folder {0}, can't add the show"
                            .format(self.showDir))
                        return

                    chmodAsParent(self.showDir)
                else:
                    logger.log(
                        u"Unable to get a show {0}, can't add the show".format(
                            self.showDir))
                    return

            # this usually only happens if they have an NFO in their show dir which gave us a Indexer ID that has no proper english version of the show
            if getattr(s, 'seriesname', None) is None:
                logger.log(
                    u"Show in {0} has no name on {1}, probably searched with the wrong language."
                    .format(self.showDir,
                            sickbeard.indexerApi(self.indexer).name),
                    logger.ERROR)

                ui.notifications.error(
                    "Unable to add show",
                    "Show in " + self.showDir + " has no name on " +
                    str(sickbeard.indexerApi(self.indexer).name) +
                    ", probably the wrong language. Delete .nfo and add manually in the correct language."
                )
                self._finishEarly()
                return
            # if the show has no episodes/seasons
            if not s:
                logger.log(u"Show " + str(s['seriesname']) + " is on " +
                           str(sickbeard.indexerApi(self.indexer).name) +
                           " but contains no season/episode data.")
                ui.notifications.error(
                    "Unable to add show", "Show " + str(s['seriesname']) +
                    " is on " + str(sickbeard.indexerApi(self.indexer).name) +
                    " but contains no season/episode data.")
                self._finishEarly()
                return
        except Exception as e:
            logger.log(
                u"{0!s} Error while loading information from indexer {1!s}. Error: {2!r}"
                .format(self.indexer_id,
                        sickbeard.indexerApi(self.indexer).name,
                        ex(e)), logger.ERROR)
            # logger.log(u"Show name with ID %s doesn't exist on %s anymore. If you are using trakt, it will be removed from your TRAKT watchlist. If you are adding manually, try removing the nfo and adding again" %
            #            (self.indexer_id, sickbeard.indexerApi(self.indexer).name), logger.WARNING)

            ui.notifications.error(
                "Unable to add show",
                "Unable to look up the show in {0!s} on {1!s} using ID {2!s}, not using the NFO. Delete .nfo and try adding manually again."
                .format(self.showDir,
                        sickbeard.indexerApi(self.indexer).name,
                        self.indexer_id))

            if sickbeard.USE_TRAKT:

                trakt_id = sickbeard.indexerApi(
                    self.indexer).config['trakt_id']
                trakt_api = TraktAPI(sickbeard.SSL_VERIFY,
                                     sickbeard.TRAKT_TIMEOUT)

                title = self.showDir.split("/")[-1]
                data = {'shows': [{'title': title, 'ids': {}}]}
                if trakt_id == 'tvdb_id':
                    data['shows'][0]['ids']['tvdb'] = self.indexer_id
                else:
                    data['shows'][0]['ids']['tvrage'] = self.indexer_id

                trakt_api.traktRequest("sync/watchlist/remove",
                                       data,
                                       method='POST')

            self._finishEarly()
            return

        try:
            try:
                newShow = TVShow(self.indexer, self.indexer_id, self.lang)
            except MultipleShowObjectsException as error:
                # If we have the show in our list, but the location is wrong, lets fix it and refresh!
                existing_show = Show.find(sickbeard.showList, self.indexer_id)
                if existing_show and not ek(os.path.isdir,
                                            existing_show._location):  # pylint: disable=protected-access
                    newShow = existing_show
                else:
                    raise error

            newShow.loadFromIndexer()

            self.show = newShow

            # set up initial values
            self.show.location = self.showDir
            self.show.subtitles = self.subtitles if self.subtitles is not None else sickbeard.SUBTITLES_DEFAULT
            self.show.quality = self.quality if self.quality else sickbeard.QUALITY_DEFAULT
            self.show.flatten_folders = self.flatten_folders if self.flatten_folders is not None else sickbeard.FLATTEN_FOLDERS_DEFAULT
            self.show.anime = self.anime if self.anime is not None else sickbeard.ANIME_DEFAULT
            self.show.scene = self.scene if self.scene is not None else sickbeard.SCENE_DEFAULT
            self.show.paused = self.paused if self.paused is not None else False

            # set up default new/missing episode status
            logger.log(
                u"Setting all episodes to the specified default status: " +
                str(self.show.default_ep_status))
            self.show.default_ep_status = self.default_status

            if self.show.anime:
                self.show.release_groups = BlackAndWhiteList(
                    self.show.indexerid)
                if self.blacklist:
                    self.show.release_groups.set_black_keywords(self.blacklist)
                if self.whitelist:
                    self.show.release_groups.set_white_keywords(self.whitelist)

            # # be smartish about this
            # if self.show.genre and "talk show" in self.show.genre.lower():
            #     self.show.air_by_date = 1
            # if self.show.genre and "documentary" in self.show.genre.lower():
            #     self.show.air_by_date = 0
            # if self.show.classification and "sports" in self.show.classification.lower():
            #     self.show.sports = 1

        except sickbeard.indexer_exception as e:
            logger.log(
                u"Unable to add show due to an error with " +
                sickbeard.indexerApi(self.indexer).name + ": " + ex(e),
                logger.ERROR)
            if self.show:
                ui.notifications.error(
                    "Unable to add " + str(self.show.name) +
                    " due to an error with " +
                    sickbeard.indexerApi(self.indexer).name + "")
            else:
                ui.notifications.error(
                    "Unable to add show due to an error with " +
                    sickbeard.indexerApi(self.indexer).name + "")
            self._finishEarly()
            return

        except MultipleShowObjectsException:
            logger.log(
                u"The show in " + self.showDir +
                " is already in your show list, skipping", logger.WARNING)
            ui.notifications.error(
                'Show skipped', "The show in " + self.showDir +
                " is already in your show list")

            self._finishEarly()
            return

        except Exception as e:
            logger.log(u"Error trying to add show: " + ex(e), logger.ERROR)
            logger.log(traceback.format_exc(), logger.DEBUG)
            self._finishEarly()
            raise

        logger.log(u"Retrieving show info from IMDb", logger.DEBUG)
        try:
            self.show.loadIMDbInfo()
        except imdb_exceptions.IMDbError as e:
            logger.log(u" Something wrong on IMDb api: " + ex(e),
                       logger.WARNING)
        except Exception as e:
            logger.log(u"Error loading IMDb info: " + ex(e), logger.ERROR)

        try:
            self.show.saveToDB()
        except Exception as e:
            logger.log(u"Error saving the show to the database: " + ex(e),
                       logger.ERROR)
            logger.log(traceback.format_exc(), logger.DEBUG)
            self._finishEarly()
            raise

        # add it to the show list
        if not Show.find(sickbeard.showList, self.indexer_id):
            sickbeard.showList.append(self.show)

        try:
            self.show.loadEpisodesFromIndexer()
        except Exception as e:
            logger.log(
                u"Error with " + sickbeard.indexerApi(self.show.indexer).name +
                ", not creating episode list: " + ex(e), logger.ERROR)
            logger.log(traceback.format_exc(), logger.DEBUG)

        # update internal name cache
        name_cache.buildNameCache(self.show)

        try:
            self.show.loadEpisodesFromDir()
        except Exception as e:
            logger.log(u"Error searching dir for episodes: " + ex(e),
                       logger.ERROR)
            logger.log(traceback.format_exc(), logger.DEBUG)

        # if they set default ep status to WANTED then run the backlog to search for episodes
        # FIXME: This needs to be a backlog queue item!!!
        if self.show.default_ep_status == WANTED:
            logger.log(
                u"Launching backlog for this show since its episodes are WANTED"
            )
            sickbeard.backlogSearchScheduler.action.searchBacklog([self.show])

        self.show.writeMetadata()
        self.show.updateMetadata()
        self.show.populateCache()

        self.show.flushEpisodes()

        if sickbeard.USE_TRAKT:
            # if there are specific episodes that need to be added by trakt
            sickbeard.traktCheckerScheduler.action.manageNewShow(self.show)

            # add show to trakt.tv library
            if sickbeard.TRAKT_SYNC:
                sickbeard.traktCheckerScheduler.action.addShowToTraktLibrary(
                    self.show)

            if sickbeard.TRAKT_SYNC_WATCHLIST:
                logger.log(u"update watchlist")
                notifiers.trakt_notifier.update_watchlist(show_obj=self.show)

        # Load XEM data to DB for show
        sickbeard.scene_numbering.xem_refresh(self.show.indexerid,
                                              self.show.indexer,
                                              force=True)

        # check if show has XEM mapping so we can determin if searches should go by scene numbering or indexer numbering.
        if not self.scene and sickbeard.scene_numbering.get_xem_numbering_for_show(
                self.show.indexerid, self.show.indexer):
            self.show.scene = 1

        # After initial add, set to default_status_after.
        self.show.default_ep_status = self.default_status_after

        self.finish()
Example #36
0
    def run(self, force=False):  # pylint: disable=too-many-branches, too-many-statements, too-many-locals
        if not sickbeard.USE_SUBTITLES:
            return

        if not sickbeard.subtitles.enabled_service_list():
            logger.log(
                u'Not enough services selected. At least 1 service is required to '
                'search subtitles in the background', logger.WARNING)
            return

        self.amActive = True

        def dhm(td):
            days = td.days
            hours = td.seconds // 60**2
            minutes = (td.seconds // 60) % 60
            ret = (u'', '{0} days, '.format(days))[days > 0] + \
                (u'', '{0} hours, '.format(hours))[hours > 0] + \
                (u'', '{0} minutes'.format(minutes))[minutes > 0]
            if days == 1:
                ret = ret.replace('days', 'day')
            if hours == 1:
                ret = ret.replace('hours', 'hour')
            if minutes == 1:
                ret = ret.replace('minutes', 'minute')
            return ret.rstrip(', ')

        if sickbeard.SUBTITLES_DOWNLOAD_IN_PP:
            self.subtitles_download_in_pp()

        logger.log(u'Checking for missed subtitles', logger.INFO)

        database = db.DBConnection()
        sql_results = database.select(
            "SELECT s.show_name, e.showid, e.season, e.episode, "
            "e.status, e.subtitles, e.subtitles_searchcount AS searchcount, "
            "e.subtitles_lastsearch AS lastsearch, e.location, (? - e.airdate) as age "
            "FROM tv_episodes AS e INNER JOIN tv_shows AS s "
            "ON (e.showid = s.indexer_id) "
            "WHERE s.subtitles = 1 AND e.subtitles NOT LIKE ? "
            "AND e.location != '' AND e.status IN (%s) ORDER BY age ASC" %
            ','.join(['?'] * len(Quality.DOWNLOADED)),
            [datetime.datetime.now().toordinal(),
             wanted_languages(True)] + Quality.DOWNLOADED)

        if not sql_results:
            logger.log(u'No subtitles to download', logger.INFO)
            self.amActive = False
            return

        for ep_to_sub in sql_results:
            try:
                # Encode path to system encoding.
                subtitle_path = ep_to_sub['location'].encode(
                    sickbeard.SYS_ENCODING)
            except UnicodeEncodeError:
                # Fallback to UTF-8.
                subtitle_path = ep_to_sub['location'].encode('utf-8')
            if not os.path.isfile(subtitle_path):
                logger.log(
                    u'Episode file does not exist, cannot download subtitles for {0} {1}'
                    .format(
                        ep_to_sub['show_name'],
                        episode_num(ep_to_sub['season'], ep_to_sub['episode'])
                        or episode_num(ep_to_sub['season'],
                                       ep_to_sub['episode'],
                                       numbering='absolute')), logger.DEBUG)
                continue

            if not needs_subtitles(ep_to_sub['subtitles']):
                logger.log(
                    u'Episode already has all needed subtitles, skipping {0} {1}'
                    .format(
                        ep_to_sub['show_name'],
                        episode_num(ep_to_sub['season'], ep_to_sub['episode'])
                        or episode_num(ep_to_sub['season'],
                                       ep_to_sub['episode'],
                                       numbering='absolute')), logger.DEBUG)
                continue

            try:
                lastsearched = datetime.datetime.strptime(
                    ep_to_sub['lastsearch'], dateTimeFormat)
            except ValueError:
                lastsearched = datetime.datetime.min

            try:
                if not force:
                    now = datetime.datetime.now()
                    days = int(ep_to_sub['age'])
                    delay_time = datetime.timedelta(
                        hours=8 if days < 10 else 7 * 24 if days < 30 else 30 *
                        24)

                    # Search every hour for the first 24 hours since aired, then every 8 hours until 10 days passes
                    # After 10 days, search every 7 days, after 30 days search once a month
                    # Will always try an episode regardless of age at least 2 times
                    if lastsearched + delay_time > now and int(
                            ep_to_sub['searchcount']) > 2 and days:
                        logger.log(
                            u'Subtitle search for {0} {1} delayed for {2}'.
                            format(
                                ep_to_sub['show_name'],
                                episode_num(ep_to_sub['season'],
                                            ep_to_sub['episode'])
                                or episode_num(ep_to_sub['season'],
                                               ep_to_sub['episode'],
                                               numbering='absolute'),
                                dhm(lastsearched + delay_time - now)),
                            logger.DEBUG)
                        continue

                logger.log(
                    u'Searching for missing subtitles of {0} {1}'.format(
                        ep_to_sub['show_name'],
                        episode_num(ep_to_sub['season'], ep_to_sub['episode'])
                        or episode_num(ep_to_sub['season'],
                                       ep_to_sub['episode'],
                                       numbering='absolute')), logger.INFO)

                show_object = Show.find(sickbeard.showList,
                                        int(ep_to_sub['showid']))
                if not show_object:
                    logger.log(
                        u'Show with ID {0} not found in the database'.format(
                            ep_to_sub['showid']), logger.DEBUG)
                    continue

                episode_object = show_object.getEpisode(
                    ep_to_sub['season'], ep_to_sub['episode'])
                if isinstance(episode_object, str):
                    logger.log(
                        u'{0} {1} not found in the database'.format(
                            ep_to_sub['show_name'],
                            episode_num(ep_to_sub['season'],
                                        ep_to_sub['episode'])
                            or episode_num(ep_to_sub['season'],
                                           ep_to_sub['episode'],
                                           numbering='absolute')),
                        logger.DEBUG)
                    continue

                try:
                    new_subtitles = episode_object.download_subtitles()
                except Exception as error:
                    logger.log(
                        u'Unable to find subtitles for {0} {1}. Error: {2}'.
                        format(
                            ep_to_sub['show_name'],
                            episode_num(ep_to_sub['season'],
                                        ep_to_sub['episode'])
                            or episode_num(ep_to_sub['season'],
                                           ep_to_sub['episode'],
                                           numbering='absolute'), ex(error)),
                        logger.ERROR)
                    continue

                if new_subtitles:
                    logger.log(u'Downloaded {0} subtitles for {1} {2}'.format(
                        ', '.join(new_subtitles), ep_to_sub['show_name'],
                        episode_num(ep_to_sub['season'], ep_to_sub['episode'])
                        or episode_num(ep_to_sub['season'],
                                       ep_to_sub['episode'],
                                       numbering='absolute')))

            except Exception as error:
                logger.log(
                    u'Error while searching subtitles for {0} {1}. Error: {2}'.
                    format(
                        ep_to_sub['show_name'],
                        episode_num(ep_to_sub['season'], ep_to_sub['episode'])
                        or episode_num(ep_to_sub['season'],
                                       ep_to_sub['episode'],
                                       numbering='absolute'), ex(error)),
                    logger.ERROR)
                continue

        logger.log(u'Finished checking for missed subtitles', logger.INFO)
        self.amActive = False
Example #37
0
    def run(self, force=False):  # pylint: disable=too-many-branches, too-many-statements

        if not sickbeard.USE_SUBTITLES:
            return

        if len(sickbeard.subtitles.enabled_service_list()) < 1:
            logger.log(u'Not enough services selected. At least 1 service is required to '
                       'search subtitles in the background', logger.WARNING)
            return

        self.amActive = True

        def dhm(td):
            days = td.days
            hours = td.seconds // 60 ** 2
            minutes = (td.seconds // 60) % 60
            ret = (u'', '%s days, ' % days)[days > 0] + \
                (u'', '%s hours, ' % hours)[hours > 0] + \
                (u'', '%s minutes' % minutes)[minutes > 0]
            if days == 1:
                ret = ret.replace('days', 'day')
            if hours == 1:
                ret = ret.replace('hours', 'hour')
            if minutes == 1:
                ret = ret.replace('minutes', 'minute')
            return ret.rstrip(', ')

        if sickbeard.SUBTITLES_DOWNLOAD_IN_PP:
            self.subtitles_download_in_pp()

        logger.log(u'Checking for missed subtitles', logger.INFO)

        statuses = list({status for status in Quality.DOWNLOADED + Quality.ARCHIVED})

        database = db.DBConnection()
        sql_results = database.select(
            "SELECT s.show_name, e.showid, e.season, e.episode, "
            "e.status, e.subtitles, e.subtitles_searchcount AS searchcount, "
            "e.subtitles_lastsearch AS lastsearch, e.location, (? - e.airdate) as age "
            "FROM tv_episodes AS e INNER JOIN tv_shows AS s "
            "ON (e.showid = s.indexer_id) "
            "WHERE s.subtitles = 1 AND e.subtitles NOT LIKE ? "
            "AND e.location != '' AND e.status IN (%s) ORDER BY age ASC" %
            ','.join(['?'] * len(statuses)),
            [datetime.datetime.now().toordinal(), wanted_languages(True)] + statuses
        )

        if not sql_results:
            logger.log(u'No subtitles to download', logger.INFO)
            self.amActive = False
            return

        for ep_to_sub in sql_results:
            if not ek(os.path.isfile, ep_to_sub['location']):
                logger.log(u'Episode file does not exist, cannot download subtitles for %s S%02dE%02d'
                           % (ep_to_sub['show_name'], ep_to_sub['season'], ep_to_sub['episode']), logger.DEBUG)
                continue

            if not needs_subtitles(ep_to_sub['subtitles']):
                logger.log(u'Episode already has all needed subtitles, skipping %s S%02dE%02d'
                           % (ep_to_sub['show_name'], ep_to_sub['season'], ep_to_sub['episode']), logger.DEBUG)
                continue

            try:
                lastsearched = datetime.datetime.strptime(ep_to_sub['lastsearch'], dateTimeFormat)
            except ValueError:
                lastsearched = datetime.datetime.min

            try:
                if not force:
                    now = datetime.datetime.now()
                    days = int(ep_to_sub['age'])
                    delay_time = datetime.timedelta(hours=8 if days < 10 else 7 * 24 if days < 30 else 30 * 24)

                    # Search every hour for the first 24 hours since aired, then every 8 hours until 10 days passes
                    # After 10 days, search every 7 days, after 30 days search once a month
                    # Will always try an episode regardless of age at least 2 times
                    if lastsearched + delay_time > now and int(ep_to_sub['searchcount']) > 2 and days:
                        logger.log(u"Subtitle search for %s S%02dE%02d delayed for %s"
                                   % (ep_to_sub['show_name'], ep_to_sub['season'], ep_to_sub['episode'],
                                      dhm(lastsearched + delay_time - now)), logger.DEBUG)
                        continue

                logger.log(u'Searching for missing subtitles of %s S%02dE%02d'
                           % (ep_to_sub['show_name'], ep_to_sub['season'], ep_to_sub['episode']), logger.INFO)

                show_object = Show.find(sickbeard.showList, int(ep_to_sub['showid']))
                if not show_object:
                    logger.log(u'Show with ID %s not found in the database' % ep_to_sub['showid'], logger.DEBUG)
                    continue

                episode_object = show_object.getEpisode(ep_to_sub["season"], ep_to_sub["episode"])
                if isinstance(episode_object, str):
                    logger.log(u'%s S%02dE%02d not found in the database'
                               % (ep_to_sub['show_name'], ep_to_sub['season'], ep_to_sub['episode']), logger.DEBUG)
                    continue

                try:
                    new_subtitles = episode_object.download_subtitles()
                except Exception as error:
                    logger.log(u'Unable to find subtitles for %s S%02dE%02d. Error: %r'
                               % (ep_to_sub['show_name'], ep_to_sub['season'], ep_to_sub['episode'],
                                  ex(error)), logger.ERROR)
                    continue

                if new_subtitles:
                    logger.log(u'Downloaded %s subtitles for %s S%02dE%02d'
                               % (', '.join(new_subtitles), ep_to_sub['show_name'],
                                  ep_to_sub["season"], ep_to_sub["episode"]))

            except Exception as error:
                logger.log(u'Error while searching subtitles for %s S%02dE%02d. Error: %r'
                           % (ep_to_sub['show_name'], ep_to_sub['season'], ep_to_sub['episode'],
                              ex(error)), logger.ERROR)
                continue

        logger.log(u'Finished checking for missed subtitles', logger.INFO)
        self.amActive = False
Example #38
0
    def run(self):  # pylint: disable=too-many-branches, too-many-statements, too-many-return-statements

        super(QueueItemAdd, self).run()

        if self.showDir:
            try:
                assert isinstance(self.showDir, six.text_type)
            except AssertionError:
                logger.log(traceback.format_exc(), logger.WARNING)
                self._finish_early()
                return

        logger.log('Starting to add show {0}'.format(
            'by ShowDir: {0}'.format(self.showDir) if self.
            showDir else 'by Indexer Id: {0}'.format(self.indexer_id)))
        # make sure the Indexer IDs are valid
        try:

            lINDEXER_API_PARMS = sickbeard.indexerApi(
                self.indexer).api_params.copy()
            lINDEXER_API_PARMS[
                'language'] = self.lang or sickbeard.INDEXER_DEFAULT_LANGUAGE

            logger.log('{0}: {1!r}'.format(
                sickbeard.indexerApi(self.indexer).name, lINDEXER_API_PARMS))

            t = sickbeard.indexerApi(
                self.indexer).indexer(**lINDEXER_API_PARMS)
            s = t[self.indexer_id]

            # Let's try to create the show Dir if it's not provided. This way we force the show dir to build build using the
            # Indexers provided series name
            if self.root_dir and not self.showDir:
                show_name = get_showname_from_indexer(self.indexer,
                                                      self.indexer_id,
                                                      self.lang)
                if not show_name:
                    logger.log(
                        'Unable to get a show {0}, can\'t add the show'.format(
                            self.showDir))
                    self._finish_early()
                    return

                self.showDir = ek(os.path.join, self.root_dir,
                                  sanitize_filename(show_name))

                dir_exists = makeDir(self.showDir)
                if not dir_exists:
                    logger.log(
                        'Unable to create the folder {0}, can\'t add the show'.
                        format(self.showDir))
                    self._finish_early()
                    return

                chmodAsParent(self.showDir)

            # this usually only happens if they have an NFO in their show dir which gave us a Indexer ID that has no proper english version of the show
            if getattr(s, 'seriesname', None) is None:
                error_string = 'Show in {0} has no name on {1}, probably searched with the wrong language. Delete .nfo and add manually in the correct language.'.format(
                    self.showDir,
                    sickbeard.indexerApi(self.indexer).name)

                logger.log(error_string, logger.WARNING)
                ui.notifications.error('Unable to add show', error_string)

                self._finish_early()
                return

            # if the show has no episodes/seasons
            if not s:
                error_string = 'Show {0} is on {1} but contains no season/episode data.'.format(
                    s[b'seriesname'],
                    sickbeard.indexerApi(self.indexer).name)

                logger.log(error_string)
                ui.notifications.error('Unable to add show', error_string)

                self._finish_early()
                return
        except Exception as error:
            error_string = 'Unable to look up the show in {0} on {1} using ID {2}, not using the NFO. Delete .nfo and try adding manually again.'.format(
                self.showDir,
                sickbeard.indexerApi(self.indexer).name, self.indexer_id)

            logger.log('{0}: {1}'.format(error_string, error), logger.ERROR)
            ui.notifications.error('Unable to add show', error_string)

            if sickbeard.USE_TRAKT:
                trakt_id = sickbeard.indexerApi(
                    self.indexer).config[b'trakt_id']
                trakt_api = TraktAPI(sickbeard.SSL_VERIFY,
                                     sickbeard.TRAKT_TIMEOUT)

                title = self.showDir.split('/')[-1]
                data = {'shows': [{'title': title, 'ids': {}}]}
                if trakt_id == 'tvdb_id':
                    data[b'shows'][0][b'ids'][b'tvdb'] = self.indexer_id
                else:
                    data[b'shows'][0][b'ids'][b'tvrage'] = self.indexer_id

                trakt_api.traktRequest('sync/watchlist/remove',
                                       data,
                                       method='POST')

            self._finish_early()
            return

        try:
            try:
                newShow = TVShow(self.indexer, self.indexer_id, self.lang)
            except MultipleShowObjectsException as error:
                # If we have the show in our list, but the location is wrong, lets fix it and refresh!
                existing_show = Show.find(sickbeard.showList, self.indexer_id)
                if existing_show and not ek(os.path.isdir,
                                            existing_show._location):  # pylint: disable=protected-access
                    newShow = existing_show
                else:
                    raise error

            newShow.loadFromIndexer()

            self.show = newShow

            # set up initial values
            self.show.location = self.showDir
            self.show.subtitles = self.subtitles if self.subtitles is not None else sickbeard.SUBTITLES_DEFAULT
            self.show.subtitles_sr_metadata = self.subtitles_sr_metadata
            self.show.quality = self.quality if self.quality else sickbeard.QUALITY_DEFAULT
            self.show.season_folders = self.season_folders if self.season_folders is not None else sickbeard.SEASON_FOLDERS_DEFAULT
            self.show.anime = self.anime if self.anime is not None else sickbeard.ANIME_DEFAULT
            self.show.scene = self.scene if self.scene is not None else sickbeard.SCENE_DEFAULT
            self.show.paused = self.paused if self.paused is not None else False

            # set up default new/missing episode status
            logger.log(
                'Setting all episodes to the specified default status: {0}'.
                format(self.show.default_ep_status))
            self.show.default_ep_status = self.default_status

            if self.show.anime:
                self.show.release_groups = BlackAndWhiteList(
                    self.show.indexerid)
                if self.blacklist:
                    self.show.release_groups.set_black_keywords(self.blacklist)
                if self.whitelist:
                    self.show.release_groups.set_white_keywords(self.whitelist)

            # # be smartish about this
            # if self.show.genre and 'talk show' in self.show.genre.lower():
            #     self.show.air_by_date = 1
            # if self.show.genre and 'documentary' in self.show.genre.lower():
            #     self.show.air_by_date = 0
            # if self.show.classification and 'sports' in self.show.classification.lower():
            #     self.show.sports = 1

        except sickbeard.indexer_exception as error:
            error_string = 'Unable to add {0} due to an error with {1}'.format(
                self.show.name if self.show else 'show',
                sickbeard.indexerApi(self.indexer).name)

            logger.log('{0}: {1}'.format(error_string, error), logger.ERROR)
            ui.notifications.error('Unable to add show', error_string)

            self._finish_early()
            return

        except MultipleShowObjectsException:
            error_string = 'The show in {0} is already in your show list, skipping'.format(
                self.showDir)
            logger.log(error_string, logger.WARNING)
            ui.notifications.error('Show skipped', error_string)

            self._finish_early()
            return

        except Exception as error:
            logger.log('Error trying to add show: {0}'.format(error),
                       logger.ERROR)
            logger.log(traceback.format_exc(), logger.DEBUG)
            self._finish_early()
            raise

        logger.log('Retrieving show info from IMDb', logger.DEBUG)
        try:
            self.show.loadIMDbInfo()
        except imdb_exceptions.IMDbError as error:
            logger.log(' Something wrong on IMDb api: {0}'.format(error),
                       logger.WARNING)
        except Exception as error:
            logger.log('Error loading IMDb info: {0}'.format(error),
                       logger.ERROR)

        try:
            self.show.saveToDB()
        except Exception as error:
            logger.log(
                'Error saving the show to the database: {0}'.format(error),
                logger.ERROR)
            logger.log(traceback.format_exc(), logger.DEBUG)
            self._finish_early()
            raise

        # add it to the show list
        if not Show.find(sickbeard.showList, self.indexer_id):
            sickbeard.showList.append(self.show)

        try:
            self.show.loadEpisodesFromIndexer()
        except Exception as error:
            logger.log(
                'Error with {0}, not creating episode list: {1}'.format(
                    sickbeard.indexerApi(self.show.indexer).name, error),
                logger.ERROR)
            logger.log(traceback.format_exc(), logger.DEBUG)

        # update internal name cache
        name_cache.buildNameCache(self.show)

        try:
            self.show.loadEpisodesFromDir()
        except Exception as error:
            logger.log('Error searching dir for episodes: {0}'.format(error),
                       logger.ERROR)
            logger.log(traceback.format_exc(), logger.DEBUG)

        # if they set default ep status to WANTED then run the backlog to search for episodes
        # FIXME: This needs to be a backlog queue item!!!
        if self.show.default_ep_status == WANTED:
            logger.log(
                'Launching backlog for this show since its episodes are WANTED'
            )
            sickbeard.backlogSearchScheduler.action.searchBacklog([self.show])

        self.show.writeMetadata()
        self.show.updateMetadata()
        self.show.populateCache()

        self.show.flushEpisodes()

        if sickbeard.USE_TRAKT:
            # if there are specific episodes that need to be added by trakt
            sickbeard.traktCheckerScheduler.action.manageNewShow(self.show)
            # add show to trakt.tv library
            if sickbeard.TRAKT_SYNC:
                sickbeard.traktCheckerScheduler.action.addShowToTraktLibrary(
                    self.show)

            if sickbeard.TRAKT_SYNC_WATCHLIST:
                logger.log('update watchlist')
                notifiers.trakt_notifier.update_watchlist(show_obj=self.show)

        # Load XEM data to DB for show
        sickbeard.scene_numbering.xem_refresh(self.show.indexerid,
                                              self.show.indexer,
                                              force=True)

        # check if show has XEM mapping so we can determin if searches should go by scene numbering or indexer numbering.
        if not self.scene and sickbeard.scene_numbering.get_xem_numbering_for_show(
                self.show.indexerid, self.show.indexer):
            self.show.scene = 1

        # After initial add, set to default_status_after.
        self.show.default_ep_status = self.default_status_after

        super(QueueItemAdd, self).finish()
        self.finish()
Example #39
0
    def find_needed_episodes(self, episode, manualSearch=False, downCurQuality=False):  # pylint:disable=too-many-locals, too-many-branches
        needed_eps = {}
        cl = []

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

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

        # for each cache entry
        for cur_result in sql_results:
            # get the show object, or if it's not one of our shows then ignore it
            show_obj = Show.find(sickbeard.showList, int(cur_result[b"indexerid"]))
            if not show_obj:
                continue

            # ignored/required words, and non-tv junk
            if not show_name_helpers.filter_bad_releases(cur_result[b"name"], show=show_obj):
                continue

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

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

            cur_ep = cur_result[b"episodes"].split("|")[1]
            if not cur_ep:
                continue

            cur_ep = int(cur_ep)

            cur_quality = int(cur_result[b"quality"])
            cur_release_group = cur_result[b"release_group"]
            cur_version = cur_result[b"version"]

            # if the show says we want that episode then add it to the list
            if not show_obj.wantEpisode(cur_season, cur_ep, cur_quality, manualSearch, downCurQuality):
                logger.log("Ignoring " + cur_result[b"name"], logger.DEBUG)
                continue

            ep_obj = show_obj.getEpisode(cur_season, cur_ep)

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

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

            result = self.provider.get_result([ep_obj])
            result.show = show_obj
            result.url = url
            result.name = title
            result.quality = cur_quality
            result.release_group = cur_release_group
            result.version = cur_version
            result.content = None

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

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

        return needed_eps
Example #40
0
    def run(self, force=False):  # pylint: disable=unused-argument

        if not sickbeard.USE_SUBTITLES:
            return

        if len(sickbeard.subtitles.enabled_service_list()) < 1:
            logger.log(u'Not enough services selected. At least 1 service is required to '
                       'search subtitles in the background', logger.WARNING)
            return

        self.amActive = True

        if sickbeard.SUBTITLES_DOWNLOAD_IN_PP:
            self.subtitles_download_in_pp()

        logger.log(u'Checking for subtitles', logger.INFO)

        # get episodes on which we want subtitles
        # criteria is:
        #  - show subtitles = 1
        #  - episode subtitles != config wanted languages or 'und' (depends on config multi)
        #  - search count < 2 and diff(airdate, now) > 1 week : now -> 1d
        #  - search count < 7 and diff(airdate, now) <= 1 week : now -> 4h -> 8h -> 16h -> 1d -> 1d -> 1d

        today = datetime.date.today().toordinal()
        database = db.DBConnection()

        sql_results = database.select(
            'SELECT s.show_name, e.showid, e.season, e.episode, e.status, e.subtitles, ' +
            'e.subtitles_searchcount AS searchcount, e.subtitles_lastsearch AS lastsearch, e.location, '
            '(? - e.airdate) AS airdate_daydiff ' +
            'FROM tv_episodes AS e INNER JOIN tv_shows AS s ON (e.showid = s.indexer_id) ' +
            'WHERE s.subtitles = 1 AND e.subtitles NOT LIKE (?) ' +
            'AND (e.subtitles_searchcount <= 2 OR (e.subtitles_searchcount <= 7 AND airdate_daydiff <= 7)) ' +
            'AND e.location != ""', [today, wanted_languages(True)])

        if len(sql_results) == 0:
            logger.log(u'No subtitles to download', logger.INFO)
            self.amActive = False
            return

        rules = self._get_rules()
        now = datetime.datetime.now()
        for ep_to_sub in sql_results:

            if not ek(os.path.isfile, ep_to_sub['location']):
                logger.log(u'Episode file does not exist, cannot download subtitles for episode %dx%d of show %s'
                           % (ep_to_sub['season'], ep_to_sub['episode'], ep_to_sub['show_name']), logger.DEBUG)
                continue

            if not needs_subtitles(ep_to_sub['subtitles']):
                logger.log(u'Episode already has all needed subtitles, skipping  episode %dx%d of show %s'
                           % (ep_to_sub['season'], ep_to_sub['episode'], ep_to_sub['show_name']), logger.DEBUG)
                continue

            # http://bugs.python.org/issue7980#msg221094
            # I dont think this needs done here, but keeping to be safe (Recent shows rule)
            datetime.datetime.strptime('20110101', '%Y%m%d')
            if ((ep_to_sub['airdate_daydiff'] > 7 and ep_to_sub['searchcount'] < 2 and
                 now - datetime.datetime.strptime(ep_to_sub['lastsearch'], dateTimeFormat) >
                 datetime.timedelta(hours=rules['old'][ep_to_sub['searchcount']])) or
                    (ep_to_sub['airdate_daydiff'] <= 7 and ep_to_sub['searchcount'] < 7 and
                     now - datetime.datetime.strptime(ep_to_sub['lastsearch'], dateTimeFormat) >
                     datetime.timedelta(hours=rules['new'][ep_to_sub['searchcount']]))):

                logger.log(u'Downloading subtitles for episode %dx%d of show %s'
                           % (ep_to_sub['season'], ep_to_sub['episode'], ep_to_sub['show_name']), logger.DEBUG)

                show_object = Show.find(sickbeard.showList, int(ep_to_sub['showid']))
                if not show_object:
                    logger.log(u'Show not found', logger.DEBUG)
                    self.amActive = False
                    return

                episode_object = show_object.getEpisode(int(ep_to_sub["season"]), int(ep_to_sub["episode"]))
                if isinstance(episode_object, str):
                    logger.log(u'Episode not found', logger.DEBUG)
                    self.amActive = False
                    return

                existing_subtitles = episode_object.subtitles

                try:
                    episode_object.download_subtitles()
                except Exception as error:
                    logger.log(u'Unable to find subtitles', logger.DEBUG)
                    logger.log(str(error), logger.DEBUG)
                    self.amActive = False
                    return

                new_subtitles = frozenset(episode_object.subtitles).difference(existing_subtitles)
                if new_subtitles:
                    logger.log(u'Downloaded subtitles for S%02dE%02d in %s'
                               % (ep_to_sub["season"], ep_to_sub["episode"], ', '.join(new_subtitles)))

        self.amActive = False
Example #41
0
    def run(self):  # pylint: disable=too-many-branches, too-many-statements, too-many-return-statements

        super(QueueItemAdd, self).run()

        if self.showDir:
            try:
                assert isinstance(self.showDir, six.text_type)
            except AssertionError:
                logger.log(traceback.format_exc(), logger.WARNING)
                self._finish_early()
                return

        logger.log('Starting to add show {0}'.format('by ShowDir: {0}'.format(self.showDir) if self.showDir else 'by Indexer Id: {0}'.format(self.indexer_id)))
        # make sure the Indexer IDs are valid
        try:

            lINDEXER_API_PARMS = sickbeard.indexerApi(self.indexer).api_params.copy()
            lINDEXER_API_PARMS['language'] = self.lang or sickbeard.INDEXER_DEFAULT_LANGUAGE

            logger.log('{0}: {1!r}'.format(sickbeard.indexerApi(self.indexer).name, lINDEXER_API_PARMS))

            t = sickbeard.indexerApi(self.indexer).indexer(**lINDEXER_API_PARMS)
            s = t[self.indexer_id]

            # Let's try to create the show Dir if it's not provided. This way we force the show dir to build build using the
            # Indexers provided series name
            if self.root_dir and not self.showDir:
                show_name = get_showname_from_indexer(self.indexer, self.indexer_id, self.lang)
                if not show_name:
                    logger.log('Unable to get a show {0}, can\'t add the show'.format(self.showDir))
                    self._finish_early()
                    return

                self.showDir = ek(os.path.join, self.root_dir, sanitize_filename(show_name))

                dir_exists = makeDir(self.showDir)
                if not dir_exists:
                    logger.log('Unable to create the folder {0}, can\'t add the show'.format(self.showDir))
                    self._finish_early()
                    return

                chmodAsParent(self.showDir)

            # this usually only happens if they have an NFO in their show dir which gave us a Indexer ID that has no proper english version of the show
            if getattr(s, 'seriesname', None) is None:
                error_string = 'Show in {0} has no name on {1}, probably searched with the wrong language. Delete .nfo and add manually in the correct language.'.format(
                    self.showDir, sickbeard.indexerApi(self.indexer).name)

                logger.log(error_string, logger.WARNING)
                ui.notifications.error('Unable to add show', error_string)

                self._finish_early()
                return

            # if the show has no episodes/seasons
            if not s:
                error_string = 'Show {0} is on {1} but contains no season/episode data.'.format(
                    s[b'seriesname'], sickbeard.indexerApi(self.indexer).name)

                logger.log(error_string)
                ui.notifications.error('Unable to add show', error_string)

                self._finish_early()
                return
        except Exception as error:
            error_string = 'Unable to look up the show in {0} on {1} using ID {2}, not using the NFO. Delete .nfo and try adding manually again.'.format(
                self.showDir, sickbeard.indexerApi(self.indexer).name, self.indexer_id)

            logger.log('{0}: {1}'.format(error_string, error), logger.ERROR)
            ui.notifications.error(
                'Unable to add show', error_string)

            if sickbeard.USE_TRAKT:
                trakt_id = sickbeard.indexerApi(self.indexer).config[b'trakt_id']
                trakt_api = TraktAPI(sickbeard.SSL_VERIFY, sickbeard.TRAKT_TIMEOUT)

                title = self.showDir.split('/')[-1]
                data = {
                    'shows': [
                        {
                            'title': title,
                            'ids': {}
                        }
                    ]
                }
                if trakt_id == 'tvdb_id':
                    data[b'shows'][0][b'ids'][b'tvdb'] = self.indexer_id
                else:
                    data[b'shows'][0][b'ids'][b'tvrage'] = self.indexer_id

                trakt_api.traktRequest('sync/watchlist/remove', data, method='POST')

            self._finish_early()
            return

        try:
            try:
                newShow = TVShow(self.indexer, self.indexer_id, self.lang)
            except MultipleShowObjectsException as error:
                # If we have the show in our list, but the location is wrong, lets fix it and refresh!
                existing_show = Show.find(sickbeard.showList, self.indexer_id)
                if existing_show and not ek(os.path.isdir, existing_show._location):  # pylint: disable=protected-access
                    newShow = existing_show
                else:
                    raise error

            newShow.loadFromIndexer()

            self.show = newShow

            # set up initial values
            self.show.location = self.showDir
            self.show.subtitles = self.subtitles if self.subtitles is not None else sickbeard.SUBTITLES_DEFAULT
            self.show.subtitles_sr_metadata = self.subtitles_sr_metadata
            self.show.quality = self.quality if self.quality else sickbeard.QUALITY_DEFAULT
            self.show.season_folders = self.season_folders if self.season_folders is not None else sickbeard.SEASON_FOLDERS_DEFAULT
            self.show.anime = self.anime if self.anime is not None else sickbeard.ANIME_DEFAULT
            self.show.scene = self.scene if self.scene is not None else sickbeard.SCENE_DEFAULT
            self.show.paused = self.paused if self.paused is not None else False

            # set up default new/missing episode status
            logger.log('Setting all episodes to the specified default status: {0}' .format(self.show.default_ep_status))
            self.show.default_ep_status = self.default_status

            if self.show.anime:
                self.show.release_groups = BlackAndWhiteList(self.show.indexerid)
                if self.blacklist:
                    self.show.release_groups.set_black_keywords(self.blacklist)
                if self.whitelist:
                    self.show.release_groups.set_white_keywords(self.whitelist)

            # # be smartish about this
            # if self.show.genre and 'talk show' in self.show.genre.lower():
            #     self.show.air_by_date = 1
            # if self.show.genre and 'documentary' in self.show.genre.lower():
            #     self.show.air_by_date = 0
            # if self.show.classification and 'sports' in self.show.classification.lower():
            #     self.show.sports = 1

        except sickbeard.indexer_exception as error:
            error_string = 'Unable to add {0} due to an error with {1}'.format(
                self.show.name if self.show else 'show', sickbeard.indexerApi(self.indexer).name)

            logger.log('{0}: {1}'.format(error_string, error), logger.ERROR)
            ui.notifications.error('Unable to add show', error_string)

            self._finish_early()
            return

        except MultipleShowObjectsException:
            error_string = 'The show in {0} is already in your show list, skipping'.format(self.showDir)
            logger.log(error_string, logger.WARNING)
            ui.notifications.error('Show skipped', error_string)

            self._finish_early()
            return

        except Exception as error:
            logger.log('Error trying to add show: {0}'.format(error), logger.ERROR)
            logger.log(traceback.format_exc(), logger.DEBUG)
            self._finish_early()
            raise

        logger.log('Retrieving show info from IMDb', logger.DEBUG)
        try:
            self.show.loadIMDbInfo()
        except imdb_exceptions.IMDbError as error:
            logger.log(' Something wrong on IMDb api: {0}'.format(error), logger.WARNING)
        except Exception as error:
            logger.log('Error loading IMDb info: {0}'.format(error), logger.ERROR)

        try:
            self.show.saveToDB()
        except Exception as error:
            logger.log('Error saving the show to the database: {0}'.format(error), logger.ERROR)
            logger.log(traceback.format_exc(), logger.DEBUG)
            self._finish_early()
            raise

        # add it to the show list
        if not Show.find(sickbeard.showList, self.indexer_id):
            sickbeard.showList.append(self.show)

        try:
            self.show.loadEpisodesFromIndexer()
        except Exception as error:
            logger.log(
                'Error with {0}, not creating episode list: {1}'.format
                (sickbeard.indexerApi(self.show.indexer).name, error), logger.ERROR)
            logger.log(traceback.format_exc(), logger.DEBUG)

        # update internal name cache
        name_cache.buildNameCache(self.show)

        try:
            self.show.loadEpisodesFromDir()
        except Exception as error:
            logger.log('Error searching dir for episodes: {0}'.format(error), logger.ERROR)
            logger.log(traceback.format_exc(), logger.DEBUG)

        # if they set default ep status to WANTED then run the backlog to search for episodes
        # FIXME: This needs to be a backlog queue item!!!
        if self.show.default_ep_status == WANTED:
            logger.log('Launching backlog for this show since its episodes are WANTED')
            sickbeard.backlogSearchScheduler.action.searchBacklog([self.show])

        self.show.writeMetadata()
        self.show.updateMetadata()
        self.show.populateCache()

        self.show.flushEpisodes()

        if sickbeard.USE_TRAKT:
            # if there are specific episodes that need to be added by trakt
            sickbeard.traktCheckerScheduler.action.manageNewShow(self.show)
            # add show to trakt.tv library
            if sickbeard.TRAKT_SYNC:
                sickbeard.traktCheckerScheduler.action.addShowToTraktLibrary(self.show)

            if sickbeard.TRAKT_SYNC_WATCHLIST:
                logger.log('update watchlist')
                notifiers.trakt_notifier.update_watchlist(show_obj=self.show)

        # Load XEM data to DB for show
        sickbeard.scene_numbering.xem_refresh(self.show.indexerid, self.show.indexer, force=True)

        # check if show has XEM mapping so we can determin if searches should go by scene numbering or indexer numbering.
        if not self.scene and sickbeard.scene_numbering.get_xem_numbering_for_show(self.show.indexerid,
                                                                                   self.show.indexer):
            self.show.scene = 1

        # After initial add, set to default_status_after.
        self.show.default_ep_status = self.default_status_after

        super(QueueItemAdd, self).finish()
        self.finish()
Example #42
0
    def run(self, force=False):  # pylint: disable=unused-argument,too-many-statements,too-many-branches

        if not sickbeard.USE_SUBTITLES:
            return

        if len(sickbeard.subtitles.enabled_service_list()) < 1:
            logger.log(
                u'Not enough services selected. At least 1 service is required to '
                'search subtitles in the background', logger.WARNING)
            return

        self.amActive = True

        if sickbeard.SUBTITLES_DOWNLOAD_IN_PP:
            self.subtitles_download_in_pp()

        logger.log(u'Checking for subtitles', logger.INFO)

        # get episodes on which we want subtitles
        # criteria is:
        #  - show subtitles = 1
        #  - episode subtitles != config wanted languages or 'und' (depends on config multi)
        #  - search count < 2 and diff(airdate, now) > 1 week : now -> 1d
        #  - search count < 7 and diff(airdate, now) <= 1 week : now -> 4h -> 8h -> 16h -> 1d -> 1d -> 1d
        """
        Defines the hours to wait between 2 subtitles search depending on:
        - the episode: new or old
        - the number of searches done so far (searchcount), represented by the index of the list
        """
        rules = {'old': [0, 24], 'new': [0, 4, 8, 4, 16, 24, 24]}

        if sickbeard.SUBTITLES_MULTI:
            query_languages = wanted_languages(True)
        else:
            query_languages = '%und%'

        today = datetime.date.today().toordinal()
        database = db.DBConnection()
        sql_results = database.select(
            'SELECT s.show_name, e.showid, e.season, e.episode, e.status, e.subtitles, '
            'e.subtitles_searchcount AS searchcount, e.subtitles_lastsearch AS lastsearch, e.location, '
            '(? - e.airdate) AS airdate_daydiff '
            'FROM tv_episodes AS e INNER JOIN tv_shows AS s ON (e.showid = s.indexer_id) '
            'WHERE s.subtitles = 1 AND e.subtitles NOT LIKE ? '
            'AND (e.subtitles_searchcount <= 2 OR (e.subtitles_searchcount <= 7 AND airdate_daydiff <= 7)) '
            'AND e.location != ""', [today, query_languages])

        if len(sql_results) == 0:
            logger.log(u'No subtitles to download', logger.INFO)
            self.amActive = False
            return

        now = datetime.datetime.now()
        for ep_to_sub in sql_results:

            if not ek(os.path.isfile, ep_to_sub['location']):
                logger.log(
                    u'Episode file does not exist, cannot download subtitles for %s S%02dE%02d'
                    % (ep_to_sub['show_name'], ep_to_sub['season'],
                       ep_to_sub['episode']), logger.DEBUG)
                continue

            if not needs_subtitles(ep_to_sub['subtitles']):
                logger.log(
                    u'Episode already has all needed subtitles, skipping %s S%02dE%02d'
                    % (ep_to_sub['show_name'], ep_to_sub['season'],
                       ep_to_sub['episode']), logger.DEBUG)
                continue

            logger.log(
                u"%s S%02dE%02d doesn't have all needed subtitles" %
                (ep_to_sub['show_name'], ep_to_sub['season'],
                 ep_to_sub['episode']), logger.DEBUG)

            try:
                try:
                    lastsearched = datetime.datetime.strptime(
                        ep_to_sub['lastsearch'], dateTimeFormat)
                except ValueError:
                    lastsearched = datetime.datetime.min

                if ((ep_to_sub['airdate_daydiff'] > 7
                     and ep_to_sub['searchcount'] < 2
                     and now - lastsearched > datetime.timedelta(
                         hours=rules['old'][ep_to_sub['searchcount']])) or
                    (ep_to_sub['airdate_daydiff'] <= 7
                     and ep_to_sub['searchcount'] < 7
                     and now - lastsearched > datetime.timedelta(
                         hours=rules['new'][ep_to_sub['searchcount']]))):

                    logger.log(
                        u'Started subtitles search for %s S%02dE%02d' %
                        (ep_to_sub['show_name'], ep_to_sub['season'],
                         ep_to_sub['episode']), logger.INFO)

                    show_object = Show.find(sickbeard.showList,
                                            int(ep_to_sub['showid']))
                    if not show_object:
                        logger.log(
                            u'Show with ID %s not found in the database' %
                            ep_to_sub['showid'], logger.DEBUG)
                        continue

                    episode_object = show_object.getEpisode(
                        int(ep_to_sub["season"]), int(ep_to_sub["episode"]))
                    if isinstance(episode_object, str):
                        logger.log(
                            u'%s S%02dE%02d not found in the database' %
                            (ep_to_sub['show_name'], ep_to_sub['season'],
                             ep_to_sub['episode']), logger.DEBUG)
                        continue

                    existing_subtitles = episode_object.subtitles

                    try:
                        episode_object.download_subtitles()
                    except Exception as error:
                        logger.log(
                            u'Unable to find subtitles for %s S%02dE%02d. Error: %r'
                            % (ep_to_sub['show_name'], ep_to_sub['season'],
                               ep_to_sub['episode'], ex(error)), logger.ERROR)
                        continue

                    new_subtitles = frozenset(
                        episode_object.subtitles).difference(
                            existing_subtitles)
                    if new_subtitles:
                        logger.log(
                            u'Downloaded %s subtitles for %s S%02dE%02d' %
                            (', '.join(new_subtitles), ep_to_sub['show_name'],
                             ep_to_sub["season"], ep_to_sub["episode"]))
            except Exception as error:
                logger.log(
                    u'Error while searching subtitles for %s S%02dE%02d. Error: %r'
                    % (ep_to_sub['show_name'], ep_to_sub['season'],
                       ep_to_sub['episode'], ex(error)), logger.ERROR)
                continue

        self.amActive = False
Example #43
0
    def run(self, force=False):  # pylint:disable=too-many-branches
        """
        Runs the daily searcher, queuing selected episodes for search

        :param force: Force search
        """
        if self.amActive:
            logger.log('Daily search is still running, not starting it again', logger.DEBUG)
            return
        elif sickbeard.forcedSearchQueueScheduler.action.is_forced_search_in_progress() and not force:
            logger.log('Manual search is running. Can\'t start Daily search', logger.WARNING)
            return

        self.amActive = True

        logger.log('Searching for newly released episodes ...')

        if not network_dict:
            update_network_dict()

        cur_time = datetime.now(sb_timezone)
        cur_date = (
            date.today() + timedelta(days=1 if network_dict else 2)
        ).toordinal()

        main_db_con = DBConnection()
        episodes_from_db = main_db_con.select(
            b'SELECT showid, airdate, season, episode '
            b'FROM tv_episodes '
            b'WHERE status = ? AND (airdate <= ? and airdate > 1)',
            [common.UNAIRED, cur_date]
        )

        new_releases = []
        show = None

        for db_episode in episodes_from_db:
            try:
                show_id = int(db_episode[b'showid'])
                if not show or show_id != show.indexerid:
                    show = Show.find(sickbeard.showList, show_id)

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

            except MultipleShowObjectsException:
                logger.log('ERROR: expected to find a single show matching {id}'.format(id=show_id))
                continue

            if show.airs and show.network:
                # This is how you assure it is always converted to local time
                show_air_time = parse_date_time(db_episode[b'airdate'], show.airs, show.network)
                end_time = show_air_time.astimezone(sb_timezone) + timedelta(minutes=try_int(show.runtime, 60))

                # filter out any episodes that haven't finished airing yet,
                if end_time > cur_time:
                    continue

            cur_ep = show.get_episode(db_episode[b'season'], db_episode[b'episode'])
            with cur_ep.lock:
                cur_ep.status = show.default_ep_status if cur_ep.season else common.SKIPPED
                logger.log('Setting status ({status}) for show airing today: {name} {special}'.format(
                    name=cur_ep.pretty_name(),
                    status=common.statusStrings[cur_ep.status],
                    special='(specials are not supported)' if not cur_ep.season else ''
                ))
                new_releases.append(cur_ep.get_sql())

        if new_releases:
            main_db_con = DBConnection()
            main_db_con.mass_action(new_releases)
        else:
            logger.log('No newly released episodes found ...')

        # queue episode for daily search
        sickbeard.searchQueueScheduler.action.add_item(
            DailySearchQueueItem()
        )

        self.amActive = False
Example #44
0
    def run(self, force=False):  # pylint: disable=too-many-branches, too-many-statements, too-many-locals
        if not sickbeard.USE_SUBTITLES:
            return

        if not sickbeard.subtitles.enabled_service_list():
            logger.log('Not enough services selected. At least 1 service is required to '
                       'search subtitles in the background', logger.WARNING)
            return

        self.amActive = True

        def dhm(td):
            days = td.days
            hours = td.seconds // 60 ** 2
            minutes = (td.seconds // 60) % 60
            ret = ('', '{0} days, '.format(days))[days > 0] + \
                  ('', '{0} hours, '.format(hours))[hours > 0] + \
                  ('', '{0} minutes'.format(minutes))[minutes > 0]
            if days == 1:
                ret = ret.replace('days', 'day')
            if hours == 1:
                ret = ret.replace('hours', 'hour')
            if minutes == 1:
                ret = ret.replace('minutes', 'minute')
            return ret.rstrip(', ')

        logger.log('Checking for missed subtitles', logger.INFO)

        database = db.DBConnection()
        sql_results = database.select(
            "SELECT s.show_name, e.showid, e.season, e.episode, "
            "e.status, e.subtitles, e.subtitles_searchcount AS searchcount, "
            "e.subtitles_lastsearch AS lastsearch, e.location, (? - e.airdate) as age "
            "FROM tv_episodes AS e INNER JOIN tv_shows AS s "
            "ON (e.showid = s.indexer_id) "
            "WHERE s.subtitles = 1 AND e.subtitles NOT LIKE ? "
            + ("AND e.season != 0 ", "")[sickbeard.SUBTITLES_INCLUDE_SPECIALS]
            + "AND e.location != '' AND e.status IN ({}) ORDER BY age ASC".format(','.join(['?'] * len(Quality.DOWNLOADED))),
            [datetime.datetime.now().toordinal(), wanted_languages(True)] + Quality.DOWNLOADED
        )

        if not sql_results:
            logger.log('No subtitles to download', logger.INFO)
            self.amActive = False
            return

        for ep_to_sub in sql_results:
            try:
                # Encode path to system encoding.
                subtitle_path = ep_to_sub[b'location'].encode(sickbeard.SYS_ENCODING)
            except UnicodeEncodeError:
                # Fallback to UTF-8.
                subtitle_path = ep_to_sub[b'location'].encode('utf-8')
            if not os.path.isfile(subtitle_path):
                logger.log('Episode file does not exist, cannot download subtitles for {0} {1}'.format
                           (ep_to_sub[b'show_name'], episode_num(ep_to_sub[b'season'], ep_to_sub[b'episode']) or
                            episode_num(ep_to_sub[b'season'], ep_to_sub[b'episode'], numbering='absolute')), logger.DEBUG)
                continue

            if not needs_subtitles(ep_to_sub[b'subtitles']):
                logger.log('Episode already has all needed subtitles, skipping {0} {1}'.format
                           (ep_to_sub[b'show_name'], episode_num(ep_to_sub[b'season'], ep_to_sub[b'episode']) or
                            episode_num(ep_to_sub[b'season'], ep_to_sub[b'episode'], numbering='absolute')), logger.DEBUG)
                continue

            try:
                lastsearched = datetime.datetime.strptime(ep_to_sub[b'lastsearch'], dateTimeFormat)
            except ValueError:
                lastsearched = datetime.datetime.min

            try:
                if not force:
                    now = datetime.datetime.now()
                    days = int(ep_to_sub[b'age'])
                    delay_time = datetime.timedelta(hours=8 if days < 10 else 7 * 24 if days < 30 else 30 * 24)

                    # Search every hour for the first 24 hours since aired, then every 8 hours until 10 days passes
                    # After 10 days, search every 7 days, after 30 days search once a month
                    # Will always try an episode regardless of age at least 2 times
                    if lastsearched + delay_time > now and int(ep_to_sub[b'searchcount']) > 2 and days:
                        logger.log('Subtitle search for {0} {1} delayed for {2}'.format
                                   (ep_to_sub[b'show_name'], episode_num(ep_to_sub[b'season'], ep_to_sub[b'episode']) or
                                    episode_num(ep_to_sub[b'season'], ep_to_sub[b'episode'], numbering='absolute'),
                                    dhm(lastsearched + delay_time - now)), logger.DEBUG)
                        continue

                logger.log('Searching for missing subtitles of {0} {1}'.format
                           (ep_to_sub[b'show_name'], episode_num(ep_to_sub[b'season'], ep_to_sub[b'episode']) or
                            episode_num(ep_to_sub[b'season'], ep_to_sub[b'episode'], numbering='absolute')), logger.INFO)

                show_object = Show.find(sickbeard.showList, int(ep_to_sub[b'showid']))
                if not show_object:
                    logger.log('Show with ID {0} not found in the database'.format(ep_to_sub[b'showid']), logger.DEBUG)
                    continue

                episode_object = show_object.getEpisode(ep_to_sub[b'season'], ep_to_sub[b'episode'])
                if isinstance(episode_object, str):
                    logger.log('{0} {1} not found in the database'.format
                               (ep_to_sub[b'show_name'], episode_num(ep_to_sub[b'season'], ep_to_sub[b'episode']) or
                                episode_num(ep_to_sub[b'season'], ep_to_sub[b'episode'], numbering='absolute')), logger.DEBUG)
                    continue

                try:
                    new_subtitles = episode_object.download_subtitles()
                except Exception as error:
                    logger.log('Unable to find subtitles for {0} {1}. Error: {2}'.format
                               (ep_to_sub[b'show_name'], episode_num(ep_to_sub[b'season'], ep_to_sub[b'episode']) or
                                episode_num(ep_to_sub[b'season'], ep_to_sub[b'episode'], numbering='absolute'), ex(error)), logger.ERROR)
                    continue

                if new_subtitles:
                    logger.log('Downloaded {0} subtitles for {1} {2}'.format
                               (', '.join(new_subtitles), ep_to_sub[b'show_name'], episode_num(ep_to_sub[b'season'], ep_to_sub[b'episode']) or
                                episode_num(ep_to_sub[b'season'], ep_to_sub[b'episode'], numbering='absolute')))

            except Exception as error:
                logger.log('Error while searching subtitles for {0} {1}. Error: {2}'.format
                           (ep_to_sub[b'show_name'], episode_num(ep_to_sub[b'season'], ep_to_sub[b'episode']) or
                            episode_num(ep_to_sub[b'season'], ep_to_sub[b'episode'], numbering='absolute'), ex(error)), logger.ERROR)
                continue

        logger.log('Finished checking for missed subtitles', logger.INFO)
        self.amActive = False
Example #45
0
    def run(self, force=False):  # pylint:disable=too-many-branches
        """
        Runs the daily searcher, queuing selected episodes for search

        :param force: Force search
        """
        if self.amActive:
            return

        self.amActive = True
        _ = force
        logger.log(u"Searching for new released episodes ...")

        if not network_timezones.network_dict:
            network_timezones.update_network_dict()

        if network_timezones.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(network_timezones.sb_timezone)

        main_db_con = db.DBConnection()
        sql_results = main_db_con.select("SELECT showid, airdate, season, episode FROM tv_episodes WHERE status = ? AND (airdate <= ? and airdate > 1)",
                                         [common.UNAIRED, curDate])

        sql_l = []
        show = None

        for sqlEp in sql_results:
            try:
                if not show or int(sqlEp["showid"]) != show.indexerid:
                    show = Show.find(sickbeard.showList, int(sqlEp["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:
                logger.log(u"ERROR: expected to find a single show matching " + str(sqlEp['showid']))
                continue

            if show.airs and show.network:
                # This is how you assure it is always converted to local time
                air_time = network_timezones.parse_date_time(sqlEp['airdate'], show.airs, show.network).astimezone(network_timezones.sb_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(sqlEp["season"], sqlEp["episode"])
            with ep.lock:
                if ep.season == 0:
                    logger.log(u"New episode " + ep.prettyName() + " airs today, setting status to SKIPPED because is a special season")
                    ep.status = common.SKIPPED
                else:
                    logger.log(u"New episode %s airs today, setting to default episode status for this show: %s" % (ep.prettyName(), common.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_con = db.DBConnection()
            main_db_con.mass_action(sql_l)
        else:
            logger.log(u"No new released episodes found ...")

        # queue episode for daily search
        dailysearch_queue_item = sickbeard.search_queue.DailySearchQueueItem()
        sickbeard.searchQueueScheduler.action.add_item(dailysearch_queue_item)

        self.amActive = False
Example #46
0
    def run(self, force=None, show=None):
        if sickbeard.showList == None:
            return
        logger.log(u"Beginning the search for french episodes older than " +
                   str(sickbeard.FRENCH_DELAY) + " days")
        foundResults = {}
        finalResults = []
        #show = self
        frenchlist = []
        #get list of english episodes that we want to search in french
        myDB = db.DBConnection()
        today = datetime.date.today().toordinal()
        if show:
            frenchsql = myDB.select(
                "SELECT showid, season, episode from tv_episodes where audio_langs='eng' and tv_episodes.showid =? and (? - tv_episodes.airdate) > ? order by showid, airdate asc",
                [show, today, sickbeard.FRENCH_DELAY])
            logger.log(
                "SELECT showid, season, episode from tv_episodes where audio_langs='eng' and tv_episodes.showid ="
                + str(show) + "and (" + str(today) +
                " - tv_episodes.airdate) > " + str(sickbeard.FRENCH_DELAY) +
                "order by showid, airdate asc")
            count = myDB.select(
                "SELECT count(*) from tv_episodes where audio_langs='eng' and tv_episodes.showid =? and (? - tv_episodes.airdate) > ?",
                [show, today, sickbeard.FRENCH_DELAY])
        else:
            frenchsql = myDB.select(
                "SELECT showid, season, episode from tv_episodes, tv_shows where audio_langs='eng' and tv_episodes.showid = tv_shows.indexer_id and tv_shows.frenchsearch = 1 and (? - tv_episodes.airdate) > ? order by showid, airdate asc",
                [today, sickbeard.FRENCH_DELAY])
            count = myDB.select(
                "SELECT count(*) from tv_episodes, tv_shows where audio_langs='eng' and tv_episodes.showid = tv_shows.indexer_id and tv_shows.frenchsearch = 1 and (? - tv_episodes.airdate) > ?",
                [today, sickbeard.FRENCH_DELAY])
        #make the episodes objects

        #logger.log("SELECT showid, season, episode from tv_episodes where audio_langs='eng' and tv_episodes.showid =" + str(show) +"and (" +str(today)+" - tv_episodes.airdate) > "+ str(sickbeard.FRENCH_DELAY) +"order by showid, airdate asc")
        logger.log(
            "SELECT showid, season, episode from tv_episodes, tv_shows where audio_langs='eng' and tv_episodes.showid = tv_shows.indexer_id and tv_shows.frenchsearch = 1 and ("
            + str(today) + " - tv_episodes.airdate) > " +
            str(sickbeard.FRENCH_DELAY) + " order by showid, airdate asc")
        logger.log(u"Searching for " + str(count[0][0]) +
                   " episodes in french")

        #logger.log(frenchsql)

        #logger.log(sickbeard.showList.)

        for episode in frenchsql:

            showObj = Show.find(sickbeard.showList, int(episode[0]))
            if showObj == None:
                logger.log("Show not in show list")

            #showObj = helpers.findCertainShow(sickbeard.showList, episode[0])
            epObj = showObj.getEpisode(episode[1], episode[2])

            #epObj = showObj.getEpisode(int(epInfo[0]), int(epInfo[1]))
            frenchlist.append(epObj)

        #for each episode in frenchlist fire a search in french
        delay = []
        temp = None
        rest = count[0][0]
        for frepisode in frenchlist:
            rest = rest - 1
            if frepisode.show.indexerid in delay:
                logger.log(
                    u"Previous episode for show " + str(frepisode.show.name) +
                    " not found in french so skipping this search",
                    logger.DEBUG)
                continue
            result = []
            for curProvider in providers.sortedProviderList():

                foundResults[curProvider.name] = {}

                if not curProvider.is_active():
                    continue

                logger.log(u"Searching for french episode on " +
                           curProvider.name + " for " + frepisode.show.name +
                           " season " + str(frepisode.season) + " episode " +
                           str(frepisode.episode))
                #try:
                #    logger.log(frepisode)
                #    temp = GenericProvider()
                #    curfrench = temp.findFrench(self, episode=frepisode, manualSearch=True)
                #curfrench =  GenericProvider.findFrench(episode=frepi  sode,manualSearch=True)
                #curProvider.findFrench(frepisode, manualSearch=True)
                #except:
                #    logger.log(u"Exception", logger.DEBUG)
                #    pass

                #for curProvider in providers:
                #    if curProvider.anime_only and not show.is_anime:
                #        logger.log(u"" + str(show.name) + " is not an anime, skipping", logger.DEBUG)
                #        continue

                curfrench = curProvider.find_search_results(
                    frepisode.show, frenchlist, 'sponly', True, True, 'french')

                #curfrench = curProvider.findFrench(frepisode, True)

                #temp = GenericProvider('temp')
                #curfrench = temp.findFrench( episode=frepisode, manualSearch=True)

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

                if not foundResults[curProvider.name]:
                    continue

                bestSeasonResult = None
                #if SEASON_RESULT in foundResults[curProvider.name]:
                #    bestSeasonResult = search.pickBestResult(foundResults[curProvider.name][SEASON_RESULT], show)
                #_______________________________________________________
                test = 0
                if foundResults[curProvider.name]:
                    for cur_episode in foundResults[curProvider.name]:
                        for x in foundResults[curProvider.name][cur_episode]:
                            tmp = x
                            if not show_name_helpers.filterBadReleases(
                                    x.name):  #x.name):
                                logger.log(
                                    u"French " + x.name +
                                    " isn't a valid scene release that we want, ignoring it",
                                    logger.DEBUG)
                                test += 1
                                continue
                            if sickbeard.IGNORE_WORDS == "":
                                ignore_words = "ztreyfgut"
                            else:
                                ignore_words = str(sickbeard.IGNORE_WORDS)
                            for fil in resultFilters + ignore_words.split(','):
                                if fil == showLanguages.get(u"fre"):
                                    continue
                                if re.search('(^|[\W_])' + fil + '($|[\W_])',
                                             x.url, re.I) or re.search(
                                                 '(^|[\W_])' + fil +
                                                 '($|[\W_])', x.name, re.I):
                                    logger.log(
                                        u"Invalid scene release: " + x.url +
                                        " contains " + fil + ", ignoring it",
                                        logger.DEBUG)
                                    test += 1

                    if test == 0:
                        result.append(x)

            best = None
            try:
                epi = {}
                epi[1] = frepisode
                best = search.pickBestResult(result, showObj)
            except:
                pass
            if best:
                best.name = best.name + ' snatchedfr'
                logger.log(u"Found french episode for " + frepisode.show.name +
                           " season " + str(frepisode.season) + " episode " +
                           str(frepisode.episode))
                try:
                    search.snatchEpisode(best, SNATCHED_FRENCH)
                except:
                    logger.log(u"Exception", logger.DEBUG)
                    pass
            else:
                delay.append(frepisode.show.indexerid)
                logger.log(u"No french episode found for " +
                           frepisode.show.name + " season " +
                           str(frepisode.season) + " episode " +
                           str(frepisode.episode))
            logger.log(str(rest) + u" episodes left")
Example #47
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

        logger.log(u"Searching for new released episodes ...")

        if not network_timezones.network_dict:
            network_timezones.update_network_dict()

        if network_timezones.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(network_timezones.sb_timezone)

        myDB = db.DBConnection()
        sqlResults = myDB.select(
            "SELECT showid, airdate, season, episode FROM tv_episodes WHERE status = ? AND (airdate <= ? and airdate > 1)",
            [common.UNAIRED, curDate])

        sql_l = []
        show = None

        for sqlEp in sqlResults:
            try:
                if not show or int(sqlEp["showid"]) != show.indexerid:
                    show = Show.find(sickbeard.showList, int(sqlEp["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:
                logger.log(u"ERROR: expected to find a single show matching " +
                           str(sqlEp['showid']))
                continue

            if show.airs and show.network:
                # This is how you assure it is always converted to local time
                air_time = network_timezones.parse_date_time(
                    sqlEp['airdate'], show.airs,
                    show.network).astimezone(network_timezones.sb_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(sqlEp["season"], sqlEp["episode"])
            with ep.lock:
                if ep.season == 0:
                    logger.log(
                        u"New episode " + ep.prettyName() +
                        " airs today, setting status to SKIPPED because is a special season"
                    )
                    ep.status = common.SKIPPED
                else:
                    logger.log(
                        u"New episode %s airs today, setting to default episode status for this show: %s"
                        % (ep.prettyName(),
                           common.statusStrings[ep.show.default_ep_status]))
                    ep.status = ep.show.default_ep_status

                sql_l.append(ep.get_sql())

        if len(sql_l) > 0:
            myDB = db.DBConnection()
            myDB.mass_action(sql_l)
        else:
            logger.log(u"No new released episodes found ...")

        # queue episode for daily search
        dailysearch_queue_item = sickbeard.search_queue.DailySearchQueueItem()
        sickbeard.searchQueueScheduler.action.add_item(dailysearch_queue_item)

        self.amActive = False
Example #48
0
    def findNeededEpisodes(self, episode, manualSearch=False, downCurQuality=False):
        neededEps = {}
        cl = []

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

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

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

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

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

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

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

            curEp = int(curEp)

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

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

            epObj = showObj.getEpisode(curSeason, curEp)

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

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

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

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

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

        return neededEps