Files
DevOps/Kodi/Lenovo/addons/plugin.video.pseudotv.live/resources/lib/cache.py

115 lines
4.9 KiB
Python

# Copyright (C) 2024 Lunatixz
#
#
# This file is part of PseudoTV Live.
#
# PseudoTV Live is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# PseudoTV Live is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with PseudoTV Live. If not, see <http://www.gnu.org/licenses/>.
#
# -*- coding: utf-8 -*-
from globals import *
from functools import wraps
from fileaccess import FileAccess
try: from simplecache import SimpleCache
except: from simplecache.simplecache import SimpleCache #pycharm stub
def cacheit(expiration=datetime.timedelta(days=MIN_GUIDEDAYS), checksum=ADDON_VERSION, json_data=False):
def internal(method):
@wraps(method)
def wrapper(*args, **kwargs):
method_class = args[0]
cacheName = "%s.%s"%(method_class.__class__.__name__, method.__name__)
for item in args[1:]: cacheName += u".%s"%item
for k, v in list(kwargs.items()): cacheName += u".%s"%(v)
results = method_class.cache.get(cacheName.lower(), checksum, json_data)
if results: return results
return method_class.cache.set(cacheName.lower(), method(*args, **kwargs), checksum, expiration, json_data)
return wrapper
return internal
class Service:
monitor = MONITOR()
def _interrupt(self) -> bool:
return xbmcgui.Window(10000).getProperty('%s.pendingInterrupt'%(ADDON_ID)) == "true"
def _suspend(self) -> bool:
return xbmcgui.Window(10000).getProperty('%s.suspendActivity'%(ADDON_ID)) == "true"
class Cache:
lock = Lock()
cache = SimpleCache()
service = Service()
@contextmanager
def cacheLocker(self, wait=0.0001): #simplecache is not thread safe, threadlock not avoiding collisions? Hack/Lazy avoidance.
while not self.service.monitor.abortRequested():
if self.service.monitor.waitForAbort(wait) or self.service._interrupt(): break
elif xbmcgui.Window(10000).getProperty('%s.cacheLocker'%(ADDON_ID)) != 'true': break
xbmcgui.Window(10000).setProperty('%s.cacheLocker'%(ADDON_ID),'true')
try: yield
finally:
xbmcgui.Window(10000).setProperty('%s.cacheLocker'%(ADDON_ID),'false')
def __init__(self, mem_cache=False, is_json=False, disable_cache=False):
self.cache.enable_mem_cache = mem_cache
self.cache.data_is_json = is_json
self.disable_cache = (disable_cache | REAL_SETTINGS.getSettingBool('Disable_Cache'))
def log(self, msg, level=xbmc.LOGDEBUG):
log('%s: %s'%(self.__class__.__name__,msg),level)
def getname(self, name):
if not name.startswith(ADDON_ID): name = '%s.%s'%(ADDON_ID,name)
return name.lower()
def set(self, name, value, checksum=ADDON_VERSION, expiration=datetime.timedelta(minutes=15), json_data=False):
if not self.disable_cache or (not isinstance(value,(bool,list,dict)) and not value):
with self.cacheLocker():
self.log('set, name = %s, value = %s'%(self.getname(name),'%s...'%(str(value)[:128])))
self.cache.set(self.getname(name),value,checksum,expiration,json_data)
return value
def get(self, name, checksum=ADDON_VERSION, json_data=False):
if not self.disable_cache:
with self.cacheLocker():
try:
value = self.cache.get(self.getname(name),checksum,json_data)
self.log('get, name = %s, value = %s'%(self.getname(name),'%s...'%(str(value)[:128])))
return value
except Exception as e:
self.log("get, name = %s failed! simplecacheDB %s"%(self.getname(name),e), xbmc.LOGERROR)
self.clear(name)
def clear(self, name, wait=15):
import sqlite3
self.log('clear, name = %s'%self.getname(name))
sc = FileAccess.translatePath(xbmcaddon.Addon(id='script.module.simplecache').getAddonInfo('profile'))
dbpath = os.path.join(sc, 'simplecache.db')
try:
connection = sqlite3.connect(dbpath, timeout=wait, isolation_level=None)
connection.execute('DELETE FROM simplecache WHERE id LIKE ?', (self.getname(name) + '%',))
connection.commit()
except sqlite3.Error as e: self.log('clear, failed! %s' % e, xbmc.LOGERROR)
finally:
if connection:
connection.close()
del connection
del sqlite3