def on_created(event): if event.is_directory: return path = event.src_path if not mimetypes.guess_type(path)[0].startswith('video'): return try: logging.info(f"Pulling subtitles for: {path}") video = scan_video(path) provider_pool = ProviderPool( providers=ENABLED_PROVIDERS, provider_configs=PROVIDER_CONFIGURATIONS) subtitles = provider_pool.list_subtitles( video=video, languages={Language('eng'), Language('nld')}) best_subtitles = provider_pool.download_best_subtitles( subtitles=subtitles, video=video, languages={Language('eng'), Language('nld')}) save_subtitles(video, best_subtitles) logging.info(f"Subtitles saved for: {path}") except Exception as e: logging.error(f"Error: {repr(e)}")
def get_provider_pool(): """Return the subliminal provider pool to be used. :return: subliminal provider pool to be used :rtype: subliminal.ProviderPool """ logger.debug(u'Creating a new ProviderPool instance') provider_configs = { 'addic7ed': { 'username': app.ADDIC7ED_USER, 'password': app.ADDIC7ED_PASS }, 'itasa': { 'username': app.ITASA_USER, 'password': app.ITASA_PASS }, 'legendastv': { 'username': app.LEGENDASTV_USER, 'password': app.LEGENDASTV_PASS }, 'opensubtitles': { 'username': app.OPENSUBTITLES_USER, 'password': app.OPENSUBTITLES_PASS } } return ProviderPool(providers=enabled_service_list(), provider_configs=provider_configs)
def __init_instance(): with SubtitleProviderPool._lock: 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 }, 'subscenter': { 'username': sickbeard.SUBSCENTER_USER, 'password': sickbeard.SUBSCENTER_PASS } } SubtitleProviderPool._instance = ProviderPool( providers=providers, provider_configs=provider_configs)
def download_callback(self, menuitem, files): # scan videos videos = [] for f in files: # ignore non-writable locations if not f.can_write(): continue # directories if f.is_directory(): try: scanned_videos = scan_videos( f.get_location().get_path(), subtitles=True, embedded_subtitles=self.config.embedded_subtitles) except: continue for video in scanned_videos: if check_video(video, languages=self.config.languages, age=self.config.age, undefined=self.config.single): videos.append(video) continue # other inputs try: video = scan_video( f.get_location().get_path(), subtitles=True, embedded_subtitles=self.config.embedded_subtitles) except: continue if check_video(video, languages=self.config.languages, undefined=self.config.single): videos.append(video) # download best subtitles downloaded_subtitles = defaultdict(list) with ProviderPool( providers=self.config.providers, provider_configs=self.config.provider_configs) as pool: for v in videos: subtitles = pool.download_best_subtitles( pool.list_subtitles( v, self.config.languages - v.subtitle_languages), v, self.config.languages, min_score=v.scores['hash'] * self.config.min_score / 100, hearing_impaired=self.config.hearing_impaired, only_one=self.config.single) downloaded_subtitles[v] = subtitles # save subtitles for v, subtitles in downloaded_subtitles.items(): save_subtitles(v, subtitles, single=self.config.single)
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 on_subtitles_treeview_row_activated(self, treeview, path, view_column): model = treeview.get_model() iter = model.get_iter(path) # return if already downloaded if model.get_value(iter, 6): return # get the subtitle object subtitle = self.subtitles[model.get_value(iter, 3).lower() + '-' + model.get_value(iter, 0)] # download the subtitle with ProviderPool( providers=self.config.providers, provider_configs=self.config.provider_configs) as pool: pool.download_subtitle(subtitle) # save the subtitle save_subtitles(self.video, [subtitle], single=self.config.single) # mark the subtitle as downloaded model.set_value(iter, 6, True)
def subtitles_download_in_pp(): # pylint: disable=too-many-locals, too-many-branches 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}, '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 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 = [x for x in files if isRarFile(x)] if rar_files and sickbeard.UNPACK: video_files = [x for x in files if isMediaFile(x)] 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 video_filename in sorted(files): try: # Remove non release groups from video file. Needed to match subtitles new_video_filename = remove_non_release_groups(video_filename) if new_video_filename != video_filename: os.rename(video_filename, new_video_filename) video_filename = new_video_filename except Exception as error: logger.log(u'Couldn\'t remove non release groups from video file. Error: {}'.format (ex(error)), logger.DEBUG) if isMediaFile(video_filename): try: video = subliminal.scan_video(os.path.join(root, video_filename), subtitles=False, embedded_subtitles=False) 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, video_filename)), logger.DEBUG) continue logger.log(u'Found subtitle(s) canditate(s) for {}'.format(video_filename), logger.INFO) hearing_impaired = sickbeard.SUBTITLES_HEARING_IMPAIRED user_score = 213 if sickbeard.SUBTITLES_PERFECT_MATCH else 204 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 = subliminal.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, video_filename), subtitle.provider_name, subtitle.language.opensubtitles), logger.DEBUG) subliminal.save_subtitles(video, found_subtitles, directory=root, single=not sickbeard.SUBTITLES_MULTI) subtitles_multi = not sickbeard.SUBTITLES_MULTI subtitle_path = subliminal.subtitle.get_subtitle_path(video.name, None if subtitles_multi else subtitle.language) if root is not None: 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, video_filename), ex(error))) if run_post_process: logger.log(u'Starting post-process with default settings now that we found subtitles') processTV.processDir(sickbeard.TV_DOWNLOAD_DIR)
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 # Check if we really need subtitles 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 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 its the same for 1080p) # Perfect match = 215 -1 -1 = 213 # No-perfect match = hash score - hearing impaired score - resolution score - release_group score # No-perfect match = 215 -1 -1 -9 = 204 # 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 204 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}, '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')), logger.DEBUG) return existing_subtitles, None for subtitle in subtitles_list: score = subliminal.score.compute_score(subtitle, video, hearing_impaired=sickbeard.SUBTITLES_HEARING_IMPAIRED) logger.log(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) subliminal.save_subtitles(video, found_subtitles, directory=subtitles_path, single=not sickbeard.SUBTITLES_MULTI) except IOError as error: if 'No space left on device' in ex(error): logger.log(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 for subtitle in found_subtitles: subtitle_path = subliminal.subtitle.get_subtitle_path(video.name, None if not sickbeard.SUBTITLES_MULTI else subtitle.language) if subtitles_path is not None: subtitle_path = os.path.join(subtitles_path, os.path.split(subtitle_path)[1]) sickbeard.helpers.chmodAsParent(subtitle_path) sickbeard.helpers.fixSetGroupID(subtitle_path) if sickbeard.SUBTITLES_HISTORY: logger.log(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_extra_scripts(subtitles_info, subtitle, video, single=not sickbeard.SUBTITLES_MULTI) new_subtitles = sorted({subtitle.language.opensubtitles for subtitle in found_subtitles}) current_subtitles = sorted({subtitle for subtitle in new_subtitles + existing_subtitles}) if existing_subtitles else new_subtitles if not sickbeard.SUBTITLES_MULTI and len(found_subtitles) == 1: new_code = found_subtitles[0].language.opensubtitles if new_code not in existing_subtitles: current_subtitles.remove(new_code) current_subtitles.append('und') return current_subtitles, new_subtitles
def subtitles_download_in_pp(): # pylint: disable=too-many-locals, too-many-branches 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}, '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 run_post_process = False # Check if PP folder is set if sickbeard.TV_DOWNLOAD_DIR and ek(os.path.isdir, sickbeard.TV_DOWNLOAD_DIR): for root, _, files in ek(os.walk, sickbeard.TV_DOWNLOAD_DIR, topdown=False): for video_filename in sorted(files): try: # Remove non release groups from video file. Needed to match subtitles new_video_filename = remove_non_release_groups(video_filename) if new_video_filename != video_filename: os.rename(video_filename, new_video_filename) video_filename = new_video_filename except Exception as error: logger.log(u'Could not remove non release groups from video file. Error: %r' % ex(error), logger.DEBUG) if isMediaFile(video_filename): try: video = subliminal.scan_video(os.path.join(root, video_filename), subtitles=False, embedded_subtitles=False) subtitles_list = pool.list_subtitles(video, languages) if not subtitles_list: logger.log(u'No subtitles found for %s' % ek(os.path.join, root, video_filename), logger.DEBUG) continue logger.log(u'Found subtitle(s) canditate(s) for %s' % video_filename, logger.INFO) hearing_impaired = sickbeard.SUBTITLES_HEARING_IMPAIRED user_score = 132 if sickbeard.SUBTITLES_PERFECT_MATCH else 111 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: matches = subtitle.get_matches(video, hearing_impaired=sickbeard.SUBTITLES_HEARING_IMPAIRED) score = subliminal.subtitle.compute_score(matches, video) logger.log(u"[%s] Subtitle score for %s is: %s (min=%s)" % (subtitle.provider_name, subtitle.id, score, user_score), logger.DEBUG) downloaded_languages = set() for subtitle in found_subtitles: logger.log(u"Found subtitle for %s in %s provider with language %s" % (os.path.join(root, video_filename), subtitle.provider_name, subtitle.language.opensubtitles), logger.DEBUG) subliminal.save_subtitles(video, found_subtitles, directory=root, single=not sickbeard.SUBTITLES_MULTI) subtitles_multi = not sickbeard.SUBTITLES_MULTI subtitle_path = subliminal.subtitle.get_subtitle_path(video.name, None if subtitles_multi else subtitle.language) if root is not None: subtitle_path = ek(os.path.join, root, ek(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: %s. Error: %r" % (os.path.join(root, video_filename), ex(error))) if run_post_process: logger.log(u"Starting post-process with default settings now that we found subtitles") processTV.processDir(sickbeard.TV_DOWNLOAD_DIR)
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 %s S%02dE%02d' % (subtitles_info['show_name'], subtitles_info['season'], subtitles_info['episode']), logger.DEBUG) return existing_subtitles, None # Check if we really need subtitles languages = get_needed_languages(existing_subtitles) if not languages: logger.log(u'No subtitles needed for %s S%02dE%02d' % (subtitles_info['show_name'], subtitles_info['season'], subtitles_info['episode']), logger.DEBUG) return existing_subtitles, None subtitles_path = get_subtitles_path(subtitles_info['location']).encode(sickbeard.SYS_ENCODING) video_path = subtitles_info['location'].encode(sickbeard.SYS_ENCODING) user_score = 132 if sickbeard.SUBTITLES_PERFECT_MATCH else 111 video = get_video(video_path, subtitles_path=subtitles_path) if not video: logger.log(u'Exception caught in subliminal.scan_video for %s S%02dE%02d' % (subtitles_info['show_name'], subtitles_info['season'], subtitles_info['episode']), logger.DEBUG) return existing_subtitles, None providers = enabled_service_list() provider_configs = {'addic7ed': {'username': sickbeard.ADDIC7ED_USER, 'password': sickbeard.ADDIC7ED_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) if not subtitles_list: logger.log(u'No subtitles found for %s S%02dE%02d on any provider' % (subtitles_info['show_name'], subtitles_info['season'], subtitles_info['episode']), logger.DEBUG) return existing_subtitles, None for subtitle in subtitles_list: matches = subtitle.get_matches(video, hearing_impaired=sickbeard.SUBTITLES_HEARING_IMPAIRED) score = subliminal.subtitle.compute_score(matches, video) logger.log(u"[%s] Subtitle score for %s is: %s (min=%s)" % (subtitle.provider_name, subtitle.id, score, user_score), logger.DEBUG) found_subtitles = pool.download_best_subtitles(subtitles_list, video, languages=languages, hearing_impaired=sickbeard.SUBTITLES_HEARING_IMPAIRED, min_score=user_score, only_one=not sickbeard.SUBTITLES_MULTI) subliminal.save_subtitles(video, found_subtitles, directory=subtitles_path, single=not sickbeard.SUBTITLES_MULTI) except IOError as error: if 'No space left on device' in ex(error): logger.log(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: %s" % video_path) logger.log(traceback.format_exc(), logger.ERROR) return existing_subtitles, None for subtitle in found_subtitles: subtitle_path = subliminal.subtitle.get_subtitle_path(video.name, None if not sickbeard.SUBTITLES_MULTI else subtitle.language) if subtitles_path is not None: subtitle_path = ek(os.path.join, subtitles_path, ek(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 %s, %s' % (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_extra_scripts(subtitles_info, subtitle, video, single=not sickbeard.SUBTITLES_MULTI) new_subtitles = sorted({subtitle.language.opensubtitles for subtitle in found_subtitles}) current_subtitles = sorted({subtitle for subtitle in new_subtitles + existing_subtitles}) if existing_subtitles else new_subtitles if not sickbeard.SUBTITLES_MULTI and len(found_subtitles) == 1: new_code = found_subtitles[0].language.opensubtitles if new_code not in existing_subtitles: current_subtitles.remove(new_code) current_subtitles.append('und') return current_subtitles, new_subtitles
def test_provider_pool_iter(mock_providers): pool = ProviderPool() assert len(list(pool)) == 0 pool['tvsubtitles'] assert len(list(pool)) == 1
def test_provider_pool_del_keyerror(): pool = ProviderPool() with pytest.raises(KeyError): del pool['addic7ed']
def download(obj, provider, language, age, directory, encoding, single, force, hearing_impaired, min_score, 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) 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 ProviderPool(providers=provider, provider_configs=obj['provider_configs']) as pool: 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: subtitles = pool.download_best_subtitles( pool.list_subtitles(v, language - v.subtitle_languages), v, language, min_score=v.scores['hash'] * min_score / 100, hearing_impaired=hearing_impaired, only_one=single) downloaded_subtitles[v] = subtitles # 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, hearing_impaired=hearing_impaired) score = compute_score(matches, v) # score color score_color = None if isinstance(v, Movie): if score < v.scores['title']: score_color = 'red' elif score < v.scores['title'] + v.scores[ 'year'] + v.scores['release_group']: score_color = 'yellow' else: score_color = 'green' elif isinstance(v, Episode): if score < v.scores['series'] + v.scores[ 'season'] + v.scores['episode']: score_color = 'red' elif score < (v.scores['series'] + v.scores['season'] + v.scores['episode'] + v.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 -= v.scores['hearing_impaired'] scaled_score *= 100 / v.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 >= v.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=v.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 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: {0}'.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: {0}'.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: {0}".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 '{0}' because we don't want subtitle language '{1}'. We only want '{2}' language(s)".format (filename, subtitle_language, ','.join(sickbeard.SUBTITLES_LANGUAGES)), logger.DEBUG) except Exception as error: logger.log(u"Couldn't delete subtitle: {0}. Error: {1}".format(filename, ex(error)), logger.DEBUG) if isMediaFile(filename) and processTV.subtitles_enabled(filename): try: video = get_video(os.path.join(root, filename), subtitles=False, embedded_subtitles=False) subtitles_list = pool.list_subtitles(video, languages) for provider in providers: if provider in pool.discarded_providers: logger.log(u'Could not search in {0} provider. Discarding for now'.format(provider), logger.DEBUG) if not subtitles_list: logger.log(u'No subtitles found for {0}'.format (os.path.join(root, filename)), logger.DEBUG) continue logger.log(u'Found subtitle(s) canditate(s) for {0}'.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 = subliminal.score.compute_score(subtitle, video, hearing_impaired=sickbeard.SUBTITLES_HEARING_IMPAIRED) logger.log(u'[{0}] Subtitle score for {1} is: {2} (min={3})'.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 {0} in {1} provider with language {2}'.format (os.path.join(root, filename), subtitle.provider_name, subtitle.language.opensubtitles), logger.INFO) subliminal.save_subtitles(video, found_subtitles, directory=root, single=not sickbeard.SUBTITLES_MULTI) subtitles_multi = not sickbeard.SUBTITLES_MULTI subtitle_path = subliminal.subtitle.get_subtitle_path(video.name, None if subtitles_multi else subtitle.language) if root is not None: 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: {0}. Error: {1}'.format (os.path.join(root, filename), ex(error))) if run_post_process: logger.log(u'Starting post-process with default settings now that we found subtitles') processTV.processDir(sickbeard.TV_DOWNLOAD_DIR)
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 # Check if we really need subtitles 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 try: subtitles_path = get_subtitles_path(subtitles_info['location']).encode( sickbeard.SYS_ENCODING) video_path = subtitles_info['location'].encode(sickbeard.SYS_ENCODING) except UnicodeEncodeError as error: logger.log( u'An error occurred while encoding \'{}\' with your current locale. ' 'Rename the file or try a different locale. Error: {}'.format( subtitles_info['location'], ex(error)), logger.WARNING) return existing_subtitles, None user_score = 367 if sickbeard.SUBTITLES_PERFECT_MATCH else 352 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 }, '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) 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')), logger.DEBUG) return existing_subtitles, None for subtitle in subtitles_list: score = subliminal.score.compute_score( subtitle, video, hearing_impaired=sickbeard.SUBTITLES_HEARING_IMPAIRED) logger.log( 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) subliminal.save_subtitles(video, found_subtitles, directory=subtitles_path, single=not sickbeard.SUBTITLES_MULTI) except IOError as error: if 'No space left on device' in ex(error): logger.log(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 for subtitle in found_subtitles: subtitle_path = subliminal.subtitle.get_subtitle_path( video.name, None if not sickbeard.SUBTITLES_MULTI else subtitle.language) if subtitles_path is not None: subtitle_path = ek(os.path.join, subtitles_path, ek(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_extra_scripts(subtitles_info, subtitle, video, single=not sickbeard.SUBTITLES_MULTI) new_subtitles = sorted( {subtitle.language.opensubtitles for subtitle in found_subtitles}) current_subtitles = sorted( {subtitle for subtitle in new_subtitles + existing_subtitles}) if existing_subtitles else new_subtitles if not sickbeard.SUBTITLES_MULTI and len(found_subtitles) == 1: new_code = found_subtitles[0].language.opensubtitles if new_code not in existing_subtitles: current_subtitles.remove(new_code) current_subtitles.append('und') return current_subtitles, new_subtitles