Compare commits

...

7 Commits

Author SHA1 Message Date
pannal 9adb7d18c0 bump DEV 2017-04-27 17:13:57 +02:00
pannal 73da57a4f7 add dogpile cache invalidation 2017-04-27 17:13:42 +02:00
pannal 261d3c5532 add data paths to config; add proper dbm cache for subliminal 2017-04-27 17:00:03 +02:00
pannal 91e55502f6 correct elif 2017-04-27 15:50:51 +02:00
pannal 26846a02b5 add hash_verifiable flag to subtitle and provider base classes 2017-04-27 15:46:42 +02:00
pannal f2ed289c70 add new Provider base class; streamlined base class patching 2017-04-27 15:42:18 +02:00
pannal 8b9109396a fix duplicate subtitles issue on synology/qnap #215 2017-04-27 14:00:09 +02:00
10 changed files with 59 additions and 43 deletions
+4 -2
View File
@@ -22,6 +22,7 @@ import support
import interface
sys.modules["interface"] = interface
from subliminal.cli import MutexLock
from subzero.constants import OS_PLEX_USERAGENT, PERSONAL_MEDIA_IDENTIFIER
from interface.menu import *
from support.plex_media import media_to_videos, get_media_item_ids, scan_videos
@@ -40,8 +41,9 @@ 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')
subliminal.region.configure('dogpile.cache.dbm', expiration_time=datetime.timedelta(days=30),
arguments={'filename': os.path.join(config.data_items_path, 'subzero.dbm'),
'lock_factory': MutexLock})
# clear expired intents
intent = get_intent()
+15
View File
@@ -804,6 +804,10 @@ def AdvancedMenu(randomize=None, header=None, message=None):
key=Callback(ResetStorage, key="ignore", randomize=timestamp()),
title=pad_title("Reset the plugin's internal ignorelist storage"),
))
oc.add(DirectoryObject(
key=Callback(InvalidateCache, randomize=timestamp()),
title=pad_title("Invalidate Sub-Zero metadata caches (subliminal)"),
))
return oc
@@ -940,3 +944,14 @@ def DownloadLogs():
zip_archive.close()
return ZipObject(buff.getvalue())
@route(PREFIX + '/invalidatecache')
def InvalidateCache(randomize=None):
from subliminal.cache import region
region.invalidate()
return AdvancedMenu(
randomize=timestamp(),
header='Success',
message='Cache invalidated'
)
+4
View File
@@ -42,6 +42,8 @@ class Config(object):
plugin_log_path = None
server_log_path = None
app_support_path = None
data_path = None
data_items_path = None
universal_plex_token = None
is_development = False
@@ -84,6 +86,8 @@ class Config(object):
self.full_version = u"%s %s" % (PLUGIN_NAME, self.version)
self.set_log_paths()
self.app_support_path = Core.app_support_path
self.data_path = getattr(Data, "_core").storage.data_path
self.data_items_path = os.path.join(self.data_path, "DataItems")
self.universal_plex_token = self.get_universal_plex_token()
self.set_plugin_mode()
+1 -1
View File
@@ -56,7 +56,7 @@ def find_subtitles(part):
global_folders.append(global_subtitle_folder)
# normalize all paths
paths = [os.path.normpath(os.path.realpath(helpers.unicodize(path))) for path in paths]
paths = [os.path.normpath(helpers.unicodize(path)) for path in paths]
# We start by building a dictionary of files to their absolute paths. We also need to know
# the number of media files that are actually present, in case the found local media asset
+1 -1
View File
@@ -32,7 +32,7 @@
<h1>Sub-Zero for Plex</h1><i>Subtitles done right</i>
Version 2.0.0.0 DEV #6
Version 2.0.0.0 DEV #7
Originally based on @bramwalet's awesome <a href="https://github.com/bramwalet/Subliminal.bundle">Subliminal.bundle</a>
@@ -1,9 +1,11 @@
# coding=utf-8
import importlib
import subliminal
# patch subliminal's subtitle and provider base
from .subtitle import PatchedSubtitle
from .providers import Provider
from .http import RetryingSession
subliminal.subtitle.Subtitle = PatchedSubtitle
@@ -13,34 +15,15 @@ except ValueError:
# already registered
pass
# inject our requests.Session wrapper for automatic retry
subliminal.providers.addic7ed.Session = RetryingSession
subliminal.providers.podnapisi.Session = RetryingSession
subliminal.providers.tvsubtitles.Session = RetryingSession
subliminal.providers.opensubtitles.Session = RetryingSession
subliminal.providers.legendastv.Session = RetryingSession
subliminal.providers.napiprojekt.Session = RetryingSession
subliminal.providers.shooter.Session = RetryingSession
subliminal.providers.subscenter.Session = RetryingSession
from subliminal.providers.addic7ed import Addic7edSubtitle
from subliminal.providers.podnapisi import PodnapisiSubtitle
from subliminal.providers.tvsubtitles import TVsubtitlesSubtitle
from subliminal.providers.opensubtitles import OpenSubtitlesSubtitle
from subliminal.providers.legendastv import LegendasTVSubtitle
from subliminal.providers.napiprojekt import NapiProjektSubtitle
from subliminal.providers.shooter import ShooterSubtitle
from subliminal.providers.subscenter import SubsCenterSubtitle
# add our patched base classes
setattr(Addic7edSubtitle, "__bases__", (PatchedSubtitle,))
setattr(PodnapisiSubtitle, "__bases__", (PatchedSubtitle,))
setattr(TVsubtitlesSubtitle, "__bases__", (PatchedSubtitle,))
setattr(OpenSubtitlesSubtitle, "__bases__", (PatchedSubtitle,))
setattr(LegendasTVSubtitle, "__bases__", (PatchedSubtitle,))
setattr(NapiProjektSubtitle, "__bases__", (PatchedSubtitle,))
setattr(ShooterSubtitle, "__bases__", (PatchedSubtitle,))
setattr(SubsCenterSubtitle, "__bases__", (PatchedSubtitle,))
for name in ("Addic7ed", "Podnapisi", "TVsubtitles", "OpenSubtitles", "LegendasTV", "NapiProjekt", "Shooter",
"SubsCenter"):
mod = importlib.import_module("subliminal.providers.%s" % name.lower())
setattr(getattr(mod, "%sSubtitle" % name), "__bases__", (PatchedSubtitle,))
setattr(getattr(mod, "%sProvider" % name), "__bases__", (Provider,))
# inject our requests.Session wrapper for automatic retry
setattr(mod, "Session", RetryingSession)
from .core import scan_video, search_external_subtitles, list_all_subtitles, save_subtitles, refine
from .score import compute_score
@@ -1,2 +1,7 @@
# coding=utf-8
from subliminal.providers import Provider as _Provider
class Provider(_Provider):
hash_verifiable = False
@@ -15,6 +15,8 @@ logger = logging.getLogger(__name__)
class OpenSubtitlesSubtitle(_OpenSubtitlesSubtitle):
hash_verifiable = True
def __init__(self, language, hearing_impaired, page_link, subtitle_id, matched_by, movie_kind, hash, movie_name,
movie_release_name, movie_year, movie_imdb_id, series_season, series_episode, query_parameters,
filename, encoding, fps):
@@ -54,6 +56,7 @@ class OpenSubtitlesSubtitle(_OpenSubtitlesSubtitle):
class OpenSubtitlesProvider(ProviderRetryMixin, _OpenSubtitlesProvider):
only_foreign = True
subtitle_class = OpenSubtitlesSubtitle
hash_verifiable = True
def __init__(self, username=None, password=None, use_tag_search=False, only_foreign=False):
if username is not None and password is None or username is None and password is not None:
@@ -40,19 +40,22 @@ def compute_score(matches, subtitle, video, hearing_impaired=None):
movie_hash_valid_if = {"video_codec", "format"}
# on hash match, discard everything else
if 'hash' in matches:
# hash is error-prone, try to fix that
hash_valid_if = episode_hash_valid_if if is_episode else movie_hash_valid_if
if subtitle.hash_verifiable:
if 'hash' in matches:
# hash is error-prone, try to fix that
hash_valid_if = episode_hash_valid_if if is_episode else movie_hash_valid_if
if hash_valid_if <= set(matches):
# series, season and episode matched, hash is valid
logger.debug('Using valid hash, as %s are correct (%r) and (%r)', hash_valid_if, matches, video)
matches &= {'hash', 'hearing_impaired'}
else:
# no match, invalidate hash
logger.debug('Ignoring hash as other matches are wrong (missing: %r) and (%r)', hash_valid_if - matches,
video)
matches -= {"hash"}
if hash_valid_if <= set(matches):
# series, season and episode matched, hash is valid
logger.debug('Using valid hash, as %s are correct (%r) and (%r)', hash_valid_if, matches, video)
matches &= {'hash', 'hearing_impaired'}
else:
# no match, invalidate hash
logger.debug('Ignoring hash as other matches are wrong (missing: %r) and (%r)', hash_valid_if - matches,
video)
matches -= {"hash"}
elif 'hash' in matches:
logger.debug('Hash not verifiable for this provider. Keeping it')
# handle equivalent matches
if is_episode:
@@ -16,6 +16,7 @@ class PatchedSubtitle(Subtitle):
storage_path = None
release_info = None
matches = None
hash_verifiable = False
def __repr__(self):
return '<%s %r [%s]>' % (