From b868cdb25eb5306af71f12df8702de66b8740f19 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sat, 18 Nov 2023 21:53:58 +0800 Subject: [PATCH] =?UTF-8?q?feat=20=E5=AE=8C=E5=96=84=E8=B1=86=E7=93=A3?= =?UTF-8?q?=E8=AF=A6=E6=83=85API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/endpoints/douban.py | 41 ++++++++++++++++++++++++++ app/chain/douban.py | 30 +++++++++++++++++++ app/chain/tmdb.py | 16 +++++------ app/core/context.py | 12 ++++++++ app/modules/douban/__init__.py | 46 ++++++++++++++++++++++++++++++ app/modules/douban/apiv2.py | 24 ++++++++++++++++ app/modules/themoviedb/__init__.py | 16 +++++------ app/schemas/tmdb.py | 11 +++++++ 8 files changed, 180 insertions(+), 16 deletions(-) diff --git a/app/api/endpoints/douban.py b/app/api/endpoints/douban.py index 48931f6d..38a6c918 100644 --- a/app/api/endpoints/douban.py +++ b/app/api/endpoints/douban.py @@ -149,6 +149,47 @@ def tv_hot(page: int = 1, return [MediaInfo(douban_info=tv).to_dict() for tv in tvs] +@router.get("/credits/{doubanid}/{type_name}", summary="豆瓣演员阵容", response_model=List[schemas.DoubanPerson]) +def douban_credits(doubanid: str, + type_name: str, + page: int = 1, + _: schemas.TokenPayload = Depends(verify_token)) -> Any: + """ + 根据TMDBID查询演员阵容,type_name: 电影/电视剧 + """ + mediatype = MediaType(type_name) + if mediatype == MediaType.MOVIE: + doubaninfos = DoubanChain().movie_credits(doubanid=doubanid, page=page) + elif mediatype == MediaType.TV: + doubaninfos = DoubanChain().tv_credits(doubanid=doubanid, page=page) + else: + return [] + if not doubaninfos: + return [] + else: + return [schemas.DoubanPerson(**doubaninfo) for doubaninfo in doubaninfos] + + +@router.get("/recommend/{doubanid}/{type_name}", summary="豆瓣推荐电影/电视剧", response_model=List[schemas.MediaInfo]) +def douban_recommend(doubanid: str, + type_name: str, + _: schemas.TokenPayload = Depends(verify_token)) -> Any: + """ + 根据豆瓣ID查询推荐电影/电视剧,type_name: 电影/电视剧 + """ + mediatype = MediaType(type_name) + if mediatype == MediaType.MOVIE: + doubaninfos = DoubanChain().movie_recommend(doubanid=doubanid) + elif mediatype == MediaType.TV: + doubaninfos = DoubanChain().tv_recommend(doubanid=doubanid) + else: + return [] + if not doubaninfos: + return [] + else: + return [MediaInfo(douban_info=doubaninfo).to_dict() for doubaninfo in doubaninfos] + + @router.get("/{doubanid}", summary="查询豆瓣详情", response_model=schemas.MediaInfo) def douban_info(doubanid: str, _: schemas.TokenPayload = Depends(verify_token)) -> Any: diff --git a/app/chain/douban.py b/app/chain/douban.py index f2e49832..ad5b3df2 100644 --- a/app/chain/douban.py +++ b/app/chain/douban.py @@ -72,3 +72,33 @@ class DoubanChain(ChainBase, metaclass=Singleton): if settings.RECOGNIZE_SOURCE != "douban": return None return self.run_module("tv_hot", page=page, count=count) + + def movie_credits(self, doubanid: str, page: int = 1) -> List[dict]: + """ + 根据TMDBID查询电影演职人员 + :param doubanid: 豆瓣ID + :param page: 页码 + """ + return self.run_module("douban_movie_credits", doubanid=doubanid, page=page) + + def tv_credits(self, doubanid: int, page: int = 1) -> List[dict]: + """ + 根据TMDBID查询电视剧演职人员 + :param doubanid: 豆瓣ID + :param page: 页码 + """ + return self.run_module("douban_tv_credits", doubanid=doubanid, page=page) + + def movie_recommend(self, doubanid: str) -> List[dict]: + """ + 根据豆瓣ID查询推荐电影 + :param doubanid: 豆瓣ID + """ + return self.run_module("douban_movie_recommend", doubanid=doubanid) + + def tv_recommend(self, doubanid: str) -> List[dict]: + """ + 根据豆瓣ID查询推荐电视剧 + :param doubanid: 豆瓣ID + """ + return self.run_module("douban_tv_recommend", doubanid=doubanid) diff --git a/app/chain/tmdb.py b/app/chain/tmdb.py index 6e00c257..0eef4728 100644 --- a/app/chain/tmdb.py +++ b/app/chain/tmdb.py @@ -62,28 +62,28 @@ class TmdbChain(ChainBase, metaclass=Singleton): 根据TMDBID查询类似电影 :param tmdbid: TMDBID """ - return self.run_module("movie_similar", tmdbid=tmdbid) + return self.run_module("tmdb_movie_similar", tmdbid=tmdbid) def tv_similar(self, tmdbid: int) -> List[dict]: """ 根据TMDBID查询类似电视剧 :param tmdbid: TMDBID """ - return self.run_module("tv_similar", tmdbid=tmdbid) + return self.run_module("tmdb_tv_similar", tmdbid=tmdbid) def movie_recommend(self, tmdbid: int) -> List[dict]: """ 根据TMDBID查询推荐电影 :param tmdbid: TMDBID """ - return self.run_module("movie_recommend", tmdbid=tmdbid) + return self.run_module("tmdb_movie_recommend", tmdbid=tmdbid) def tv_recommend(self, tmdbid: int) -> List[dict]: """ 根据TMDBID查询推荐电视剧 :param tmdbid: TMDBID """ - return self.run_module("tv_recommend", tmdbid=tmdbid) + return self.run_module("tmdb_tv_recommend", tmdbid=tmdbid) def movie_credits(self, tmdbid: int, page: int = 1) -> List[dict]: """ @@ -91,7 +91,7 @@ class TmdbChain(ChainBase, metaclass=Singleton): :param tmdbid: TMDBID :param page: 页码 """ - return self.run_module("movie_credits", tmdbid=tmdbid, page=page) + return self.run_module("tmdb_movie_credits", tmdbid=tmdbid, page=page) def tv_credits(self, tmdbid: int, page: int = 1) -> List[dict]: """ @@ -99,14 +99,14 @@ class TmdbChain(ChainBase, metaclass=Singleton): :param tmdbid: TMDBID :param page: 页码 """ - return self.run_module("tv_credits", tmdbid=tmdbid, page=page) + return self.run_module("tmdb_tv_credits", tmdbid=tmdbid, page=page) def person_detail(self, person_id: int) -> dict: """ 根据TMDBID查询演职员详情 :param person_id: 人物ID """ - return self.run_module("person_detail", person_id=person_id) + return self.run_module("tmdb_person_detail", person_id=person_id) def person_credits(self, person_id: int, page: int = 1) -> List[dict]: """ @@ -114,7 +114,7 @@ class TmdbChain(ChainBase, metaclass=Singleton): :param person_id: 人物ID :param page: 页码 """ - return self.run_module("person_credits", person_id=person_id, page=page) + return self.run_module("tmdb_person_credits", person_id=person_id, page=page) @cached(cache=TTLCache(maxsize=1, ttl=3600)) def get_random_wallpager(self): diff --git a/app/core/context.py b/app/core/context.py index 447ede2d..bfc2054d 100644 --- a/app/core/context.py +++ b/app/core/context.py @@ -495,6 +495,18 @@ class MediaInfo: self.season_years = { season: self.year } + # 风格 + if not self.genres: + self.genres = [{"id": genre, "name": genre} for genre in info.get("genres") or []] + # 时长 + if not self.runtime and info.get("durations"): + # 查找数字 + match = re.search(r'\d+', info.get("durations")[0]) + if match: + self.runtime = int(match.group()) + # 国家 + if not self.production_countries: + self.production_countries = [{"id": country, "name": country} for country in info.get("countries") or []] # 剩余属性赋值 for key, value in info.items(): if not hasattr(self, key): diff --git a/app/modules/douban/__init__.py b/app/modules/douban/__init__.py index b0f7b942..e7244f87 100644 --- a/app/modules/douban/__init__.py +++ b/app/modules/douban/__init__.py @@ -664,3 +664,49 @@ class DoubanModule(_ModuleBase): """ self.doubanapi.clear_cache() self.cache.clear() + + def douban_movie_credits(self, doubanid: str, page: int = 1, count: int = 20) -> List[dict]: + """ + 根据TMDBID查询电影演职员表 + :param doubanid: 豆瓣ID + :param page: 页码 + :param count: 数量 + """ + result = self.doubanapi.movie_celebrities(subject_id=doubanid) + if not result: + return [] + ret_list = result.get("actors") or [] + if ret_list: + return ret_list[(page - 1) * count: page * count] + else: + return [] + + def douban_tv_credits(self, doubanid: str, page: int = 1, count: int = 20) -> List[dict]: + """ + 根据TMDBID查询电视剧演职员表 + :param doubanid: 豆瓣ID + :param page: 页码 + :param count: 数量 + """ + result = self.doubanapi.tv_celebrities(subject_id=doubanid) + if not result: + return [] + ret_list = result.get("actors") or [] + if ret_list: + return ret_list[(page - 1) * count: page * count] + else: + return [] + + def douban_movie_recommend(self, doubanid: int) -> List[dict]: + """ + 根据豆瓣ID查询推荐电影 + :param doubanid: 豆瓣ID + """ + return self.doubanapi.movie_recommendations(subject_id=doubanid) or [] + + def douban_tv_recommend(self, doubanid: int) -> List[dict]: + """ + 根据豆瓣ID查询推荐电视剧 + :param doubanid: 豆瓣ID + """ + return self.doubanapi.tv_recommendations(subject_id=doubanid) or [] diff --git a/app/modules/douban/apiv2.py b/app/modules/douban/apiv2.py index 1c0b076a..8597974f 100644 --- a/app/modules/douban/apiv2.py +++ b/app/modules/douban/apiv2.py @@ -427,6 +427,30 @@ class DoubanApi(metaclass=Singleton): return self.__invoke(self._urls["doulist_items"] % subject_id, start=start, count=count, _ts=ts) + def movie_recommendations(self, subject_id: str, start: int = 0, count: int = 20, + ts=datetime.strftime(datetime.now(), '%Y%m%d')): + """ + 电影推荐 + :param subject_id: 电影id + :param start: 开始 + :param count: 数量 + :param ts: 时间戳 + """ + return self.__invoke(self._urls["movie_recommendations"] % subject_id, + start=start, count=count, _ts=ts) + + def tv_recommendations(self, subject_id: str, start: int = 0, count: int = 20, + ts=datetime.strftime(datetime.now(), '%Y%m%d')): + """ + 电视剧推荐 + :param subject_id: 电视剧id + :param start: 开始 + :param count: 数量 + :param ts: 时间戳 + """ + return self.__invoke(self._urls["tv_recommendations"] % subject_id, + start=start, count=count, _ts=ts) + def clear_cache(self): """ 清空LRU缓存 diff --git a/app/modules/themoviedb/__init__.py b/app/modules/themoviedb/__init__.py index b4a4509d..defac15e 100644 --- a/app/modules/themoviedb/__init__.py +++ b/app/modules/themoviedb/__init__.py @@ -382,35 +382,35 @@ class TheMovieDbModule(_ModuleBase): return f"https://{settings.TMDB_IMAGE_DOMAIN}/t/p/{image_prefix}{image_path}" return None - def movie_similar(self, tmdbid: int) -> List[dict]: + def tmdb_movie_similar(self, tmdbid: int) -> List[dict]: """ 根据TMDBID查询类似电影 :param tmdbid: TMDBID """ return self.tmdb.get_movie_similar(tmdbid=tmdbid) - def tv_similar(self, tmdbid: int) -> List[dict]: + def tmdb_tv_similar(self, tmdbid: int) -> List[dict]: """ 根据TMDBID查询类似电视剧 :param tmdbid: TMDBID """ return self.tmdb.get_tv_similar(tmdbid=tmdbid) - def movie_recommend(self, tmdbid: int) -> List[dict]: + def tmdb_movie_recommend(self, tmdbid: int) -> List[dict]: """ 根据TMDBID查询推荐电影 :param tmdbid: TMDBID """ return self.tmdb.get_movie_recommend(tmdbid=tmdbid) - def tv_recommend(self, tmdbid: int) -> List[dict]: + def tmdb_tv_recommend(self, tmdbid: int) -> List[dict]: """ 根据TMDBID查询推荐电视剧 :param tmdbid: TMDBID """ return self.tmdb.get_tv_recommend(tmdbid=tmdbid) - def movie_credits(self, tmdbid: int, page: int = 1) -> List[dict]: + def tmdb_movie_credits(self, tmdbid: int, page: int = 1) -> List[dict]: """ 根据TMDBID查询电影演职员表 :param tmdbid: TMDBID @@ -418,7 +418,7 @@ class TheMovieDbModule(_ModuleBase): """ return self.tmdb.get_movie_credits(tmdbid=tmdbid, page=page) - def tv_credits(self, tmdbid: int, page: int = 1) -> List[dict]: + def tmdb_tv_credits(self, tmdbid: int, page: int = 1) -> List[dict]: """ 根据TMDBID查询电视剧演职员表 :param tmdbid: TMDBID @@ -426,14 +426,14 @@ class TheMovieDbModule(_ModuleBase): """ return self.tmdb.get_tv_credits(tmdbid=tmdbid, page=page) - def person_detail(self, person_id: int) -> dict: + def tmdb_person_detail(self, person_id: int) -> dict: """ 根据TMDBID查询人物详情 :param person_id: 人物ID """ return self.tmdb.get_person_detail(person_id=person_id) - def person_credits(self, person_id: int, page: int = 1) -> List[dict]: + def tmdb_person_credits(self, person_id: int, page: int = 1) -> List[dict]: """ 根据TMDBID查询人物参演作品 :param person_id: 人物ID diff --git a/app/schemas/tmdb.py b/app/schemas/tmdb.py index 696e8446..cb21d2b1 100644 --- a/app/schemas/tmdb.py +++ b/app/schemas/tmdb.py @@ -49,3 +49,14 @@ class TmdbPerson(BaseModel): popularity: Optional[float] = None images: Optional[dict] = {} biography: Optional[str] = None + + +class DoubanPerson(BaseModel): + id: Optional[str] = None + name: Optional[str] = None + roles: Optional[list] = [] + title: Optional[str] = None + url: Optional[str] = None + character: Optional[str] = None + avatar: Optional[dict] = None + latin_name: Optional[str] = None