208 lines
9.8 KiB
Python
208 lines
9.8 KiB
Python
# coding=utf-8
|
|
import os
|
|
import subprocess
|
|
import traceback
|
|
|
|
from support.helpers import quote_args, mswindows, get_title_for_video_metadata, cast_bool, \
|
|
audio_streams_match_languages
|
|
from support.i18n import _
|
|
from support.items import get_item_kind_from_item, refresh_item, get_all_items, get_item, MI_KEY
|
|
from support.storage import get_subtitle_storage, save_subtitles
|
|
from support.config import config
|
|
from support.history import get_history
|
|
from support.plex_media import get_all_parts, get_embedded_subtitle_streams, get_part, get_plex_metadata, \
|
|
update_stream_info, is_stream_forced
|
|
from support.scanning import scan_videos
|
|
from subzero.language import Language
|
|
from subliminal_patch.subtitle import ModifiedSubtitle
|
|
|
|
|
|
def agent_extract_embedded(video_part_map, set_as_existing=False):
|
|
try:
|
|
subtitle_storage = get_subtitle_storage()
|
|
|
|
to_extract = []
|
|
item_count = 0
|
|
|
|
threads = []
|
|
|
|
for scanned_video, part_info in video_part_map.iteritems():
|
|
plexapi_item = scanned_video.plexapi_metadata["item"]
|
|
stored_subs = subtitle_storage.load_or_new(plexapi_item)
|
|
valid_langs_in_media = \
|
|
audio_streams_match_languages(scanned_video, config.get_lang_list(ordered=True))
|
|
|
|
if not config.lang_list.difference(valid_langs_in_media):
|
|
Log.Debug("Skipping embedded subtitle extraction for %s, audio streams are in correct language(s)",
|
|
plexapi_item.rating_key)
|
|
continue
|
|
|
|
for plexapi_part in get_all_parts(plexapi_item):
|
|
item_count = item_count + 1
|
|
used_one_unknown_stream = False
|
|
used_one_known_stream = False
|
|
for requested_language in config.lang_list:
|
|
skip_unknown = used_one_unknown_stream or used_one_known_stream
|
|
embedded_subs = stored_subs.get_by_provider(plexapi_part.id, requested_language, "embedded")
|
|
current = stored_subs.get_any(plexapi_part.id, requested_language) or \
|
|
requested_language in scanned_video.external_subtitle_languages
|
|
|
|
if not embedded_subs:
|
|
stream_data = get_embedded_subtitle_streams(plexapi_part, requested_language=requested_language,
|
|
skip_unknown=skip_unknown)
|
|
|
|
if stream_data and stream_data[0]["language"]:
|
|
stream = stream_data[0]["stream"]
|
|
if stream_data[0]["is_unknown"]:
|
|
used_one_unknown_stream = True
|
|
else:
|
|
used_one_known_stream = True
|
|
|
|
to_extract.append(({scanned_video: part_info}, plexapi_part, str(stream.index),
|
|
str(requested_language), not current))
|
|
|
|
if not cast_bool(Prefs["subtitles.search_after_autoextract"]) or set_as_existing:
|
|
scanned_video.subtitle_languages.update({requested_language})
|
|
else:
|
|
Log.Debug("Skipping embedded subtitle extraction for %s, already got %r from %s",
|
|
plexapi_item.rating_key, requested_language, embedded_subs[0].id)
|
|
if to_extract:
|
|
Log.Info("Triggering extraction of %d embedded subtitles of %d items", len(to_extract), item_count)
|
|
threads.append(Thread.Create(multi_extract_embedded, stream_list=to_extract, refresh=True, with_mods=True,
|
|
single_thread=not config.advanced.auto_extract_multithread))
|
|
return threads
|
|
except:
|
|
Log.Error("Something went wrong when auto-extracting subtitles, continuing: %s", traceback.format_exc())
|
|
|
|
|
|
def multi_extract_embedded(stream_list, refresh=False, with_mods=False, single_thread=True, extract_mode="a",
|
|
history_storage=None):
|
|
def execute():
|
|
for video_part_map, plexapi_part, stream_index, language, set_current in stream_list:
|
|
plexapi_item = video_part_map.keys()[0].plexapi_metadata["item"]
|
|
|
|
extract_embedded_sub(rating_key=plexapi_item.rating_key, part_id=plexapi_part.id,
|
|
plex_item=plexapi_item, part=plexapi_part, scanned_videos=video_part_map,
|
|
stream_index=stream_index, set_current=set_current,
|
|
language=language, with_mods=with_mods, refresh=refresh, extract_mode=extract_mode,
|
|
history_storage=history_storage)
|
|
|
|
if single_thread:
|
|
with Thread.Lock(key="extract_embedded"):
|
|
execute()
|
|
else:
|
|
execute()
|
|
|
|
|
|
def season_extract_embedded(rating_key, requested_language, with_mods=False, force=False):
|
|
# get stored subtitle info for item id
|
|
subtitle_storage = get_subtitle_storage()
|
|
|
|
try:
|
|
for data in get_all_items(key="children", value=rating_key, base="library/metadata"):
|
|
item = get_item(data[MI_KEY])
|
|
if item:
|
|
stored_subs = subtitle_storage.load_or_new(item)
|
|
for part in get_all_parts(item):
|
|
embedded_subs = stored_subs.get_by_provider(part.id, requested_language, "embedded")
|
|
current = stored_subs.get_any(part.id, requested_language)
|
|
if not embedded_subs or force:
|
|
stream_data = get_embedded_subtitle_streams(part, requested_language=requested_language)
|
|
if stream_data:
|
|
stream = stream_data[0]["stream"]
|
|
|
|
set_current = not current or force
|
|
refresh = not current
|
|
|
|
extract_embedded_sub(rating_key=item.rating_key, part_id=part.id,
|
|
stream_index=str(stream.index), set_current=set_current,
|
|
refresh=refresh, language=requested_language, with_mods=with_mods,
|
|
extract_mode="m")
|
|
finally:
|
|
subtitle_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
|
|
|
|
from interface.menu_helpers import set_refresh_menu_state
|
|
|
|
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)
|
|
|
|
update_stream_info(part)
|
|
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 |