mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-05 15:38:19 +08:00
feat(recommend): add cached_with_empty_check decorator
This commit is contained in:
+64
-1
@@ -1,4 +1,8 @@
|
|||||||
from typing import Any
|
from functools import wraps
|
||||||
|
from typing import Any, Callable
|
||||||
|
|
||||||
|
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
|
||||||
@@ -9,6 +13,35 @@ from app.schemas import MediaType
|
|||||||
from app.utils.common import log_execution_time
|
from app.utils.common import log_execution_time
|
||||||
from app.utils.singleton import Singleton
|
from app.utils.singleton import Singleton
|
||||||
|
|
||||||
|
# 推荐相关的专用缓存
|
||||||
|
recommend_ttl = 6 * 3600
|
||||||
|
recommend_cache = TTLCache(maxsize=256, ttl=recommend_ttl)
|
||||||
|
|
||||||
|
|
||||||
|
# 推荐缓存装饰器,避免偶发网络获取数据为空时,页面由于缓存长时间渲染异常问题
|
||||||
|
def cached_with_empty_check(func: Callable):
|
||||||
|
"""
|
||||||
|
缓存装饰器,用于缓存函数的返回结果,仅在结果非空时进行缓存
|
||||||
|
|
||||||
|
:param func: 被装饰的函数
|
||||||
|
:return: 包装后的函数
|
||||||
|
"""
|
||||||
|
|
||||||
|
@wraps(func)
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
# 使用 cachetools 缓存,构造缓存键
|
||||||
|
cache_key = hashkey(*args, **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):
|
||||||
"""
|
"""
|
||||||
@@ -21,7 +54,25 @@ class RecommendChain(ChainBase, metaclass=Singleton):
|
|||||||
self.doubanchain = DoubanChain()
|
self.doubanchain = DoubanChain()
|
||||||
self.bangumichain = BangumiChain()
|
self.bangumichain = BangumiChain()
|
||||||
|
|
||||||
|
def refresh_recommend(self):
|
||||||
|
"""
|
||||||
|
刷新推荐
|
||||||
|
"""
|
||||||
|
self.tmdb_movies()
|
||||||
|
self.tmdb_tvs()
|
||||||
|
self.tmdb_trending()
|
||||||
|
self.bangumi_calendar()
|
||||||
|
self.douban_movies()
|
||||||
|
self.douban_tvs()
|
||||||
|
self.movie_top250()
|
||||||
|
self.tv_weekly_chinese()
|
||||||
|
self.tv_weekly_global()
|
||||||
|
self.tv_animation()
|
||||||
|
self.movie_hot()
|
||||||
|
self.tv_hot()
|
||||||
|
|
||||||
@log_execution_time(logger=logger)
|
@log_execution_time(logger=logger)
|
||||||
|
@cached_with_empty_check
|
||||||
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:
|
||||||
"""
|
"""
|
||||||
@@ -35,6 +86,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
|
||||||
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 = "", page: int = 1) -> Any:
|
with_original_language: str = "", page: int = 1) -> Any:
|
||||||
"""
|
"""
|
||||||
@@ -48,6 +100,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
|
||||||
def tmdb_trending(self, page: int = 1) -> Any:
|
def tmdb_trending(self, page: int = 1) -> Any:
|
||||||
"""
|
"""
|
||||||
TMDB流行趋势
|
TMDB流行趋势
|
||||||
@@ -56,6 +109,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
|
||||||
def bangumi_calendar(self, page: int = 1, count: int = 30) -> Any:
|
def bangumi_calendar(self, page: int = 1, count: int = 30) -> Any:
|
||||||
"""
|
"""
|
||||||
Bangumi每日放送
|
Bangumi每日放送
|
||||||
@@ -64,6 +118,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
|
||||||
def movie_showing(self, page: int = 1, count: int = 30) -> Any:
|
def movie_showing(self, page: int = 1, count: int = 30) -> Any:
|
||||||
"""
|
"""
|
||||||
豆瓣正在热映
|
豆瓣正在热映
|
||||||
@@ -72,6 +127,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
|
||||||
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:
|
||||||
"""
|
"""
|
||||||
豆瓣最新电影
|
豆瓣最新电影
|
||||||
@@ -81,6 +137,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
|
||||||
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:
|
||||||
"""
|
"""
|
||||||
豆瓣最新电视剧
|
豆瓣最新电视剧
|
||||||
@@ -90,6 +147,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
|
||||||
def movie_top250(self, page: int = 1, count: int = 30) -> Any:
|
def movie_top250(self, page: int = 1, count: int = 30) -> Any:
|
||||||
"""
|
"""
|
||||||
豆瓣电影TOP250
|
豆瓣电影TOP250
|
||||||
@@ -98,6 +156,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
|
||||||
def tv_weekly_chinese(self, page: int = 1, count: int = 30) -> Any:
|
def tv_weekly_chinese(self, page: int = 1, count: int = 30) -> Any:
|
||||||
"""
|
"""
|
||||||
豆瓣国产剧集榜
|
豆瓣国产剧集榜
|
||||||
@@ -106,6 +165,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
|
||||||
def tv_weekly_global(self, page: int = 1, count: int = 30) -> Any:
|
def tv_weekly_global(self, page: int = 1, count: int = 30) -> Any:
|
||||||
"""
|
"""
|
||||||
豆瓣全球剧集榜
|
豆瓣全球剧集榜
|
||||||
@@ -114,6 +174,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
|
||||||
def tv_animation(self, page: int = 1, count: int = 30) -> Any:
|
def tv_animation(self, page: int = 1, count: int = 30) -> Any:
|
||||||
"""
|
"""
|
||||||
豆瓣热门动漫
|
豆瓣热门动漫
|
||||||
@@ -122,6 +183,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
|
||||||
def movie_hot(self, page: int = 1, count: int = 30) -> Any:
|
def movie_hot(self, page: int = 1, count: int = 30) -> Any:
|
||||||
"""
|
"""
|
||||||
豆瓣热门电影
|
豆瓣热门电影
|
||||||
@@ -130,6 +192,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
|
||||||
def tv_hot(self, page: int = 1, count: int = 30) -> Any:
|
def tv_hot(self, page: int = 1, count: int = 30) -> Any:
|
||||||
"""
|
"""
|
||||||
豆瓣热门电视剧
|
豆瓣热门电视剧
|
||||||
|
|||||||
Reference in New Issue
Block a user