275 lines
10 KiB
Python
Executable File
275 lines
10 KiB
Python
Executable File
# coding=utf-8
|
|
import os
|
|
import sys
|
|
|
|
# just some slight modifications to support sum and iter again
|
|
from subzero.sandbox import restore_builtins
|
|
|
|
module = sys.modules['__main__']
|
|
restore_builtins(module, {})
|
|
|
|
globals = getattr(module, "__builtins__")["globals"]
|
|
for key, value in getattr(module, "__builtins__").iteritems():
|
|
if key != "globals":
|
|
globals()[key] = value
|
|
|
|
import logger
|
|
import logging
|
|
|
|
# temporarily add the console handler and set it to DEBUG to catch errors upon imports
|
|
Core.log.addHandler(logger.console_handler)
|
|
Core.log.setLevel(logging.DEBUG)
|
|
|
|
sys.modules["logger"] = logger
|
|
|
|
import subliminal
|
|
import subliminal_patch
|
|
import support
|
|
|
|
import interface
|
|
sys.modules["interface"] = interface
|
|
|
|
from subzero.constants import OS_PLEX_USERAGENT, PERSONAL_MEDIA_IDENTIFIER
|
|
from subzero import intent
|
|
from interface.menu import *
|
|
from support.plex_media import convert_media_to_parts, get_media_item_ids, scan_parts
|
|
from support.subtitlehelpers import get_subtitles_from_metadata, force_utf8
|
|
from support.helpers import notify_executable
|
|
from support.storage import store_subtitle_info, whack_missing_parts
|
|
from support.items import is_ignored
|
|
from support.config import config
|
|
|
|
|
|
def Start():
|
|
HTTP.CacheTime = 0
|
|
HTTP.Headers['User-agent'] = OS_PLEX_USERAGENT
|
|
|
|
# configured cache to be in memory as per https://github.com/Diaoul/subliminal/issues/303
|
|
subliminal.region.configure('dogpile.cache.memory')
|
|
|
|
# init defaults; perhaps not the best idea to use ValidatePrefs here, but we'll see
|
|
ValidatePrefs()
|
|
Log.Debug(config.full_version)
|
|
|
|
if not config.permissions_ok:
|
|
Log.Error("Insufficient permissions on library folders:")
|
|
for title, path in config.missing_permissions:
|
|
Log.Error("Insufficient permissions on library %s, folder: %s" % (title, path))
|
|
return
|
|
|
|
scheduler.run()
|
|
|
|
|
|
def init_subliminal_patches():
|
|
# configure custom subtitle destination folders for scanning pre-existing subs
|
|
dest_folder = config.subtitle_destination_folder
|
|
subliminal_patch.patch_video.CUSTOM_PATHS = [dest_folder] if dest_folder else []
|
|
subliminal_patch.patch_provider_pool.DOWNLOAD_TRIES = int(Prefs['subtitles.try_downloads'])
|
|
subliminal_patch.patch_providers.addic7ed.USE_BOOST = bool(Prefs['provider.addic7ed.boost'])
|
|
|
|
|
|
def download_best_subtitles(video_part_map, min_score=0):
|
|
hearing_impaired = Prefs['subtitles.search.hearingImpaired']
|
|
languages = config.lang_list
|
|
if not languages:
|
|
return
|
|
|
|
missing_languages = False
|
|
for video, part in video_part_map.iteritems():
|
|
if not Prefs['subtitles.save.filesystem']:
|
|
# scan for existing metadata subtitles
|
|
meta_subs = get_subtitles_from_metadata(part)
|
|
for language, subList in meta_subs.iteritems():
|
|
if subList:
|
|
video.subtitle_languages.add(language)
|
|
Log.Debug("Found metadata subtitle %s for %s", language, video)
|
|
|
|
missing_subs = (languages - video.subtitle_languages)
|
|
|
|
# all languages are found if we either really have subs for all languages or we only want to have exactly one language
|
|
# and we've only found one (the case for a selected language, Prefs['subtitles.only_one'] (one found sub matches any language))
|
|
found_one_which_is_enough = len(video.subtitle_languages) >= 1 and Prefs['subtitles.only_one']
|
|
if not missing_subs or found_one_which_is_enough:
|
|
if found_one_which_is_enough:
|
|
Log.Debug('Only one language was requested, and we\'ve got a subtitle for %s', video)
|
|
else:
|
|
Log.Debug('All languages %r exist for %s', languages, video)
|
|
continue
|
|
missing_languages = True
|
|
break
|
|
|
|
if missing_languages:
|
|
Log.Debug("Download best subtitles using settings: min_score: %s, hearing_impaired: %s" % (min_score, hearing_impaired))
|
|
|
|
return subliminal.api.download_best_subtitles(video_part_map.keys(), languages, min_score, hearing_impaired, providers=config.providers,
|
|
provider_configs=config.provider_settings)
|
|
Log.Debug("All languages for all requested videos exist. Doing nothing.")
|
|
|
|
|
|
def save_subtitles(videos, subtitles):
|
|
meta_fallback = False
|
|
save_successful = False
|
|
storage = "metadata"
|
|
if Prefs['subtitles.save.filesystem']:
|
|
storage = "filesystem"
|
|
try:
|
|
Log.Debug("Using filesystem as subtitle storage")
|
|
save_subtitles_to_file(subtitles)
|
|
except OSError:
|
|
if Prefs["subtitles.save.metadata_fallback"]:
|
|
meta_fallback = True
|
|
else:
|
|
raise
|
|
else:
|
|
save_successful = True
|
|
|
|
if not Prefs['subtitles.save.filesystem'] 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(videos, subtitles)
|
|
|
|
if save_successful and config.notify_executable:
|
|
notify_executable(config.notify_executable, videos, subtitles, storage)
|
|
|
|
store_subtitle_info(videos, subtitles, storage)
|
|
|
|
|
|
def save_subtitles_to_file(subtitles):
|
|
fld_custom = Prefs["subtitles.save.subFolder.Custom"].strip() if bool(Prefs["subtitles.save.subFolder.Custom"]) else None
|
|
|
|
for video, video_subtitles in subtitles.items():
|
|
if not video_subtitles:
|
|
continue
|
|
|
|
fld = 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(video.name)[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"])
|
|
if not os.path.exists(fld):
|
|
os.makedirs(fld)
|
|
subliminal.api.save_subtitles(video, video_subtitles, directory=fld, single=Prefs['subtitles.only_one'],
|
|
encode_with=force_utf8 if Prefs['subtitles.enforce_encoding'] else None)
|
|
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 = force_utf8(subtitle.text) if Prefs['subtitles.enforce_encoding'] else subtitle.content
|
|
mediaPart.subtitles[Locale.Language.Match(subtitle.language.alpha2)][subtitle.page_link] = Proxy.Media(content, ext="srt")
|
|
return True
|
|
|
|
|
|
def update_local_media(metadata, media, media_type="movies"):
|
|
# Look for subtitles
|
|
if media_type == "movies":
|
|
for item in media.items:
|
|
for part in item.parts:
|
|
support.localmedia.find_subtitles(part)
|
|
return
|
|
|
|
# Look for subtitles for each episode.
|
|
for s in media.seasons:
|
|
# If we've got a date based season, ignore it for now, otherwise it'll collide with S/E folders/XML and PMS
|
|
# prefers date-based (why?)
|
|
if int(s) < 1900 or metadata.guid.startswith(PERSONAL_MEDIA_IDENTIFIER):
|
|
for e in media.seasons[s].episodes:
|
|
for i in media.seasons[s].episodes[e].items:
|
|
|
|
# Look for subtitles.
|
|
for part in i.parts:
|
|
support.localmedia.find_subtitles(part)
|
|
else:
|
|
pass
|
|
|
|
|
|
class SubZeroAgent(object):
|
|
agent_type = None
|
|
agent_type_verbose = None
|
|
languages = [Locale.Language.English]
|
|
primary_provider = False
|
|
score_prefs_key = None
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super(SubZeroAgent, self).__init__(*args, **kwargs)
|
|
self.agent_type = "movies" if isinstance(self, Agent.Movies) else "series"
|
|
self.name = "Sub-Zero Subtitles (%s, %s)" % (self.agent_type_verbose, config.get_version())
|
|
|
|
def search(self, results, media, lang):
|
|
Log.Debug("Sub-Zero %s, %s search" % (config.version, self.agent_type))
|
|
results.Append(MetadataSearchResult(id='null', score=100))
|
|
|
|
def update(self, metadata, media, lang):
|
|
Log.Debug("Sub-Zero %s, %s update called" % (config.version, self.agent_type))
|
|
|
|
if not media:
|
|
Log.Error("Called with empty media, something is really wrong with your setup!")
|
|
return
|
|
|
|
set_refresh_menu_state(media, media_type=self.agent_type)
|
|
|
|
item_ids = []
|
|
try:
|
|
init_subliminal_patches()
|
|
parts = convert_media_to_parts(media, kind=self.agent_type)
|
|
|
|
# media ignored?
|
|
use_any_parts = False
|
|
for part in parts:
|
|
if is_ignored(part["id"]):
|
|
Log.Debug(u"Ignoring %s" % part)
|
|
continue
|
|
use_any_parts = True
|
|
|
|
if not use_any_parts:
|
|
Log.Debug(u"Nothing to do.")
|
|
return
|
|
|
|
use_score = Prefs[self.score_prefs_key]
|
|
scanned_parts = scan_parts(parts, kind=self.agent_type)
|
|
subtitles = download_best_subtitles(scanned_parts, min_score=int(use_score))
|
|
item_ids = get_media_item_ids(media, kind=self.agent_type)
|
|
|
|
whack_missing_parts(scanned_parts)
|
|
|
|
if subtitles:
|
|
save_subtitles(scanned_parts, subtitles)
|
|
|
|
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()
|
|
|
|
|
|
class SubZeroSubtitlesAgentMovies(SubZeroAgent, Agent.Movies):
|
|
contributes_to = ['com.plexapp.agents.imdb', 'com.plexapp.agents.xbmcnfo', 'com.plexapp.agents.themoviedb', 'com.plexapp.agents.hama']
|
|
score_prefs_key = "subtitles.search.minimumMovieScore"
|
|
agent_type_verbose = "Movies"
|
|
|
|
|
|
class SubZeroSubtitlesAgentTvShows(SubZeroAgent, Agent.TV_Shows):
|
|
contributes_to = ['com.plexapp.agents.thetvdb', 'com.plexapp.agents.themoviedb',
|
|
'com.plexapp.agents.thetvdbdvdorder', 'com.plexapp.agents.xbmcnfotv', 'com.plexapp.agents.hama']
|
|
score_prefs_key = "subtitles.search.minimumTVScore"
|
|
agent_type_verbose = "TV"
|