mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-05 15:38:19 +08:00
feat(cache): add cache region support
This commit is contained in:
+17
-55
@@ -1,18 +1,15 @@
|
|||||||
import inspect
|
|
||||||
import io
|
import io
|
||||||
import tempfile
|
import tempfile
|
||||||
from functools import wraps
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Callable, List
|
from typing import Any, List
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from cachetools import TTLCache
|
|
||||||
from cachetools.keys import hashkey
|
|
||||||
|
|
||||||
from app.chain import ChainBase
|
from app.chain import ChainBase
|
||||||
from app.chain.bangumi import BangumiChain
|
from app.chain.bangumi import BangumiChain
|
||||||
from app.chain.douban import DoubanChain
|
from app.chain.douban import DoubanChain
|
||||||
from app.chain.tmdb import TmdbChain
|
from app.chain.tmdb import TmdbChain
|
||||||
|
from app.core.cache import cache_backend, cached
|
||||||
from app.core.config import settings, global_vars
|
from app.core.config import settings, global_vars
|
||||||
from app.log import logger
|
from app.log import logger
|
||||||
from app.schemas import MediaType
|
from app.schemas import MediaType
|
||||||
@@ -23,42 +20,7 @@ from app.utils.singleton import Singleton
|
|||||||
|
|
||||||
# 推荐相关的专用缓存
|
# 推荐相关的专用缓存
|
||||||
recommend_ttl = 24 * 3600
|
recommend_ttl = 24 * 3600
|
||||||
recommend_cache = TTLCache(maxsize=256, ttl=recommend_ttl)
|
recommend_cache_region = "recommend"
|
||||||
|
|
||||||
|
|
||||||
# 推荐缓存装饰器,避免偶发网络获取数据为空时,页面由于缓存为空长时间渲染异常问题
|
|
||||||
def cached_with_empty_check(func: Callable):
|
|
||||||
"""
|
|
||||||
缓存装饰器,用于缓存函数的返回结果,仅在结果非空时进行缓存
|
|
||||||
|
|
||||||
:param func: 被装饰的函数
|
|
||||||
:return: 包装后的函数
|
|
||||||
"""
|
|
||||||
|
|
||||||
@wraps(func)
|
|
||||||
def wrapper(*args, **kwargs):
|
|
||||||
signature = inspect.signature(func)
|
|
||||||
resolved_kwargs = {}
|
|
||||||
# 获取默认值并结合传递的参数(如果有)
|
|
||||||
for param, value in signature.parameters.items():
|
|
||||||
if param in kwargs:
|
|
||||||
# 使用显式传递的参数
|
|
||||||
resolved_kwargs[param] = kwargs[param]
|
|
||||||
elif value.default is not inspect.Parameter.empty:
|
|
||||||
# 没有传递参数时使用默认值
|
|
||||||
resolved_kwargs[param] = value.default
|
|
||||||
# 使用 cachetools 缓存,构造缓存键
|
|
||||||
cache_key = f"{func.__name__}_{hashkey(*args, **resolved_kwargs)}"
|
|
||||||
if cache_key in recommend_cache:
|
|
||||||
return recommend_cache[cache_key]
|
|
||||||
result = func(*args, **kwargs)
|
|
||||||
# 如果返回值为空,则不缓存
|
|
||||||
if result in [None, [], {}]:
|
|
||||||
return result
|
|
||||||
recommend_cache[cache_key] = result
|
|
||||||
return result
|
|
||||||
|
|
||||||
return wrapper
|
|
||||||
|
|
||||||
|
|
||||||
class RecommendChain(ChainBase, metaclass=Singleton):
|
class RecommendChain(ChainBase, metaclass=Singleton):
|
||||||
@@ -78,7 +40,7 @@ class RecommendChain(ChainBase, metaclass=Singleton):
|
|||||||
刷新推荐
|
刷新推荐
|
||||||
"""
|
"""
|
||||||
logger.debug("Starting to refresh Recommend data.")
|
logger.debug("Starting to refresh Recommend data.")
|
||||||
recommend_cache.clear()
|
cache_backend.clear(region=recommend_cache_region)
|
||||||
logger.debug("Recommend Cache has been cleared.")
|
logger.debug("Recommend Cache has been cleared.")
|
||||||
|
|
||||||
# 推荐来源方法
|
# 推荐来源方法
|
||||||
@@ -194,7 +156,7 @@ class RecommendChain(ChainBase, metaclass=Singleton):
|
|||||||
logger.debug(f"Failed to write cache file {cache_path} for URL {url}: {e}")
|
logger.debug(f"Failed to write cache file {cache_path} for URL {url}: {e}")
|
||||||
|
|
||||||
@log_execution_time(logger=logger)
|
@log_execution_time(logger=logger)
|
||||||
@cached_with_empty_check
|
@cached(maxsize=16, ttl=recommend_ttl, region=recommend_cache_region)
|
||||||
def tmdb_movies(self, sort_by: str = "popularity.desc", with_genres: str = "",
|
def tmdb_movies(self, sort_by: str = "popularity.desc", with_genres: str = "",
|
||||||
with_original_language: str = "", page: int = 1) -> Any:
|
with_original_language: str = "", page: int = 1) -> Any:
|
||||||
"""
|
"""
|
||||||
@@ -208,7 +170,7 @@ class RecommendChain(ChainBase, metaclass=Singleton):
|
|||||||
return [movie.to_dict() for movie in movies] if movies else []
|
return [movie.to_dict() for movie in movies] if movies else []
|
||||||
|
|
||||||
@log_execution_time(logger=logger)
|
@log_execution_time(logger=logger)
|
||||||
@cached_with_empty_check
|
@cached(maxsize=16, ttl=recommend_ttl, region=recommend_cache_region)
|
||||||
def tmdb_tvs(self, sort_by: str = "popularity.desc", with_genres: str = "",
|
def tmdb_tvs(self, sort_by: str = "popularity.desc", with_genres: str = "",
|
||||||
with_original_language: str = "zh|en|ja|ko", page: int = 1) -> Any:
|
with_original_language: str = "zh|en|ja|ko", page: int = 1) -> Any:
|
||||||
"""
|
"""
|
||||||
@@ -222,7 +184,7 @@ class RecommendChain(ChainBase, metaclass=Singleton):
|
|||||||
return [tv.to_dict() for tv in tvs] if tvs else []
|
return [tv.to_dict() for tv in tvs] if tvs else []
|
||||||
|
|
||||||
@log_execution_time(logger=logger)
|
@log_execution_time(logger=logger)
|
||||||
@cached_with_empty_check
|
@cached(maxsize=16, ttl=recommend_ttl, region=recommend_cache_region)
|
||||||
def tmdb_trending(self, page: int = 1) -> Any:
|
def tmdb_trending(self, page: int = 1) -> Any:
|
||||||
"""
|
"""
|
||||||
TMDB流行趋势
|
TMDB流行趋势
|
||||||
@@ -231,7 +193,7 @@ class RecommendChain(ChainBase, metaclass=Singleton):
|
|||||||
return [info.to_dict() for info in infos] if infos else []
|
return [info.to_dict() for info in infos] if infos else []
|
||||||
|
|
||||||
@log_execution_time(logger=logger)
|
@log_execution_time(logger=logger)
|
||||||
@cached_with_empty_check
|
@cached(maxsize=16, ttl=recommend_ttl, region=recommend_cache_region)
|
||||||
def bangumi_calendar(self, page: int = 1, count: int = 30) -> Any:
|
def bangumi_calendar(self, page: int = 1, count: int = 30) -> Any:
|
||||||
"""
|
"""
|
||||||
Bangumi每日放送
|
Bangumi每日放送
|
||||||
@@ -240,7 +202,7 @@ class RecommendChain(ChainBase, metaclass=Singleton):
|
|||||||
return [media.to_dict() for media in medias[(page - 1) * count: page * count]] if medias else []
|
return [media.to_dict() for media in medias[(page - 1) * count: page * count]] if medias else []
|
||||||
|
|
||||||
@log_execution_time(logger=logger)
|
@log_execution_time(logger=logger)
|
||||||
@cached_with_empty_check
|
@cached(maxsize=16, ttl=recommend_ttl, region=recommend_cache_region)
|
||||||
def douban_movie_showing(self, page: int = 1, count: int = 30) -> Any:
|
def douban_movie_showing(self, page: int = 1, count: int = 30) -> Any:
|
||||||
"""
|
"""
|
||||||
豆瓣正在热映
|
豆瓣正在热映
|
||||||
@@ -249,7 +211,7 @@ class RecommendChain(ChainBase, metaclass=Singleton):
|
|||||||
return [media.to_dict() for media in movies] if movies else []
|
return [media.to_dict() for media in movies] if movies else []
|
||||||
|
|
||||||
@log_execution_time(logger=logger)
|
@log_execution_time(logger=logger)
|
||||||
@cached_with_empty_check
|
@cached(maxsize=16, ttl=recommend_ttl, region=recommend_cache_region)
|
||||||
def douban_movies(self, sort: str = "R", tags: str = "", page: int = 1, count: int = 30) -> Any:
|
def douban_movies(self, sort: str = "R", tags: str = "", page: int = 1, count: int = 30) -> Any:
|
||||||
"""
|
"""
|
||||||
豆瓣最新电影
|
豆瓣最新电影
|
||||||
@@ -259,7 +221,7 @@ class RecommendChain(ChainBase, metaclass=Singleton):
|
|||||||
return [media.to_dict() for media in movies] if movies else []
|
return [media.to_dict() for media in movies] if movies else []
|
||||||
|
|
||||||
@log_execution_time(logger=logger)
|
@log_execution_time(logger=logger)
|
||||||
@cached_with_empty_check
|
@cached(maxsize=16, ttl=recommend_ttl, region=recommend_cache_region)
|
||||||
def douban_tvs(self, sort: str = "R", tags: str = "", page: int = 1, count: int = 30) -> Any:
|
def douban_tvs(self, sort: str = "R", tags: str = "", page: int = 1, count: int = 30) -> Any:
|
||||||
"""
|
"""
|
||||||
豆瓣最新电视剧
|
豆瓣最新电视剧
|
||||||
@@ -269,7 +231,7 @@ class RecommendChain(ChainBase, metaclass=Singleton):
|
|||||||
return [media.to_dict() for media in tvs] if tvs else []
|
return [media.to_dict() for media in tvs] if tvs else []
|
||||||
|
|
||||||
@log_execution_time(logger=logger)
|
@log_execution_time(logger=logger)
|
||||||
@cached_with_empty_check
|
@cached(maxsize=16, ttl=recommend_ttl, region=recommend_cache_region)
|
||||||
def douban_movie_top250(self, page: int = 1, count: int = 30) -> Any:
|
def douban_movie_top250(self, page: int = 1, count: int = 30) -> Any:
|
||||||
"""
|
"""
|
||||||
豆瓣电影TOP250
|
豆瓣电影TOP250
|
||||||
@@ -278,7 +240,7 @@ class RecommendChain(ChainBase, metaclass=Singleton):
|
|||||||
return [media.to_dict() for media in movies] if movies else []
|
return [media.to_dict() for media in movies] if movies else []
|
||||||
|
|
||||||
@log_execution_time(logger=logger)
|
@log_execution_time(logger=logger)
|
||||||
@cached_with_empty_check
|
@cached(maxsize=16, ttl=recommend_ttl, region=recommend_cache_region)
|
||||||
def douban_tv_weekly_chinese(self, page: int = 1, count: int = 30) -> Any:
|
def douban_tv_weekly_chinese(self, page: int = 1, count: int = 30) -> Any:
|
||||||
"""
|
"""
|
||||||
豆瓣国产剧集榜
|
豆瓣国产剧集榜
|
||||||
@@ -287,7 +249,7 @@ class RecommendChain(ChainBase, metaclass=Singleton):
|
|||||||
return [media.to_dict() for media in tvs] if tvs else []
|
return [media.to_dict() for media in tvs] if tvs else []
|
||||||
|
|
||||||
@log_execution_time(logger=logger)
|
@log_execution_time(logger=logger)
|
||||||
@cached_with_empty_check
|
@cached(maxsize=16, ttl=recommend_ttl, region=recommend_cache_region)
|
||||||
def douban_tv_weekly_global(self, page: int = 1, count: int = 30) -> Any:
|
def douban_tv_weekly_global(self, page: int = 1, count: int = 30) -> Any:
|
||||||
"""
|
"""
|
||||||
豆瓣全球剧集榜
|
豆瓣全球剧集榜
|
||||||
@@ -296,7 +258,7 @@ class RecommendChain(ChainBase, metaclass=Singleton):
|
|||||||
return [media.to_dict() for media in tvs] if tvs else []
|
return [media.to_dict() for media in tvs] if tvs else []
|
||||||
|
|
||||||
@log_execution_time(logger=logger)
|
@log_execution_time(logger=logger)
|
||||||
@cached_with_empty_check
|
@cached(maxsize=16, ttl=recommend_ttl, region=recommend_cache_region)
|
||||||
def douban_tv_animation(self, page: int = 1, count: int = 30) -> Any:
|
def douban_tv_animation(self, page: int = 1, count: int = 30) -> Any:
|
||||||
"""
|
"""
|
||||||
豆瓣热门动漫
|
豆瓣热门动漫
|
||||||
@@ -305,7 +267,7 @@ class RecommendChain(ChainBase, metaclass=Singleton):
|
|||||||
return [media.to_dict() for media in tvs] if tvs else []
|
return [media.to_dict() for media in tvs] if tvs else []
|
||||||
|
|
||||||
@log_execution_time(logger=logger)
|
@log_execution_time(logger=logger)
|
||||||
@cached_with_empty_check
|
@cached(maxsize=16, ttl=recommend_ttl, region=recommend_cache_region)
|
||||||
def douban_movie_hot(self, page: int = 1, count: int = 30) -> Any:
|
def douban_movie_hot(self, page: int = 1, count: int = 30) -> Any:
|
||||||
"""
|
"""
|
||||||
豆瓣热门电影
|
豆瓣热门电影
|
||||||
@@ -314,7 +276,7 @@ class RecommendChain(ChainBase, metaclass=Singleton):
|
|||||||
return [media.to_dict() for media in movies] if movies else []
|
return [media.to_dict() for media in movies] if movies else []
|
||||||
|
|
||||||
@log_execution_time(logger=logger)
|
@log_execution_time(logger=logger)
|
||||||
@cached_with_empty_check
|
@cached(maxsize=16, ttl=recommend_ttl, region=recommend_cache_region)
|
||||||
def douban_tv_hot(self, page: int = 1, count: int = 30) -> Any:
|
def douban_tv_hot(self, page: int = 1, count: int = 30) -> Any:
|
||||||
"""
|
"""
|
||||||
豆瓣热门电视剧
|
豆瓣热门电视剧
|
||||||
|
|||||||
+19
-15
@@ -9,6 +9,9 @@ import redis
|
|||||||
from cachetools import TTLCache
|
from cachetools import TTLCache
|
||||||
from cachetools.keys import hashkey
|
from cachetools.keys import hashkey
|
||||||
|
|
||||||
|
# 默认缓存区
|
||||||
|
DEFAULT_CACHE_REGION = "DEFAULT"
|
||||||
|
|
||||||
|
|
||||||
class CacheBackend(ABC):
|
class CacheBackend(ABC):
|
||||||
"""
|
"""
|
||||||
@@ -16,7 +19,7 @@ class CacheBackend(ABC):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def set(self, key: str, value: Any, ttl: int, region: str = "default", **kwargs) -> None:
|
def set(self, key: str, value: Any, ttl: int, region: str = DEFAULT_CACHE_REGION, **kwargs) -> None:
|
||||||
"""
|
"""
|
||||||
设置缓存
|
设置缓存
|
||||||
|
|
||||||
@@ -29,7 +32,7 @@ class CacheBackend(ABC):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def get(self, key: str, region: str = "default") -> Any:
|
def get(self, key: str, region: str = DEFAULT_CACHE_REGION) -> Any:
|
||||||
"""
|
"""
|
||||||
获取缓存
|
获取缓存
|
||||||
|
|
||||||
@@ -40,7 +43,7 @@ class CacheBackend(ABC):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def delete(self, key: str, region: str = "default") -> None:
|
def delete(self, key: str, region: str = DEFAULT_CACHE_REGION) -> None:
|
||||||
"""
|
"""
|
||||||
删除缓存
|
删除缓存
|
||||||
|
|
||||||
@@ -59,7 +62,7 @@ class CacheBackend(ABC):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_region(region: str = "default"):
|
def get_region(region: str = DEFAULT_CACHE_REGION):
|
||||||
"""
|
"""
|
||||||
获取缓存的区
|
获取缓存的区
|
||||||
"""
|
"""
|
||||||
@@ -83,7 +86,7 @@ class CacheToolsBackend(CacheBackend):
|
|||||||
# 存储各个 region 的缓存实例,region -> {key -> TTLCache}
|
# 存储各个 region 的缓存实例,region -> {key -> TTLCache}
|
||||||
self._region_caches: Dict[str, Dict[str, TTLCache]] = defaultdict(dict)
|
self._region_caches: Dict[str, Dict[str, TTLCache]] = defaultdict(dict)
|
||||||
|
|
||||||
def set(self, key: str, value: Any, ttl: int = None, region: str = "default", **kwargs) -> None:
|
def set(self, key: str, value: Any, ttl: int = None, region: str = DEFAULT_CACHE_REGION, **kwargs) -> None:
|
||||||
"""
|
"""
|
||||||
设置缓存值支持每个 key 独立配置 TTL 和 Maxsize
|
设置缓存值支持每个 key 独立配置 TTL 和 Maxsize
|
||||||
|
|
||||||
@@ -105,7 +108,7 @@ class CacheToolsBackend(CacheBackend):
|
|||||||
# 设置缓存值
|
# 设置缓存值
|
||||||
cache[key] = value
|
cache[key] = value
|
||||||
|
|
||||||
def get(self, key: str, region: str = "default") -> Any:
|
def get(self, key: str, region: str = DEFAULT_CACHE_REGION) -> Any:
|
||||||
"""
|
"""
|
||||||
获取缓存的值
|
获取缓存的值
|
||||||
|
|
||||||
@@ -121,7 +124,7 @@ class CacheToolsBackend(CacheBackend):
|
|||||||
cache = region_cache[key]
|
cache = region_cache[key]
|
||||||
return cache.get(key)
|
return cache.get(key)
|
||||||
|
|
||||||
def delete(self, key: str, region: str = "default") -> None:
|
def delete(self, key: str, region: str = DEFAULT_CACHE_REGION) -> None:
|
||||||
"""
|
"""
|
||||||
删除缓存
|
删除缓存
|
||||||
|
|
||||||
@@ -143,6 +146,7 @@ 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._region_caches[region]
|
||||||
for cache in region_cache.values():
|
for cache in region_cache.values():
|
||||||
cache.clear()
|
cache.clear()
|
||||||
@@ -176,7 +180,7 @@ class RedisBackend(CacheBackend):
|
|||||||
# 使用 region 作为缓存键的一部分
|
# 使用 region 作为缓存键的一部分
|
||||||
return f"region:{region}:key:{key}"
|
return f"region:{region}:key:{key}"
|
||||||
|
|
||||||
def set(self, key: str, value: Any, ttl: int = None, region: str = "default", **kwargs) -> None:
|
def set(self, key: str, value: Any, ttl: int = None, region: str = DEFAULT_CACHE_REGION, **kwargs) -> None:
|
||||||
"""
|
"""
|
||||||
设置缓存
|
设置缓存
|
||||||
|
|
||||||
@@ -190,7 +194,7 @@ class RedisBackend(CacheBackend):
|
|||||||
redis_key = self.get_redis_key(region, key)
|
redis_key = self.get_redis_key(region, key)
|
||||||
self.client.setex(redis_key, ttl, value)
|
self.client.setex(redis_key, ttl, value)
|
||||||
|
|
||||||
def get(self, key: str, region: str = "default") -> Any:
|
def get(self, key: str, region: str = DEFAULT_CACHE_REGION) -> Any:
|
||||||
"""
|
"""
|
||||||
获取缓存的值
|
获取缓存的值
|
||||||
|
|
||||||
@@ -202,7 +206,7 @@ class RedisBackend(CacheBackend):
|
|||||||
value = self.client.get(redis_key)
|
value = self.client.get(redis_key)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def delete(self, key: str, region: str = "default") -> None:
|
def delete(self, key: str, region: str = DEFAULT_CACHE_REGION) -> None:
|
||||||
"""
|
"""
|
||||||
删除缓存
|
删除缓存
|
||||||
|
|
||||||
@@ -244,11 +248,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,
|
||||||
cache_backend = get_cache_backend()
|
|
||||||
|
|
||||||
|
|
||||||
def cached(region: str = "default", maxsize: int = 1000, ttl: int = 1800,
|
|
||||||
skip_none: bool = True, skip_empty: bool = True):
|
skip_none: bool = True, skip_empty: bool = True):
|
||||||
"""
|
"""
|
||||||
自定义缓存装饰器,支持为每个 key 动态传递 maxsize 和 ttl
|
自定义缓存装饰器,支持为每个 key 动态传递 maxsize 和 ttl
|
||||||
@@ -318,3 +318,7 @@ def cached(region: str = "default", maxsize: int = 1000, ttl: int = 1800,
|
|||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
|
# 缓存后端实例
|
||||||
|
cache_backend = get_cache_backend()
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
from threading import Thread
|
from threading import Thread
|
||||||
from typing import List, Tuple
|
from typing import List, Tuple
|
||||||
|
|
||||||
from cachetools import TTLCache, cached
|
from app.core.cache import cached, cache_backend
|
||||||
|
|
||||||
from app.core.config import settings
|
from app.core.config import settings
|
||||||
from app.db.subscribe_oper import SubscribeOper
|
from app.db.subscribe_oper import SubscribeOper
|
||||||
from app.db.systemconfig_oper import SystemConfigOper
|
from app.db.systemconfig_oper import SystemConfigOper
|
||||||
@@ -31,7 +30,7 @@ class SubscribeHelper(metaclass=Singleton):
|
|||||||
|
|
||||||
_sub_fork = f"{settings.MP_SERVER_HOST}/subscribe/fork/%s"
|
_sub_fork = f"{settings.MP_SERVER_HOST}/subscribe/fork/%s"
|
||||||
|
|
||||||
_shares_cache = TTLCache(maxsize=20, ttl=1800)
|
_shares_cache_region = "subscribe_share"
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.systemconfig = SystemConfigOper()
|
self.systemconfig = SystemConfigOper()
|
||||||
@@ -41,7 +40,7 @@ class SubscribeHelper(metaclass=Singleton):
|
|||||||
if self.sub_report():
|
if self.sub_report():
|
||||||
self.systemconfig.set(SystemConfigKey.SubscribeReport, "1")
|
self.systemconfig.set(SystemConfigKey.SubscribeReport, "1")
|
||||||
|
|
||||||
@cached(cache=TTLCache(maxsize=20, ttl=1800))
|
@cached(maxsize=20, ttl=1800)
|
||||||
def get_statistic(self, stype: str, page: int = 1, count: int = 30) -> List[dict]:
|
def get_statistic(self, stype: str, page: int = 1, count: int = 30) -> List[dict]:
|
||||||
"""
|
"""
|
||||||
获取订阅统计数据
|
获取订阅统计数据
|
||||||
@@ -129,6 +128,7 @@ class SubscribeHelper(metaclass=Singleton):
|
|||||||
return False, "订阅不存在"
|
return False, "订阅不存在"
|
||||||
subscribe_dict = subscribe.to_dict()
|
subscribe_dict = subscribe.to_dict()
|
||||||
subscribe_dict.pop("id")
|
subscribe_dict.pop("id")
|
||||||
|
cache_backend.clear(region=self._shares_cache_region)
|
||||||
res = RequestUtils(proxies=settings.PROXY, content_type="application/json",
|
res = RequestUtils(proxies=settings.PROXY, content_type="application/json",
|
||||||
timeout=10).post(self._sub_share,
|
timeout=10).post(self._sub_share,
|
||||||
json={
|
json={
|
||||||
@@ -142,7 +142,7 @@ class SubscribeHelper(metaclass=Singleton):
|
|||||||
return False, "连接MoviePilot服务器失败"
|
return False, "连接MoviePilot服务器失败"
|
||||||
if res.ok:
|
if res.ok:
|
||||||
# 清除 get_shares 的缓存,以便实时看到结果
|
# 清除 get_shares 的缓存,以便实时看到结果
|
||||||
self._shares_cache.clear()
|
cache_backend.clear(region=self._shares_cache_region)
|
||||||
return True, ""
|
return True, ""
|
||||||
else:
|
else:
|
||||||
return False, res.json().get("message")
|
return False, res.json().get("message")
|
||||||
@@ -160,7 +160,7 @@ class SubscribeHelper(metaclass=Singleton):
|
|||||||
return False, "连接MoviePilot服务器失败"
|
return False, "连接MoviePilot服务器失败"
|
||||||
if res.ok:
|
if res.ok:
|
||||||
# 清除 get_shares 的缓存,以便实时看到结果
|
# 清除 get_shares 的缓存,以便实时看到结果
|
||||||
self._shares_cache.clear()
|
cache_backend.clear(region=self._shares_cache_region)
|
||||||
return True, ""
|
return True, ""
|
||||||
else:
|
else:
|
||||||
return False, res.json().get("message")
|
return False, res.json().get("message")
|
||||||
@@ -181,7 +181,7 @@ class SubscribeHelper(metaclass=Singleton):
|
|||||||
else:
|
else:
|
||||||
return False, res.json().get("message")
|
return False, res.json().get("message")
|
||||||
|
|
||||||
@cached(cache=_shares_cache)
|
@cached(region=_shares_cache_region)
|
||||||
def get_shares(self, name: str, page: int = 1, count: int = 30) -> List[dict]:
|
def get_shares(self, name: str, page: int = 1, count: int = 30) -> List[dict]:
|
||||||
"""
|
"""
|
||||||
获取订阅分享数据
|
获取订阅分享数据
|
||||||
|
|||||||
Reference in New Issue
Block a user