Files
2019-03-02 02:47:49 +01:00

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())