def download_subtitle(self, subtitle, rating_key, mode="m"): from interface.menu_helpers import set_refresh_menu_state item_type = subtitle.item_type part_id = subtitle.part_id metadata = get_plex_metadata(rating_key, part_id, item_type) providers = config.get_providers(media_type="series" if item_type == "episode" else "movies") scanned_parts = scan_videos([metadata], ignore_all=True, providers=providers) video, plex_part = scanned_parts.items()[0] pre_download_hook(subtitle) # downloaded_subtitles = {subliminal.Video: [subtitle, subtitle, ...]} download_subtitles([subtitle], providers=providers, provider_configs=config.provider_settings, pool_class=config.provider_pool, throttle_callback=config.provider_throttle) post_download_hook(subtitle) # may be redundant subtitle.pack_data = None download_successful = False if subtitle.content: try: save_subtitles(scanned_parts, {video: [subtitle]}, mode=mode, mods=config.default_mods) if mode == "m": Log.Debug(u"%s: Manually downloaded subtitle for: %s", self.name, rating_key) track_usage("Subtitle", "manual", "download", 1) elif mode == "b": Log.Debug(u"%s: Downloaded better subtitle for: %s", self.name, rating_key) track_usage("Subtitle", "better", "download", 1) download_successful = True refresh_item(rating_key) except: Log.Error(u"%s: Something went wrong when downloading specific subtitle: %s", self.name, traceback.format_exc()) finally: set_refresh_menu_state(None) if download_successful: # store item in history from support.history import get_history item_title = get_title_for_video_metadata(metadata, add_section_title=False) history = get_history() history.add(item_title, video.id, section_title=video.plexapi_metadata["section"], subtitle=subtitle, mode=mode) history.destroy() # clear missing subtitles menu data if not scheduler.is_task_running("MissingSubtitles"): scheduler.clear_task_data("MissingSubtitles") else: set_refresh_menu_state(u"%s: Subtitle download failed (%s)" % (self.name, rating_key)) return download_successful
def list_subtitles(self, rating_key, item_type, part_id, language): metadata = get_plex_metadata(rating_key, part_id, item_type) if item_type == "episode": min_score = 66 else: min_score = 23 scanned_parts = scan_videos( [metadata], kind="series" if item_type == "episode" else "movie", ignore_all=True) if not scanned_parts: Log.Error("Couldn't list available subtitles for %s", rating_key) return video, plex_part = scanned_parts.items()[0] config.init_subliminal_patches() available_subs = list_all_subtitles( scanned_parts, {Language.fromietf(language)}, providers=config.providers, provider_configs=config.provider_settings) use_hearing_impaired = Prefs['subtitles.search.hearingImpaired'] in ( "prefer", "force HI") # sort subtitles by score unsorted_subtitles = [] for s in available_subs[video]: Log.Debug("Starting score computation for %s", s) try: matches = s.get_matches(video, hearing_impaired=use_hearing_impaired) except AttributeError: Log.Error("Match computation failed for %s: %s", s, traceback.format_exc()) continue unsorted_subtitles.append((s, compute_score(matches, video), matches)) scored_subtitles = sorted(unsorted_subtitles, key=operator.itemgetter(1), reverse=True) subtitles = [] for subtitle, score, matches in scored_subtitles: # check score if score < min_score: Log.Info('Score %d is below min_score (%d)', score, min_score) continue subtitle.score = score subtitle.matches = matches subtitle.part_id = part_id subtitle.item_type = item_type subtitles.append(subtitle) return subtitles
def save_stored_sub(stored_subtitle, rating_key, part_id, language, item_type, plex_item=None, storage=None, stored_subs=None): from support.plex_media import get_plex_metadata from support.scanning import scan_videos from support.storage import save_subtitles, get_subtitle_storage plex_item = plex_item or get_item(rating_key) storage = storage or get_subtitle_storage() cleanup = not storage stored_subs = stored_subs or storage.load(plex_item.rating_key) if not all([plex_item, stored_subs]): return try: metadata = get_plex_metadata(rating_key, part_id, item_type, plex_item=plex_item) except PartUnknownException: return scanned_parts = scan_videos([metadata], ignore_all=True, skip_hashing=True) video, plex_part = scanned_parts.items()[0] subtitle = ModifiedSubtitle(language, mods=stored_subtitle.mods) subtitle.content = stored_subtitle.content if stored_subtitle.encoding: # thanks plex setattr(subtitle, "_guessed_encoding", stored_subtitle.encoding) if stored_subtitle.encoding != "utf-8": subtitle.normalize() stored_subtitle.content = subtitle.content stored_subtitle.encoding = "utf-8" storage.save(stored_subs) subtitle.plex_media_fps = plex_part.fps subtitle.page_link = stored_subtitle.id subtitle.language = language subtitle.id = stored_subtitle.id try: save_subtitles(scanned_parts, {video: [subtitle]}, mode="m", bare_save=True) Log.Debug("Modified %s subtitle for: %s:%s with: %s", language.name, rating_key, part_id, ", ".join(stored_subtitle.mods) if stored_subtitle.mods else "none") except: Log.Error("Something went wrong when modifying subtitle: %s", traceback.format_exc()) if subtitle.storage_path: stored_subtitle.last_mod = datetime.datetime.fromtimestamp(os.path.getmtime(subtitle.storage_path)) storage.save(stored_subs) if cleanup: storage.destroy()
def download_subtitle(self, subtitle, rating_key, mode="m"): from interface.menu_helpers import set_refresh_menu_state item_type = subtitle.item_type part_id = subtitle.part_id metadata = get_plex_metadata(rating_key, part_id, item_type) scanned_parts = scan_videos( [metadata], kind="series" if item_type == "episode" else "movie", ignore_all=True) video, plex_part = scanned_parts.items()[0] # downloaded_subtitles = {subliminal.Video: [subtitle, subtitle, ...]} download_subtitles([subtitle], providers=config.providers, provider_configs=config.provider_settings, pool_class=config.provider_pool) download_successful = False if subtitle.content: try: save_subtitles(scanned_parts, {video: [subtitle]}, mode=mode, mods=config.default_mods) Log.Debug(u"%s: Manually downloaded subtitle for: %s", self.name, rating_key) download_successful = True refresh_item(rating_key) track_usage("Subtitle", "manual", "download", 1) except: Log.Error( u"%s: Something went wrong when downloading specific subtitle: %s", self.name, traceback.format_exc()) finally: set_refresh_menu_state(None) if download_successful: # store item in history from support.history import get_history item_title = get_title_for_video_metadata( metadata, add_section_title=False) history = get_history() history.add( item_title, video.id, section_title=video.plexapi_metadata["section"], subtitle=subtitle, mode=mode) else: set_refresh_menu_state(u"%s: Subtitle download failed (%s)", self.name, rating_key) return download_successful
def SubtitleFPSModMenu(**kwargs): rating_key = kwargs["rating_key"] part_id = kwargs["part_id"] item_type = kwargs["item_type"] kwargs.pop("randomize") oc = SubFolderObjectContainer(title2=kwargs["title"], replace_parent=True) oc.add( DirectoryObject(key=Callback(SubtitleModificationsMenu, randomize=timestamp(), **kwargs), title="< Back to subtitle modification menu")) metadata = get_plex_metadata(rating_key, part_id, item_type) scanned_parts = scan_videos( [metadata], kind="series" if item_type == "episode" else "movie", ignore_all=True) video, plex_part = scanned_parts.items()[0] target_fps = plex_part.fps for fps in [ "23.976", "24.000", "25.000", "29.970", "30.000", "50.000", "59.940", "60.000" ]: if float(fps) == float(target_fps): continue if float(fps) > float(target_fps): indicator = "subs constantly getting faster" else: indicator = "subs constantly getting slower" mod_ident = SubtitleModifications.get_mod_signature( "change_FPS", **{ "from": fps, "to": target_fps }) oc.add( DirectoryObject(key=Callback(SubtitleSetMods, mods=mod_ident, mode="add", randomize=timestamp(), **kwargs), title="%s fps -> %s fps (%s)" % (fps, target_fps, indicator))) return oc
def SubtitleFPSModMenu(**kwargs): rating_key = kwargs["rating_key"] part_id = kwargs["part_id"] item_type = kwargs["item_type"] kwargs.pop("randomize") oc = SubFolderObjectContainer(title2=kwargs["title"], replace_parent=True) oc.add(DirectoryObject( key=Callback(SubtitleModificationsMenu, randomize=timestamp(), **kwargs), title=_("< Back to subtitle modification menu") )) metadata = get_plex_metadata(rating_key, part_id, item_type) scanned_parts = scan_videos([metadata], ignore_all=True, skip_hashing=True) video, plex_part = scanned_parts.items()[0] target_fps = plex_part.fps for fps in ["23.980", "23.976", "24.000", "25.000", "29.970", "30.000", "50.000", "59.940", "60.000"]: if float(fps) == float(target_fps): continue if float(fps) > float(target_fps): indicator = _("subs constantly getting faster") else: indicator = _("subs constantly getting slower") mod_ident = SubtitleModifications.get_mod_signature("change_FPS", **{"from": fps, "to": target_fps}) oc.add(DirectoryObject( key=Callback(SubtitleSetMods, mods=mod_ident, mode="add", randomize=timestamp(), **kwargs), title=_("%(from_fps)s fps -> %(to_fps)s fps (%(slower_or_faster_indicator)s)", from_fps=fps, to_fps=target_fps, slower_or_faster_indicator=indicator) )) return oc
def run(self): super(SearchAllRecentlyAddedMissing, self).run() self.running = True self.prepare() from support.history import get_history history = get_history() now = datetime.datetime.now() min_score_series = int( Prefs["subtitles.search.minimumTVScore2"].strip()) min_score_movies = int( Prefs["subtitles.search.minimumMovieScore2"].strip()) series_providers = config.get_providers(media_type="series") movie_providers = config.get_providers(media_type="movies") is_recent_str = Prefs["scheduler.item_is_recent_age"] num, ident = is_recent_str.split() max_search_days = 0 if ident == "days": max_search_days = int(num) elif ident == "weeks": max_search_days = int(num) * 7 subtitle_storage = get_subtitle_storage() recent_files = subtitle_storage.get_recent_files( age_days=max_search_days) self.items_searching = len(recent_files) download_count = 0 videos_with_downloads = 0 config.init_subliminal_patches() Log.Info(u"%s: Searching for subtitles for %s items", self.name, self.items_searching) def skip_item(): self.items_searching = self.items_searching - 1 self.percentage = int( self.items_done * 100 / self.items_searching) if self.items_searching > 0 else 100 # search for subtitles in viable items try: for fn in recent_files: stored_subs = subtitle_storage.load(filename=fn) if not stored_subs: Log.Debug("Skipping item %s because storage is empty", fn) skip_item() continue video_id = stored_subs.video_id # added_date <= max_search_days? if stored_subs.added_at + datetime.timedelta( days=max_search_days) <= now: Log.Debug("Skipping item %s because it's too old", video_id) skip_item() continue if stored_subs.item_type == "episode": min_score = min_score_series providers = series_providers else: min_score = min_score_movies providers = movie_providers parts = [] plex_item = get_item(video_id) if not plex_item: Log.Info(u"%s: Item %s unknown, skipping", self.name, video_id) skip_item() continue if not is_wanted(video_id, item=plex_item): skip_item() continue for media in plex_item.media: parts += media.parts downloads_per_video = 0 hit_providers = False for part in parts: part_id = part.id try: metadata = get_plex_metadata(video_id, part_id, stored_subs.item_type) except PartUnknownException: Log.Info(u"%s: Part %s:%s unknown, skipping", self.name, video_id, part_id) continue if not metadata: Log.Info(u"%s: Part %s:%s unknown, skipping", self.name, video_id, part_id) continue Log.Debug(u"%s: Looking for missing subtitles: %s", self.name, get_item_title(plex_item)) scanned_parts = scan_videos([metadata], providers=providers) downloaded_subtitles = download_best_subtitles( scanned_parts, min_score=min_score, providers=providers) hit_providers = downloaded_subtitles is not None download_successful = False if downloaded_subtitles: downloaded_any = any(downloaded_subtitles.values()) if not downloaded_any: continue try: save_subtitles(scanned_parts, downloaded_subtitles, mode="a", mods=config.default_mods) Log.Debug( u"%s: Downloaded subtitle for item with missing subs: %s", self.name, video_id) download_successful = True refresh_item(video_id) track_usage("Subtitle", "manual", "download", 1) except: Log.Error( u"%s: Something went wrong when downloading specific subtitle: %s", self.name, traceback.format_exc()) finally: scanned_parts = None try: item_title = get_title_for_video_metadata( metadata, add_section_title=False) if download_successful: # store item in history for video, video_subtitles in downloaded_subtitles.items( ): if not video_subtitles: continue for subtitle in video_subtitles: downloads_per_video += 1 history.add( item_title, video.id, section_title=metadata[ "section"], thumb=video.plexapi_metadata[ "super_thumb"], subtitle=subtitle, mode="a") downloaded_subtitles = None except: Log.Error(u"%s: DEBUG HIT: %s", self.name, traceback.format_exc()) Log.Debug(u"%s: Waiting %s seconds before continuing", self.name, self.PROVIDER_SLACK) Thread.Sleep(self.PROVIDER_SLACK) download_count += downloads_per_video if downloads_per_video: videos_with_downloads += 1 self.items_done = self.items_done + 1 self.percentage = int( self.items_done * 100 / self.items_searching) if self.items_searching > 0 else 100 stored_subs = None if downloads_per_video: Log.Debug( u"%s: Subtitles have been downloaded, " u"waiting %s seconds before continuing", self.name, self.DL_PROVIDER_SLACK) Thread.Sleep(self.DL_PROVIDER_SLACK) else: if hit_providers: Log.Debug(u"%s: Waiting %s seconds before continuing", self.name, self.PROVIDER_SLACK) Thread.Sleep(self.PROVIDER_SLACK) finally: subtitle_storage.destroy() history.destroy() if download_count: Log.Debug( u"%s: done. Missing subtitles found for %s/%s items (%s subs downloaded)", self.name, videos_with_downloads, self.items_searching, download_count) else: Log.Debug(u"%s: done. No subtitles found for %s items", self.name, self.items_searching)
def list_subtitles(self, rating_key, item_type, part_id, language, skip_wrong_fps=True, metadata=None, scanned_parts=None, air_date_cutoff=None): if not metadata: metadata = get_plex_metadata(rating_key, part_id, item_type) if not metadata: return providers = config.get_providers( media_type="series" if item_type == "episode" else "movies") if not scanned_parts: scanned_parts = scan_videos([metadata], ignore_all=True, providers=providers) if not scanned_parts: Log.Error(u"%s: Couldn't list available subtitles for %s", self.name, rating_key) return video, plex_part = scanned_parts.items()[0] refine_video(video, refiner_settings=config.refiner_settings) if air_date_cutoff is not None and metadata["item"].year and \ metadata["item"].year + air_date_cutoff < datetime.date.today().year: Log.Debug( "Skipping searching for subtitles: %s, it aired over %s year(s) ago.", rating_key, air_date_cutoff) return config.init_subliminal_patches() provider_settings = config.provider_settings if not skip_wrong_fps: provider_settings["opensubtitles"]["skip_wrong_fps"] = False if item_type == "episode": min_score = 240 if video.is_special: min_score = 180 else: min_score = 60 languages = {Language.fromietf(language)} available_subs = list_all_subtitles( [video], languages, providers=providers, provider_configs=provider_settings, pool_class=config.provider_pool, throttle_callback=config.provider_throttle, language_hook=language_hook) use_hearing_impaired = Prefs['subtitles.search.hearingImpaired'] in ( "prefer", "force HI") # sort subtitles by score unsorted_subtitles = [] for s in available_subs[video]: Log.Debug(u"%s: Starting score computation for %s", self.name, s) try: matches = s.get_matches(video) except AttributeError: Log.Error(u"%s: Match computation failed for %s: %s", self.name, s, traceback.format_exc()) continue # skip wrong season/episodes if item_type == "episode": can_verify_series = True if not s.hash_verifiable and "hash" in matches: can_verify_series = False if can_verify_series and not {"series", "season", "episode" }.issubset(matches): if "series" not in matches: s.wrong_series = True else: s.wrong_season_ep = True unsorted_subtitles.append( (s, compute_score(matches, s, video, hearing_impaired=use_hearing_impaired), matches)) scored_subtitles = sorted(unsorted_subtitles, key=operator.itemgetter(1), reverse=True) subtitles = [] for subtitle, score, matches in scored_subtitles: # check score if score < min_score and not subtitle.wrong_series: Log.Info(u'%s: Score %d is below min_score (%d)', self.name, score, min_score) continue subtitle.score = score subtitle.matches = matches subtitle.part_id = part_id subtitle.item_type = item_type subtitles.append(subtitle) return subtitles
def ListAvailableSubsForItemMenu(rating_key=None, part_id=None, title=None, item_title=None, filename=None, item_type="episode", language=None, language_name=None, force=False, current_id=None, current_data=None, current_provider=None, current_score=None, randomize=None): assert rating_key, part_id running = scheduler.is_task_running("AvailableSubsForItem") search_results = get_item_task_data("AvailableSubsForItem", rating_key, language) if (search_results is None or force) and not running: scheduler.dispatch_task("AvailableSubsForItem", rating_key=rating_key, item_type=item_type, part_id=part_id, language=language) running = True oc = SubFolderObjectContainer(title2=unicode(title), replace_parent=True) oc.add(DirectoryObject( key=Callback(ItemDetailsMenu, rating_key=rating_key, item_title=item_title, title=title, randomize=timestamp()), title=u"< Back to %s" % title, summary=current_data, thumb=default_thumb )) metadata = get_plex_metadata(rating_key, part_id, item_type) plex_part = None if not config.low_impact_mode: scanned_parts = scan_videos([metadata], ignore_all=True) if not scanned_parts: Log.Error("Couldn't list available subtitles for %s", rating_key) return oc video, plex_part = scanned_parts.items()[0] video_display_data = [video.format] if video.format else [] if video.release_group: video_display_data.append(u"by %s" % video.release_group) video_display_data = " ".join(video_display_data) else: video_display_data = metadata["filename"] current_display = (u"Current: %s (%s) " % (current_provider, current_score) if current_provider else "") if not running: oc.add(DirectoryObject( key=Callback(ListAvailableSubsForItemMenu, rating_key=rating_key, item_title=item_title, language=language, filename=filename, part_id=part_id, title=title, current_id=current_id, force=True, current_provider=current_provider, current_score=current_score, current_data=current_data, item_type=item_type, randomize=timestamp()), title=u"Search for %s subs (%s)" % (get_language(language).name, video_display_data), summary=u"%sFilename: %s" % (current_display, filename), thumb=default_thumb )) if search_results == "found_none": oc.add(DirectoryObject( key=Callback(ListAvailableSubsForItemMenu, rating_key=rating_key, item_title=item_title, language=language, filename=filename, current_data=current_data, force=True, part_id=part_id, title=title, current_id=current_id, item_type=item_type, current_provider=current_provider, current_score=current_score, randomize=timestamp()), title=u"No subtitles found", summary=u"%sFilename: %s" % (current_display, filename), thumb=default_thumb )) else: oc.add(DirectoryObject( key=Callback(ListAvailableSubsForItemMenu, rating_key=rating_key, item_title=item_title, language=language, filename=filename, current_data=current_data, part_id=part_id, title=title, current_id=current_id, item_type=item_type, current_provider=current_provider, current_score=current_score, randomize=timestamp()), title=u"Searching for %s subs (%s), refresh here ..." % (display_language(get_language(language)), video_display_data), summary=u"%sFilename: %s" % (current_display, filename), thumb=default_thumb )) if not search_results or search_results == "found_none": return oc current_sub, stored_subs, storage = get_current_sub(rating_key, part_id, language) current_bl, subs = stored_subs.get_blacklist(part_id, language) seen = [] for subtitle in search_results: if subtitle.id in seen: continue bl_addon = "" if (str(subtitle.provider_name), str(subtitle.id)) in current_bl: bl_addon = "Blacklisted " wrong_fps_addon = "" if subtitle.wrong_fps: if plex_part: wrong_fps_addon = " (wrong FPS, sub: %s, media: %s)" % (subtitle.fps, plex_part.fps) else: wrong_fps_addon = " (wrong FPS, sub: %s, media: unknown, low impact mode)" % subtitle.fps oc.add(DirectoryObject( key=Callback(TriggerDownloadSubtitle, rating_key=rating_key, randomize=timestamp(), item_title=item_title, subtitle_id=str(subtitle.id), language=language), title=u"%s%s: %s, score: %s%s" % (bl_addon, "Available" if current_id != subtitle.id else "Current", subtitle.provider_name, subtitle.score, wrong_fps_addon), summary=u"Release: %s, Matches: %s" % (subtitle.release_info, ", ".join(subtitle.matches)), thumb=default_thumb )) seen.append(subtitle.id) return oc
def list_subtitles(self, rating_key, item_type, part_id, language, skip_wrong_fps=True, metadata=None, scanned_parts=None): if not metadata: metadata = get_plex_metadata(rating_key, part_id, item_type) if not metadata: return if not scanned_parts: scanned_parts = scan_videos( [metadata], kind="series" if item_type == "episode" else "movie", ignore_all=True) if not scanned_parts: Log.Error(u"%s: Couldn't list available subtitles for %s", self.name, rating_key) return video, plex_part = scanned_parts.items()[0] config.init_subliminal_patches() provider_settings = config.provider_settings.copy() if not skip_wrong_fps: provider_settings = config.provider_settings.copy() provider_settings["opensubtitles"]["skip_wrong_fps"] = False if item_type == "episode": min_score = 240 if video.is_special: min_score = 180 else: min_score = 60 languages = {Language.fromietf(language)} available_subs = list_all_subtitles(scanned_parts, languages, providers=config.providers, provider_configs=provider_settings, pool_class=config.provider_pool) use_hearing_impaired = Prefs['subtitles.search.hearingImpaired'] in ( "prefer", "force HI") # sort subtitles by score unsorted_subtitles = [] for s in available_subs[video]: Log.Debug(u"%s: Starting score computation for %s", self.name, s) try: matches = s.get_matches(video) except AttributeError: Log.Error(u"%s: Match computation failed for %s: %s", self.name, s, traceback.format_exc()) continue unsorted_subtitles.append( (s, compute_score(matches, s, video, hearing_impaired=use_hearing_impaired), matches)) scored_subtitles = sorted(unsorted_subtitles, key=operator.itemgetter(1), reverse=True) subtitles = [] for subtitle, score, matches in scored_subtitles: # check score if score < min_score: Log.Info(u'%s: Score %d is below min_score (%d)', self.name, score, min_score) continue subtitle.score = score subtitle.matches = matches subtitle.part_id = part_id subtitle.item_type = item_type subtitles.append(subtitle) return subtitles
def ListAvailableSubsForItemMenu(rating_key=None, part_id=None, title=None, item_title=None, filename=None, item_type="episode", language=None, force=False, current_id=None, current_data=None, current_provider=None, current_score=None, randomize=None): assert rating_key, part_id running = scheduler.is_task_running("AvailableSubsForItem") search_results = get_item_task_data("AvailableSubsForItem", rating_key, language) if (search_results is None or force) and not running: scheduler.dispatch_task("AvailableSubsForItem", rating_key=rating_key, item_type=item_type, part_id=part_id, language=language) running = True oc = SubFolderObjectContainer(title2=unicode(title), replace_parent=True) oc.add( DirectoryObject(key=Callback(ItemDetailsMenu, rating_key=rating_key, item_title=item_title, title=title, randomize=timestamp()), title=u"Back to: %s" % title, summary=current_data, thumb=default_thumb)) metadata = get_plex_metadata(rating_key, part_id, item_type) scanned_parts = scan_videos( [metadata], kind="series" if item_type == "episode" else "movie", ignore_all=True) if not scanned_parts: Log.Error("Couldn't list available subtitles for %s", rating_key) return oc video, plex_part = scanned_parts.items()[0] video_display_data = [video.format] if video.format else [] if video.release_group: video_display_data.append(u"by %s" % video.release_group) video_display_data = " ".join(video_display_data) current_display = (u"Current: %s (%s) " % (current_provider, current_score) if current_provider else "") if not running: oc.add( DirectoryObject(key=Callback(ListAvailableSubsForItemMenu, rating_key=rating_key, item_title=item_title, language=language, filename=filename, part_id=part_id, title=title, current_id=current_id, force=True, current_provider=current_provider, current_score=current_score, current_data=current_data, item_type=item_type, randomize=timestamp()), title=u"Search for %s subs (%s)" % (get_language(language).name, video_display_data), summary=u"%sFilename: %s" % (current_display, filename), thumb=default_thumb)) else: oc.add( DirectoryObject( key=Callback(ListAvailableSubsForItemMenu, rating_key=rating_key, item_title=item_title, language=language, filename=filename, current_data=current_data, part_id=part_id, title=title, current_id=current_id, item_type=item_type, current_provider=current_provider, current_score=current_score, randomize=timestamp()), title=u"Searching for %s subs (%s), refresh here ..." % (get_language(language).name, video_display_data), summary=u"%sFilename: %s" % (current_display, filename), thumb=default_thumb)) if not search_results: return oc for subtitle in search_results: oc.add( DirectoryObject( key=Callback(TriggerDownloadSubtitle, rating_key=rating_key, randomize=timestamp(), item_title=item_title, subtitle_id=str(subtitle.id), language=language), title=u"%s: %s, score: %s" % ("Available" if current_id != subtitle.id else "Current", subtitle.provider_name, subtitle.score), summary=u"Release: %s, Matches: %s" % (subtitle.release_info, ", ".join(subtitle.matches)), thumb=default_thumb)) return oc
def set_mods_for_part(rating_key, part_id, language, item_type, mods, mode="add"): from support.plex_media import get_plex_metadata from support.scanning import scan_videos from support.storage import save_subtitles plex_item = get_item(rating_key) if not plex_item: return current_sub, stored_subs, storage = get_current_sub(rating_key, part_id, language, plex_item=plex_item) if mode == "add": for mod in mods: identifier, args = SubtitleModifications.parse_identifier(mod) mod_class = SubtitleModifications.get_mod_class(identifier) if identifier not in mod_registry.mods_available: raise NotImplementedError("Mod unknown or not registered") # clean exclusive mods if mod_class.exclusive and current_sub.mods: for current_mod in current_sub.mods[:]: if current_mod.startswith(identifier): current_sub.mods.remove(current_mod) Log.Info("Removing superseded mod %s" % current_mod) current_sub.add_mod(mod) elif mode == "clear": current_sub.add_mod(None) elif mode == "remove": for mod in mods: current_sub.mods.remove(mod) elif mode == "remove_last": if current_sub.mods: current_sub.mods.pop() else: raise NotImplementedError("Wrong mode given") storage.save(stored_subs) try: metadata = get_plex_metadata(rating_key, part_id, item_type, plex_item=plex_item) except PartUnknownException: return scanned_parts = scan_videos( [metadata], kind="series" if item_type == "episode" else "movie", ignore_all=True, no_refining=True) video, plex_part = scanned_parts.items()[0] subtitle = ModifiedSubtitle(language, mods=current_sub.mods) subtitle.content = current_sub.content if current_sub.encoding: # thanks plex setattr(subtitle, "_guessed_encoding", current_sub.encoding) if current_sub.encoding != "utf-8": subtitle.normalize() current_sub.content = subtitle.content current_sub.encoding = "utf-8" storage.save(stored_subs) storage.destroy() subtitle.plex_media_fps = plex_part.fps subtitle.page_link = "modify subtitles with: %s" % (", ".join( current_sub.mods) if current_sub.mods else "none") subtitle.language = language subtitle.id = current_sub.id try: save_subtitles(scanned_parts, {video: [subtitle]}, mode="m", bare_save=True) Log.Debug("Modified %s subtitle for: %s:%s with: %s", language.name, rating_key, part_id, ", ".join(current_sub.mods) if current_sub.mods else "none") except: Log.Error("Something went wrong when modifying subtitle: %s", traceback.format_exc())
def extract_embedded_sub(**kwargs): rating_key = kwargs["rating_key"] part_id = kwargs.pop("part_id") stream_index = kwargs.pop("stream_index") with_mods = kwargs.pop("with_mods", False) language = Language.fromietf(kwargs.pop("language")) refresh = kwargs.pop("refresh", True) set_current = kwargs.pop("set_current", True) plex_item = kwargs.pop("plex_item", get_item(rating_key)) item_type = get_item_kind_from_item(plex_item) part = kwargs.pop("part", get_part(plex_item, part_id)) scanned_videos = kwargs.pop("scanned_videos", None) extract_mode = kwargs.pop("extract_mode", "a") any_successful = False if part: if not scanned_videos: metadata = get_plex_metadata(rating_key, part_id, item_type, plex_item=plex_item) scanned_videos = scan_videos([metadata], ignore_all=True, skip_hashing=True) for stream in part.streams: # subtitle stream if str(stream.index) == stream_index: is_forced = is_stream_forced(stream) bn = os.path.basename(part.file) set_refresh_menu_state(_(u"Extracting subtitle %(stream_index)s of %(filename)s", stream_index=stream_index, filename=bn)) Log.Info(u"Extracting stream %s (%s) of %s", stream_index, str(language), bn) out_codec = stream.codec if stream.codec != "mov_text" else "srt" args = [ config.plex_transcoder, "-i", part.file, "-map", "0:%s" % stream_index, "-f", out_codec, "-" ] cmdline = quote_args(args) Log.Debug(u"Calling: %s", cmdline) if mswindows: Log.Debug("MSWindows: Fixing encoding") cmdline = cmdline.encode("mbcs") output = None try: output = subprocess.check_output(cmdline, stderr=subprocess.PIPE, shell=True) except: Log.Error("Extraction failed: %s", traceback.format_exc()) if output: subtitle = ModifiedSubtitle(language, mods=config.default_mods if with_mods else None) subtitle.content = output subtitle.provider_name = "embedded" subtitle.id = "stream_%s" % stream_index subtitle.score = 0 subtitle.set_encoding("utf-8") # fixme: speedup video; only video.name is needed video = scanned_videos.keys()[0] save_successful = save_subtitles(scanned_videos, {video: [subtitle]}, mode="m", set_current=set_current) set_refresh_menu_state(None) if save_successful and refresh: refresh_item(rating_key) # add item to history item_title = get_title_for_video_metadata(video.plexapi_metadata, add_section_title=False, add_episode_title=True) history = get_history() history.add(item_title, video.id, section_title=video.plexapi_metadata["section"], thumb=video.plexapi_metadata["super_thumb"], subtitle=subtitle, mode=extract_mode) history.destroy() any_successful = True return any_successful
def ListAvailableSubsForItemMenu(rating_key=None, part_id=None, title=None, item_title=None, filename=None, item_type="episode", language=None, language_name=None, force=False, current_id=None, current_data=None, current_provider=None, current_score=None, randomize=None): assert rating_key, part_id running = scheduler.is_task_running("AvailableSubsForItem") search_results = get_item_task_data("AvailableSubsForItem", rating_key, language) current_data = unicode(current_data) if current_data else None if (search_results is None or force) and not running: scheduler.dispatch_task("AvailableSubsForItem", rating_key=rating_key, item_type=item_type, part_id=part_id, language=language) running = True oc = SubFolderObjectContainer(title2=unicode(title), replace_parent=True) oc.add(DirectoryObject( key=Callback(ItemDetailsMenu, rating_key=rating_key, item_title=item_title, title=title, randomize=timestamp()), title=_(u"< Back to %s", title), summary=current_data, thumb=default_thumb )) metadata = get_plex_metadata(rating_key, part_id, item_type) plex_part = None if not config.low_impact_mode: scanned_parts = scan_videos([metadata], ignore_all=True) if not scanned_parts: Log.Error("Couldn't list available subtitles for %s", rating_key) return oc video, plex_part = scanned_parts.items()[0] video_display_data = [video.format] if video.format else [] if video.release_group: video_display_data.append(unicode(_(u"by %(release_group)s", release_group=video.release_group))) video_display_data = " ".join(video_display_data) else: video_display_data = metadata["filename"] current_display = (_(u"Current: %(provider_name)s (%(score)s) ", provider_name=_(current_provider), score=current_score if current_provider else "")) if not running: oc.add(DirectoryObject( key=Callback(ListAvailableSubsForItemMenu, rating_key=rating_key, item_title=item_title, language=language, filename=filename, part_id=part_id, title=title, current_id=current_id, force=True, current_provider=current_provider, current_score=current_score, current_data=current_data, item_type=item_type, randomize=timestamp()), title=_(u"Search for %(language)s subs (%(video_data)s)", language=get_language(language).name, video_data=video_display_data), summary=_(u"%(current_info)sFilename: %(filename)s", current_info=current_display, filename=filename), thumb=default_thumb )) if search_results == "found_none": oc.add(DirectoryObject( key=Callback(ListAvailableSubsForItemMenu, rating_key=rating_key, item_title=item_title, language=language, filename=filename, current_data=current_data, force=True, part_id=part_id, title=title, current_id=current_id, item_type=item_type, current_provider=current_provider, current_score=current_score, randomize=timestamp()), title=_(u"No subtitles found"), summary=_(u"%(current_info)sFilename: %(filename)s", current_info=current_display, filename=filename), thumb=default_thumb )) else: oc.add(DirectoryObject( key=Callback(ListAvailableSubsForItemMenu, rating_key=rating_key, item_title=item_title, language=language, filename=filename, current_data=current_data, part_id=part_id, title=title, current_id=current_id, item_type=item_type, current_provider=current_provider, current_score=current_score, randomize=timestamp()), title=_(u"Searching for %(language)s subs (%(video_data)s), refresh here ...", language=display_language(get_language(language)), video_data=video_display_data), summary=_(u"%(current_info)sFilename: %(filename)s", current_info=current_display, filename=filename), thumb=default_thumb )) if not search_results or search_results == "found_none": return oc current_sub, stored_subs, storage = get_current_sub(rating_key, part_id, language) current_bl, subs = stored_subs.get_blacklist(part_id, language) seen = [] for subtitle in search_results: if subtitle.id in seen: continue bl_addon = "" if (str(subtitle.provider_name), str(subtitle.id)) in current_bl: bl_addon = "Blacklisted " wrong_fps_addon = "" wrong_series_addon = "" wrong_season_ep_addon = "" if subtitle.wrong_fps: if plex_part: wrong_fps_addon = _(" (wrong FPS, sub: %(subtitle_fps)s, media: %(media_fps)s)", subtitle_fps=subtitle.fps, media_fps=plex_part.fps) else: wrong_fps_addon = _(" (wrong FPS, sub: %(subtitle_fps)s, media: unknown, low impact mode)", subtitle_fps=subtitle.fps) if subtitle.wrong_series: wrong_series_addon = _(" (possibly wrong series)") if subtitle.wrong_season_ep: wrong_season_ep_addon = _(" (possibly wrong season/episode)") oc.add(DirectoryObject( key=Callback(TriggerDownloadSubtitle, rating_key=rating_key, randomize=timestamp(), item_title=item_title, subtitle_id=str(subtitle.id), language=language), title=_(u"%(blacklisted_state)s%(current_state)s: %(provider_name)s, score: %(score)s%(wrong_fps_state)s" u"%(wrong_series_state)s%(wrong_season_ep_state)s", blacklisted_state=bl_addon, current_state=_("Available") if current_id != subtitle.id else _("Current"), provider_name=_(subtitle.provider_name), score=subtitle.score, wrong_fps_state=wrong_fps_addon, wrong_series_state=wrong_series_addon, wrong_season_ep_state=wrong_season_ep_addon), summary=_(u"Release: %(release_info)s, Matches: %(matches)s", release_info=subtitle.release_info, matches=", ".join(subtitle.matches)), thumb=default_thumb )) seen.append(subtitle.id) return oc
def save_stored_sub(stored_subtitle, rating_key, part_id, language, item_type, plex_item=None, storage=None, stored_subs=None): """ in order for this to work, if the calling supplies stored_subs and storage, it has to trigger its saving and destruction explicitly :param stored_subtitle: :param rating_key: :param part_id: :param language: :param item_type: :param plex_item: :param storage: :param stored_subs: :return: """ from support.plex_media import get_plex_metadata from support.scanning import scan_videos from support.storage import save_subtitles, get_subtitle_storage plex_item = plex_item or get_item(rating_key) stored_subs_was_provided = True if not stored_subs or not storage: storage = get_subtitle_storage() stored_subs = storage.load(plex_item.rating_key) stored_subs_was_provided = False if not all([plex_item, stored_subs]): return try: metadata = get_plex_metadata(rating_key, part_id, item_type, plex_item=plex_item) except PartUnknownException: return scanned_parts = scan_videos([metadata], ignore_all=True, skip_hashing=True) video, plex_part = scanned_parts.items()[0] subtitle = ModifiedSubtitle(language, mods=stored_subtitle.mods) subtitle.content = stored_subtitle.content if stored_subtitle.encoding: # thanks plex setattr(subtitle, "_guessed_encoding", stored_subtitle.encoding) if stored_subtitle.encoding != "utf-8": subtitle.normalize() stored_subtitle.content = subtitle.content stored_subtitle.encoding = "utf-8" storage.save(stored_subs) subtitle.plex_media_fps = plex_part.fps subtitle.page_link = stored_subtitle.id subtitle.language = language subtitle.id = stored_subtitle.id try: save_subtitles(scanned_parts, {video: [subtitle]}, mode="m", bare_save=True) stored_subtitle.mods = subtitle.mods Log.Debug("Modified %s subtitle for: %s:%s with: %s", language.name, rating_key, part_id, ", ".join(subtitle.mods) if subtitle.mods else "none") except: Log.Error("Something went wrong when modifying subtitle: %s", traceback.format_exc()) if subtitle.storage_path: stored_subtitle.last_mod = datetime.datetime.fromtimestamp(os.path.getmtime(subtitle.storage_path)) if not stored_subs_was_provided: storage.save(stored_subs) storage.destroy()
def extract_embedded_sub(**kwargs): rating_key = kwargs["rating_key"] part_id = kwargs.pop("part_id") stream_index = kwargs.pop("stream_index") with_mods = kwargs.pop("with_mods", False) language = Language.fromietf(kwargs.pop("language")) refresh = kwargs.pop("refresh", True) set_current = kwargs.pop("set_current", True) plex_item = kwargs.pop("plex_item", get_item(rating_key)) item_type = get_item_kind_from_item(plex_item) part = kwargs.pop("part", get_part(plex_item, part_id)) scanned_videos = kwargs.pop("scanned_videos", None) extract_mode = kwargs.pop("extract_mode", "a") any_successful = False if part: if not scanned_videos: metadata = get_plex_metadata(rating_key, part_id, item_type, plex_item=plex_item) scanned_videos = scan_videos([metadata], ignore_all=True, skip_hashing=True) for stream in part.streams: # subtitle stream if str(stream.index) == stream_index: is_forced = is_stream_forced(stream) bn = os.path.basename(part.file) set_refresh_menu_state( _(u"Extracting subtitle %(stream_index)s of %(filename)s", stream_index=stream_index, filename=bn)) Log.Info(u"Extracting stream %s (%s) of %s", stream_index, str(language), bn) out_codec = stream.codec if stream.codec != "mov_text" else "srt" args = [ config.plex_transcoder, "-i", part.file, "-map", "0:%s" % stream_index, "-f", out_codec, "-" ] output = None try: output = subprocess.check_output(quote_args(args), stderr=subprocess.PIPE, shell=True) except: Log.Error("Extraction failed: %s", traceback.format_exc()) if output: subtitle = ModifiedSubtitle( language, mods=config.default_mods if with_mods else None) subtitle.content = output subtitle.provider_name = "embedded" subtitle.id = "stream_%s" % stream_index subtitle.score = 0 subtitle.set_encoding("utf-8") # fixme: speedup video; only video.name is needed video = scanned_videos.keys()[0] save_successful = save_subtitles(scanned_videos, {video: [subtitle]}, mode="m", set_current=set_current) set_refresh_menu_state(None) if save_successful and refresh: refresh_item(rating_key) # add item to history item_title = get_title_for_video_metadata( video.plexapi_metadata, add_section_title=False, add_episode_title=True) history = get_history() history.add( item_title, video.id, section_title=video.plexapi_metadata["section"], thumb=video.plexapi_metadata["super_thumb"], subtitle=subtitle, mode=extract_mode) history.destroy() any_successful = True return any_successful
def extract_embedded_sub(**kwargs): rating_key = kwargs["rating_key"] part_id = kwargs.pop("part_id") stream_index = kwargs.pop("stream_index") with_mods = kwargs.pop("with_mods", False) language = Language.fromietf(kwargs.pop("language")) refresh = kwargs.pop("refresh", True) set_current = kwargs.pop("set_current", True) plex_item = get_item(rating_key) item_type = get_item_kind_from_item(plex_item) part = get_part(plex_item, part_id) if part: metadata = get_plex_metadata(rating_key, part_id, item_type, plex_item=plex_item) scanned_parts = scan_videos([metadata], ignore_all=True, skip_hashing=True) for stream in part.streams: # subtitle stream if str(stream.index) == stream_index: forced = stream.forced bn = os.path.basename(part.file) set_refresh_menu_state(u"Extracting subtitle %s of %s" % (stream_index, bn)) Log.Info(u"Extracting stream %s (%s) of %s", stream_index, display_language(language), bn) args = [ config.plex_transcoder, "-i", part.file, "-map", "0:%s" % stream_index, "-f", "srt", "-" ] output = None try: output = subprocess.check_output(quote_args(args), stderr=subprocess.PIPE, shell=True) except: Log.Error("Extraction failed: %s", traceback.format_exc()) if output: subtitle = ModifiedSubtitle( language, mods=config.default_mods if with_mods else None) subtitle.content = output subtitle.provider_name = "embedded" subtitle.id = "stream_%s" % stream_index subtitle.score = 0 subtitle.set_encoding("utf-8") # fixme: speedup video; only video.name is needed save_successful = save_subtitles( scanned_parts, {scanned_parts.keys()[0]: [subtitle]}, mode="m", set_current=set_current) set_refresh_menu_state(None) if save_successful and refresh: refresh_item(rating_key)