Example #1
0
def setEpisodeToWanted(show, s, e):
    """
    Sets an episode to wanted, only if it is currently skipped
    """
    epObj = show.getEpisode(s, e)
    if epObj:

        with epObj.lock:
            if epObj.status != SKIPPED or epObj.airdate == datetime.date.fromordinal(
                    1):
                return

            logger.log("Setting episode {show} {ep} to wanted".format(
                show=show.name, ep=episode_num(s, e)))
            # figure out what segment the episode is in and remember it so we can backlog it

            epObj.status = WANTED
            epObj.saveToDB()

        cur_backlog_queue_item = search_queue.BacklogQueueItem(show, [epObj])
        sickbeard.searchQueueScheduler.action.add_item(cur_backlog_queue_item)

        logger.log(
            "Starting backlog search for {show} {ep} because some episodes were set to wanted"
            .format(show=show.name, ep=episode_num(s, e)))
Example #2
0
def refresh_subtitles(episode):
    video = get_video(episode.location)
    if not video:
        logger.log("Exception caught in subliminal.scan_video, subtitles couldn't be refreshed", logger.DEBUG)
        return episode.subtitles, None
    current_subtitles = get_subtitles(video)
    if episode.subtitles == current_subtitles:
        logger.log('No changed subtitles for {0} {1}'.format
                   (episode.show.name, episode_num(episode.season, episode.episode) or
                    episode_num(episode.season, episode.episode, numbering='absolute')), logger.DEBUG)
        return episode.subtitles, None
    else:
        return current_subtitles, True
Example #3
0
def refresh_subtitles(episode):
    video = get_video(episode.location)
    if not video:
        logger.log("Exception caught in subliminal.scan_video, subtitles couldn't be refreshed", logger.DEBUG)
        return episode.subtitles, None
    current_subtitles = get_subtitles(video)
    if episode.subtitles == current_subtitles:
        logger.log('No changed subtitles for {0} {1}'.format
                   (episode.show.name, episode_num(episode.season, episode.episode) or
                    episode_num(episode.season, episode.episode, numbering='absolute')), logger.DEBUG)
        return episode.subtitles, None
    else:
        return current_subtitles, True
Example #4
0
    def addEpisodeToTraktWatchList(self):
        if sickbeard.TRAKT_SYNC_WATCHLIST and sickbeard.USE_TRAKT:
            logger.log("WATCHLIST::ADD::START - Look for Episodes to Add to Trakt Watchlist", logger.DEBUG)

            main_db_con = db.DBConnection()
            sql_selection = 'select tv_shows.indexer, tv_shows.startyear, showid, show_name, season, episode from tv_episodes,tv_shows where tv_shows.indexer_id = tv_episodes.showid and tv_episodes.status in (' + ','.join([str(x) for x in Quality.SNATCHED + Quality.SNATCHED_PROPER + [WANTED]]) + ')'
            episodes = main_db_con.select(sql_selection)

            if episodes is not None:
                trakt_data = []

                for cur_episode in episodes:
                    if not self._checkInList(sickchill.indexer.slug(cur_episode[b"indexer"]), str(cur_episode[b"showid"]), str(cur_episode[b"season"]), str(cur_episode[b"episode"])):
                        logger.log("Adding Episode {show} {ep} to watchlist".format
                                   (show=cur_episode[b"show_name"],
                                    ep=episode_num(cur_episode[b"season"], cur_episode[b"episode"])),
                                   logger.DEBUG)
                        trakt_data.append((cur_episode[b"showid"], cur_episode[b"indexer"], cur_episode[b"show_name"], cur_episode[b"startyear"], cur_episode[b"season"],
                                           cur_episode[b"episode"]))

                if trakt_data:
                    try:
                        data = self.trakt_bulk_data_generate(trakt_data)
                        self.trakt_api.traktRequest("sync/watchlist", data, method='POST')
                        self._getEpisodeWatchlist()
                    except traktException as e:
                        logger.log("Could not connect to Trakt service. Error {0}".format(ex(e)), logger.WARNING)

            logger.log("WATCHLIST::ADD::FINISH - Look for Episodes to Add to Trakt Watchlist", logger.DEBUG)
Example #5
0
    def _get_episode_search_strings(self, ep_obj, add_string=''):

        if not ep_obj:
            return [{}]

        to_return = []
        search_params = {'category': 'Episode'}

        # episode
        if ep_obj.show.air_by_date or ep_obj.show.sports:
            date_str = str(ep_obj.airdate)

            # BTN uses dots in dates, we just search for the date since that
            # combined with the series identifier should result in just one episode
            search_params['name'] = date_str.replace('-', '.')
        else:
            # BTN uses the same format for both Anime and TV
            # Do a general name search for the episode, formatted like SXXEYY
            search_params['name'] = "{ep}".format(ep=episode_num(ep_obj.scene_season, ep_obj.scene_episode))

        # search
        if ep_obj.show.indexer == 1:
            search_params['tvdb'] = ep_obj.show.indexerid
            to_return.append(search_params)
        else:
            # add new query string for every exception
            name_exceptions = list(
                set(scene_exceptions.get_scene_exceptions(ep_obj.show.indexerid) + [ep_obj.show.name]))
            for cur_exception in name_exceptions:
                search_params['series'] = sanitizeSceneName(cur_exception)
                to_return.append(search_params)

        return to_return
Example #6
0
    def addEpisodeToTraktWatchList(self):
        if sickbeard.TRAKT_SYNC_WATCHLIST and sickbeard.USE_TRAKT:
            logger.log("WATCHLIST::ADD::START - Look for Episodes to Add to Trakt Watchlist", logger.DEBUG)

            main_db_con = db.DBConnection()
            sql_selection = 'select tv_shows.indexer, tv_shows.startyear, showid, show_name, season, episode from tv_episodes,tv_shows where tv_shows.indexer_id = tv_episodes.showid and tv_episodes.status in (' + ','.join([str(x) for x in Quality.SNATCHED + Quality.SNATCHED_PROPER + [WANTED]]) + ')'
            episodes = main_db_con.select(sql_selection)

            if episodes is not None:
                trakt_data = []

                for cur_episode in episodes:
                    trakt_id = sickbeard.indexerApi(cur_episode[b"indexer"]).config['trakt_id']

                    if not self._checkInList(trakt_id, str(cur_episode[b"showid"]), str(cur_episode[b"season"]), str(cur_episode[b"episode"])):
                        logger.log("Adding Episode {show} {ep} to watchlist".format
                                   (show=cur_episode[b"show_name"],
                                    ep=episode_num(cur_episode[b"season"], cur_episode[b"episode"])),
                                   logger.DEBUG)
                        trakt_data.append((cur_episode[b"showid"], cur_episode[b"indexer"], cur_episode[b"show_name"], cur_episode[b"startyear"], cur_episode[b"season"],
                                           cur_episode[b"episode"]))

                if trakt_data:
                    try:
                        data = self.trakt_bulk_data_generate(trakt_data)
                        self.trakt_api.traktRequest("sync/watchlist", data, method='POST')
                        self._getEpisodeWatchlist()
                    except traktException as e:
                        logger.log("Could not connect to Trakt service. Error {0}".format(ex(e)), logger.WARNING)

            logger.log("WATCHLIST::ADD::FINISH - Look for Episodes to Add to Trakt Watchlist", logger.DEBUG)
Example #7
0
    def removeEpisodeFromTraktCollection(self):
        if sickbeard.TRAKT_SYNC_REMOVE and sickbeard.TRAKT_SYNC and sickbeard.USE_TRAKT:
            logger.log("COLLECTION::REMOVE::START - Look for Episodes to Remove From Trakt Collection", logger.DEBUG)

            main_db_con = db.DBConnection()
            sql_selection = 'select tv_shows.indexer, tv_shows.startyear, showid, show_name, season, episode, tv_episodes.status, tv_episodes.location from tv_episodes,tv_shows where tv_shows.indexer_id = tv_episodes.showid'
            episodes = main_db_con.select(sql_selection)

            if episodes is not None:
                trakt_data = []

                for cur_episode in episodes:
                    trakt_id = sickbeard.indexerApi(cur_episode[b"indexer"]).config[b'trakt_id']

                    if self._checkInList(trakt_id, str(cur_episode[b"showid"]), str(cur_episode[b"season"]), str(cur_episode[b"episode"]), List='Collection'):
                        if cur_episode[b"location"] == '':
                            logger.log("Removing Episode {show} {ep} from collection".format(
                                show=cur_episode[b"show_name"], ep=episode_num(cur_episode[b"season"], cur_episode[b"episode"])), logger.DEBUG
                            )
                            trakt_data.append((cur_episode[b"showid"], cur_episode[b"indexer"], cur_episode[b"show_name"], cur_episode[b"startyear"],
                                               cur_episode[b"season"], cur_episode[b"episode"]))

                if trakt_data:
                    try:
                        data = self.trakt_bulk_data_generate(trakt_data)
                        self.trakt_api.traktRequest("sync/collection/remove", data, method='POST')
                        self._getShowCollection()
                    except traktException as e:
                        logger.log("Could not connect to Trakt service. Error: {0}".format(ex(e)), logger.WARNING)

            logger.log("COLLECTION::REMOVE::FINISH - Look for Episodes to Remove From Trakt Collection", logger.DEBUG)
Example #8
0
    def convert_archived_to_compound(self):
        logger.debug(_('Checking for archived episodes not qualified'))

        sql_results = self.connection.select(
            "SELECT episode_id, showid, status, location, season, episode FROM tv_episodes WHERE status = ?", [common.ARCHIVED]
        )
        if sql_results:
            logger.warning(_(f"Found {len(sql_results)} shows with bare archived status, attempting automatic conversion..."))

        for archivedEp in sql_results:
            fixed_status = common.Quality.compositeStatus(common.ARCHIVED, common.Quality.UNKNOWN)
            existing = archivedEp['location'] and os.path.exists(archivedEp['location'])
            if existing:
                quality = common.Quality.nameQuality(archivedEp['location'])
                fixed_status = common.Quality.compositeStatus(common.ARCHIVED, quality)

            old_status = common.statusStrings[common.ARCHIVED]
            new_status = common.statusStrings[fixed_status]
            archived_episode = archivedEp['showid']
            ep = episode_num(archivedEp['season'])
            episode_id = archivedEp['episode_id']
            location = archivedEp['location'] or 'unknown location'
            result = ('NOT FOUND', 'EXISTS')[bool(existing)]

            logger.info(_(f'Changing status from {old_status} to {new_status} for {archived_episode}: {ep} at {location} (File {result})'))

            self.connection.action("UPDATE tv_episodes SET status = ? WHERE episode_id = ?", [fixed_status, episode_id])
Example #9
0
    def convert_archived_to_compound(self):
        logger.debug(_("Checking for archived episodes not qualified"))

        sql_results = self.connection.select(
            "SELECT episode_id, showid, status, location, season, episode FROM tv_episodes WHERE status = ?", [common.ARCHIVED]
        )
        if sql_results:
            logger.warning(_("Found {count} shows with bare archived status, attempting automatic conversion...".format(count=len(sql_results))))

        for archivedEp in sql_results:
            fixed_status = common.Quality.compositeStatus(common.ARCHIVED, common.Quality.UNKNOWN)
            existing = archivedEp["location"] and os.path.exists(archivedEp["location"])
            if existing:
                quality = common.Quality.nameQuality(archivedEp["location"])
                fixed_status = common.Quality.compositeStatus(common.ARCHIVED, quality)

            old_status = common.statusStrings[common.ARCHIVED]
            new_status = common.statusStrings[fixed_status]
            archived_episode = archivedEp["showid"]
            ep = episode_num(archivedEp["season"])
            episode_id = archivedEp["episode_id"]
            location = archivedEp["location"] or "unknown location"
            result = ("NOT FOUND", "EXISTS")[bool(existing)]

            logger.info(
                _(
                    "Changing status from {old_status} to {new_status} for {archived_episode}: {ep} at {location} (File {result})".format(
                        old_status=old_status, new_status=new_status, archived_episode=archived_episode, ep=ep, location=location, result=result
                    )
                )
            )

            self.connection.action("UPDATE tv_episodes SET status = ? WHERE episode_id = ?", [fixed_status, episode_id])
Example #10
0
    def _get_episode_search_strings(self, ep_obj, add_string=''):

        if not ep_obj:
            return [{}]

        to_return = []
        search_params = {'category': 'Episode'}

        # episode
        if ep_obj.show.air_by_date or ep_obj.show.sports:
            date_str = str(ep_obj.airdate)

            # BTN uses dots in dates, we just search for the date since that
            # combined with the series identifier should result in just one episode
            search_params['name'] = date_str.replace('-', '.')
        else:
            # BTN uses the same format for both Anime and TV
            # Do a general name search for the episode, formatted like SXXEYY
            search_params['name'] = "{ep}".format(ep=episode_num(ep_obj.scene_season, ep_obj.scene_episode))

        # search
        if ep_obj.show.indexer == 1:
            search_params['tvdb'] = ep_obj.show.indexerid
            to_return.append(search_params)
        else:
            # add new query string for every exception
            name_exceptions = list(
                set(scene_exceptions.get_scene_exceptions(ep_obj.show.indexerid) + [ep_obj.show.name]))
            for cur_exception in name_exceptions:
                search_params['series'] = sanitizeSceneName(cur_exception)
                to_return.append(search_params)

        return to_return
Example #11
0
    def removeEpisodeFromTraktCollection(self):
        if sickbeard.TRAKT_SYNC_REMOVE and sickbeard.TRAKT_SYNC and sickbeard.USE_TRAKT:
            logger.log("COLLECTION::REMOVE::START - Look for Episodes to Remove From Trakt Collection", logger.DEBUG)

            main_db_con = db.DBConnection()
            sql_selection = 'select tv_shows.indexer, tv_shows.startyear, showid, show_name, season, episode, tv_episodes.status, tv_episodes.location from tv_episodes,tv_shows where tv_shows.indexer_id = tv_episodes.showid'
            episodes = main_db_con.select(sql_selection)

            if episodes is not None:
                trakt_data = []

                for cur_episode in episodes:
                    if self._checkInList(sickchill.indexer.slug(cur_episode[b"indexer"]), str(cur_episode[b"showid"]), str(cur_episode[b"season"]),
                                         str(cur_episode[b"episode"]),
                                         List='Collection'):
                        if cur_episode[b"location"] == '':
                            logger.log("Removing Episode {show} {ep} from collection".format(
                                show=cur_episode[b"show_name"], ep=episode_num(cur_episode[b"season"], cur_episode[b"episode"])), logger.DEBUG
                            )
                            trakt_data.append((cur_episode[b"showid"], cur_episode[b"indexer"], cur_episode[b"show_name"], cur_episode[b"startyear"],
                                               cur_episode[b"season"], cur_episode[b"episode"]))

                if trakt_data:
                    try:
                        data = self.trakt_bulk_data_generate(trakt_data)
                        self.trakt_api.traktRequest("sync/collection/remove", data, method='POST')
                        self._getShowCollection()
                    except traktException as e:
                        logger.log("Could not connect to Trakt service. Error: {0}".format(ex(e)), logger.WARNING)

            logger.log("COLLECTION::REMOVE::FINISH - Look for Episodes to Remove From Trakt Collection", logger.DEBUG)
Example #12
0
    def addEpisodeToTraktCollection(self):
        if settings.TRAKT_SYNC and settings.USE_TRAKT:
            logger.debug(
                "COLLECTION::ADD::START - Look for Episodes to Add to Trakt Collection"
            )

            main_db_con = db.DBConnection()
            sql_selection = (
                "select tv_shows.indexer, tv_shows.startyear, showid, show_name, season, episode from tv_episodes,tv_shows where tv_shows.indexer_id = tv_episodes.showid and tv_episodes.status in ("
                + ",".join(
                    [str(x)
                     for x in Quality.DOWNLOADED + Quality.ARCHIVED]) + ")")
            episodes = main_db_con.select(sql_selection)

            if episodes is not None:
                trakt_data = []

                for cur_episode in episodes:
                    if not self._checkInList(
                            sickchill.indexer.slug(cur_episode["indexer"]),
                            str(cur_episode["showid"]),
                            str(cur_episode["season"]),
                            str(cur_episode["episode"]),
                            List="Collection",
                    ):
                        logger.debug(
                            "Adding Episode {show} {ep} to collection".format(
                                show=cur_episode["show_name"],
                                ep=episode_num(cur_episode["season"],
                                               cur_episode["episode"])))
                        trakt_data.append((
                            cur_episode["showid"],
                            cur_episode["indexer"],
                            cur_episode["show_name"],
                            cur_episode["startyear"],
                            cur_episode["season"],
                            cur_episode["episode"],
                        ))

                if trakt_data:
                    try:
                        data = self.trakt_bulk_data_generate(trakt_data)
                        self.trakt_api.traktRequest("sync/collection",
                                                    data,
                                                    method="POST")
                        self._getShowCollection()
                    except traktException as e:
                        logger.warning(
                            "Could not connect to Trakt service. Error: {0}".
                            format(str(e)))

            logger.debug(
                "COLLECTION::ADD::FINISH - Look for Episodes to Add to Trakt Collection"
            )
Example #13
0
    def removeEpisodeFromTraktWatchList(self):
        if sickbeard.TRAKT_SYNC_WATCHLIST and sickbeard.USE_TRAKT:
            logger.log(
                "WATCHLIST::REMOVE::START - Look for Episodes to Remove from Trakt Watchlist",
                logger.DEBUG)

            main_db_con = db.DBConnection()
            sql_selection = 'select tv_shows.indexer, tv_shows.startyear, showid, show_name, season, episode, tv_episodes.status from tv_episodes,tv_shows where tv_shows.indexer_id = tv_episodes.showid'
            episodes = main_db_con.select(sql_selection)

            if episodes is not None:
                trakt_data = []

                for cur_episode in episodes:
                    trakt_id = sickbeard.indexerApi(
                        cur_episode[b"indexer"]).config['trakt_id']

                    if self._checkInList(trakt_id, str(cur_episode[b"showid"]),
                                         str(cur_episode[b"season"]),
                                         str(cur_episode[b"episode"])):
                        if cur_episode[
                                b"status"] not in Quality.SNATCHED + Quality.SNATCHED_PROPER + [
                                    UNKNOWN
                                ] + [WANTED]:
                            logger.log(
                                "Removing Episode {show} {ep} from watchlist".
                                format(
                                    show=cur_episode[b"show_name"],
                                    ep=episode_num(cur_episode[b"season"],
                                                   cur_episode[b"episode"])),
                                logger.DEBUG)
                            trakt_data.append((cur_episode[b"showid"],
                                               cur_episode[b"indexer"],
                                               cur_episode[b"show_name"],
                                               cur_episode[b"startyear"],
                                               cur_episode[b"season"],
                                               cur_episode[b"episode"]))

                if trakt_data:
                    try:
                        data = self.trakt_bulk_data_generate(trakt_data)
                        self.trakt_api.traktRequest("sync/watchlist/remove",
                                                    data,
                                                    method='POST')
                        self._getEpisodeWatchlist()
                    except traktException as e:
                        logger.log(
                            "Could not connect to Trakt service. Error: {0}".
                            format(ex(e)), logger.WARNING)

                logger.log(
                    "WATCHLIST::REMOVE::FINISH - Look for Episodes to Remove from Trakt Watchlist",
                    logger.DEBUG)
Example #14
0
def setEpisodeToWanted(show, s, e):
    """
    Sets an episode to wanted, only if it is currently skipped
    """
    epObj = show.getEpisode(s, e)
    if epObj:

        with epObj.lock:
            if epObj.status != SKIPPED or epObj.airdate == datetime.date.fromordinal(1):
                return

            logger.log("Setting episode {show} {ep} to wanted".format
                       (show=show.name, ep=episode_num(s, e)))
            # figure out what segment the episode is in and remember it so we can backlog it

            epObj.status = WANTED
            epObj.saveToDB()

        cur_backlog_queue_item = search_queue.BacklogQueueItem(show, [epObj])
        sickbeard.searchQueueScheduler.action.add_item(cur_backlog_queue_item)

        logger.log("Starting backlog search for {show} {ep} because some episodes were set to wanted".format
                   (show=show.name, ep=episode_num(s, e)))
Example #15
0
    def addEpisodeToTraktCollection(self):
        if sickbeard.TRAKT_SYNC and sickbeard.USE_TRAKT:
            logger.log(
                "COLLECTION::ADD::START - Look for Episodes to Add to Trakt Collection",
                logger.DEBUG)

            main_db_con = db.DBConnection()
            sql_selection = 'select tv_shows.indexer, tv_shows.startyear, showid, show_name, season, episode from tv_episodes,tv_shows where tv_shows.indexer_id = tv_episodes.showid and tv_episodes.status in (' + ','.join(
                [str(x) for x in Quality.DOWNLOADED + Quality.ARCHIVED]) + ')'
            episodes = main_db_con.select(sql_selection)

            if episodes is not None:
                trakt_data = []

                for cur_episode in episodes:
                    trakt_id = sickbeard.indexerApi(
                        cur_episode[b"indexer"]).config['trakt_id']

                    if not self._checkInList(trakt_id,
                                             str(cur_episode[b"showid"]),
                                             str(cur_episode[b"season"]),
                                             str(cur_episode[b"episode"]),
                                             List='Collection'):
                        logger.log(
                            "Adding Episode {show} {ep} to collection".format(
                                show=cur_episode[b"show_name"],
                                ep=episode_num(cur_episode[b"season"],
                                               cur_episode[b"episode"])),
                            logger.DEBUG)
                        trakt_data.append(
                            (cur_episode[b"showid"], cur_episode[b"indexer"],
                             cur_episode[b"show_name"],
                             cur_episode[b"startyear"], cur_episode[b"season"],
                             cur_episode[b"episode"]))

                if trakt_data:
                    try:
                        data = self.trakt_bulk_data_generate(trakt_data)
                        self.trakt_api.traktRequest("sync/collection",
                                                    data,
                                                    method='POST')
                        self._getShowCollection()
                    except traktException as e:
                        logger.log(
                            "Could not connect to Trakt service. Error: {0}".
                            format(ex(e)), logger.WARNING)

            logger.log(
                "COLLECTION::ADD::FINISH - Look for Episodes to Add to Trakt Collection",
                logger.DEBUG)
Example #16
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
Example #17
0
def download_subtitles(episode, force_lang=None):
    existing_subtitles = episode.subtitles

    if not needs_subtitles(existing_subtitles, force_lang):
        logger.debug(
            "Episode already has all needed subtitles, skipping {0} {1}".
            format(
                episode.show.name,
                episode_num(episode.season, episode.episode) or episode_num(
                    episode.season, episode.episode, numbering="absolute")))
        return existing_subtitles, None

    if not force_lang:
        languages = get_needed_languages(existing_subtitles)
    else:
        languages = {from_code(force_lang)}

    if not languages:
        logger.debug("No subtitles needed for {0} {1}".format(
            episode.show.name,
            episode_num(episode.season, episode.episode) or episode_num(
                episode.season, episode.episode, numbering="absolute")))
        return existing_subtitles, None

    subtitles_path = get_subtitles_path(episode.location)
    video_path = episode.location

    # Perfect match = hash score - hearing impaired score - resolution score
    # (subtitle for 720p is the same as for 1080p)
    # Perfect match = 215 - 1 - 1 = 213
    # Non-perfect match = series + year + season + episode
    # Non-perfect match = 108 + 54 + 18 + 18 = 198
    # From latest subliminal code:
    # episode_scores = {'hash': 215, 'series': 108, 'year': 54, 'season': 18, 'episode': 18, 'release_group': 9,
    #                   'source': 4, 'audio_codec': 2, 'resolution': 1, 'hearing_impaired': 1, 'video_codec': 1}
    user_score = 213 if settings.SUBTITLES_PERFECT_MATCH else 198

    video = get_video(video_path,
                      subtitles_path=subtitles_path,
                      episode=episode)
    if not video:
        logger.debug(
            "Exception caught in subliminal.scan_video for {0} {1}".format(
                episode.show.name,
                episode_num(episode.season, episode.episode) or episode_num(
                    episode.season, episode.episode, numbering="absolute")))
        return existing_subtitles, None

    providers = enabled_service_list()
    pool = SubtitleProviderPool()

    try:
        subtitles_list = pool.list_subtitles(video, languages)

        for provider in providers:
            if provider in pool.discarded_providers:
                logger.debug(
                    "Could not search in {0} provider. Discarding for now".
                    format(provider))

        if not subtitles_list:
            logger.debug("No subtitles found for {0} {1}".format(
                episode.show.name,
                episode_num(episode.season, episode.episode) or episode_num(
                    episode.season, episode.episode, numbering="absolute")))
            return existing_subtitles, None

        for subtitle in subtitles_list:
            score = subliminal.score.compute_score(
                subtitle,
                video,
                hearing_impaired=settings.SUBTITLES_HEARING_IMPAIRED)
            logger.debug(
                "[{0}] Subtitle score for {1} is: {2} (min={3})".format(
                    subtitle.provider_name, subtitle.id, score, user_score))

        found_subtitles = pool.download_best_subtitles(
            subtitles_list,
            video,
            languages=languages,
            hearing_impaired=settings.SUBTITLES_HEARING_IMPAIRED,
            min_score=user_score,
            only_one=not settings.SUBTITLES_MULTI,
        )

        subliminal.save_subtitles(video,
                                  found_subtitles,
                                  directory=subtitles_path,
                                  single=not settings.SUBTITLES_MULTI,
                                  encoding="utf8")
    except IOError as error:
        if "No space left on device" in str(error):
            logger.warning("Not enough space on the drive to save subtitles")
        else:
            logger.warning(traceback.format_exc())
        return existing_subtitles, None
    except Exception:
        logger.info(
            "Error occurred when downloading subtitles for: {0}".format(
                video_path))
        logger.exception(traceback.format_exc())
        return existing_subtitles, None

    for subtitle in found_subtitles:
        subtitle_path = subliminal.subtitle.get_subtitle_path(
            video.name,
            None if not settings.SUBTITLES_MULTI else subtitle.language)
        if subtitles_path is not None:
            subtitle_path = os.path.join(subtitles_path,
                                         os.path.split(subtitle_path)[1])

        sickchill.oldbeard.helpers.chmodAsParent(subtitle_path)
        sickchill.oldbeard.helpers.fixSetGroupID(subtitle_path)

        if settings.SUBTITLES_HISTORY:
            logger.debug("history.logSubtitle {0}, {1}".format(
                subtitle.provider_name, subtitle.language.opensubtitles))

            history.logSubtitle(episode.show.indexerid, episode.season,
                                episode.episode, episode.status, subtitle)

        if settings.SUBTITLES_EXTRA_SCRIPTS and is_media_file(
                video_path) and not settings.EMBEDDED_SUBTITLES_ALL:

            run_subs_extra_scripts(episode,
                                   subtitle,
                                   video,
                                   single=not settings.SUBTITLES_MULTI)

    new_subtitles = sorted(
        {subtitle.language.opensubtitles
         for subtitle in found_subtitles})
    current_subtitles = sorted(
        {subtitle
         for subtitle in new_subtitles +
         existing_subtitles}) if existing_subtitles else new_subtitles
    if not settings.SUBTITLES_MULTI and len(found_subtitles) == 1:
        new_code = found_subtitles[0].language.opensubtitles
        if new_code not in existing_subtitles:
            current_subtitles.remove(new_code)
        current_subtitles.append("und")

    return current_subtitles, new_subtitles
Example #18
0
    def test_episode_num(self):
        # Standard numbering
        self.assertEqual(episode_num(0, 1), 'S00E01')  # Seasons start at 0 for specials
        self.assertEqual(episode_num(1, 1), 'S01E01')

        # Absolute numbering
        self.assertEqual(episode_num(1, numbering='absolute'), '001')
        self.assertEqual(episode_num(0, 1, numbering='absolute'), '001')
        self.assertEqual(episode_num(1, 0, numbering='absolute'), '001')

        # Must have both season and episode for standard numbering
        self.assertEqual(episode_num(0), None)
        self.assertEqual(episode_num(1), None)

        # Episode numbering starts at 1
        self.assertEqual(episode_num(0, 0), None)
        self.assertEqual(episode_num(1, 0), None)

        # Absolute numbering starts at 1
        self.assertEqual(episode_num(0, 0, numbering='absolute'), None)

        # Absolute numbering can't have both season and episode
        self.assertEqual(episode_num(1, 1, numbering='absolute'), None)
Example #19
0
    def test_episode_num(self):
        # Standard numbering
        self.assertEqual(episode_num(0, 1),
                         'S00E01')  # Seasons start at 0 for specials
        self.assertEqual(episode_num(1, 1), 'S01E01')

        # Absolute numbering
        self.assertEqual(episode_num(1, numbering='absolute'), '001')
        self.assertEqual(episode_num(0, 1, numbering='absolute'), '001')
        self.assertEqual(episode_num(1, 0, numbering='absolute'), '001')

        # Must have both season and episode for standard numbering
        self.assertEqual(episode_num(0), None)
        self.assertEqual(episode_num(1), None)

        # Episode numbering starts at 1
        self.assertEqual(episode_num(0, 0), None)
        self.assertEqual(episode_num(1, 0), None)

        # Absolute numbering starts at 1
        self.assertEqual(episode_num(0, 0, numbering='absolute'), None)

        # Absolute numbering can't have both season and episode
        self.assertEqual(episode_num(1, 1, numbering='absolute'), None)
Example #20
0
    def test_episode_num(self):
        # Standard numbering
        assert episode_num(0, 1) == "S00E01"  # Seasons start at 0 for specials
        assert episode_num(1, 1) == "S01E01"

        # Absolute numbering
        assert episode_num(1, numbering="absolute") == "001"
        assert episode_num(0, 1, numbering="absolute") == "001"
        assert episode_num(1, 0, numbering="absolute") == "001"

        # Must have both season and episode for standard numbering
        assert episode_num(0) is None
        assert episode_num(1) is None

        # Episode numbering starts at 1
        assert episode_num(0, 0) is None
        assert episode_num(1, 0) is None

        # Absolute numbering starts at 1
        assert episode_num(0, 0, numbering="absolute") is None

        # Absolute numbering can't have both season and episode
        assert episode_num(1, 1, numbering="absolute") is None
Example #21
0
    def run(self, force=False):
        if not sickbeard.USE_SUBTITLES:
            return

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

        self.amActive = True

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        logger.log('Finished checking for missed subtitles', logger.INFO)
        self.amActive = False
Example #22
0
    def run(self, force=False):  # pylint: disable=too-many-branches, too-many-statements, too-many-locals
        if not sickbeard.USE_SUBTITLES:
            return

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

        self.amActive = True

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        logger.log('Finished checking for missed subtitles', logger.INFO)
        self.amActive = False
Example #23
0
def download_subtitles(episode, force_lang=None):  # pylint: disable=too-many-locals, too-many-branches, too-many-statements
    existing_subtitles = episode.subtitles

    if not needs_subtitles(existing_subtitles, force_lang):
        logger.log('Episode already has all needed subtitles, skipping {0} {1}'.format
                   (episode.show.name, episode_num(episode.season, episode.episode) or
                    episode_num(episode.season, episode.episode, numbering='absolute')), logger.DEBUG)
        return existing_subtitles, None

    if not force_lang:
        languages = get_needed_languages(existing_subtitles)
    else:
        languages = {from_code(force_lang)}

    if not languages:
        logger.log('No subtitles needed for {0} {1}'.format
                   (episode.show.name, episode_num(episode.season, episode.episode) or
                    episode_num(episode.season, episode.episode, numbering='absolute')), logger.DEBUG)
        return existing_subtitles, None

    subtitles_path = get_subtitles_path(episode.location)
    video_path = episode.location

    # Perfect match = hash score - hearing impaired score - resolution score
    # (subtitle for 720p is the same as for 1080p)
    # Perfect match = 215 - 1 - 1 = 213
    # Non-perfect match = series + year + season + episode
    # Non-perfect match = 108 + 54 + 18 + 18 = 198
    # From latest subliminal code:
    # episode_scores = {'hash': 215, 'series': 108, 'year': 54, 'season': 18, 'episode': 18, 'release_group': 9,
    #                   'format': 4, 'audio_codec': 2, 'resolution': 1, 'hearing_impaired': 1, 'video_codec': 1}
    user_score = 213 if sickbeard.SUBTITLES_PERFECT_MATCH else 198

    video = get_video(video_path, subtitles_path=subtitles_path, episode=episode)
    if not video:
        logger.log('Exception caught in subliminal.scan_video for {0} {1}'.format
                   (episode.show.name, episode_num(episode.season, episode.episode) or
                    episode_num(episode.season, episode.episode, numbering='absolute')), logger.DEBUG)
        return existing_subtitles, None

    providers = enabled_service_list()
    pool = SubtitleProviderPool()

    try:
        subtitles_list = pool.list_subtitles(video, languages)

        for provider in providers:
            if provider in pool.discarded_providers:
                logger.log('Could not search in {0} provider. Discarding for now'.format(provider), logger.DEBUG)

        if not subtitles_list:
            logger.log('No subtitles found for {0} {1}'.format
                       (episode.show.name, episode_num(episode.season, episode.episode) or
                        episode_num(episode.season, episode.episode, numbering='absolute')), logger.DEBUG)
            return existing_subtitles, None

        for subtitle in subtitles_list:
            score = subliminal.score.compute_score(subtitle, video,
                                                   hearing_impaired=sickbeard.SUBTITLES_HEARING_IMPAIRED)
            logger.log('[{0}] Subtitle score for {1} is: {2} (min={3})'.format
                       (subtitle.provider_name, subtitle.id, score, user_score), logger.DEBUG)

        found_subtitles = pool.download_best_subtitles(subtitles_list, video, languages=languages,
                                                       hearing_impaired=sickbeard.SUBTITLES_HEARING_IMPAIRED,
                                                       min_score=user_score, only_one=not sickbeard.SUBTITLES_MULTI)

        subliminal.save_subtitles(video, found_subtitles, directory=subtitles_path,
                                  single=not sickbeard.SUBTITLES_MULTI)
    except IOError as error:
        if 'No space left on device' in ex(error):
            logger.log('Not enough space on the drive to save subtitles', logger.WARNING)
        else:
            logger.log(traceback.format_exc(), logger.WARNING)
    except Exception:
        logger.log('Error occurred when downloading subtitles for: {0}'.format(video_path))
        logger.log(traceback.format_exc(), logger.ERROR)
        return existing_subtitles, None

    for subtitle in found_subtitles:
        subtitle_path = subliminal.subtitle.get_subtitle_path(video.name,
                                                              None if not sickbeard.SUBTITLES_MULTI else
                                                              subtitle.language)
        if subtitles_path is not None:
            subtitle_path = os.path.join(subtitles_path, os.path.split(subtitle_path)[1])

        sickbeard.helpers.chmodAsParent(subtitle_path)
        sickbeard.helpers.fixSetGroupID(subtitle_path)

        if sickbeard.SUBTITLES_HISTORY:
            logger.log('history.logSubtitle {0}, {1}'.format
                       (subtitle.provider_name, subtitle.language.opensubtitles), logger.DEBUG)

            history.logSubtitle(episode.show.indexerid, episode.season, episode.episode, episode.status, subtitle)

        if sickbeard.SUBTITLES_EXTRA_SCRIPTS and is_media_file(video_path) and not sickbeard.EMBEDDED_SUBTITLES_ALL:

            run_subs_extra_scripts(episode, subtitle, video, single=not sickbeard.SUBTITLES_MULTI)

    new_subtitles = sorted({subtitle.language.opensubtitles for subtitle in found_subtitles})
    current_subtitles = sorted({subtitle for subtitle in new_subtitles + existing_subtitles}) if existing_subtitles else new_subtitles
    if not sickbeard.SUBTITLES_MULTI and len(found_subtitles) == 1:
        new_code = found_subtitles[0].language.opensubtitles
        if new_code not in existing_subtitles:
            current_subtitles.remove(new_code)
        current_subtitles.append('und')

    return current_subtitles, new_subtitles