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 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 update(self, metadata, media, lang): Log.Debug("Sub-Zero %s, %s update called" % (config.version, self.agent_type)) intent = get_intent() if not media: Log.Error( "Called with empty media, something is really wrong with your setup!" ) return item_ids = [] try: config.init_subliminal_patches() videos = media_to_videos(media, kind=self.agent_type) # find local media update_local_media(metadata, media, media_type=self.agent_type) # media ignored? use_any_parts = False for video in videos: if is_ignored(video["id"]): Log.Debug(u"Ignoring %s" % video) continue use_any_parts = True if not use_any_parts: Log.Debug(u"Nothing to do.") return try: use_score = int(Prefs[self.score_prefs_key].strip()) except ValueError: Log.Error( "Please only put numbers into the scores setting. Exiting") return set_refresh_menu_state(media, media_type=self.agent_type) # scanned_video_part_map = {subliminal.Video: plex_part, ...} scanned_video_part_map = scan_videos(videos, kind=self.agent_type) downloaded_subtitles = None if not config.enable_agent: Log.Debug("Skipping Sub-Zero agent(s)") else: # downloaded_subtitles = {subliminal.Video: [subtitle, subtitle, ...]} downloaded_subtitles = download_best_subtitles( scanned_video_part_map, min_score=use_score) item_ids = get_media_item_ids(media, kind=self.agent_type) downloaded_any = False if downloaded_subtitles: downloaded_any = any(downloaded_subtitles.values()) if downloaded_any: save_subtitles(scanned_video_part_map, downloaded_subtitles, mods=config.default_mods) track_usage("Subtitle", "refreshed", "download", 1) for video, video_subtitles in downloaded_subtitles.items(): # store item(s) in history for subtitle in video_subtitles: item_title = get_title_for_video_metadata( video.plexapi_metadata, add_section_title=False) history = get_history() history.add( item_title, video.id, section_title=video.plexapi_metadata["section"], subtitle=subtitle) else: # store subtitle info even if we've downloaded none store_subtitle_info( scanned_video_part_map, dict((k, []) for k in scanned_video_part_map.keys()), None, mode="a") update_local_media(metadata, media, media_type=self.agent_type) finally: # update the menu state set_refresh_menu_state(None) # notify any running tasks about our finished update for item_id in item_ids: #scheduler.signal("updated_metadata", item_id) # resolve existing intent for that id intent.resolve("force", item_id) Dict.Save()
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()) 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_sub_fns = subtitle_storage.get_recent_files( age_days=max_search_days) viable_items = {} # determine viable items for fn in recent_sub_fns: # added_date <= max_search_days? stored_subs = subtitle_storage.load(filename=fn) if not stored_subs: continue if stored_subs.added_at + datetime.timedelta( days=max_search_days) <= now: continue viable_items[fn] = stored_subs subtitle_storage.destroy() self.items_searching = len(viable_items) 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) # search for subtitles in viable items for fn, stored_subs in viable_items.iteritems(): video_id = stored_subs.video_id if stored_subs.item_type == "episode": min_score = min_score_series else: min_score = min_score_movies parts = [] plex_item = get_item(video_id) if not plex_item: Log.Info(u"%s: Item %s unknown, skipping", self.name, video_id) continue if is_ignored(video_id, item=plex_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:%s", self.name, video_id, part_id) scanned_parts = scan_videos( [metadata], kind="series" if stored_subs.item_type == "episode" else "movie") downloaded_subtitles = download_best_subtitles( scanned_parts, min_score=min_score) 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: 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"], subtitle=subtitle, mode="a") Log.Debug(u"%s: Waiting %s seconds before continuing", self.name, PROVIDER_SLACK) time.sleep(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 downloads_per_video: Log.Debug( u"%s: Subtitles have been downloaded, " u"waiting %s seconds before continuing", self.name, DL_PROVIDER_SLACK) time.sleep(DL_PROVIDER_SLACK) else: if hit_providers: Log.Debug(u"%s: Waiting %s seconds before continuing", self.name, PROVIDER_SLACK) time.sleep(PROVIDER_SLACK) 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 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, scan_videos from support.storage import save_subtitles current_sub, stored_subs, storage = get_current_sub(rating_key, part_id, language) 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) 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.set_encoding("utf-8") 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())