256 lines
9.2 KiB
Python
256 lines
9.2 KiB
Python
# coding=utf-8
|
|
|
|
import datetime
|
|
import os
|
|
import pprint
|
|
import copy
|
|
import traceback
|
|
import types
|
|
|
|
from subliminal_patch.core import save_subtitles as subliminal_save_subtitles
|
|
from subzero.subtitle_storage import StoredSubtitlesManager
|
|
from subzero.lib.io import FileIO
|
|
|
|
from subtitlehelpers import force_utf8
|
|
from config import config
|
|
from helpers import notify_executable, get_title_for_video_metadata, cast_bool, force_unicode
|
|
from plex_media import PMSMediaProxy
|
|
from support.items import get_item
|
|
|
|
|
|
def get_subtitle_storage():
|
|
return StoredSubtitlesManager(Data, Thread, get_item)
|
|
|
|
|
|
def store_subtitle_info(scanned_video_part_map, downloaded_subtitles, storage_type, mode="a", set_current=True):
|
|
"""
|
|
stores information about downloaded subtitles in plex's Dict()
|
|
"""
|
|
subtitle_storage = get_subtitle_storage()
|
|
for video, video_subtitles in downloaded_subtitles.items():
|
|
part = scanned_video_part_map[video]
|
|
part_id = str(part.id)
|
|
video_id = str(video.id)
|
|
plex_item = get_item(video_id)
|
|
if not plex_item:
|
|
Log.Warn("Plex item not found: %s", video_id)
|
|
continue
|
|
|
|
metadata = video.plexapi_metadata
|
|
title = get_title_for_video_metadata(metadata)
|
|
|
|
stored_subs = subtitle_storage.load(video_id)
|
|
is_new = False
|
|
if not stored_subs:
|
|
is_new = True
|
|
Log.Debug(u"Creating new subtitle storage: %s, %s", video_id, part_id)
|
|
stored_subs = subtitle_storage.new(plex_item)
|
|
|
|
for subtitle in video_subtitles:
|
|
lang = str(subtitle.language)
|
|
subtitle.normalize()
|
|
Log.Debug(u"Adding subtitle to storage: %s, %s, %s, %s, %s" % (video_id, part_id, lang, title,
|
|
subtitle.guess_encoding()))
|
|
|
|
last_mod = None
|
|
if subtitle.storage_path:
|
|
last_mod = datetime.datetime.fromtimestamp(os.path.getmtime(subtitle.storage_path))
|
|
|
|
ret_val = stored_subs.add(part_id, lang, subtitle, storage_type, mode=mode, last_mod=last_mod,
|
|
set_current=set_current)
|
|
|
|
if ret_val:
|
|
Log.Debug("Subtitle stored")
|
|
|
|
else:
|
|
Log.Debug("Subtitle already existing in storage")
|
|
|
|
if is_new or video_subtitles:
|
|
Log.Debug("Saving subtitle storage for %s" % video_id)
|
|
subtitle_storage.save(stored_subs)
|
|
|
|
subtitle_storage.destroy()
|
|
|
|
|
|
def reset_storage(key):
|
|
"""
|
|
resets the Dict[key] storage, thanks to https://docs.google.com/document/d/1hhLjV1pI-TA5y91TiJq64BdgKwdLnFt4hWgeOqpz1NA/edit#
|
|
We can't use the nice Plex interface for this, as it calls get multiple times before set
|
|
#Plex[":/plugins/*/prefs"].set("com.plexapp.agents.subzero", "reset_storage", False)
|
|
"""
|
|
|
|
Log.Debug("resetting storage")
|
|
Dict[key] = {}
|
|
Dict.Save()
|
|
|
|
|
|
def log_storage(key):
|
|
if not key:
|
|
Log.Debug(pprint.pformat(getattr(Dict, "_dict")))
|
|
if key in Dict:
|
|
Log.Debug(pprint.pformat(Dict[key]))
|
|
|
|
|
|
def get_target_folder(file_path):
|
|
fld = None
|
|
fld_custom = Prefs["subtitles.save.subFolder.Custom"].strip() \
|
|
if Prefs["subtitles.save.subFolder.Custom"] else None
|
|
|
|
if fld_custom or Prefs["subtitles.save.subFolder"] != "current folder":
|
|
# specific subFolder requested, create it if it doesn't exist
|
|
fld_base = os.path.split(file_path)[0]
|
|
if fld_custom:
|
|
if fld_custom.startswith("/"):
|
|
# absolute folder
|
|
fld = fld_custom
|
|
else:
|
|
fld = os.path.join(fld_base, fld_custom)
|
|
else:
|
|
fld = os.path.join(fld_base, Prefs["subtitles.save.subFolder"])
|
|
fld = force_unicode(fld)
|
|
if not os.path.exists(fld):
|
|
os.makedirs(fld)
|
|
return fld
|
|
|
|
|
|
def save_subtitles_to_file(subtitles, tags=None):
|
|
for video, video_subtitles in subtitles.items():
|
|
if not video_subtitles:
|
|
continue
|
|
|
|
if not isinstance(video, types.StringTypes):
|
|
file_path = video.name
|
|
else:
|
|
file_path = video
|
|
|
|
fld = get_target_folder(file_path)
|
|
subliminal_save_subtitles(file_path, video_subtitles, directory=fld, single=cast_bool(Prefs['subtitles.only_one']),
|
|
chmod=config.chmod, path_decoder=force_unicode,
|
|
debug_mods=config.debug_mods, formats=config.subtitle_formats, tags=tags)
|
|
return True
|
|
|
|
|
|
def save_subtitles_to_metadata(videos, subtitles):
|
|
for video, video_subtitles in subtitles.items():
|
|
mediaPart = videos[video]
|
|
for subtitle in video_subtitles:
|
|
content = subtitle.get_modified_content(debug=config.debug_mods)
|
|
|
|
if not isinstance(mediaPart, Framework.api.agentkit.MediaPart):
|
|
# we're being handed a Plex.py model instance here, not an internal PMS MediaPart object.
|
|
# get the correct one
|
|
mp = PMSMediaProxy(video.id).get_part(mediaPart.id)
|
|
else:
|
|
mp = mediaPart
|
|
pm = Proxy.Media(content, ext="srt", forced="1" if subtitle.language.forced else None)
|
|
new_key = "subzero_md" + ("_forced" if subtitle.language.forced else "")
|
|
lang = Locale.Language.Match(subtitle.language.alpha2)
|
|
|
|
for key, proxy in getattr(mp.subtitles[lang], "_proxies").iteritems():
|
|
if not proxy or not len(proxy) >= 5:
|
|
Log.Debug("Can't parse metadata: %s" % repr(proxy))
|
|
continue
|
|
if proxy[0] == "Media":
|
|
if not key.startswith("subzero_"):
|
|
if key == "subzero":
|
|
Log.Debug("Removing legacy metadata subtitle for %s", lang)
|
|
del mp.subtitles[lang][key]
|
|
Log.Debug("Existing metadata subtitle for %s: %s", lang, key)
|
|
|
|
Log.Debug("Adding metadata sub for %s: %s", lang, subtitle)
|
|
mp.subtitles[lang][new_key] = pm
|
|
return True
|
|
|
|
|
|
def save_subtitles(scanned_video_part_map, downloaded_subtitles, mode="a", bare_save=False, mods=None,
|
|
set_current=True):
|
|
"""
|
|
|
|
:param set_current: save the subtitle as the current one
|
|
:param scanned_video_part_map:
|
|
:param downloaded_subtitles:
|
|
:param mode:
|
|
:param bare_save: don't trigger anything; don't store information
|
|
:param mods: enabled mods
|
|
:return:
|
|
"""
|
|
meta_fallback = False
|
|
save_successful = False
|
|
|
|
# big fixme: scanned_video_part_map isn't needed to the current extent. rewrite.
|
|
|
|
if mods:
|
|
for video, video_subtitles in downloaded_subtitles.items():
|
|
if not video_subtitles:
|
|
continue
|
|
|
|
for subtitle in video_subtitles:
|
|
Log.Info("Applying mods: %s to %s", mods, subtitle)
|
|
subtitle.mods = mods
|
|
subtitle.plex_media_fps = video.fps
|
|
|
|
storage = "metadata"
|
|
save_to_fs = cast_bool(Prefs['subtitles.save.filesystem'])
|
|
if save_to_fs:
|
|
storage = "filesystem"
|
|
|
|
if set_current:
|
|
if save_to_fs:
|
|
try:
|
|
Log.Debug("Using filesystem as subtitle storage")
|
|
save_subtitles_to_file(downloaded_subtitles)
|
|
except OSError:
|
|
if cast_bool(Prefs["subtitles.save.metadata_fallback"]):
|
|
meta_fallback = True
|
|
storage = "metadata"
|
|
else:
|
|
raise
|
|
else:
|
|
save_successful = True
|
|
|
|
if not save_to_fs or meta_fallback:
|
|
if meta_fallback:
|
|
Log.Debug("Using metadata as subtitle storage, because filesystem storage failed")
|
|
else:
|
|
Log.Debug("Using metadata as subtitle storage")
|
|
save_successful = save_subtitles_to_metadata(scanned_video_part_map, downloaded_subtitles)
|
|
|
|
if not bare_save and save_successful and config.notify_executable:
|
|
notify_executable(config.notify_executable, scanned_video_part_map, downloaded_subtitles, storage)
|
|
|
|
if (not bare_save and save_successful) or not set_current:
|
|
store_subtitle_info(scanned_video_part_map, downloaded_subtitles, storage, mode=mode, set_current=set_current)
|
|
|
|
return save_successful
|
|
|
|
|
|
def get_pack_id(subtitle):
|
|
return "%s_%s" % (subtitle.provider_name, subtitle.numeric_id)
|
|
|
|
|
|
def get_pack_data(subtitle):
|
|
subtitle_id = get_pack_id(subtitle)
|
|
|
|
archive = os.path.join(config.pack_cache_dir, subtitle_id + ".archive")
|
|
if os.path.isfile(archive):
|
|
Log.Info("Loading archive from pack cache: %s", subtitle_id)
|
|
try:
|
|
data = FileIO.read(archive, 'rb')
|
|
|
|
return data
|
|
except:
|
|
Log.Error("Couldn't load archive from pack cache: %s: %s", subtitle_id, traceback.format_exc())
|
|
|
|
|
|
def store_pack_data(subtitle, data):
|
|
subtitle_id = get_pack_id(subtitle)
|
|
|
|
archive = os.path.join(config.pack_cache_dir, subtitle_id + ".archive")
|
|
|
|
Log.Info("Storing archive in pack cache: %s", subtitle_id)
|
|
try:
|
|
FileIO.write(archive, data, 'wb')
|
|
|
|
except:
|
|
Log.Error("Couldn't store archive in pack cache: %s: %s", subtitle_id, traceback.format_exc())
|