def _list_subtitles():
            # list subtitles
            with AsyncProviderPool(
                    providers=self.config.providers,
                    provider_configs=self.config.provider_configs) as pool:
                subtitles = pool.list_subtitles(video, self.config.languages)

            # fill the subtitle liststore
            subtitle_liststore = builder.get_object('subtitle_liststore')
            for s in subtitles:
                scaled_score = compute_score(s, video)
                scores = get_scores(video)
                if s.hearing_impaired == self.config.hearing_impaired:
                    scaled_score -= scores['hearing_impaired']
                scaled_score *= 100 / scores['hash']
                subtitle_liststore.append([
                    s.id,
                    nice_language(s.language), scaled_score,
                    s.provider_name.capitalize(), s.hearing_impaired,
                    s.page_link, False
                ])
            subtitle_liststore.set_sort_column_id(2, Gtk.SortType.DESCENDING)

            # stop the spinner
            spinner.stop()

            # connect signals
            builder.connect_signals(
                ChooseHandler(self.config, video, subtitles, spinner))
Example #2
0
    def search(self, path, languages):
        languages = {language_converter.from_english(l): l for l in languages}
        xbmc.log('Languages: %s' % languages, level=xbmc.LOGDEBUG)
        video = self.get_video(path)

        providers = self.get_providers()
        provider_configs = self.get_provider_configs()
        max_workers = self.get_max_workers()
        xbmc.log('Providers: %s' % providers, level=xbmc.LOGDEBUG)
        xbmc.log('Provider Configs: %s' % provider_configs, level=xbmc.LOGDEBUG)
        with AsyncProviderPool(max_workers=max_workers, providers=providers, provider_configs=provider_configs) as p:
            subtitles = p.list_subtitles(video, languages=set(languages.keys()))
            max_score = episode_scores['hash'] if isinstance(video, Episode) else movie_scores['hash']

            scored_subtitles = sorted([(s, compute_score(s, video))
                                       for s in subtitles], key=operator.itemgetter(1), reverse=True)
            for subtitle, score in scored_subtitles:
                option = SubtitleOption(subtitle)
                option.get_subtitle(subtitle.id)
                l = languages[subtitle.language]
                release_name = '[%s] %s' % (subtitle.provider_name, self.get_release_name(subtitle))
                rating = int(round(float(5 * (score+2)/max_score)))
                sync = score + 2 >= max_score
                option.add_directory_item(self.base_url, self.handle, release_name, l, rating, sync)
            xbmc.log('%s' % subtitles, level=xbmc.LOGDEBUG)

        return True
Example #3
0
def list_best_subtitles(video, language):
    """ Input: object video, language 3-code identifier
        Output: returns a dict with subtitle and corresponding score, in decreasing score order
        Throws: ValueError
    """

    subtitles = list_subtitles([video], {Language(language)})
    dic = dict()
    for s in subtitles[video]:
        dic[s] = compute_score(s.get_matches(video), video)
    sorted_d = sorted(dic.items(), key=operator.itemgetter(1), reverse=True)
    return sorted_d
Example #4
0
    def choose_callback(self, menuitem, files):
        # scan and check the video
        video = scan_video(files[0].get_location().get_path(),
                           subtitles=True,
                           embedded_subtitles=self.config.embedded_subtitles)
        if not check_video(video,
                           languages=self.config.languages,
                           undefined=self.config.single):
            return

        # list subtitles
        with ProviderPool(
                providers=self.config.providers,
                provider_configs=self.config.provider_configs) as pool:
            subtitles = pool.list_subtitles(video, self.config.languages)

        # load the interface
        builder = Gtk.Builder()
        builder.set_translation_domain('subliminal')
        builder.add_from_file(
            os.path.join(os.path.dirname(__file__), 'subliminal', 'ui',
                         'choose.glade'))

        # set the video filename
        video_filename = builder.get_object('video_filename_label')
        video_filename.set_text(files[0].get_name())

        # fill the subtitle liststore
        subtitle_liststore = builder.get_object('subtitle_liststore')
        for s in subtitles:
            matches = s.get_matches(
                video, hearing_impaired=self.config.hearing_impaired)
            scaled_score = compute_score(matches, video)
            if s.hearing_impaired == self.config.hearing_impaired:
                scaled_score -= video.scores['hearing_impaired']
            scaled_score *= 100 / video.scores['hash']
            subtitle_liststore.append([
                s.id,
                nice_language(s.language), scaled_score,
                s.provider_name.capitalize(), s.hearing_impaired, s.page_link,
                False
            ])
        subtitle_liststore.set_sort_column_id(2, Gtk.SortType.DESCENDING)

        # connect signals
        builder.connect_signals(ChooseHandler(self.config, video, subtitles))

        # display window
        window = builder.get_object('subtitle_window')
        window.show_all()
        Gtk.main()
Example #5
0
def score_subtitles(subtitles_list, video):
    """Score all subtitles in the specified list for the given video.

    :param subtitles_list:
    :type subtitles_list: list of subliminal.subtitle.Subtitle
    :param video:
    :type video: subliminal.video.Video
    :return:
    :rtype: tuple(subliminal.subtitle.Subtitle, int)
    """
    providers_order = {d['name']: i for i, d in enumerate(sorted_service_list())}
    result = sorted([(s, compute_score(s, video, hearing_impaired=app.SUBTITLES_HEARING_IMPAIRED),
                    -1 * providers_order.get(s.provider_name, 1000))
                     for s in subtitles_list], key=operator.itemgetter(1, 2), reverse=True)
    return [(s, score) for (s, score, provider_order) in result]
Example #6
0
def score_subtitles(subtitles_list, video):
    """Score all subtitles in the specified list for the given video.

    :param subtitles_list:
    :type subtitles_list: list of subliminal.subtitle.Subtitle
    :param video:
    :type video: subliminal.video.Video
    :return:
    :rtype: tuple(subliminal.subtitle.Subtitle, int)
    """
    providers_order = {d['name']: i for i, d in enumerate(sorted_service_list())}
    result = sorted([(s, compute_score(s, video, hearing_impaired=app.SUBTITLES_HEARING_IMPAIRED),
                    -1 * providers_order.get(s.provider_name, 1000))
                     for s in subtitles_list], key=operator.itemgetter(1, 2), reverse=True)
    return [(s, score) for (s, score, provider_order) in result]
        def _list_subtitles():
            # list subtitles
            with ProviderPool(providers=self.config.providers, provider_configs=self.config.provider_configs) as pool:
                subtitles = pool.list_subtitles(video, self.config.languages)

            # fill the subtitle liststore
            subtitle_liststore = builder.get_object('subtitle_liststore')
            for s in subtitles:
                matches = s.get_matches(video, hearing_impaired=self.config.hearing_impaired)
                scaled_score = compute_score(matches, video)
                if s.hearing_impaired == self.config.hearing_impaired:
                    scaled_score -= video.scores['hearing_impaired']
                scaled_score *= 100 / video.scores['hash']
                subtitle_liststore.append([s.id, nice_language(s.language), scaled_score, s.provider_name.capitalize(),
                                           s.hearing_impaired, s.page_link, False])
            subtitle_liststore.set_sort_column_id(2, Gtk.SortType.DESCENDING)

            # stop the spinner
            spinner.stop()

            # connect signals
            builder.connect_signals(ChooseHandler(self.config, video, subtitles, spinner))
Example #8
0
    def choose_callback(self, menuitem, files):
        # scan and check the video
        video = scan_video(files[0].get_location().get_path(), subtitles=True,
                           embedded_subtitles=self.config.embedded_subtitles)
        if not check_video(video, languages=self.config.languages, undefined=self.config.single):
            return

        # list subtitles
        with ProviderPool(providers=self.config.providers, provider_configs=self.config.provider_configs) as pool:
            subtitles = pool.list_subtitles(video, self.config.languages)

        # load the interface
        builder = Gtk.Builder()
        builder.set_translation_domain('subliminal')
        builder.add_from_file(os.path.join(os.path.dirname(__file__), 'subliminal', 'ui', 'choose.glade'))

        # set the video filename
        video_filename = builder.get_object('video_filename_label')
        video_filename.set_text(files[0].get_name())

        # fill the subtitle liststore
        subtitle_liststore = builder.get_object('subtitle_liststore')
        for s in subtitles:
            matches = s.get_matches(video, hearing_impaired=self.config.hearing_impaired)
            scaled_score = compute_score(matches, video)
            if s.hearing_impaired == self.config.hearing_impaired:
                scaled_score -= video.scores['hearing_impaired']
            scaled_score *= 100 / video.scores['hash']
            subtitle_liststore.append([s.id, nice_language(s.language), scaled_score, s.provider_name.capitalize(),
                                       s.hearing_impaired, s.page_link, False])
        subtitle_liststore.set_sort_column_id(2, Gtk.SortType.DESCENDING)

        # connect signals
        builder.connect_signals(ChooseHandler(self.config, video, subtitles))

        # display window
        window = builder.get_object('subtitle_window')
        window.show_all()
        Gtk.main()
Example #9
0
def download_best_subs(video_path, subtitles_dir, release_name, languages, subtitles=True, embedded_subtitles=True,
                       provider_pool=None):
    """Download the best subtitle for the given video.

    :param video_path: the video path
    :type video_path: str
    :param subtitles_dir: the subtitles directory
    :type subtitles_dir: str
    :param release_name: the release name for the given video
    :type release_name: str
    :param languages: the needed languages
    :type languages: set of babelfish.Language
    :param subtitles: True if existing external subtitles should be taken into account
    :type subtitles: bool
    :param embedded_subtitles: True if embedded subtitles should be taken into account
    :type embedded_subtitles: bool
    :param provider_pool: provider pool to be used
    :type provider_pool: subliminal.ProviderPool
    :return: the downloaded subtitles
    :rtype: list of subliminal.subtitle.Subtitle
    """
    try:
        video = get_video(video_path, subtitles_dir=subtitles_dir, subtitles=subtitles,
                          embedded_subtitles=embedded_subtitles, release_name=release_name)

        if not video:
            logger.info(u'Exception caught in subliminal.scan_video for %s', video_path)
            return []

        pool = provider_pool or get_provider_pool()

        if sickbeard.SUBTITLES_PRE_SCRIPTS:
            run_subs_pre_scripts(video_path)

        subtitles_list = pool.list_subtitles(video, languages)
        for provider in pool.providers:
            if provider in pool.discarded_providers:
                logger.debug(u'Could not search in %s provider. Discarding for now', provider)

        if not subtitles_list:
            logger.info(u'No subtitles found for %s', os.path.basename(video_path))
            return []

        min_score = get_min_score()
        scored_subtitles = sorted([(s, compute_score(s, video, hearing_impaired=sickbeard.SUBTITLES_HEARING_IMPAIRED))
                                  for s in subtitles_list], key=operator.itemgetter(1), reverse=True)
        for subtitle, score in scored_subtitles:
            logger.debug(u'[{0:>13s}:{1:<5s}] score = {2:3d}/{3:3d} for {4}'.format(
                subtitle.provider_name, subtitle.language, score, min_score, get_subtitle_description(subtitle)))

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

        if not found_subtitles:
            logger.info(u'No subtitles found for %s with a minimum score of %d',
                        os.path.basename(video_path), min_score)
            return []

        save_subtitles(video, found_subtitles, directory=_encode(subtitles_dir), single=not sickbeard.SUBTITLES_MULTI)

        for subtitle in found_subtitles:
            logger.info(u'Found subtitle for %s in %s provider with language %s', os.path.basename(video_path),
                        subtitle.provider_name, subtitle.language.opensubtitles)
            subtitle_path = compute_subtitle_path(subtitle, video_path, subtitles_dir)

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

        return found_subtitles
    except IOError as error:
        if 'No space left on device' in ex(error):
            logger.warning(u'Not enough space on the drive to save subtitles')
        else:
            logger.warning(traceback.format_exc())
    except Exception as error:
        logger.debug(u'Exception: %s', error)
        logger.info(u'Error occurred when downloading subtitles for: %s', video_path)
        logger.error(traceback.format_exc())

    return []
Example #10
0
def download_subtitle(path, language, hi, providers, providers_auth, sceneName, media_type):
    if hi == "True":
        hi = True
    else:
        hi = False
    language_set = set()
    if language == 'pob':
        language_set.add(Language('por', 'BR'))
    else:
        language_set.add(Language(language))

    use_scenename = get_general_settings()[9]
    minimum_score = get_general_settings()[8]
    minimum_score_movie = get_general_settings()[22]
    use_postprocessing = get_general_settings()[10]
    postprocessing_cmd = get_general_settings()[11]

    try:
        if sceneName == "None" or use_scenename is False:
            used_sceneName = False
            video = scan_video(path)
        else:
            used_sceneName = True
            video = Video.fromname(sceneName)
    except Exception as e:
        logging.exception("Error trying to get video information for this file: " + path)
    else:
        if media_type == "movie":
            max_score = 120.0
        elif media_type == "series":
            max_score = 360.0

        try:
            with AsyncProviderPool(max_workers=None, providers=providers, provider_configs=providers_auth) as p:
                subtitles = p.list_subtitles(video, language_set)
        except Exception as e:
            logging.exception("Error trying to get subtitle list from provider")
        else:
            subtitles_list = []
            sorted_subtitles = sorted([(s, compute_score(s, video, hearing_impaired=hi)) for s in subtitles], key=operator.itemgetter(1), reverse=True)
            for s, preliminary_score in sorted_subtitles:
                if media_type == "movie":
                    if (preliminary_score / max_score * 100) < int(minimum_score_movie):
                        continue
                    matched = set(s.get_matches(video))
                    if hi == s.hearing_impaired:
                        matched.add('hearing_impaired')
                    not_matched = set(score.movie_scores.keys()) - matched
                    required = set(['title'])
                    if any(elem in required for elem in not_matched):
                        continue
                elif media_type == "series":
                    if (preliminary_score / max_score * 100) < int(minimum_score):
                        continue
                    matched = set(s.get_matches(video))
                    if hi == s.hearing_impaired:
                        matched.add('hearing_impaired')
                    not_matched = set(score.episode_scores.keys()) - matched
                    required = set(['series', 'season', 'episode'])
                    if any(elem in required for elem in not_matched):
                        continue
                subtitles_list.append(s)
            if len(subtitles_list) > 0:
                best_subtitle = subtitles_list[0]
                download_subtitles([best_subtitle], providers=providers, provider_configs=providers_auth)
                try:
                    calculated_score = round(float(compute_score(best_subtitle, video, hearing_impaired=hi)) / max_score * 100, 2)
                    if used_sceneName == True:
                        video = scan_video(path)
                    single = get_general_settings()[7]
                    if single is True:
                        result = save_subtitles(video, [best_subtitle], single=True, encoding='utf-8')
                    else:
                        result = save_subtitles(video, [best_subtitle], encoding='utf-8')
                except Exception as e:
                    logging.exception('Error saving subtitles file to disk.')
                    return None
                else:
                    if len(result) > 0:
                        downloaded_provider = result[0].provider_name
                        downloaded_language = language_from_alpha3(result[0].language.alpha3)
                        downloaded_language_code2 = alpha2_from_alpha3(result[0].language.alpha3)
                        downloaded_language_code3 = result[0].language.alpha3
                        downloaded_path = get_subtitle_path(path, language=language_set)
                        if used_sceneName == True:
                            message = downloaded_language + " subtitles downloaded from " + downloaded_provider + " with a score of " + unicode(calculated_score) + "% using this scene name: " + sceneName
                        else:
                            message = downloaded_language + " subtitles downloaded from " + downloaded_provider + " with a score of " + unicode(calculated_score) + "% using filename guessing."

                        if use_postprocessing is True:
                            command = pp_replace(postprocessing_cmd, path, downloaded_path, downloaded_language, downloaded_language_code2, downloaded_language_code3)
                            try:
                                if os.name == 'nt':
                                    codepage = subprocess.Popen("chcp", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                                    # wait for the process to terminate
                                    out_codepage, err_codepage = codepage.communicate()
                                    encoding = out_codepage.split(':')[-1].strip()

                                process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                                # wait for the process to terminate
                                out, err = process.communicate()

                                if os.name == 'nt':
                                    out = out.decode(encoding)

                            except:
                                if out == "":
                                    logging.error('Post-processing result for file ' + path + ' : Nothing returned from command execution')
                                else:
                                    logging.error('Post-processing result for file ' + path + ' : ' + out)
                            else:
                                if out == "":
                                    logging.info('Post-processing result for file ' + path + ' : Nothing returned from command execution')
                                else:
                                    logging.info('Post-processing result for file ' + path + ' : ' + out)

                        return message
                    else:
                        return None
            else:
                return None
Example #11
0
def download(obj, provider, refiner, language, age, directory, encoding, single, force, hearing_impaired, min_score,
             max_workers, archives, verbose, path):
    """Download best subtitles.

    PATH can be an directory containing videos, a video file path or a video file name. It can be used multiple times.

    If an existing subtitle is detected (external or embedded) in the correct language, the download is skipped for
    the associated video.

    """
    # process parameters
    language = set(language)

    # scan videos
    videos = []
    ignored_videos = []
    errored_paths = []
    with click.progressbar(path, label='Collecting videos', item_show_func=lambda p: p or '') as bar:
        for p in bar:
            logger.debug('Collecting path %s', p)

            # non-existing
            if not os.path.exists(p):
                try:
                    video = Video.fromname(p)
                except:
                    logger.exception('Unexpected error while collecting non-existing path %s', p)
                    errored_paths.append(p)
                    continue
                if not force:
                    video.subtitle_languages |= set(search_external_subtitles(video.name, directory=directory).values())
                refine(video, episode_refiners=refiner, movie_refiners=refiner, embedded_subtitles=not force)
                videos.append(video)
                continue

            # directories
            if os.path.isdir(p):
                try:
                    scanned_videos = scan_videos(p, age=age, archives=archives)
                except:
                    logger.exception('Unexpected error while collecting directory path %s', p)
                    errored_paths.append(p)
                    continue
                for video in scanned_videos:
                    if not force:
                        video.subtitle_languages |= set(search_external_subtitles(video.name,
                                                                                  directory=directory).values())
                    if check_video(video, languages=language, age=age, undefined=single):
                        refine(video, episode_refiners=refiner, movie_refiners=refiner, embedded_subtitles=not force)
                        videos.append(video)
                    else:
                        ignored_videos.append(video)
                continue

            # other inputs
            try:
                video = scan_video(p)
            except:
                logger.exception('Unexpected error while collecting path %s', p)
                errored_paths.append(p)
                continue
            if not force:
                video.subtitle_languages |= set(search_external_subtitles(video.name, directory=directory).values())
            if check_video(video, languages=language, age=age, undefined=single):
                refine(video, episode_refiners=refiner, movie_refiners=refiner, embedded_subtitles=not force)
                videos.append(video)
            else:
                ignored_videos.append(video)

    # output errored paths
    if verbose > 0:
        for p in errored_paths:
            click.secho('%s errored' % p, fg='red')

    # output ignored videos
    if verbose > 1:
        for video in ignored_videos:
            click.secho('%s ignored - subtitles: %s / age: %d day%s' % (
                os.path.split(video.name)[1],
                ', '.join(str(s) for s in video.subtitle_languages) or 'none',
                video.age.days,
                's' if video.age.days > 1 else ''
            ), fg='yellow')

    # report collected videos
    click.echo('%s video%s collected / %s video%s ignored / %s error%s' % (
        click.style(str(len(videos)), bold=True, fg='green' if videos else None),
        's' if len(videos) > 1 else '',
        click.style(str(len(ignored_videos)), bold=True, fg='yellow' if ignored_videos else None),
        's' if len(ignored_videos) > 1 else '',
        click.style(str(len(errored_paths)), bold=True, fg='red' if errored_paths else None),
        's' if len(errored_paths) > 1 else '',
    ))

    # exit if no video collected
    if not videos:
        return

    # download best subtitles
    downloaded_subtitles = defaultdict(list)
    with AsyncProviderPool(max_workers=max_workers, providers=provider, provider_configs=obj['provider_configs']) as p:
        with click.progressbar(videos, label='Downloading subtitles',
                               item_show_func=lambda v: os.path.split(v.name)[1] if v is not None else '') as bar:
            for v in bar:
                scores = get_scores(v)
                subtitles = p.download_best_subtitles(p.list_subtitles(v, language - v.subtitle_languages),
                                                      v, language, min_score=scores['hash'] * min_score / 100,
                                                      hearing_impaired=hearing_impaired, only_one=single)
                downloaded_subtitles[v] = subtitles

        if p.discarded_providers:
            click.secho('Some providers have been discarded due to unexpected errors: %s' %
                        ', '.join(p.discarded_providers), fg='yellow')

    # save subtitles
    total_subtitles = 0
    for v, subtitles in downloaded_subtitles.items():
        saved_subtitles = save_subtitles(v, subtitles, single=single, directory=directory, encoding=encoding)
        total_subtitles += len(saved_subtitles)

        if verbose > 0:
            click.echo('%s subtitle%s downloaded for %s' % (click.style(str(len(saved_subtitles)), bold=True),
                                                            's' if len(saved_subtitles) > 1 else '',
                                                            os.path.split(v.name)[1]))

        if verbose > 1:
            for s in saved_subtitles:
                matches = s.get_matches(v)
                score = compute_score(s, v)

                # score color
                score_color = None
                scores = get_scores(v)
                if isinstance(v, Movie):
                    if score < scores['title']:
                        score_color = 'red'
                    elif score < scores['title'] + scores['year'] + scores['release_group']:
                        score_color = 'yellow'
                    else:
                        score_color = 'green'
                elif isinstance(v, Episode):
                    if score < scores['series'] + scores['season'] + scores['episode']:
                        score_color = 'red'
                    elif score < scores['series'] + scores['season'] + scores['episode'] + scores['release_group']:
                        score_color = 'yellow'
                    else:
                        score_color = 'green'

                # scale score from 0 to 100 taking out preferences
                scaled_score = score
                if s.hearing_impaired == hearing_impaired:
                    scaled_score -= scores['hearing_impaired']
                scaled_score *= 100 / scores['hash']

                # echo some nice colored output
                click.echo('  - [{score}] {language} subtitle from {provider_name} (match on {matches})'.format(
                    score=click.style('{:5.1f}'.format(scaled_score), fg=score_color, bold=score >= scores['hash']),
                    language=s.language.name if s.language.country is None else '%s (%s)' % (s.language.name,
                                                                                             s.language.country.name),
                    provider_name=s.provider_name,
                    matches=', '.join(sorted(matches, key=scores.get, reverse=True))
                ))

    if verbose == 0:
        click.echo('Downloaded %s subtitle%s' % (click.style(str(total_subtitles), bold=True),
                                                 's' if total_subtitles > 1 else ''))
Example #12
0
def download_subtitles(tv_episode,
                       video_path=None,
                       subtitles=True,
                       embedded_subtitles=True):
    """Download missing subtitles for the given episode.

    Checks whether subtitles are needed or not

    :param tv_episode: the episode to download subtitles
    :type tv_episode: medusa.tv.TVEpisode
    :param video_path: the video path. If none, the episode location will be used
    :type video_path: str
    :param subtitles: True if existing external subtitles should be taken into account
    :type subtitles: bool
    :param embedded_subtitles: True if embedded subtitles should be taken into account
    :type embedded_subtitles: bool
    :return: a sorted list of the opensubtitles codes for the downloaded subtitles
    :rtype: list of str
    """
    video_path = video_path or tv_episode.location
    show_name = tv_episode.show.name
    season = tv_episode.season
    episode = tv_episode.episode
    episode_name = tv_episode.name
    show_indexerid = tv_episode.show.indexerid
    status = tv_episode.status
    release_name = tv_episode.release_name
    ep_num = episode_num(season, episode) or episode_num(
        season, episode, numbering='absolute')
    subtitles_dir = get_subtitles_dir(video_path)
    languages = get_needed_languages(tv_episode.subtitles)

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

    try:
        logger.debug(u'Checking subtitle candidates for %s %s (%s)', show_name,
                     ep_num, os.path.basename(video_path))
        video = get_video(tv_episode,
                          video_path,
                          subtitles_dir=subtitles_dir,
                          subtitles=subtitles,
                          embedded_subtitles=embedded_subtitles,
                          release_name=release_name)
        if not video:
            logger.info(u'Exception caught in subliminal.scan_video for %s',
                        video_path)
            return []

        if app.SUBTITLES_PRE_SCRIPTS:
            run_subs_pre_scripts(video_path)

        pool = get_provider_pool()
        subtitles_list = pool.list_subtitles(video, languages)
        for provider in pool.providers:
            if provider in pool.discarded_providers:
                logger.debug(
                    u'Could not search in %s provider. Discarding for now',
                    provider)

        if not subtitles_list:
            logger.info(u'No subtitles found for %s',
                        os.path.basename(video_path))
            return []

        min_score = get_min_score()
        scored_subtitles = sorted(
            [(s,
              compute_score(
                  s, video, hearing_impaired=app.SUBTITLES_HEARING_IMPAIRED))
             for s in subtitles_list],
            key=operator.itemgetter(1),
            reverse=True)
        for subtitle, score in scored_subtitles:
            logger.debug(
                u'[{0:>13s}:{1:<5s}] score = {2:3d}/{3:3d} for {4}'.format(
                    subtitle.provider_name, subtitle.language, score,
                    min_score, get_subtitle_description(subtitle)))

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

        if not found_subtitles:
            logger.info(
                u'No subtitles found for %s with a minimum score of %d',
                os.path.basename(video_path), min_score)
            return []

        saved_subtitles = save_subtitles(video,
                                         found_subtitles,
                                         directory=_encode(subtitles_dir),
                                         single=not app.SUBTITLES_MULTI)

        for subtitle in saved_subtitles:
            logger.info(
                u'Found subtitle for %s in %s provider with language %s',
                os.path.basename(video_path), subtitle.provider_name,
                subtitle.language.opensubtitles)
            subtitle_path = compute_subtitle_path(subtitle, video_path,
                                                  subtitles_dir)
            app.helpers.chmodAsParent(subtitle_path)
            app.helpers.fixSetGroupID(subtitle_path)

            if app.SUBTITLES_EXTRA_SCRIPTS and isMediaFile(video_path):
                subtitle_path = compute_subtitle_path(subtitle, video_path,
                                                      subtitles_dir)
                run_subs_extra_scripts(video_path=video_path,
                                       subtitle_path=subtitle_path,
                                       subtitle_language=subtitle.language,
                                       show_name=show_name,
                                       season=season,
                                       episode=episode,
                                       episode_name=episode_name,
                                       show_indexerid=show_indexerid)

            if app.SUBTITLES_HISTORY:
                logger.debug(u'history.logSubtitle %s, %s',
                             subtitle.provider_name,
                             subtitle.language.opensubtitles)
                history.logSubtitle(show_indexerid, season, episode, status,
                                    subtitle)

        return sorted(
            {subtitle.language.opensubtitles
             for subtitle in saved_subtitles})
    except IOError as error:
        if 'No space left on device' in ex(error):
            logger.warning(u'Not enough space on the drive to save subtitles')
        else:
            logger.warning(traceback.format_exc())
    except Exception as error:
        logger.debug(u'Exception: %s', error)
        logger.info(u'Error occurred when downloading subtitles for: %s',
                    video_path)
        logger.error(traceback.format_exc())

    return []
Example #13
0
def manual_download_subtitle(path, language, hi, subtitle, provider, providers_auth, sceneName, media_type):
    logging.debug('BAZARR Manually downloading subtitles for this file: ' + path)
    if hi == "True":
        hi = True
    else:
        hi = False
    subtitle = pickle.loads(codecs.decode(subtitle.encode(), "base64"))
    if media_type == 'series':
        type_of_score = 360
    elif media_type == 'movie':
        type_of_score = 120
    use_scenename = settings.general.getboolean('use_scenename')
    use_postprocessing = settings.general.getboolean('use_postprocessing')
    postprocessing_cmd = settings.general.postprocessing_cmd

    language = alpha3_from_alpha2(language)
    if language == 'pob':
        lang_obj = Language('por', 'BR')
    else:
        lang_obj = Language(language)

    try:
        if sceneName is None or use_scenename is False:
            used_sceneName = False
            video = scan_video(path)
        else:
            used_sceneName = True
            video = Video.fromname(sceneName)
    except Exception as e:
        logging.exception("BAZARR Error trying to get video information for this file: " + path)
        pass
    else:
        try:
            download_subtitles([subtitle], providers=provider, provider_configs=providers_auth)
            logging.debug('BAZARR Subtitles file downloaded for this file:' + path)
        except Exception as e:
            logging.exception('BAZARR Error downloading subtitles for this file ' + path)
            return None
        else:
            single = settings.general.getboolean('single_language')
            try:
                score = round(float(compute_score(subtitle, video, hearing_impaired=hi)) / type_of_score * 100, 2)
                if used_sceneName == True:
                    video = scan_video(path)
                if single is True:
                    result = save_subtitles(video, [subtitle], single=True, encoding='utf-8')
                else:
                    result = save_subtitles(video, [subtitle], encoding='utf-8')
            except Exception as e:
                logging.exception('BAZARR Error saving subtitles file to disk for this file:' + path)
                return None
            else:
                if len(result) > 0:
                    downloaded_provider = result[0].provider_name
                    downloaded_language = language_from_alpha3(result[0].language.alpha3)
                    downloaded_language_code2 = alpha2_from_alpha3(result[0].language.alpha3)
                    downloaded_language_code3 = result[0].language.alpha3
                    downloaded_path = get_subtitle_path(path, downloaded_language_code2)
                    logging.debug('BAZARR Subtitles file saved to disk: ' + downloaded_path)
                    message = downloaded_language + " subtitles downloaded from " + downloaded_provider + " with a score of " + unicode(score) + "% using manual search."

                    if use_postprocessing is True:
                        command = pp_replace(postprocessing_cmd, path, downloaded_path, downloaded_language, downloaded_language_code2, downloaded_language_code3)
                        try:
                            if os.name == 'nt':
                                codepage = subprocess.Popen("chcp", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                                # wait for the process to terminate
                                out_codepage, err_codepage = codepage.communicate()
                                encoding = out_codepage.split(':')[-1].strip()

                            process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                            # wait for the process to terminate
                            out, err = process.communicate()

                            if os.name == 'nt':
                                out = out.decode(encoding)

                        except:
                            if out == "":
                                logging.error('BAZARR Post-processing result for file ' + path + ' : Nothing returned from command execution')
                            else:
                                logging.error('BAZARR Post-processing result for file ' + path + ' : ' + out)
                        else:
                            if out == "":
                                logging.info('BAZARR Post-processing result for file ' + path + ' : Nothing returned from command execution')
                            else:
                                logging.info('BAZARR Post-processing result for file ' + path + ' : ' + out)

                    return message
                else:
                    logging.error("BAZARR Tried to manually download a subtitles for file: " + path + " but we weren't able to do (probably throttled by " + str(subtitle.provider_name) + ". Please retry later or select a subtitles from another provider.")
                    return None
    logging.debug('BAZARR Ended manually downloading subtitles for file: ' + path)
Example #14
0
def download_subtitle(path, language, hi, providers, providers_auth, sceneName, media_type):
    logging.debug('BAZARR Searching subtitles for this file: ' + path)
    if hi == "True":
        hi = True
    else:
        hi = False
    language_set = set()
    if language == 'pob':
        language_set.add(Language('por', 'BR'))
    else:
        language_set.add(Language(language))

    use_scenename = settings.general.getboolean('use_scenename')
    minimum_score = settings.general.minimum_score
    minimum_score_movie = settings.general.minimum_score_movie
    use_postprocessing = settings.general.getboolean('use_postprocessing')
    postprocessing_cmd = settings.general.postprocessing_cmd

    try:
        if sceneName == "None" or use_scenename is False:
            used_sceneName = False
            video = scan_video(path)
        else:
            used_sceneName = True
            video = Video.fromname(sceneName)
    except Exception as e:
        logging.exception("BAZARR Error trying to get video information for this file: " + path)
        pass
    else:
        if media_type == "movie":
            max_score = 120.0
        elif media_type == "series":
            max_score = 360.0

        try:
            with AsyncProviderPool(max_workers=None, providers=providers, provider_configs=providers_auth) as p:
                subtitles = p.list_subtitles(video, language_set)
        except Exception as e:
            logging.exception("BAZARR Error trying to get subtitle list from provider for this file: " + path)
        else:
            subtitles_list = []
            try:
                sorted_subtitles = sorted([(s, compute_score(s, video, hearing_impaired=hi)) for s in subtitles], key=operator.itemgetter(1), reverse=True)
            except Exception as e:
                logging.exception('BAZARR Exception raised while trying to compute score for this file: ' + path)
                return None
            else:
                for s, preliminary_score in sorted_subtitles:
                    if media_type == "movie":
                        if (preliminary_score / max_score * 100) < int(minimum_score_movie):
                            continue
                        matched = set(s.get_matches(video))
                        if hi == s.hearing_impaired:
                            matched.add('hearing_impaired')
                        not_matched = set(score.movie_scores.keys()) - matched
                        required = set(['title'])
                        if any(elem in required for elem in not_matched):
                            continue
                    elif media_type == "series":
                        if (preliminary_score / max_score * 100) < int(minimum_score):
                            continue
                        matched = set(s.get_matches(video))
                        if hi == s.hearing_impaired:
                            matched.add('hearing_impaired')
                        not_matched = set(score.episode_scores.keys()) - matched
                        required = set(['series', 'season', 'episode'])
                        if any(elem in required for elem in not_matched):
                            continue
                    subtitles_list.append(s)
                logging.debug('BAZARR ' + str(len(subtitles_list)) + " subtitles have been found for this file: " + path)
                if len(subtitles_list) > 0:
                    try:
                        download_result = False
                        for subtitle in subtitles_list:
                            download_result = p.download_subtitle(subtitle)
                            if download_result:
                                logging.debug('BAZARR Subtitles file downloaded from ' + str(subtitle.provider_name) + ' for this file: ' + path)
                                break
                            else:
                                logging.warning('BAZARR Subtitles file skipped from ' + str(subtitle.provider_name) + ' for this file: ' + path + ' because no content was returned by the provider (probably throttled).')
                                continue
                        if not download_result:
                            logging.error('BAZARR Tried to download a subtitles for file: ' + path + " but we weren't able to do it this time (probably being throttled). Going to retry on next search.")
                            return None
                    except Exception as e:
                        logging.exception('BAZARR Error downloading subtitles for this file ' + path)
                        return None
                    else:
                        try:
                            calculated_score = round(float(compute_score(subtitle, video, hearing_impaired=hi)) / max_score * 100, 2)
                            if used_sceneName:
                                video = scan_video(path)
                            single = settings.general.getboolean('single_language')
                            if single is True:
                                result = save_subtitles(video, [subtitle], single=True, encoding='utf-8')
                            else:
                                result = save_subtitles(video, [subtitle], encoding='utf-8')
                        except Exception as e:
                            logging.exception('BAZARR Error saving subtitles file to disk for this file:' + path)
                            pass
                        else:
                            downloaded_provider = result[0].provider_name
                            downloaded_language = language_from_alpha3(result[0].language.alpha3)
                            downloaded_language_code2 = alpha2_from_alpha3(result[0].language.alpha3)
                            downloaded_language_code3 = result[0].language.alpha3
                            downloaded_path = get_subtitle_path(path, downloaded_language_code2)
                            logging.debug('BAZARR Subtitles file saved to disk: ' + downloaded_path)
                            if used_sceneName:
                                message = downloaded_language + " subtitles downloaded from " + downloaded_provider + " with a score of " + unicode(calculated_score) + "% using this scene name: " + sceneName
                            else:
                                message = downloaded_language + " subtitles downloaded from " + downloaded_provider + " with a score of " + unicode(calculated_score) + "% using filename guessing."

                            if use_postprocessing is True:
                                command = pp_replace(postprocessing_cmd, path, downloaded_path, downloaded_language, downloaded_language_code2, downloaded_language_code3)
                                try:
                                    if os.name == 'nt':
                                        codepage = subprocess.Popen("chcp", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                                        # wait for the process to terminate
                                        out_codepage, err_codepage = codepage.communicate()
                                        encoding = out_codepage.split(':')[-1].strip()

                                    process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                                    # wait for the process to terminate
                                    out, err = process.communicate()

                                    if os.name == 'nt':
                                        out = out.decode(encoding)

                                except:
                                    if out == "":
                                        logging.error('BAZARR Post-processing result for file ' + path + ' : Nothing returned from command execution')
                                    else:
                                        logging.error('BAZARR Post-processing result for file ' + path + ' : ' + out)
                                else:
                                    if out == "":
                                        logging.info('BAZARR Post-processing result for file ' + path + ' : Nothing returned from command execution')
                                    else:
                                        logging.info('BAZARR Post-processing result for file ' + path + ' : ' + out)

                            return message
                else:
                    logging.debug('BAZARR No subtitles were found for this file: ' + path)
                    return None
    logging.debug('BAZARR Ended searching subtitles for file: ' + path)
Example #15
0
def manual_search(path, language, hi, providers, providers_auth, sceneName, media_type):
    logging.debug('BAZARR Manually searching subtitles for this file: ' + path)

    subtitles_dict = {}

    if hi == "True":
        hi = True
    else:
        hi = False
    language_set = set()
    for lang in ast.literal_eval(language):
        lang = alpha3_from_alpha2(lang)
        if lang == 'pob':
            language_set.add(Language('por', 'BR'))
        else:
            language_set.add(Language(lang))

    use_scenename = settings.general.getboolean('use_scenename')
    use_postprocessing = settings.general.getboolean('use_postprocessing')
    postprocessing_cmd = settings.general.postprocessing_cmd

    try:
        if sceneName == "None" or use_scenename is False:
            used_sceneName = False
            video = scan_video(path)
        else:
            used_sceneName = True
            video = Video.fromname(sceneName)
    except:
        logging.exception("BAZARR Error trying to get video information for this file: " + path)
    else:
        if media_type == "movie":
            max_score = 120.0
        elif media_type == "series":
            max_score = 360.0

        try:
            with AsyncProviderPool(max_workers=None, providers=providers, provider_configs=providers_auth) as p:
                subtitles = p.list_subtitles(video, language_set)
        except Exception as e:
            logging.exception("BAZARR Error trying to get subtitle list from provider for this file: " + path)
        else:
            subtitles_list = []
            for s in subtitles:
                {s: compute_score(s, video, hearing_impaired=hi)}
                if media_type == "movie":
                    matched = set(s.get_matches(video))
                    if hi == s.hearing_impaired:
                        matched.add('hearing_impaired')
                    not_matched = set(score.movie_scores.keys()) - matched
                    required = set(['title'])
                    if any(elem in required for elem in not_matched):
                        continue
                    if used_sceneName:
                        not_matched.remove('hash')
                    if type(s) is LegendasTVSubtitle:
                        # The pickle doesn't work very well with RAR (rarfile.RarFile) or ZIP (zipfile.ZipFile)
                        s.archive.content = None
                elif media_type == "series":
                    matched = set(s.get_matches(video))
                    if hi == s.hearing_impaired:
                        matched.add('hearing_impaired')
                    not_matched = set(score.episode_scores.keys()) - matched
                    required = set(['series', 'season', 'episode'])
                    if any(elem in required for elem in not_matched):
                        continue
                    if used_sceneName:
                        not_matched.remove('hash')
                    if type(s) is LegendasTVSubtitle:
                        # The pickle doesn't work very well with RAR (rarfile.RarFile) or ZIP (zipfile.ZipFile)
                        s.archive.content = None
                subtitles_list.append(dict(score=round((compute_score(s, video, hearing_impaired=hi) / max_score * 100), 2), language=alpha2_from_alpha3(s.language.alpha3), hearing_impaired=str(s.hearing_impaired), provider=s.provider_name, subtitle=codecs.encode(pickle.dumps(s), "base64").decode(), url=s.page_link, matches=list(matched), dont_matches=list(not_matched)))
            subtitles_dict = sorted(subtitles_list, key=lambda x: x['score'], reverse=True)
            logging.debug('BAZARR ' + str(len(subtitles_dict)) + " subtitles have been found for this file: " + path)
            logging.debug('BAZARR Ended searching subtitles for this file: ' + path)
        return(subtitles_dict)
Example #16
0
def search_subtitle(wanted_item_index, lang):
    log.info("Searching for an individual subtitle")
    subs = []

    # Get wanted queue lock
    if not utils.get_wanted_queue_lock():
        return subs, "Skipping! Cannot get a wanted queue lock because another threat is using the queues!"

    # Get wanted_item
    wanted_item = autosubliminal.WANTEDQUEUE[int(wanted_item_index)]

    # Scan wanted_item for video
    video = _scan_wanted_item_for_video(wanted_item)
    if video:
        # Search the subtitles with the default minimal score (to get all the possibilities to select from)
        subtitles, language, single = _search_subtitles(video, lang, False)
        # Check if subtitles are found for the video
        if subtitles[video]:
            # Add found subtitles to wanted_item
            wanted_item['found_subtitles'] = {
                'subtitles': subtitles,
                'language': language,
                'single': single
            }
            # Order subtitles by score and create new dict
            # Use subliminal scoring (scores=None)
            for index, subtitle, score in sorted([
                (index, s,
                 subliminal.compute_score(s.get_matches(
                     video, hearing_impaired=utils.include_hearing_impaired()),
                                          video,
                                          scores=None))
                    for index, s in enumerate(subtitles[video])
            ],
                                                 key=operator.itemgetter(2),
                                                 reverse=True):
                # Only add subtitle when content is found
                if subtitle.content:
                    # Create new sub dict for showing result
                    sub = {
                        'subtitle_index': index,
                        'score': score,
                        'provider_name': subtitle.provider_name,
                        'content': subtitle.content,
                        'language': language,
                        'single': single,
                        'page_link': subtitle.page_link,
                        'releases': _get_releases(subtitle),
                        'wanted_item_index': wanted_item_index,
                        'playvideo_url': _construct_playvideo_url(wanted_item)
                    }
                    # Get content preview (the first 28 lines and last 30 lines of the subtitle)
                    content_split = subtitle.content.splitlines(False)
                    if len(content_split) < 58:
                        content_preview = "This seems to be an invalid subtitle."
                        content_preview += "<br> It has less than 58 lines to preview."
                    else:
                        try:
                            # First 28 lines
                            content_preview = "<br>".join(
                                x.replace('"', "'")
                                for x in content_split[:28])
                            # Separator
                            content_preview += "<br>"
                            content_preview += "<br>"
                            content_preview += "..."
                            content_preview += "<br>"
                            content_preview += "<br>"
                            # Last 30 lines
                            content_preview += "<br>".join(
                                x.replace('"', "'")
                                for x in content_split[len(content_split) -
                                                       30:])
                        except:
                            content_preview = "Problem with parsing the first 28 and/or last 30 lines of the file."
                    sub['content_preview'] = content_preview
                    subs.append(sub)

    # Release wanted queue lock
    utils.release_wanted_queue_lock()

    if not len(subs):
        return subs, "No subtitles could be found or downloaded!"

    return subs, None
Example #17
0
 def _score(st):
   try:
     return subliminal.compute_score(st, video)
   except Exception as e:
     logger.warn('subliminal.compute_score() returned an error: %s', e)
     return 0
Example #18
0
    def subtitles_download_in_pp():  # pylint: disable=too-many-locals, too-many-branches, too-many-statements
        logger.log(u'Checking for needed subtitles in Post-Process folder', logger.INFO)

        providers = enabled_service_list()
        provider_configs = {'addic7ed': {'username': sickbeard.ADDIC7ED_USER,
                                         'password': sickbeard.ADDIC7ED_PASS},
                            'itasa': {'username': sickbeard.ITASA_USER,
                                      'password': sickbeard.ITASA_PASS},
                            'legendastv': {'username': sickbeard.LEGENDASTV_USER,
                                           'password': sickbeard.LEGENDASTV_PASS},
                            'opensubtitles': {'username': sickbeard.OPENSUBTITLES_USER,
                                              'password': sickbeard.OPENSUBTITLES_PASS}}

        pool = ProviderPool(providers=providers, provider_configs=provider_configs)

        # Search for all wanted languages
        languages = {from_code(language) for language in wanted_languages()}
        if not languages:
            return

        # Dict of language exceptions to use with subliminal
        language_exceptions = {'pt-br': 'pob'}

        run_post_process = False
        # Check if PP folder is set
        if sickbeard.TV_DOWNLOAD_DIR and os.path.isdir(sickbeard.TV_DOWNLOAD_DIR):

            for root, _, files in os.walk(sickbeard.TV_DOWNLOAD_DIR, topdown=False):
                rar_files = [rar_file for rar_file in files if isRarFile(rar_file)]
                if rar_files and sickbeard.UNPACK:
                    video_files = [video_file for video_file in files if isMediaFile(video_file)]
                    if u'_UNPACK' not in root and (not video_files or root == sickbeard.TV_DOWNLOAD_DIR):
                        logger.log(u'Found rar files in post-process folder: {}'.format(rar_files), logger.DEBUG)
                        result = processTV.ProcessResult()
                        processTV.unRAR(root, rar_files, False, result)
                elif rar_files and not sickbeard.UNPACK:
                    logger.log(u'Unpack is disabled. Skipping: {}'.format(rar_files), logger.WARNING)

            for root, _, files in os.walk(sickbeard.TV_DOWNLOAD_DIR, topdown=False):
                for filename in sorted(files):
                    try:
                        # Remove non release groups from video file. Needed to match subtitles
                        new_filename = remove_non_release_groups(filename)
                        if new_filename != filename:
                            os.rename(filename, new_filename)
                            filename = new_filename
                    except Exception as error:
                        logger.log(u"Couldn't remove non release groups from video file. Error: {}".format
                                   (ex(error)), logger.DEBUG)

                    # Delete unwanted subtitles before downloading new ones
                    if sickbeard.SUBTITLES_MULTI and sickbeard.SUBTITLES_KEEP_ONLY_WANTED and filename.rpartition('.')[2] in subtitle_extensions:
                        subtitle_language = filename.rsplit('.', 2)[1].lower()
                        if len(subtitle_language) == 2 and subtitle_language in language_converters['opensubtitles'].codes:
                            subtitle_language = Language.fromcode(subtitle_language, 'alpha2').opensubtitles
                        elif subtitle_language in language_exceptions:
                            subtitle_language = language_exceptions.get(subtitle_language, subtitle_language)
                        elif subtitle_language not in language_converters['opensubtitles'].codes:
                            subtitle_language = 'unknown'
                        if subtitle_language not in sickbeard.SUBTITLES_LANGUAGES:
                            try:
                                os.remove(os.path.join(root, filename))
                                logger.log(u"Deleted '{}' because we don't want subtitle language '{}'. We only want '{}' language(s)".format
                                           (filename, subtitle_language, ','.join(sickbeard.SUBTITLES_LANGUAGES)), logger.DEBUG)
                            except Exception as error:
                                logger.log(u"Couldn't delete subtitle: {}. Error: {}".format(filename, ex(error)), logger.DEBUG)

                    if isMediaFile(filename):
                        subtitles_enabled = processTV.subtitles_enabled(filename)
                        if subtitles_enabled:
                            if sickbeard.SUBTITLES_PRE_SCRIPTS and not sickbeard.EMBEDDED_SUBTITLES_ALL:
                                run_subs_scripts(None, None, None, filename, is_pre=True)
    
                            try:
                                video = scan_video(os.path.join(root, filename))
                                subtitles_list = pool.list_subtitles(video, languages)
    
                                for provider in providers:
                                    if provider in pool.discarded_providers:
                                        logger.log(u'Could not search in {} provider. Discarding for now'.format(provider), logger.DEBUG)
    
                                if not subtitles_list:
                                    logger.log(u'No subtitles found for {}'.format
                                               (os.path.join(root, filename)), logger.DEBUG)
                                    continue
    
                                logger.log(u'Found subtitle(s) canditate(s) for {}'.format(filename), logger.INFO)
                                hearing_impaired = sickbeard.SUBTITLES_HEARING_IMPAIRED
                                user_score = 213 if sickbeard.SUBTITLES_PERFECT_MATCH else 198
                                found_subtitles = pool.download_best_subtitles(subtitles_list, video, languages=languages,
                                                                               hearing_impaired=hearing_impaired,
                                                                               min_score=user_score,
                                                                               only_one=not sickbeard.SUBTITLES_MULTI)
    
                                for subtitle in subtitles_list:
                                    score = compute_score(subtitle, video, hearing_impaired=sickbeard.SUBTITLES_HEARING_IMPAIRED)
                                    logger.log(u'[{}] Subtitle score for {} is: {} (min={})'.format
                                               (subtitle.provider_name, subtitle.id, score, user_score), logger.DEBUG)
    
                                downloaded_languages = set()
                                for subtitle in found_subtitles:
                                    logger.log(u'Found subtitle for {} in {} provider with language {}'.format
                                               (os.path.join(root, filename), subtitle.provider_name,
                                                subtitle.language.opensubtitles), logger.INFO)
                                    save_subtitles(video, found_subtitles, directory=root, single=not sickbeard.SUBTITLES_MULTI)
    
                                    subtitles_multi = not sickbeard.SUBTITLES_MULTI
                                    subtitle_path = get_subtitle_path(video.name, None if subtitles_multi else subtitle.language)
                                    if root:
                                        subtitle_path = os.path.join(root, os.path.split(subtitle_path)[1])
                                    sickbeard.helpers.chmodAsParent(subtitle_path)
                                    sickbeard.helpers.fixSetGroupID(subtitle_path)
    
                                    downloaded_languages.add(subtitle.language.opensubtitles)
    
                                # Don't run post processor unless at least one file has all of the needed subtitles
                                if not needs_subtitles(downloaded_languages):
                                    run_post_process = True
                            except Exception as error:
                                logger.log(u'Error occurred when downloading subtitles for: {}. Error: {}'.format
                                           (os.path.join(root, filename), ex(error)))
                        elif subtitles_enabled is False:
                            logger.log(u"Subtitle disabled for show: {}".format(filename), logger.DEBUG)
                            
            if run_post_process:
                logger.log(u'Starting post-process with default settings now that we found subtitles')
                processTV.processDir(sickbeard.TV_DOWNLOAD_DIR)
        else:
            logger.log(u'You must set a valid post-process folder in "Post Processing" settings', logger.WARNING)
Example #19
0
def download_subtitles(subtitles_info):  # pylint: disable=too-many-locals, too-many-branches, too-many-statements
    existing_subtitles = subtitles_info['subtitles']

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

    languages = get_needed_languages(existing_subtitles)
    if not languages:
        logger.log(u'No subtitles needed for {} {}'.format
                   (subtitles_info['show_name'], episode_num(subtitles_info['season'], subtitles_info['episode']) or
                    episode_num(subtitles_info['season'], subtitles_info['episode'], numbering='absolute')), logger.DEBUG)
        return existing_subtitles, None

    logger.log(u'Checking subtitle candidates for {} {} ({})'.format
               (subtitles_info['show_name'], episode_num(subtitles_info['season'], subtitles_info['episode']) or
                episode_num(subtitles_info['season'], subtitles_info['episode'], numbering='absolute'),
                os.path.basename(subtitles_info['location'])), logger.DEBUG)

    subtitles_path = get_subtitles_path(subtitles_info['location'])
    video_path = subtitles_info['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)
    if not video:
        logger.log(u'Exception caught in subliminal.scan_video for {} {}'.format
                   (subtitles_info['show_name'], episode_num(subtitles_info['season'], subtitles_info['episode']) or
                    episode_num(subtitles_info['season'], subtitles_info['episode'], numbering='absolute')), logger.DEBUG)
        return existing_subtitles, None

    providers = enabled_service_list()
    provider_configs = {'addic7ed': {'username': sickbeard.ADDIC7ED_USER,
                                     'password': sickbeard.ADDIC7ED_PASS},
                        'itasa': {'username': sickbeard.ITASA_USER,
                                  'password': sickbeard.ITASA_PASS},
                        'legendastv': {'username': sickbeard.LEGENDASTV_USER,
                                       'password': sickbeard.LEGENDASTV_PASS},
                        'opensubtitles': {'username': sickbeard.OPENSUBTITLES_USER,
                                          'password': sickbeard.OPENSUBTITLES_PASS}}

    pool = ProviderPool(providers=providers, provider_configs=provider_configs)

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

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

        if not subtitles_list:
            logger.log(u'No subtitles found for {} {}'.format
                       (subtitles_info['show_name'], episode_num(subtitles_info['season'], subtitles_info['episode']) or
                        episode_num(subtitles_info['season'], subtitles_info['episode'], numbering='absolute')))
            return existing_subtitles, None

        for subtitle in subtitles_list:
            score = compute_score(subtitle, video, hearing_impaired=sickbeard.SUBTITLES_HEARING_IMPAIRED)
            logger.log(u'[{}] Subtitle score for {} is: {} (min={})'.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)

        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(u'Not enough space on the drive to save subtitles', logger.WARNING)
        else:
            logger.log(traceback.format_exc(), logger.WARNING)
    except Exception:
        logger.log(u'Error occurred when downloading subtitles for: {}'.format(video_path))
        logger.log(traceback.format_exc(), logger.ERROR)
        return existing_subtitles, None

    if not found_subtitles:
        logger.log(u'No subtitles matched for {} {}'.format
                   (subtitles_info['show_name'], episode_num(subtitles_info['season'], subtitles_info['episode']) or
                    episode_num(subtitles_info['season'], subtitles_info['episode'], numbering='absolute')))
        return existing_subtitles, None

    for subtitle in found_subtitles:
        subtitle_path = get_subtitle_path(video.name, None if not sickbeard.SUBTITLES_MULTI else subtitle.language)
        if subtitles_path:
            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(u'history.logSubtitle {}, {}'.format
                       (subtitle.provider_name, subtitle.language.opensubtitles), logger.DEBUG)

            history.logSubtitle(subtitles_info['show_indexerid'], subtitles_info['season'],
                                subtitles_info['episode'], subtitles_info['status'], subtitle)

        if sickbeard.SUBTITLES_EXTRA_SCRIPTS and isMediaFile(video_path) and not sickbeard.EMBEDDED_SUBTITLES_ALL:
            run_subs_scripts(subtitles_info, subtitle.language, subtitle_path, video.name)

    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
Example #20
0
def search_subtitle(wanted_item_index, lang):
    log.info('Searching for an individual subtitle')
    subs = []

    # Get wanted queue lock
    if not get_wanted_queue_lock():
        return subs, 'Skipping! Cannot get a wanted queue lock because another thread is using the queues!'

    # Setup provider pool
    provider_pool = _get_provider_pool()
    if provider_pool:
        log.info('Searching subtitles with providers: %s', ', '.join(provider_pool.providers))

        # Get wanted_item
        wanted_item = autosubliminal.WANTEDQUEUE[int(wanted_item_index)]
        log.info('Searching subtitles for video: %s', wanted_item.videopath)

        # Scan wanted_item for video
        video = _scan_wanted_item_for_video(wanted_item, is_manual=True)
        if video:
            # Search the subtitles with the default minimal score (to get all the possibilities to select from)
            default_min_score = _get_min_match_score(video, is_manual=True)
            subtitles, language, single = _search_subtitles(video, lang, False, provider_pool)

            # Check if subtitles are found for the video
            if subtitles:
                # Add found subtitles to wanted_item
                wanted_item.found_subtitles = {'subtitles': subtitles, 'language': language, 'single': single}

                # Order subtitles by score and create new dict
                # Use subliminal default compute_score
                for index, subtitle, score in sorted(
                        [(index, s, subliminal.compute_score(s, video, autosubliminal.PREFERHEARINGIMPAIRED))
                         for index, s in enumerate(subtitles)], key=operator.itemgetter(2), reverse=True):

                    # Filter out subtitles that do not match the default score
                    if score < default_min_score:
                        log.debug('Skipping subtitle %s with score below %d', subtitle, default_min_score)
                        break

                    # Only add subtitle when content is found
                    if subtitle.content:
                        # Create new sub dict for showing result
                        sub = {'subtitle_index': index, 'score': score, 'provider_name': subtitle.provider_name,
                               'content': subtitle.content, 'language': language, 'single': single,
                               'page_link': subtitle.page_link, 'releases': _get_releases(subtitle),
                               'wanted_item_index': wanted_item_index,
                               'playvideo_url': _construct_playvideo_url(wanted_item)}
                        # Get content preview (the first 28 lines and last 30 lines of the subtitle)
                        # Use the subtitle text (decoded content) instead of content to generate the preview
                        content_split = subtitle.text.splitlines(False)
                        if len(content_split) < 58:
                            content_preview = 'This seems to be an invalid subtitle.'
                            content_preview += '<br> It has less than 58 lines to preview.'
                        else:
                            try:
                                # First 28 lines
                                content_preview = '<br>'.join(x.replace('"', '\'') for x in content_split[:28])
                                # Separator
                                content_preview += '<br>'
                                content_preview += '<br>'
                                content_preview += '...'
                                content_preview += '<br>'
                                content_preview += '<br>'
                                # Last 30 lines
                                content_preview += '<br>'.join(
                                    x.replace('"', '\'') for x in content_split[len(content_split) - 30:])
                            except Exception:
                                content_preview = 'Problem with parsing the first 28 and/or last 30 lines of the file.'
                        sub['content_preview'] = content_preview
                        subs.append(sub)

    # Release wanted queue lock
    release_wanted_queue_lock()

    if not provider_pool:
        return subs, 'Skipping! No subliminal providers are configured!'

    if not len(subs):
        return subs, 'No subtitles could be found or downloaded!'

    return subs, None
Example #21
0
def manual_download_subtitle(path, language, hi, subtitle, provider, providers_auth, sceneName, media_type):
    if hi == "True":
        hi = True
    else:
        hi = False
    subtitle = pickle.loads(codecs.decode(subtitle.encode(), "base64"))
    if media_type == 'series':
        type_of_score = 360
    elif media_type == 'movie':
        type_of_score = 120
    use_scenename = get_general_settings()[9]
    use_postprocessing = get_general_settings()[10]
    postprocessing_cmd = get_general_settings()[11]

    language = alpha3_from_alpha2(language)
    if language == 'pob':
        lang_obj = Language('por', 'BR')
    else:
        lang_obj = Language(language)

    try:
        if sceneName is None or use_scenename is False:
            used_sceneName = False
            video = scan_video(path)
        else:
            used_sceneName = True
            video = Video.fromname(sceneName)
    except Exception as e:
        logging.exception('Error trying to extract information from this filename: ' + path)
        return None
    else:
        try:
            best_subtitle = subtitle
            download_subtitles([best_subtitle], providers=provider, provider_configs=providers_auth)
        except Exception as e:
            logging.exception('Error downloading subtitles for ' + path)
            return None
        else:
            single = get_general_settings()[7]
            try:
                score = round(float(compute_score(best_subtitle, video, hearing_impaired=hi)) / type_of_score * 100, 2)
                if used_sceneName == True:
                    video = scan_video(path)
                if single is True:
                    result = save_subtitles(video, [best_subtitle], single=True, encoding='utf-8')
                else:
                    result = save_subtitles(video, [best_subtitle], encoding='utf-8')
            except Exception as e:
                logging.exception('Error saving subtitles file to disk.')
                return None
            else:
                if len(result) > 0:
                    downloaded_provider = result[0].provider_name
                    downloaded_language = language_from_alpha3(result[0].language.alpha3)
                    downloaded_language_code2 = alpha2_from_alpha3(result[0].language.alpha3)
                    downloaded_language_code3 = result[0].language.alpha3
                    downloaded_path = get_subtitle_path(path, language=lang_obj)
                    message = downloaded_language + " subtitles downloaded from " + downloaded_provider + " with a score of " + unicode(score) + "% using manual search."

                    if use_postprocessing is True:
                        command = pp_replace(postprocessing_cmd, path, downloaded_path, downloaded_language, downloaded_language_code2, downloaded_language_code3)
                        try:
                            if os.name == 'nt':
                                codepage = subprocess.Popen("chcp", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                                # wait for the process to terminate
                                out_codepage, err_codepage = codepage.communicate()
                                encoding = out_codepage.split(':')[-1].strip()

                            process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                            # wait for the process to terminate
                            out, err = process.communicate()

                            if os.name == 'nt':
                                out = out.decode(encoding)

                        except:
                            if out == "":
                                logging.error('Post-processing result for file ' + path + ' : Nothing returned from command execution')
                            else:
                                logging.error('Post-processing result for file ' + path + ' : ' + out)
                        else:
                            if out == "":
                                logging.info('Post-processing result for file ' + path + ' : Nothing returned from command execution')
                            else:
                                logging.info('Post-processing result for file ' + path + ' : ' + out)

                    return message
                else:
                    return None
Example #22
0
def download(obj, provider, refiner, language, age, directory, encoding,
             single, force, hearing_impaired, min_score, max_workers, archives,
             verbose, path):
    """Download best subtitles.

    PATH can be an directory containing videos, a video file path or a video file name. It can be used multiple times.

    If an existing subtitle is detected (external or embedded) in the correct language, the download is skipped for
    the associated video.

    """
    # process parameters
    language = set(language)

    # scan videos
    videos = []
    ignored_videos = []
    errored_paths = []
    with click.progressbar(path,
                           label='Collecting videos',
                           item_show_func=lambda p: p or '') as bar:
        for p in bar:
            logger.debug('Collecting path %s', p)

            # non-existing
            if not os.path.exists(p):
                try:
                    video = Video.fromname(p)
                except:
                    logger.exception(
                        'Unexpected error while collecting non-existing path %s',
                        p)
                    errored_paths.append(p)
                    continue
                if not force:
                    video.subtitle_languages |= set(
                        search_external_subtitles(
                            video.name, directory=directory).values())
                refine(video,
                       episode_refiners=refiner,
                       movie_refiners=refiner,
                       embedded_subtitles=not force)
                videos.append(video)
                continue

            # directories
            if os.path.isdir(p):
                try:
                    scanned_videos = scan_videos(p, age=age, archives=archives)
                except:
                    logger.exception(
                        'Unexpected error while collecting directory path %s',
                        p)
                    errored_paths.append(p)
                    continue
                for video in scanned_videos:
                    if check_video(video,
                                   languages=language,
                                   age=age,
                                   undefined=single):
                        if not force:
                            video.subtitle_languages |= set(
                                search_external_subtitles(
                                    video.name, directory=directory).values())
                        refine(video,
                               episode_refiners=refiner,
                               movie_refiners=refiner,
                               embedded_subtitles=not force)
                        videos.append(video)
                    else:
                        ignored_videos.append(video)
                continue

            # other inputs
            try:
                video = scan_video(p)
            except:
                logger.exception('Unexpected error while collecting path %s',
                                 p)
                errored_paths.append(p)
                continue
            if check_video(video,
                           languages=language,
                           age=age,
                           undefined=single):
                if not force:
                    video.subtitle_languages |= set(
                        search_external_subtitles(
                            video.name, directory=directory).values())
                refine(video,
                       episode_refiners=refiner,
                       movie_refiners=refiner,
                       embedded_subtitles=not force)
                videos.append(video)
            else:
                ignored_videos.append(video)

    # output errored paths
    if verbose > 0:
        for p in errored_paths:
            click.secho('%s errored' % p, fg='red')

    # output ignored videos
    if verbose > 1:
        for video in ignored_videos:
            click.secho(
                '%s ignored - subtitles: %s / age: %d day%s' %
                (os.path.split(video.name)[1],
                 ', '.join(str(s) for s in video.subtitle_languages)
                 or 'none', video.age.days, 's' if video.age.days > 1 else ''),
                fg='yellow')

    # report collected videos
    click.echo('%s video%s collected / %s video%s ignored / %s error%s' % (
        click.style(
            str(len(videos)), bold=True, fg='green' if videos else None),
        's' if len(videos) > 1 else '',
        click.style(str(len(ignored_videos)),
                    bold=True,
                    fg='yellow' if ignored_videos else None),
        's' if len(ignored_videos) > 1 else '',
        click.style(str(len(errored_paths)),
                    bold=True,
                    fg='red' if errored_paths else None),
        's' if len(errored_paths) > 1 else '',
    ))

    # exit if no video collected
    if not videos:
        return

    # download best subtitles
    downloaded_subtitles = defaultdict(list)
    with AsyncProviderPool(max_workers=max_workers,
                           providers=provider,
                           provider_configs=obj['provider_configs']) as p:
        with click.progressbar(
                videos,
                label='Downloading subtitles',
                item_show_func=lambda v: os.path.split(v.name)[1]
                if v is not None else '') as bar:
            for v in bar:
                scores = get_scores(v)
                subtitles = p.download_best_subtitles(
                    p.list_subtitles(v, language - v.subtitle_languages),
                    v,
                    language,
                    min_score=scores['hash'] * min_score / 100,
                    hearing_impaired=hearing_impaired,
                    only_one=single)
                downloaded_subtitles[v] = subtitles

        if p.discarded_providers:
            click.secho(
                'Some providers have been discarded due to unexpected errors: %s'
                % ', '.join(p.discarded_providers),
                fg='yellow')

    # save subtitles
    total_subtitles = 0
    for v, subtitles in downloaded_subtitles.items():
        saved_subtitles = save_subtitles(v,
                                         subtitles,
                                         single=single,
                                         directory=directory,
                                         encoding=encoding)
        total_subtitles += len(saved_subtitles)

        if verbose > 0:
            click.echo(
                '%s subtitle%s downloaded for %s' %
                (click.style(str(len(saved_subtitles)), bold=True), 's' if
                 len(saved_subtitles) > 1 else '', os.path.split(v.name)[1]))

        if verbose > 1:
            for s in saved_subtitles:
                matches = s.get_matches(v)
                score = compute_score(s, v)

                # score color
                score_color = None
                scores = get_scores(v)
                if isinstance(v, Movie):
                    if score < scores['title']:
                        score_color = 'red'
                    elif score < scores['title'] + scores['year'] + scores[
                            'release_group']:
                        score_color = 'yellow'
                    else:
                        score_color = 'green'
                elif isinstance(v, Episode):
                    if score < scores['series'] + scores['season'] + scores[
                            'episode']:
                        score_color = 'red'
                    elif score < scores['series'] + scores['season'] + scores[
                            'episode'] + scores['release_group']:
                        score_color = 'yellow'
                    else:
                        score_color = 'green'

                # scale score from 0 to 100 taking out preferences
                scaled_score = score
                if s.hearing_impaired == hearing_impaired:
                    scaled_score -= scores['hearing_impaired']
                scaled_score *= 100 / scores['hash']

                # echo some nice colored output
                click.echo(
                    '  - [{score}] {language} subtitle from {provider_name} (match on {matches})'
                    .format(score=click.style('{:5.1f}'.format(scaled_score),
                                              fg=score_color,
                                              bold=score >= scores['hash']),
                            language=s.language.name
                            if s.language.country is None else '%s (%s)' %
                            (s.language.name, s.language.country.name),
                            provider_name=s.provider_name,
                            matches=', '.join(
                                sorted(matches, key=scores.get,
                                       reverse=True))))

    if verbose == 0:
        click.echo('Downloaded %s subtitle%s' %
                   (click.style(str(total_subtitles), bold=True),
                    's' if total_subtitles > 1 else ''))
Example #23
0
def search_subtitle(wanted_item_index, lang):
    log.info("Searching for an individual subtitle")
    subs = []

    # Get wanted queue lock
    if not utils.get_wanted_queue_lock():
        return subs, "Skipping! Cannot get a wanted queue lock because another threat is using the queues!"

    # Get wanted_item
    wanted_item = autosubliminal.WANTEDQUEUE[int(wanted_item_index)]

    # Scan wanted_item for video
    video = _scan_wanted_item_for_video(wanted_item)
    if video:
        # Search the subtitles with the default minimal score (to get all the possibilities to select from)
        subtitles, language, single = _search_subtitles(video, lang, False)
        # Check if subtitles are found for the video
        if subtitles[video]:
            # Add found subtitles to wanted_item
            wanted_item['found_subtitles'] = {'subtitles': subtitles, 'language': language, 'single': single}
            # Order subtitles by score and create new dict
            # Use subliminal scoring (scores=None)
            for index, subtitle, score in sorted([(index, s, subliminal.compute_score(
                    s.get_matches(video, hearing_impaired=utils.include_hearing_impaired()), video, scores=None))
                                                  for index, s in enumerate(subtitles[video])],
                                                 key=operator.itemgetter(2), reverse=True):
                # Only add subtitle when content is found
                if subtitle.content:
                    # Create new sub dict for showing result
                    sub = {'subtitle_index': index, 'score': score, 'provider_name': subtitle.provider_name,
                           'content': subtitle.content, 'language': language, 'single': single,
                           'page_link': subtitle.page_link, 'releases': _get_releases(subtitle),
                           'wanted_item_index': wanted_item_index,
                           'playvideo_url': _construct_playvideo_url(wanted_item)}
                    # Get content preview (the first 28 lines and last 30 lines of the subtitle)
                    content_split = subtitle.content.splitlines(False)
                    if len(content_split) < 58:
                        content_preview = "This seems to be an invalid subtitle."
                        content_preview += "<br> It has less than 58 lines to preview."
                    else:
                        try:
                            # First 28 lines
                            content_preview = "<br>".join(
                                x.replace('"', "'") for x in content_split[:28])
                            # Separator
                            content_preview += "<br>"
                            content_preview += "<br>"
                            content_preview += "..."
                            content_preview += "<br>"
                            content_preview += "<br>"
                            # Last 30 lines
                            content_preview += "<br>".join(
                                x.replace('"', "'") for x in content_split[len(content_split) - 30:])
                        except:
                            content_preview = "Problem with parsing the first 28 and/or last 30 lines of the file."
                    sub['content_preview'] = content_preview
                    subs.append(sub)

    # Release wanted queue lock
    utils.release_wanted_queue_lock()

    if not len(subs):
        return subs, "No subtitles could be found or downloaded!"

    return subs, None
Example #24
0
def download(
    obj,
    provider,
    language,
    age,
    directory,
    encoding,
    single,
    force,
    hearing_impaired,
    min_score,
    max_workers,
    verbose,
    path,
):
    """Download best subtitles.

    PATH can be an directory containing videos, a video file path or a video file name. It can be used multiple times.

    If an existing subtitle is detected (external or embedded) in the correct language, the download is skipped for
    the associated video.

    """
    # process parameters
    language = set(language)

    # scan videos
    videos = []
    ignored_videos = []
    errored_paths = []
    with click.progressbar(path, label="Collecting videos", item_show_func=lambda p: p or "") as bar:
        for p in bar:
            logger.debug("Collecting path %s", p)

            # non-existing
            if not os.path.exists(p):
                try:
                    video = Video.fromname(p)
                except:
                    logger.exception("Unexpected error while collecting non-existing path %s", p)
                    errored_paths.append(p)
                    continue
                videos.append(video)
                continue

            # directories
            if os.path.isdir(p):
                try:
                    scanned_videos = scan_videos(
                        p, subtitles=not force, embedded_subtitles=not force, subtitles_dir=directory, age=age
                    )
                except:
                    logger.exception("Unexpected error while collecting directory path %s", p)
                    errored_paths.append(p)
                    continue
                for video in scanned_videos:
                    if check_video(video, languages=language, age=age, undefined=single):
                        videos.append(video)
                    else:
                        ignored_videos.append(video)
                continue

            # other inputs
            try:
                video = scan_video(p, subtitles=not force, embedded_subtitles=not force, subtitles_dir=directory)
            except:
                logger.exception("Unexpected error while collecting path %s", p)
                errored_paths.append(p)
                continue
            if check_video(video, languages=language, age=age, undefined=single):
                videos.append(video)
            else:
                ignored_videos.append(video)

    # output errored paths
    if verbose > 0:
        for p in errored_paths:
            click.secho("%s errored" % p, fg="red")

    # output ignored videos
    if verbose > 1:
        for video in ignored_videos:
            click.secho(
                "%s ignored - subtitles: %s / age: %d day%s"
                % (
                    os.path.split(video.name)[1],
                    ", ".join(str(s) for s in video.subtitle_languages) or "none",
                    video.age.days,
                    "s" if video.age.days > 1 else "",
                ),
                fg="yellow",
            )

    # report collected videos
    click.echo(
        "%s video%s collected / %s video%s ignored / %s error%s"
        % (
            click.style(str(len(videos)), bold=True, fg="green" if videos else None),
            "s" if len(videos) > 1 else "",
            click.style(str(len(ignored_videos)), bold=True, fg="yellow" if ignored_videos else None),
            "s" if len(ignored_videos) > 1 else "",
            click.style(str(len(errored_paths)), bold=True, fg="red" if errored_paths else None),
            "s" if len(errored_paths) > 1 else "",
        )
    )

    # exit if no video collected
    if not videos:
        return

    # download best subtitles
    downloaded_subtitles = defaultdict(list)
    with AsyncProviderPool(max_workers=max_workers, providers=provider, provider_configs=obj["provider_configs"]) as p:
        with click.progressbar(
            videos,
            label="Downloading subtitles",
            item_show_func=lambda v: os.path.split(v.name)[1] if v is not None else "",
        ) as bar:
            for v in bar:
                scores = get_scores(v)
                subtitles = p.download_best_subtitles(
                    p.list_subtitles(v, language - v.subtitle_languages),
                    v,
                    language,
                    min_score=scores["hash"] * min_score / 100,
                    hearing_impaired=hearing_impaired,
                    only_one=single,
                )
                downloaded_subtitles[v] = subtitles

    # TODO: warn about discarded providers
    # save subtitles
    total_subtitles = 0
    for v, subtitles in downloaded_subtitles.items():
        saved_subtitles = save_subtitles(v, subtitles, single=single, directory=directory, encoding=encoding)
        total_subtitles += len(saved_subtitles)

        if verbose > 0:
            click.echo(
                "%s subtitle%s downloaded for %s"
                % (
                    click.style(str(len(saved_subtitles)), bold=True),
                    "s" if len(saved_subtitles) > 1 else "",
                    os.path.split(v.name)[1],
                )
            )

        if verbose > 1:
            for s in saved_subtitles:
                matches = s.get_matches(v)
                score = compute_score(s, v)

                # score color
                score_color = None
                scores = get_scores(v)
                if isinstance(v, Movie):
                    if score < scores["title"]:
                        score_color = "red"
                    elif score < scores["title"] + scores["year"] + scores["release_group"]:
                        score_color = "yellow"
                    else:
                        score_color = "green"
                elif isinstance(v, Episode):
                    if score < scores["series"] + scores["season"] + scores["episode"]:
                        score_color = "red"
                    elif score < scores["series"] + scores["season"] + scores["episode"] + scores["release_group"]:
                        score_color = "yellow"
                    else:
                        score_color = "green"

                # scale score from 0 to 100 taking out preferences
                scaled_score = score
                if s.hearing_impaired == hearing_impaired:
                    scaled_score -= scores["hearing_impaired"]
                scaled_score *= 100 / scores["hash"]

                # echo some nice colored output
                click.echo(
                    "  - [{score}] {language} subtitle from {provider_name} (match on {matches})".format(
                        score=click.style("{:5.1f}".format(scaled_score), fg=score_color, bold=score >= scores["hash"]),
                        language=s.language.name
                        if s.language.country is None
                        else "%s (%s)" % (s.language.name, s.language.country.name),
                        provider_name=s.provider_name,
                        matches=", ".join(sorted(matches, key=scores.get, reverse=True)),
                    )
                )

    if verbose == 0:
        click.echo(
            "Downloaded %s subtitle%s"
            % (click.style(str(total_subtitles), bold=True), "s" if total_subtitles > 1 else "")
        )
Example #25
0
def manual_search(path, language, hi, providers, providers_auth, sceneName, media_type):
    if hi == "True":
        hi = True
    else:
        hi = False
    language_set = set()
    for lang in ast.literal_eval(language):
        lang = alpha3_from_alpha2(lang)
        if lang == 'pob':
            language_set.add(Language('por', 'BR'))
        else:
            language_set.add(Language(lang))

    use_scenename = get_general_settings()[9]
    use_postprocessing = get_general_settings()[10]
    postprocessing_cmd = get_general_settings()[11]

    try:
        if sceneName == "None" or use_scenename is False:
            used_sceneName = False
            video = scan_video(path)
        else:
            used_sceneName = True
            video = Video.fromname(sceneName)
    except:
        logging.error("Error trying to get video information.")
    else:
        if media_type == "movie":
            max_score = 120.0
        elif media_type == "series":
            max_score = 360.0

        try:
            with AsyncProviderPool(max_workers=None, providers=providers, provider_configs=providers_auth) as p:
                subtitles = p.list_subtitles(video, language_set)
        except Exception as e:
            logging.exception("Error trying to get subtitle list from provider")
        else:
            subtitles_list = []
            for s in subtitles:
                {s: compute_score(s, video, hearing_impaired=hi)}
                if media_type == "movie":
                    matched = set(s.get_matches(video))
                    if hi == s.hearing_impaired:
                        matched.add('hearing_impaired')
                    not_matched = set(score.movie_scores.keys()) - matched
                    required = set(['title'])
                    if any(elem in required for elem in not_matched):
                        continue
                    if used_sceneName:
                        not_matched.remove('hash')
                elif media_type == "series":
                    matched = set(s.get_matches(video))
                    if hi == s.hearing_impaired:
                        matched.add('hearing_impaired')
                    not_matched = set(score.episode_scores.keys()) - matched
                    required = set(['series', 'season', 'episode'])
                    if any(elem in required for elem in not_matched):
                        continue
                    if used_sceneName:
                        not_matched.remove('hash')
                subtitles_list.append(dict(score=round((compute_score(s, video, hearing_impaired=hi) / max_score * 100), 2), language=alpha2_from_alpha3(s.language.alpha3), hearing_impaired=str(s.hearing_impaired), provider=s.provider_name, subtitle=codecs.encode(pickle.dumps(s), "base64").decode(), url=s.page_link, matches=list(matched), dont_matches=list(not_matched)))
            subtitles_dict = {}
            subtitles_dict = sorted(subtitles_list, key=lambda x: x['score'], reverse=True)
            return(subtitles_dict)