Exemplo n.º 1
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/")
Exemplo n.º 2
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 + ') and e.is_proper = 0')

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

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

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

                    for search_string in search_strings:
                        for item in self.search(search_string):
                            title, url = self._get_title_and_url(item)

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

        return results
Exemplo n.º 3
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("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("Unable to create the folder {0} , can't add the show".format(showPath), logger.WARNING)
                    return
                else:
                    helpers.chmodAsParent(showPath)

                sickbeard.showQueueScheduler.action.add_show(int(indexer), int(indexer_id), showPath,
                                                             default_status=status,
                                                             quality=int(sickbeard.QUALITY_DEFAULT),
                                                             season_folders=int(sickbeard.SEASON_FOLDERS_DEFAULT),
                                                             paused=sickbeard.TRAKT_START_PAUSED,
                                                             default_status_after=status)
            else:
                logger.log("There was an error creating the show, no root directory setting found", logger.WARNING)
                return
Exemplo n.º 4
0
    def updateShows(self):
        logger.debug("SHOW_WATCHLIST::CHECK::START - Trakt Show Watchlist")

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

        for index, indexer in sickchill.indexer:
            if indexer.slug in self.ShowWatchlist:
                for show_el in self.ShowWatchlist[indexer.slug]:
                    indexer_id = int(str(show_el))
                    show = self.ShowWatchlist[indexer.slug][show_el]

                    # logger.debug("Checking Show: %s %s %s" % (slug, indexer_id, show['title']))
                    if int(settings.TRAKT_METHOD_ADD) != 2:
                        self.addDefaultShow(index, indexer_id, show["title"],
                                            SKIPPED)
                    else:
                        self.addDefaultShow(index, indexer_id, show["title"],
                                            WANTED)

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

                        if newShow is not None:
                            setEpisodeToWanted(newShow, 1, 1)
                        else:
                            self.todoWanted.append((indexer_id, 1, 1))
        logger.debug("SHOW_WATCHLIST::CHECK::FINISH - Trakt Show Watchlist")
Exemplo n.º 5
0
def get_scene_exceptions(indexer_id, season=-1):
    """
    Given a indexer_id, return a list of all the scene exceptions.
    """

    if indexer_id not in exceptions_cache or season not in exceptions_cache[indexer_id]:
        cache_db_con = db.DBConnection("cache.db")
        exceptions = cache_db_con.select("SELECT show_name FROM scene_exceptions WHERE indexer_id = ? and season = ?", [indexer_id, season])
        if exceptions:
            exeptions_list = list({cur_exception["show_name"] for cur_exception in exceptions})
            if indexer_id not in exceptions_cache:
                exceptions_cache[indexer_id] = {}
            exceptions_cache[indexer_id][season] = exeptions_list

    results = []
    if indexer_id in exceptions_cache and season in exceptions_cache[indexer_id]:
        results += exceptions_cache[indexer_id][season]

    # Add generic exceptions regardless of the season if there is no exception for season
    if season != -1:
        get_scene_exceptions(indexer_id)
        if indexer_id in exceptions_cache and -1 in exceptions_cache[indexer_id]:
            results += exceptions_cache[indexer_id][-1]
    else:
        show = Show.find(settings.showList, indexer_id)
        if show:
            if show.show_name:
                results.append(helpers.full_sanitizeSceneName(show.show_name))
            if show.custom_name:
                results.append(helpers.full_sanitizeSceneName(show.custom_name))

    response = list({result for result in results})
    logger.debug(f"get_scene_exceptions: {response}")
    logger.debug(f"exceptions_cache: {exceptions_cache.get(indexer_id)}")
    return response
Exemplo n.º 6
0
    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)
Exemplo n.º 7
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("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("Unable to create the folder {0} , can't add the show".format(showPath), logger.WARNING)
                    return
                else:
                    helpers.chmodAsParent(showPath)

                sickbeard.showQueueScheduler.action.add_show(int(indexer), int(indexer_id), showPath,
                                                             default_status=status,
                                                             quality=int(sickbeard.QUALITY_DEFAULT),
                                                             season_folders=int(sickbeard.SEASON_FOLDERS_DEFAULT),
                                                             paused=sickbeard.TRAKT_START_PAUSED,
                                                             default_status_after=status)
            else:
                logger.log("There was an error creating the show, no root directory setting found", logger.WARNING)
                return
Exemplo n.º 8
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
Exemplo n.º 9
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(
                    "SELECT season, episode FROM tv_episodes WHERE (status LIKE '%4' OR status LIKE '%6') {0} AND showid = ? AND location != ''".format(
                        ("AND season != 0 ", "")[settings.SUBTITLES_INCLUDE_SPECIALS]
                    ),
                    [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(settings.showList, int(cur_indexer_id))
                show.getEpisode(season, episode).download_subtitles()

        return self.redirect("/manage/subtitleMissed/")
Exemplo n.º 10
0
def get_scene_numbering(indexer_id,
                        indexer,
                        season,
                        episode,
                        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 indexer numbering.
    (so the return values will always be set)

    :param indexer_id: int
    :param season: int
    :param episode: 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 season is None or episode is None:
        return season, episode

    showObj = Show.find(settings.showList, int(indexer_id))
    if showObj and not showObj.is_scene:
        return season, episode

    result = find_scene_numbering(int(indexer_id), int(indexer), season,
                                  episode)
    if result:
        return result
    else:
        if fallback_to_xem:
            xem_result = find_xem_numbering(int(indexer_id), int(indexer),
                                            season, episode)
            if xem_result:
                return xem_result
        return season, episode
Exemplo n.º 11
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()
Exemplo n.º 12
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)
Exemplo n.º 13
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)
Exemplo n.º 14
0
    def test_find(self):
        """
        Test find tv shows by indexer_id
        """
        settings.QUALITY_DEFAULT = Quality.FULLHDTV

        settings.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"): show123,
            (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"): show123,
        }

        for tests in test_cases, unicode_test_cases:
            for ((use_shows, indexer_id), result) in tests.items():
                if use_shows:
                    assert Show.find(shows, indexer_id) == result
                else:
                    assert Show.find(None, indexer_id) == result

        with self.assertRaises(MultipleShowObjectsException):
            Show.find(shows_duplicate, 456)
Exemplo n.º 15
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
Exemplo n.º 16
0
def get_all_scene_exceptions(indexer_id):
    """
    Get all scene exceptions for a show ID

    :param indexer_id: ID to check
    :return: dict of exceptions
    """
    all_exceptions_dict = {}

    cache_db_con = db.DBConnection("cache.db")
    exceptions = cache_db_con.select("SELECT show_name, season, custom FROM scene_exceptions WHERE indexer_id = ?", [indexer_id])

    if indexer_id in exceptions_cache:
        del exceptions_cache[indexer_id]

    for cur_exception in exceptions:
        if cur_exception["season"] not in all_exceptions_dict:
            all_exceptions_dict[cur_exception["season"]] = []
        all_exceptions_dict[cur_exception["season"]].append({"show_name": cur_exception["show_name"], "custom": bool(cur_exception["custom"])})

        if indexer_id not in exceptions_cache:
            exceptions_cache[indexer_id] = {}

        if cur_exception["season"] not in exceptions_cache[indexer_id]:
            exceptions_cache[indexer_id][cur_exception["season"]] = []

        exceptions_cache[indexer_id][cur_exception["season"]].append(cur_exception["show_name"])

    show = Show.find(settings.showList, indexer_id)
    if show:
        sanitized_name = helpers.full_sanitizeSceneName(show.show_name)
        sanitized_custom_name = helpers.full_sanitizeSceneName(show.custom_name)

        if sanitized_name or sanitized_custom_name:

            if -1 not in all_exceptions_dict:
                all_exceptions_dict[-1] = []

            if indexer_id not in exceptions_cache:
                exceptions_cache[indexer_id] = {}

            if -1 not in exceptions_cache[indexer_id]:
                exceptions_cache[indexer_id][-1] = []

            if sanitized_name:
                all_exceptions_dict[-1].append({"show_name": sanitized_name, "custom": False})
                if sanitized_name not in exceptions_cache[indexer_id][-1]:
                    exceptions_cache[indexer_id][-1].append(sanitized_name)
            if sanitized_custom_name:
                all_exceptions_dict[-1].append({"show_name": sanitized_custom_name, "custom": False})
                if sanitized_custom_name not in exceptions_cache[indexer_id][-1]:
                    exceptions_cache[indexer_id][-1].append(sanitized_custom_name)

    logger.debug(f"get_all_scene_exceptions: {all_exceptions_dict}")
    logger.debug(f"exceptions_cache for {indexer_id}: {exceptions_cache.get(indexer_id)}")
    return all_exceptions_dict
Exemplo n.º 17
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
                ]
            ]
Exemplo n.º 18
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 = []

        for index, indexer in sickchill.indexer:
            if indexer.slug in self.EpisodeWatchlist:
                for show_el in self.EpisodeWatchlist[indexer.slug]:
                    indexer_id = int(show_el)
                    show = self.EpisodeWatchlist[indexer.slug][show_el]

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

                    try:
                        if newShow is None:
                            if indexer_id not in managed_show:
                                self.addDefaultShow(index, 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)
Exemplo n.º 19
0
    def fetch_indexer_favorites(self):
        """Get favorited show information from Indexers"""

        indexer_favorites = sickchill.indexer.get_indexer_favorites()
        results = []
        for series in indexer_favorites:
            if Show().find(settings.showList, series.id):
                continue
            results.append(series)
            self.cache_image(series.id)

        return results
Exemplo n.º 20
0
    def test_validate_indexer_id(self):
        """
        Tests if the indexer_id is valid and if so if it returns the right show
        """
        settings.QUALITY_DEFAULT = Quality.FULLHDTV

        settings.showList = []

        show123 = TestTVShow(0, 123)
        show456 = TestTVShow(0, 456)
        show789 = TestTVShow(0, 789)
        settings.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,
        ]

        assert 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):
            assert Show._validate_indexer_id(indexer_id) == results_list[index]
Exemplo n.º 21
0
def get_id_from_name(name):
    """
    Looks up the given name in the scene_names table in cache.db.

    :param name: The show name to look up.
    :return: the TVDB id that resulted from the cache lookup or None if the show wasn't found in the cache
    """
    name = helpers.full_sanitizeSceneName(name)
    if name not in name_cache:
        cache_db_con = db.DBConnection("cache.db")
        results = cache_db_con.select_one("SELECT indexer_id FROM scene_names WHERE name = ?", [name])
        if results:
            indexer_id = results["indexer_id"]
            show = Show.find(settings.showList, indexer_id)
            if show:
                build_name_cache(show)
    else:
        return int(name_cache[name])
Exemplo n.º 22
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)
Exemplo n.º 23
0
    def index(self, show=None, imageType="", provider: int = None):
        if not show:
            return self._genericMessage(_("Error"),
                                        _("You must specify a show"))

        show_obj = Show.find(sickchill.settings.showList, int(show))
        if not show_obj:
            return self._genericMessage(_("Error"), _("Show not in show list"))

        self.set_header("Cache-Control", "max-age=0,no-cache,no-store")
        self.set_header("Content-Type", "application/json")

        provider = int(provider)
        if provider == ShowIndexer.FANART:
            metadata_generator = GenericMetadata()
            images = metadata_generator._retrieve_show_image_urls_from_fanart(
                show_obj, imageType, multiple=True)
            images = list({
                "image": image,
                "thumb": re.sub("/fanart/", "/preview/", image)
            } for image in images)
        elif provider == ShowIndexer.TMDB:
            metadata_generator = GenericMetadata()
            images = metadata_generator._retrieve_show_image_urls_from_tmdb(
                show_obj, imageType, multiple=True)
            images = list({"image": image, "thumb": image} for image in images)
        else:
            if "poster" == imageType:
                images = sickchill.indexer[provider].series_poster_url(
                    show_obj, multiple=True)
            elif "banner" == imageType:
                images = sickchill.indexer[provider].series_banner_url(
                    show_obj, multiple=True)
            elif "fanart" == imageType:
                images = sickchill.indexer[provider].series_fanart_url(
                    show_obj, multiple=True)
            else:
                return self._genericMessage(_("Error"),
                                            _("Invalid image provider"))

            images = list({"image": image, "thumb": image} for image in images)

        return json.dumps(images)
Exemplo n.º 24
0
def set_scene_numbering(indexer_id,
                        indexer,
                        season=None,
                        episode=None,
                        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(settings.showList, indexer_id)
    show.flushEpisodes()
Exemplo n.º 25
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
Exemplo n.º 26
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
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
Exemplo n.º 28
0
    def run(self):

        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:
            s = sickchill.indexer.series_by_id(indexerid=self.indexer_id,
                                               indexer=self.indexer,
                                               language=self.lang)
            if not s:
                error_string = 'Could not find show with id:{0} on {1}, skipping'.format(
                    self.indexer_id, sickchill.indexer.name(self.indexer))

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

                self._finish_early()
                return

            # 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:
                if not s.seriesName:
                    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(s.seriesName))

                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:
                # noinspection PyPep8
                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, sickchill.indexer.name(self.indexer))

                logger.log(error_string, logger.WARNING)
                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, sickchill.indexer.name(self.indexer),
                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_api = TraktAPI(sickbeard.SSL_VERIFY,
                                     sickbeard.TRAKT_TIMEOUT)

                title = self.showDir.split('/')[-1]
                data = {
                    'shows': [{
                        'title': title,
                        'ids': {
                            sickchill.indexer.slug(self.indexer):
                            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)
                # noinspection PyProtectedMember
                if existing_show and not ek(os.path.isdir,
                                            existing_show._location):
                    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 smart-ish 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 Exception as error:
            error_string = 'Unable to add {0} due to an error with {1}'.format(
                self.show.name if self.show else 'show',
                sickchill.indexer.name(self.indexer))

            logger.log('{0}: {1}'.format(error_string, error), logger.ERROR)

            logger.log('Error trying to add show: {0}'.format(error),
                       logger.ERROR)
            logger.log(traceback.format_exc(), logger.DEBUG)

            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

        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(
                    self.show.idxr.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
        scene_numbering.xem_refresh(self.show.indexerid,
                                    self.show.indexer,
                                    force=True)

        # check if show has XEM mapping so we can determine if searches should go by scene numbering or indexer numbering.
        if not self.scene and 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()
Exemplo n.º 29
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:
                # noinspection PyPep8
                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['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._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)
                # noinspection PyProtectedMember
                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 smart-ish 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
        scene_numbering.xem_refresh(self.show.indexerid, self.show.indexer, force=True)

        # check if show has XEM mapping so we can determine if searches should go by scene numbering or indexer numbering.
        if not self.scene and 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()
Exemplo n.º 30
0
    def find_needed_episodes(self,
                             episode,
                             manualSearch=False,
                             downCurQuality=False):
        needed_eps = {}
        cl = []

        cache_db_con = self._get_db()
        if not episode:
            sql_results = cache_db_con.select(
                "SELECT * FROM results WHERE provider = ?", [self.provider_id])
        elif not isinstance(episode, list):
            sql_results = cache_db_con.select(
                "SELECT * FROM results WHERE provider = ? AND indexerid = ? AND season = ? AND episodes LIKE ?",
                [
                    self.provider_id, episode.show.indexerid, episode.season,
                    "%|" + str(episode.episode) + "|%"
                ])
        else:
            for ep_obj in episode:
                cl.append([
                    "SELECT * FROM results WHERE provider = ? AND indexerid = ? AND season = ? AND episodes LIKE ? AND quality IN ("
                    + ",".join([str(x) for x in ep_obj.wantedQuality]) + ")",
                    [
                        self.provider_id, 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(settings.showList,
                                 int(cur_result["indexerid"]))
            if not show_obj:
                continue

            # ignored/required words, and non-tv junk
            if not show_name_helpers.filter_bad_releases(cur_result["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.debug("" + str(show_obj.name) +
                             " is not an anime, skiping")
                continue

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

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

            cur_ep = int(cur_ep)

            cur_quality = int(cur_result["quality"])
            cur_release_group = cur_result["release_group"]
            cur_version = cur_result["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.debug("Ignoring " + cur_result["name"])
                continue

            ep_obj = show_obj.getEpisode(cur_season, cur_ep)

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

            logger.info("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
Exemplo n.º 31
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("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[b"showid"]) != show.indexerid:
                    show = Show.find(sickbeard.showList, int(sqlEp[b"showid"]))

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

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

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

                sql_l.append(ep.get_sql())

        if sql_l:
            main_db_con = db.DBConnection()
            main_db_con.mass_action(sql_l)
        else:
            logger.log("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
Exemplo n.º 32
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
        logger.info(_("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(settings.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.info("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.info(
                        "New episode " + ep.pretty_name +
                        " airs today, setting status to SKIPPED because is a special season"
                    )
                    ep.status = common.SKIPPED
                else:
                    logger.info(
                        "New episode {0} airs today, setting to default episode status for this show: {1}"
                        .format(
                            ep.pretty_name,
                            common.statusStrings[ep.show.default_ep_status]))
                    ep.status = ep.show.default_ep_status

                sql_l.append(ep.get_sql())

        if sql_l:
            main_db_con = db.DBConnection()
            main_db_con.mass_action(sql_l)
        else:
            logger.info("No new released episodes found ...")

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

        self.amActive = False
Exemplo n.º 33
0
    def _add_cache_entry(self,
                         name,
                         url,
                         size,
                         seeders,
                         leechers,
                         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(settings.showList, indexer_id)

            try:
                parse_result = NameParser(showObj=show_obj).parse(name)
            except (InvalidNameException, InvalidShowException) as error:
                logger.debug("{0}".format(error))
                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 usage 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 separated string
            episode_text = "|" + "|".join(
                {str(episode)
                 for episode in sorted(episodes) if episode}) + "|"

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

            # get quality of release
            quality = parse_result.quality

            # get release group
            release_group = parse_result.release_group

            # get version
            version = parse_result.version

            logger.debug(
                _("Added RSS item: [{}] to cache: {}").format(
                    name, self.provider_id))
            return ({
                'provider': self.provider_id,
                'name': name,
                'season': season,
                'episodes': episode_text,
                'indexerid': parse_result.show.indexerid,
                'url': url,
                'time': cur_timestamp,
                'quality': quality,
                'release_group': release_group,
                'version': version,
                'seeders': seeders,
                'leechers': leechers,
                'size': size
            }, {
                'url': url
            })
Exemplo n.º 34
0
    def massEdit(self, toEdit=None):
        t = PageTemplate(rh=self, filename="manage_massEdit.mako")

        if not toEdit:
            return self.redirect("/manage/")

        showIDs = toEdit.split("|")
        showList = []
        showNames = []
        for curID in showIDs:
            curID = int(curID)
            show_obj = Show.find(sickbeard.showList, curID)
            if show_obj:
                showList.append(show_obj)
                showNames.append(show_obj.name)

        season_folders_all_same = True
        last_season_folders = None

        paused_all_same = True
        last_paused = None

        default_ep_status_all_same = True
        last_default_ep_status = None

        anime_all_same = True
        last_anime = None

        sports_all_same = True
        last_sports = None

        quality_all_same = True
        last_quality = None

        subtitles_all_same = True
        last_subtitles = None

        scene_all_same = True
        last_scene = None

        air_by_date_all_same = True
        last_air_by_date = None

        root_dir_list = []

        for curShow in showList:

            cur_root_dir = self.__gooey_path(curShow._location, 'dirname')
            if cur_root_dir and cur_root_dir != curShow._location and cur_root_dir not in root_dir_list:
                root_dir_list.append(cur_root_dir)

            # if we know they're not all the same then no point even bothering
            if paused_all_same:
                # if we had a value already and this value is different then they're not all the same
                if last_paused not in (None, curShow.paused):
                    paused_all_same = False
                else:
                    last_paused = curShow.paused

            if default_ep_status_all_same:
                if last_default_ep_status not in (None,
                                                  curShow.default_ep_status):
                    default_ep_status_all_same = False
                else:
                    last_default_ep_status = curShow.default_ep_status

            if anime_all_same:
                # if we had a value already and this value is different then they're not all the same
                if last_anime not in (None, curShow.is_anime):
                    anime_all_same = False
                else:
                    last_anime = curShow.anime

            if season_folders_all_same:
                if last_season_folders not in (None, curShow.season_folders):
                    season_folders_all_same = False
                else:
                    last_season_folders = curShow.season_folders

            if quality_all_same:
                if last_quality not in (None, curShow.quality):
                    quality_all_same = False
                else:
                    last_quality = curShow.quality

            if subtitles_all_same:
                if last_subtitles not in (None, curShow.subtitles):
                    subtitles_all_same = False
                else:
                    last_subtitles = curShow.subtitles

            if scene_all_same:
                if last_scene not in (None, curShow.scene):
                    scene_all_same = False
                else:
                    last_scene = curShow.scene

            if sports_all_same:
                if last_sports not in (None, curShow.sports):
                    sports_all_same = False
                else:
                    last_sports = curShow.sports

            if air_by_date_all_same:
                if last_air_by_date not in (None, curShow.air_by_date):
                    air_by_date_all_same = False
                else:
                    last_air_by_date = curShow.air_by_date

        default_ep_status_value = last_default_ep_status if default_ep_status_all_same else None
        paused_value = last_paused if paused_all_same else None
        anime_value = last_anime if anime_all_same else None
        season_folders_value = last_season_folders if season_folders_all_same else None
        quality_value = last_quality if quality_all_same else None
        subtitles_value = last_subtitles if subtitles_all_same else None
        scene_value = last_scene if scene_all_same else None
        sports_value = last_sports if sports_all_same else None
        air_by_date_value = last_air_by_date if air_by_date_all_same else None

        return t.render(showList=toEdit,
                        showNames=showNames,
                        default_ep_status_value=default_ep_status_value,
                        paused_value=paused_value,
                        anime_value=anime_value,
                        season_folders_value=season_folders_value,
                        quality_value=quality_value,
                        subtitles_value=subtitles_value,
                        scene_value=scene_value,
                        sports_value=sports_value,
                        air_by_date_value=air_by_date_value,
                        root_dir_list=root_dir_list,
                        title=_('Mass Edit'),
                        header=_('Mass Edit'),
                        controller='manage',
                        action='massEdit',
                        topmenu='manage')
Exemplo n.º 35
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
Exemplo n.º 36
0
    def addShowByID(
        self,
        indexer_id,
        show_name,
        indexer="TVDB",
        which_series=None,
        indexer_lang=None,
        root_dir=None,
        default_status=None,
        quality_preset=None,
        any_qualities=None,
        best_qualities=None,
        season_folders=None,
        subtitles=None,
        full_show_path=None,
        other_shows=None,
        skip_show=None,
        provided_indexer=None,
        anime=None,
        scene=None,
        blacklist=None,
        whitelist=None,
        default_status_after=None,
        default_season_folders=None,
        configure_show_options=None,
    ):

        if indexer != "TVDB":
            indexer_id = helpers.tvdbid_from_remote_id(indexer_id,
                                                       indexer.upper())
            if not indexer_id:
                logger.info(
                    "Unable to to find tvdb ID to add {0}".format(show_name))
                ui.notifications.error(
                    "Unable to add {0}".format(show_name),
                    "Could not add {0}.  We were unable to locate the tvdb id at this time."
                    .format(show_name))
                return

        indexer_id = try_int(indexer_id)

        if indexer_id <= 0 or Show.find(settings.showList, indexer_id):
            return

        # Sanitize the parameter anyQualities and bestQualities. As these would normally be passed as lists
        any_qualities = any_qualities.split(",") if any_qualities else []
        best_qualities = best_qualities.split(",") if best_qualities else []

        # If configure_show_options is enabled let's use the provided settings
        if config.checkbox_to_value(configure_show_options):
            # prepare the inputs for passing along
            scene = config.checkbox_to_value(scene)
            anime = config.checkbox_to_value(anime)
            season_folders = config.checkbox_to_value(season_folders)
            subtitles = config.checkbox_to_value(subtitles)

            if whitelist:
                whitelist = short_group_names(whitelist)
            if blacklist:
                blacklist = short_group_names(blacklist)

            if not any_qualities:
                any_qualities = []

            if not best_qualities or try_int(quality_preset, None):
                best_qualities = []

            if not isinstance(any_qualities, list):
                any_qualities = [any_qualities]

            if not isinstance(best_qualities, list):
                best_qualities = [best_qualities]

            quality = Quality.combineQualities(
                [int(q) for q in any_qualities],
                [int(q) for q in best_qualities])

            location = root_dir

        else:
            default_status = settings.STATUS_DEFAULT
            quality = settings.QUALITY_DEFAULT
            season_folders = settings.SEASON_FOLDERS_DEFAULT
            subtitles = settings.SUBTITLES_DEFAULT
            anime = settings.ANIME_DEFAULT
            scene = settings.SCENE_DEFAULT
            default_status_after = settings.STATUS_DEFAULT_AFTER

            if settings.ROOT_DIRS:
                root_dirs = settings.ROOT_DIRS.split("|")
                location = root_dirs[int(root_dirs[0]) + 1]
            else:
                location = None

        if not location:
            logger.info(
                "There was an error creating the show, no root directory setting found"
            )
            return _("No root directories setup, please go back and add one.")

        show_name = sickchill.indexer[1].get_series_by_id(
            indexer_id, indexer_lang).seriesName
        show_dir = None

        if not show_name:
            ui.notifications.error(_("Unable to add show"))
            return self.redirect("/home/")

        # add the show
        settings.showQueueScheduler.action.add_show(
            indexer=1,
            indexer_id=indexer_id,
            showDir=show_dir,
            default_status=default_status,
            quality=quality,
            season_folders=season_folders,
            lang=indexer_lang,
            subtitles=subtitles,
            subtitles_sr_metadata=None,
            anime=anime,
            scene=scene,
            paused=None,
            blacklist=blacklist,
            whitelist=whitelist,
            default_status_after=default_status_after,
            root_dir=location,
        )

        ui.notifications.message(
            _("Show added"),
            _("Adding the specified show {show_name}").format(
                show_name=show_name))

        # done adding show
        return self.redirect("/home/")
Exemplo n.º 37
0
    def massAddTable(self, rootDir=None):
        t = PageTemplate(rh=self, filename="home_massAddTable.mako")

        if not rootDir:
            return _("No folders selected.")
        elif not isinstance(rootDir, list):
            root_dirs = [rootDir]
        else:
            root_dirs = rootDir

        root_dirs = [unquote_plus(xhtml_unescape(x)) for x in root_dirs]

        if settings.ROOT_DIRS:
            default_index = int(settings.ROOT_DIRS.split("|")[0])
        else:
            default_index = 0

        if len(root_dirs) > default_index:
            tmp = root_dirs[default_index]
            if tmp in root_dirs:
                root_dirs.remove(tmp)
                root_dirs.insert(0, tmp)

        dir_list = []

        main_db_con = db.DBConnection()
        for root_dir in root_dirs:
            # noinspection PyBroadException
            try:
                file_list = os.listdir(root_dir)
            except Exception:
                continue

            for cur_file in file_list:
                # noinspection PyBroadException
                try:
                    cur_path = os.path.normpath(
                        os.path.join(root_dir, cur_file))
                    if not os.path.isdir(cur_path):
                        continue
                    # ignore Synology folders
                    if cur_file.lower() in ["#recycle", "@eadir"]:
                        continue
                except Exception:
                    continue

                cur_dir = {
                    "dir":
                    cur_path,
                    "existing_info": (None, None, None),
                    "display_dir":
                    "<b>" + os.path.dirname(cur_path) + os.sep + "</b>" +
                    os.path.basename(cur_path),
                }

                # see if the folder is in KODI already
                dirResults = main_db_con.select(
                    "SELECT indexer_id FROM tv_shows WHERE location = ? LIMIT 1",
                    [cur_path])

                if dirResults:
                    cur_dir["added_already"] = True
                else:
                    cur_dir["added_already"] = False

                dir_list.append(cur_dir)

                indexer_id = show_name = indexer = None
                for cur_provider in settings.metadata_provider_dict.values():
                    if not (indexer_id and show_name):
                        (indexer_id, show_name,
                         indexer) = cur_provider.retrieveShowMetadata(cur_path)
                        if all((indexer_id, show_name, indexer)):
                            break

                if all((indexer_id, show_name, indexer)):
                    cur_dir["existing_info"] = (indexer_id, show_name, indexer)

                if indexer_id and Show.find(settings.showList, indexer_id):
                    cur_dir["added_already"] = True
        return t.render(dirList=dir_list)
Exemplo n.º 38
0
    def massEditSubmit(self,
                       paused=None,
                       default_ep_status=None,
                       anime=None,
                       sports=None,
                       scene=None,
                       season_folders=None,
                       quality_preset=None,
                       subtitles=None,
                       air_by_date=None,
                       anyQualities=None,
                       bestQualities=None,
                       toEdit=None,
                       *args,
                       **kwargs):
        dir_map = {}
        for cur_arg in filter(lambda x: x.startswith('orig_root_dir_'),
                              kwargs):
            dir_map[kwargs[cur_arg]] = ek(
                six.text_type, kwargs[cur_arg.replace('orig_root_dir_',
                                                      'new_root_dir_')],
                'utf-8')

        showIDs = toEdit.split("|")
        errors = []
        for curShow in showIDs:
            curErrors = []
            show_obj = Show.find(sickbeard.showList, int(curShow or 0))
            if not show_obj:
                continue

            cur_root_dir = self.__gooey_path(show_obj._location, 'dirname')
            cur_show_dir = self.__gooey_path(show_obj._location, 'basename')
            if cur_root_dir and dir_map.get(
                    cur_root_dir
            ) and cur_root_dir != dir_map.get(cur_root_dir):
                new_show_dir = ek(os.path.join, dir_map[cur_root_dir],
                                  cur_show_dir)
                logger.log("For show " + show_obj.name +
                           " changing dir from " + show_obj._location +
                           " to " + new_show_dir)
            else:
                new_show_dir = show_obj._location

            new_paused = ('off', 'on')[(paused == 'enable',
                                        show_obj.paused)[paused == 'keep']]
            new_default_ep_status = (
                default_ep_status,
                show_obj.default_ep_status)[default_ep_status == 'keep']
            new_anime = ('off', 'on')[(anime == 'enable',
                                       show_obj.anime)[anime == 'keep']]
            new_sports = ('off', 'on')[(sports == 'enable',
                                        show_obj.sports)[sports == 'keep']]
            new_scene = ('off', 'on')[(scene == 'enable',
                                       show_obj.scene)[scene == 'keep']]
            new_air_by_date = (
                'off', 'on')[(air_by_date == 'enable',
                              show_obj.air_by_date)[air_by_date == 'keep']]
            new_season_folders = ('off', 'on')[(
                season_folders == 'enable',
                show_obj.season_folders)[season_folders == 'keep']]
            new_subtitles = ('off',
                             'on')[(subtitles == 'enable',
                                    show_obj.subtitles)[subtitles == 'keep']]

            if quality_preset == 'keep':
                anyQualities, bestQualities = Quality.splitQuality(
                    show_obj.quality)
            elif try_int(quality_preset, None):
                bestQualities = []

            exceptions_list = []

            curErrors += self.editShow(curShow,
                                       new_show_dir,
                                       anyQualities,
                                       bestQualities,
                                       exceptions_list,
                                       defaultEpStatus=new_default_ep_status,
                                       season_folders=new_season_folders,
                                       paused=new_paused,
                                       sports=new_sports,
                                       subtitles=new_subtitles,
                                       anime=new_anime,
                                       scene=new_scene,
                                       air_by_date=new_air_by_date,
                                       directCall=True)

            if curErrors:
                logger.log("Errors: " + str(curErrors), logger.ERROR)
                errors.append(
                    '<b>{0}:</b>\n<ul>'.format(show_obj.name) + ' '.join(
                        ['<li>{0}</li>'.format(error)
                         for error in curErrors]) + "</ul>")

        if len(errors) > 0:
            ui.notifications.error(
                _('{num_errors:d} error{plural} while saving changes:').format(
                    num_errors=len(errors),
                    plural="" if len(errors) == 1 else "s"), " ".join(errors))

        return self.redirect("/manage/")
Exemplo n.º 39
0
    def run(self, force=False):
        if not settings.USE_SUBTITLES:
            return

        if not enabled_service_list():
            logger.warning(
                "Not enough services selected. At least 1 service is required to "
                "search subtitles in the background")
            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.info("Checking for missed subtitles")

        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 ", "")[settings.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.info("No subtitles to download")
            self.amActive = False
            return

        for ep_to_sub in sql_results:
            if not os.path.isfile(ep_to_sub["location"]):
                logger.debug(
                    "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"),
                    ))
                continue

            if not needs_subtitles(ep_to_sub["subtitles"]):
                logger.debug(
                    "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"),
                    ))
                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.debug(
                            "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),
                            ))
                        continue

                logger.info(
                    "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"),
                    ))

                show_object = Show.find(settings.showList,
                                        int(ep_to_sub["showid"]))
                if not show_object:
                    logger.debug(
                        "Show with ID {0} not found in the database".format(
                            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("{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"),
                    ))
                    continue

                try:
                    new_subtitles = episode_object.download_subtitles()
                except Exception as error:
                    logger.error(
                        "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"),
                            str(error),
                        ))
                    continue

                if new_subtitles:
                    logger.info("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.error(
                    "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"),
                        str(error),
                    ))
                continue

        logger.info("Finished checking for missed subtitles")
        self.amActive = False
Exemplo n.º 40
0
    def massUpdate(self,
                   toUpdate=None,
                   toRefresh=None,
                   toRename=None,
                   toDelete=None,
                   toRemove=None,
                   toMetadata=None,
                   toSubtitle=None):

        toUpdate = toUpdate.split('|') if toUpdate else []
        toRefresh = toRefresh.split('|') if toRefresh else []
        toRename = toRename.split('|') if toRename else []
        toSubtitle = toSubtitle.split('|') if toSubtitle else []
        toDelete = toDelete.split('|') if toDelete else []
        toRemove = toRemove.split('|') if toRemove else []
        toMetadata = toMetadata.split('|') if toMetadata else []

        errors = []
        refreshes = []
        updates = []
        renames = []
        subtitles = []

        for curShowID in set(toUpdate + toRefresh + toRename + toSubtitle +
                             toDelete + toRemove + toMetadata):

            if curShowID == '':
                continue

            show_obj = Show.find(sickbeard.showList, int(curShowID))
            if not show_obj:
                continue

            if curShowID in toDelete:
                sickbeard.showQueueScheduler.action.remove_show(show_obj, True)
                # don't do anything else if it's being deleted
                continue

            if curShowID in toRemove:
                sickbeard.showQueueScheduler.action.remove_show(show_obj)
                # don't do anything else if it's being remove
                continue

            if curShowID in toUpdate:
                try:
                    sickbeard.showQueueScheduler.action.update_show(
                        show_obj, True)
                    updates.append(show_obj.name)
                except CantUpdateShowException as e:
                    errors.append(
                        _("Unable to update show: {exception_format}").format(
                            exception_format=e))

            # don't bother refreshing shows that were updated anyway
            if curShowID in toRefresh and curShowID not in toUpdate:
                try:
                    sickbeard.showQueueScheduler.action.refresh_show(show_obj)
                    refreshes.append(show_obj.name)
                except CantRefreshShowException as e:
                    errors.append(
                        _("Unable to refresh show {show_name}: {exception_format}"
                          ).format(show_name=show_obj.name,
                                   exception_format=e))

            if curShowID in toRename:
                sickbeard.showQueueScheduler.action.rename_show_episodes(
                    show_obj)
                renames.append(show_obj.name)

            if curShowID in toSubtitle:
                sickbeard.showQueueScheduler.action.download_subtitles(
                    show_obj)
                subtitles.append(show_obj.name)

        if errors:
            ui.notifications.error(_("Errors encountered"),
                                   '<br >\n'.join(errors))

        messageDetail = ""

        if updates:
            messageDetail += "<br><b>" + _("Updates") + "</b><br><ul><li>"
            messageDetail += "</li><li>".join(updates)
            messageDetail += "</li></ul>"

        if refreshes:
            messageDetail += "<br><b>" + _("Refreshes") + "</b><br><ul><li>"
            messageDetail += "</li><li>".join(refreshes)
            messageDetail += "</li></ul>"

        if renames:
            messageDetail += "<br><b>" + _("Renames") + "</b><br><ul><li>"
            messageDetail += "</li><li>".join(renames)
            messageDetail += "</li></ul>"

        if subtitles:
            messageDetail += "<br><b>" + _("Subtitles") + "</b><br><ul><li>"
            messageDetail += "</li><li>".join(subtitles)
            messageDetail += "</li></ul>"

        if updates + refreshes + renames + subtitles:
            ui.notifications.message(
                _("The following actions were queued") + ":", messageDetail)

        return self.redirect("/manage/")