make intents thread safe by using DictProxy

This commit is contained in:
panni
2016-10-11 13:06:01 +02:00
parent 18822a5c89
commit 36856cbff0
8 changed files with 63 additions and 34 deletions
+6 -1
View File
@@ -25,7 +25,6 @@ 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 media_to_videos, get_media_item_ids, scan_videos
from support.subtitlehelpers import get_subtitles_from_metadata, force_utf8
@@ -33,6 +32,7 @@ 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
from support.lib import get_intent
def Start():
@@ -42,6 +42,10 @@ def Start():
# configured cache to be in memory as per https://github.com/Diaoul/subliminal/issues/303
subliminal.region.configure('dogpile.cache.memory')
# clear expired intents
intent = get_intent()
intent.cleanup()
# init defaults; perhaps not the best idea to use ValidatePrefs here, but we'll see
ValidatePrefs()
Log.Debug(config.full_version)
@@ -207,6 +211,7 @@ class SubZeroAgent(object):
def update(self, metadata, media, lang):
Log.Debug("Sub-Zero %s, %s update called" % (config.version, self.agent_type))
intent = get_intent()
if not media:
Log.Error("Called with empty media, something is really wrong with your setup!")
+3 -1
View File
@@ -2,9 +2,9 @@
import types
from support.items import get_kind, get_item_thumb
from subzero import intent
from support.helpers import get_video_display_title
from support.ignore import ignore_list
from support.lib import get_intent
from subzero.constants import ICON
from subzero.func import debouncer
@@ -93,6 +93,8 @@ def set_refresh_menu_state(state_or_media, media_type="movies"):
title = get_video_display_title("show", ep.title, parent_title=media.title, season=int(season), episode=int(episode))
else:
title = get_video_display_title("movie", media.title)
intent = get_intent()
force_refresh = intent.get("force", media_id)
Dict["current_refresh_state"] = u"%sRefreshing %s" % ("Force-" if force_refresh else "", unicode(title))
+6 -2
View File
@@ -6,8 +6,7 @@ import types
import os
from ignore import ignore_list
from helpers import is_recent, get_plex_item_display_title, query_plex
from subzero import intent
from lib import Plex
from lib import Plex, get_intent
from config import config, IGNORE_FN
logger = logging.getLogger(__name__)
@@ -260,11 +259,16 @@ def is_ignored(rating_key, item=None):
def refresh_item(rating_key, force=False, timeout=8000, refresh_kind=None, parent_rating_key=None):
intent = get_intent()
# timeout actually is the time for which the intent will be valid
if force:
Log.Debug("Setting intent for force-refresh of %s to timeout: %s", rating_key, timeout)
intent.set("force", rating_key, timeout=timeout)
# force Dict.Save()
intent.store.save()
refresh = [rating_key]
if refresh_kind == "season":
+17
View File
@@ -1,6 +1,8 @@
# coding=utf-8
import plex
from subzero.intent import TempIntent
from subzero.lib.dict import DictProxy
from subzero.lib.httpfake import PlexPyNativeResponseProxy
@@ -35,3 +37,18 @@ class PlexPyNativeRequestProxy(object):
plex.request.Request = PlexPyNativeRequestProxy
Plex = plex.Plex
class IntentDictStorage(DictProxy):
store = "intent"
def setup_defaults(self):
return {"force": {}}
def get_intent():
"""
use this to get an intent from inside a separate thread
:return:
"""
return TempIntent(store=IntentDictStorage(Dict))
+4 -2
View File
@@ -5,7 +5,7 @@ import subliminal
import helpers
from items import get_item
from subzero import intent
from lib import get_intent
def get_metadata_dict(item, part, add):
@@ -113,8 +113,10 @@ def scan_videos(videos, kind="series"):
"""
ret = {}
for video in videos:
intent = get_intent()
force_refresh = intent.get("force", video["id"], video["series_id"], video["season_id"])
Log.Debug("Determining force-refresh, result: %s" % force_refresh)
Log.Debug("Determining force-refresh (video: %s, series: %s, season: %s), result: %s"
% (video["id"], video["series_id"], video["season_id"], force_refresh))
hints = helpers.get_item_hints(video["title"], kind, series=video["series"] if kind == "series" else None)
video["plex_part"].fps = get_stream_fps(video["plex_part"].streams)
@@ -1,7 +1,5 @@
# coding=utf-8
from intent import intent
OS_PLEX_USERAGENT = 'plexapp.com v9.0'
DEPENDENCY_MODULE_NAMES = ['subliminal', 'subliminal_patch', 'enzyme', 'guessit', 'requests']
+23 -26
View File
@@ -6,25 +6,16 @@ import threading
lock = threading.Lock()
class TempIntent(dict):
class TempIntent(object):
timeout = 1000 # milliseconds
store = None
def __init__(self, timeout=1000):
def __init__(self, timeout=1000, store=None):
self.timeout = timeout
with lock:
self.store = {}
if store is None:
raise NotImplementedError
def __getattr__(self, name):
if name in self:
return self[name]
def __setattr__(self, name, value):
self[name] = value
def __delattr__(self, name):
if name in self:
del self[name]
self.store = store
def get(self, kind, *keys):
with lock:
@@ -37,13 +28,13 @@ class TempIntent(dict):
continue
# valid kind?
if kind in self["store"]:
if kind in self.store:
now = datetime.datetime.now()
# iter all known kinds (previously created)
for known_key in self["store"][kind].keys():
for known_key in self.store[kind].keys():
# may need locking, for now just play it safe
ends = self["store"][kind].get(known_key, None)
ends = self.store[kind].get(known_key, None)
if not ends:
continue
@@ -57,7 +48,7 @@ class TempIntent(dict):
if timed_out:
try:
del self["store"][kind][key]
del self.store[kind][key]
except:
continue
@@ -67,22 +58,28 @@ class TempIntent(dict):
def resolve(self, kind, key):
with lock:
if kind in self["store"] and key in self["store"][kind]:
del self["store"][kind][key]
if kind in self.store and key in self.store[kind]:
del self.store[kind][key]
return True
return False
def set(self, kind, key, timeout=None):
with lock:
if kind not in self["store"]:
self["store"][kind] = {}
self["store"][kind][key] = datetime.datetime.now() + datetime.timedelta(milliseconds=timeout or self.timeout)
if kind not in self.store:
self.store[kind] = {}
self.store[kind][key] = datetime.datetime.now() + datetime.timedelta(milliseconds=timeout or self.timeout)
def has(self, kind, key):
with lock:
if kind not in self["store"]:
if kind not in self.store:
return False
return key in self["store"][kind]
return key in self.store[kind]
def cleanup(self):
now = datetime.datetime.now()
for kind, data in self.store.items():
for key, timeout in data.iteritems():
if now > timeout:
del self.store[kind][key]
self.store.save()
intent = TempIntent()
@@ -10,6 +10,7 @@ class DictProxy(object):
if self.store not in self.Dict or not self.Dict[self.store]:
self.Dict[self.store] = self.setup_defaults()
self.save()
def __getattr__(self, name):
if name in self.Dict[self.store]:
@@ -45,6 +46,9 @@ class DictProxy(object):
def __delitem__(self, key):
del self.Dict[self.store][key]
def save(self):
self.Dict.Save()
def clear(self):
del self.Dict[self.store]
return None