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))
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
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
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()
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))
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()
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 []
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
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 ''))
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 []
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)
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)
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)
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
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
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)
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
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
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
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 ''))
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
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 "") )
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)