mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-07-10 23:11:47 +08:00
Merge pull request #3751 from InfinityPacer/feature/cache
This commit is contained in:
@@ -1,7 +1,6 @@
|
|||||||
import inspect
|
import inspect
|
||||||
import os
|
import os
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from collections import defaultdict
|
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from typing import Any, Dict, Optional
|
from typing import Any, Dict, Optional
|
||||||
|
|
||||||
@@ -83,8 +82,15 @@ class CacheToolsBackend(CacheBackend):
|
|||||||
"""
|
"""
|
||||||
self.maxsize = maxsize
|
self.maxsize = maxsize
|
||||||
self.ttl = ttl
|
self.ttl = ttl
|
||||||
# 存储各个 region 的缓存实例,region -> {key -> TTLCache}
|
# 存储各个 region 的缓存实例,region -> TTLCache
|
||||||
self._region_caches: Dict[str, Dict[str, TTLCache]] = defaultdict(dict)
|
self._region_caches: Dict[str, TTLCache] = {}
|
||||||
|
|
||||||
|
def __get_region_cache(self, region: str) -> Optional[TTLCache]:
|
||||||
|
"""
|
||||||
|
获取指定区域的缓存实例,如果不存在则返回 None
|
||||||
|
"""
|
||||||
|
region = self.get_region(region)
|
||||||
|
return self._region_caches.get(region)
|
||||||
|
|
||||||
def set(self, key: str, value: Any, ttl: int = None, region: str = DEFAULT_CACHE_REGION, **kwargs) -> None:
|
def set(self, key: str, value: Any, ttl: int = None, region: str = DEFAULT_CACHE_REGION, **kwargs) -> None:
|
||||||
"""
|
"""
|
||||||
@@ -100,13 +106,9 @@ class CacheToolsBackend(CacheBackend):
|
|||||||
maxsize = kwargs.get("maxsize", self.maxsize)
|
maxsize = kwargs.get("maxsize", self.maxsize)
|
||||||
region = self.get_region(region)
|
region = self.get_region(region)
|
||||||
# 如果该 key 尚未有缓存实例,则创建一个新的 TTLCache 实例
|
# 如果该 key 尚未有缓存实例,则创建一个新的 TTLCache 实例
|
||||||
region_cache = self._region_caches[region]
|
region_cache = self._region_caches.setdefault(region, TTLCache(maxsize=maxsize, ttl=ttl))
|
||||||
if key not in region_cache:
|
|
||||||
region_cache[key] = TTLCache(maxsize=maxsize, ttl=ttl)
|
|
||||||
# 为每个 key 获取独立的缓存实例
|
|
||||||
cache = region_cache[key]
|
|
||||||
# 设置缓存值
|
# 设置缓存值
|
||||||
cache[key] = value
|
region_cache[key] = value
|
||||||
|
|
||||||
def get(self, key: str, region: str = DEFAULT_CACHE_REGION) -> Any:
|
def get(self, key: str, region: str = DEFAULT_CACHE_REGION) -> Any:
|
||||||
"""
|
"""
|
||||||
@@ -116,13 +118,10 @@ class CacheToolsBackend(CacheBackend):
|
|||||||
:param region: 缓存的区
|
:param region: 缓存的区
|
||||||
:return: 返回缓存的值,如果缓存不存在返回 None
|
:return: 返回缓存的值,如果缓存不存在返回 None
|
||||||
"""
|
"""
|
||||||
region = self.get_region(region)
|
region_cache = self.__get_region_cache(region)
|
||||||
region_cache = self._region_caches[region]
|
if region_cache is None:
|
||||||
if key not in region_cache:
|
|
||||||
return None
|
return None
|
||||||
# 获取缓存实例并返回缓存值
|
return region_cache.get(key)
|
||||||
cache = region_cache[key]
|
|
||||||
return cache.get(key)
|
|
||||||
|
|
||||||
def delete(self, key: str, region: str = DEFAULT_CACHE_REGION) -> None:
|
def delete(self, key: str, region: str = DEFAULT_CACHE_REGION) -> None:
|
||||||
"""
|
"""
|
||||||
@@ -131,13 +130,10 @@ class CacheToolsBackend(CacheBackend):
|
|||||||
:param key: 缓存的键
|
:param key: 缓存的键
|
||||||
:param region: 缓存的区
|
:param region: 缓存的区
|
||||||
"""
|
"""
|
||||||
region = self.get_region(region)
|
region_cache = self.__get_region_cache(region)
|
||||||
region_cache = self._region_caches[region]
|
if region_cache is None:
|
||||||
if key not in region_cache:
|
|
||||||
return None
|
return None
|
||||||
# 获取缓存实例并删除指定的缓存
|
del region_cache[key]
|
||||||
cache = region_cache[key]
|
|
||||||
del cache[key]
|
|
||||||
|
|
||||||
def clear(self, region: Optional[str] = None) -> None:
|
def clear(self, region: Optional[str] = None) -> None:
|
||||||
"""
|
"""
|
||||||
@@ -146,14 +142,14 @@ class CacheToolsBackend(CacheBackend):
|
|||||||
:param region: 缓存的区
|
:param region: 缓存的区
|
||||||
"""
|
"""
|
||||||
if region:
|
if region:
|
||||||
region = self.get_region(region)
|
# 清理指定缓存区
|
||||||
region_cache = self._region_caches[region]
|
region_cache = self.__get_region_cache(region)
|
||||||
for cache in region_cache.values():
|
if region_cache:
|
||||||
cache.clear()
|
region_cache.clear()
|
||||||
else:
|
else:
|
||||||
|
# 清除所有区域的缓存
|
||||||
for region_cache in self._region_caches.values():
|
for region_cache in self._region_caches.values():
|
||||||
for cache in region_cache.values():
|
region_cache.clear()
|
||||||
cache.clear()
|
|
||||||
|
|
||||||
|
|
||||||
class RedisBackend(CacheBackend):
|
class RedisBackend(CacheBackend):
|
||||||
@@ -248,7 +244,7 @@ def get_cache_backend(maxsize: int = 1000, ttl: int = 1800) -> CacheBackend:
|
|||||||
return CacheToolsBackend(maxsize=maxsize, ttl=ttl)
|
return CacheToolsBackend(maxsize=maxsize, ttl=ttl)
|
||||||
|
|
||||||
|
|
||||||
def cached(region: str = DEFAULT_CACHE_REGION, maxsize: int = 1000, ttl: int = 1800,
|
def cached(region: Optional[str] = None, maxsize: int = 1000, ttl: int = 1800,
|
||||||
skip_none: bool = True, skip_empty: bool = False):
|
skip_none: bool = True, skip_empty: bool = False):
|
||||||
"""
|
"""
|
||||||
自定义缓存装饰器,支持为每个 key 动态传递 maxsize 和 ttl
|
自定义缓存装饰器,支持为每个 key 动态传递 maxsize 和 ttl
|
||||||
@@ -294,16 +290,21 @@ def cached(region: str = DEFAULT_CACHE_REGION, maxsize: int = 1000, ttl: int = 1
|
|||||||
elif value.default is not inspect.Parameter.empty:
|
elif value.default is not inspect.Parameter.empty:
|
||||||
# 没有传递参数时使用默认值
|
# 没有传递参数时使用默认值
|
||||||
resolved_kwargs[param] = value.default
|
resolved_kwargs[param] = value.default
|
||||||
# 构造缓存键
|
# 构造缓存键,忽略实例(self 或 cls)
|
||||||
return f"{func.__name__}_{hashkey(*args, **resolved_kwargs)}"
|
params_to_hash = args[1:] if len(args) > 1 else []
|
||||||
|
return f"{func.__name__}_{hashkey(*params_to_hash, **resolved_kwargs)}"
|
||||||
|
|
||||||
def decorator(func):
|
def decorator(func):
|
||||||
|
|
||||||
|
# 获取缓存区
|
||||||
|
cache_region = region if region is not None else f"{func.__module__}.{func.__name__}"
|
||||||
|
|
||||||
@wraps(func)
|
@wraps(func)
|
||||||
def wrapper(*args, **kwargs):
|
def wrapper(*args, **kwargs):
|
||||||
# 获取缓存键
|
# 获取缓存键
|
||||||
cache_key = get_cache_key(func, args, kwargs)
|
cache_key = get_cache_key(func, args, kwargs)
|
||||||
# 尝试获取缓存
|
# 尝试获取缓存
|
||||||
cached_value = cache_backend.get(cache_key, region=region)
|
cached_value = cache_backend.get(cache_key, region=cache_region)
|
||||||
if should_cache(cached_value):
|
if should_cache(cached_value):
|
||||||
return cached_value
|
return cached_value
|
||||||
# 执行函数并缓存结果
|
# 执行函数并缓存结果
|
||||||
@@ -312,9 +313,19 @@ def cached(region: str = DEFAULT_CACHE_REGION, maxsize: int = 1000, ttl: int = 1
|
|||||||
if not should_cache(result):
|
if not should_cache(result):
|
||||||
return result
|
return result
|
||||||
# 设置缓存(如果有传入的 maxsize 和 ttl,则覆盖默认值)
|
# 设置缓存(如果有传入的 maxsize 和 ttl,则覆盖默认值)
|
||||||
cache_backend.set(cache_key, result, ttl=ttl, maxsize=maxsize, region=region)
|
cache_backend.set(cache_key, result, ttl=ttl, maxsize=maxsize, region=cache_region)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def cache_clear():
|
||||||
|
"""
|
||||||
|
清理缓存区
|
||||||
|
"""
|
||||||
|
# 清理缓存区
|
||||||
|
cache_backend.clear(region=cache_region)
|
||||||
|
print(f"{cache_region} region cache is cleared")
|
||||||
|
|
||||||
|
wrapper.cache_region = cache_region
|
||||||
|
wrapper.cache_clear = cache_clear
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
return decorator
|
return decorator
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from ..tmdb import TMDb
|
|||||||
class Trending(TMDb):
|
class Trending(TMDb):
|
||||||
_urls = {"trending": "/trending/%s/%s"}
|
_urls = {"trending": "/trending/%s/%s"}
|
||||||
|
|
||||||
@cached(maxsize=1, ttl=43200)
|
@cached(maxsize=1024, ttl=43200)
|
||||||
def _trending(self, media_type="all", time_window="day", page=1):
|
def _trending(self, media_type="all", time_window="day", page=1):
|
||||||
"""
|
"""
|
||||||
Get trending, TTLCache 12 hours
|
Get trending, TTLCache 12 hours
|
||||||
|
|||||||
@@ -549,7 +549,6 @@ class Scheduler(metaclass=Singleton):
|
|||||||
"""
|
"""
|
||||||
清理缓存
|
清理缓存
|
||||||
"""
|
"""
|
||||||
TorrentsChain().clear_cache()
|
|
||||||
SchedulerChain().clear_cache()
|
SchedulerChain().clear_cache()
|
||||||
|
|
||||||
def user_auth(self):
|
def user_auth(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user