From 99bd8aade3ca5c1a5aed56cd6812deccc19cd1a9 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sat, 10 Jun 2023 19:22:40 +0800 Subject: [PATCH] fix bugs --- app/api/endpoints/subscribes.py | 2 +- app/chain/__init__.py | 5 ++-- app/chain/download.py | 16 ++++++++----- app/chain/subscribe.py | 8 +++---- app/chain/user_message.py | 36 +++++++++++++++++++--------- app/core/context.py | 17 +++++++++---- app/db/models/subscribe.py | 4 ++-- app/modules/__init__.py | 6 +++-- app/modules/emby/emby.py | 2 +- app/modules/jellyfin/jellyfin.py | 2 +- app/modules/telegram/telegram.py | 3 ++- app/modules/themoviedb/__init__.py | 8 ++++--- app/modules/themoviedb/tmdb.py | 26 ++++++++++++-------- app/modules/themoviedb/tmdb_cache.py | 6 ++--- app/schemas/context.py | 2 +- app/schemas/subscribe.py | 2 +- tests/test_recognize.py | 2 +- 17 files changed, 92 insertions(+), 55 deletions(-) diff --git a/app/api/endpoints/subscribes.py b/app/api/endpoints/subscribes.py index 511bdef7..e41d85b2 100644 --- a/app/api/endpoints/subscribes.py +++ b/app/api/endpoints/subscribes.py @@ -16,7 +16,7 @@ router = APIRouter() def start_subscribe_chain(title: str, - mtype: MediaType, tmdbid: str, season: int, username: str): + mtype: MediaType, tmdbid: int, season: int, username: str): """ 启动订阅链式任务 """ diff --git a/app/chain/__init__.py b/app/chain/__init__.py index 3c7c3dc9..41b2a12d 100644 --- a/app/chain/__init__.py +++ b/app/chain/__init__.py @@ -11,7 +11,7 @@ from app.core.context import MediaInfo, TorrentInfo from app.core.meta import MetaBase from app.log import logger from app.utils.singleton import AbstractSingleton, Singleton -from app.utils.types import TorrentStatus +from app.utils.types import TorrentStatus, MediaType class ChainBase(AbstractSingleton, metaclass=Singleton): @@ -69,7 +69,8 @@ class ChainBase(AbstractSingleton, metaclass=Singleton): return self.run_module("prepare_recognize", title=title, subtitle=subtitle) def recognize_media(self, meta: MetaBase, - tmdbid: str = None) -> Optional[MediaInfo]: + mtype: MediaType = None, + tmdbid: int = None) -> Optional[MediaInfo]: return self.run_module("recognize_media", meta=meta, tmdbid=tmdbid) def douban_info(self, doubanid: str) -> Optional[dict]: diff --git a/app/chain/download.py b/app/chain/download.py index a92cdb10..3a1c378a 100644 --- a/app/chain/download.py +++ b/app/chain/download.py @@ -133,7 +133,7 @@ class DownloadChain(ChainBase): userid=userid) return _hash - def __update_seasons(tmdbid: str, need: list, current: list) -> list: + def __update_seasons(tmdbid: int, need: list, current: list) -> list: """ 更新need_tvs季数,返回剩余季数 """ @@ -146,7 +146,7 @@ class DownloadChain(ChainBase): need_tvs.pop(tmdbid) return need - def __update_episodes(tmdbid: str, seq: int, need: list, current: set) -> list: + def __update_episodes(tmdbid: int, seq: int, need: list, current: set) -> list: """ 更新need_tvs集数,返回剩余集数 """ @@ -159,7 +159,7 @@ class DownloadChain(ChainBase): need_tvs.pop(tmdbid) return need - def __get_season_episodes(tmdbid: str, season: int) -> int: + def __get_season_episodes(tmdbid: int, season: int) -> int: """ 获取需要的季的集数 """ @@ -181,7 +181,7 @@ class DownloadChain(ChainBase): # 电视剧整季匹配 if need_tvs: # 先把整季缺失的拿出来,看是否刚好有所有季都满足的种子 - need_seasons: Dict[str, list] = {} + need_seasons: Dict[int, list] = {} for need_tmdbid, need_tv in need_tvs.items(): for tv in need_tv: if not tv: @@ -364,6 +364,7 @@ class DownloadChain(ChainBase): if not mediainfo.seasons: # 补充媒体信息 mediainfo: MediaInfo = self.recognize_media(meta=MetaInfo(title=mediainfo.get_title_string()), + mtype=mediainfo.type, tmdbid=mediainfo.tmdb_id) if not mediainfo: return False, {} @@ -388,8 +389,11 @@ class DownloadChain(ChainBase): if not episodes: # 全部集存在 continue - # 添加不存在的季集信息 - __append_no_exists(season, episodes, len(episodes), min(episodes)) + # 添加不存在的季集信息 + __append_no_exists(season, episodes, len(episodes), min(episodes)) + else: + # 全季不存在 + __append_no_exists(season, [], len(episodes), min(episodes)) # 存在不完整的剧集 if no_exists: logger.info(f"媒体库中已存在部分剧集,缺失:{no_exists}") diff --git a/app/chain/subscribe.py b/app/chain/subscribe.py index b33cd326..4c3b92ee 100644 --- a/app/chain/subscribe.py +++ b/app/chain/subscribe.py @@ -30,7 +30,7 @@ class SubscribeChain(ChainBase): def process(self, title: str, mtype: MediaType = None, - tmdbid: str = None, + tmdbid: int = None, season: int = None, userid: str = None, username: str = None, @@ -51,7 +51,7 @@ class SubscribeChain(ChainBase): metainfo.type = MediaType.TV metainfo.begin_season = season # 识别媒体信息 - mediainfo: MediaInfo = self.recognize_media(meta=metainfo, tmdbid=tmdbid) + mediainfo: MediaInfo = self.recognize_media(meta=metainfo, mtype=mtype, tmdbid=tmdbid) if not mediainfo: logger.warn(f'未识别到媒体信息,标题:{title},tmdbid:{tmdbid}') return False @@ -99,7 +99,7 @@ class SubscribeChain(ChainBase): meta.begin_season = subscribe.season meta.type = MediaType.MOVIE if subscribe.type == MediaType.MOVIE.value else MediaType.TV # 识别媒体信息 - mediainfo: MediaInfo = self.recognize_media(meta=meta, tmdbid=subscribe.tmdbid) + mediainfo: MediaInfo = self.recognize_media(meta=meta, mtype=meta.type, tmdbid=subscribe.tmdbid) if not mediainfo: logger.warn(f'未识别到媒体信息,标题:{subscribe.name},tmdbid:{subscribe.tmdbid}') continue @@ -183,7 +183,7 @@ class SubscribeChain(ChainBase): meta.begin_season = subscribe.season meta.type = MediaType.MOVIE if subscribe.type == MediaType.MOVIE.value else MediaType.TV # 识别媒体信息 - mediainfo: MediaInfo = self.recognize_media(meta=meta, tmdbid=subscribe.tmdbid) + mediainfo: MediaInfo = self.recognize_media(meta=meta, mtype=meta.type, tmdbid=subscribe.tmdbid) if not mediainfo: logger.warn(f'未识别到媒体信息,标题:{subscribe.name},tmdbid:{subscribe.tmdbid}') continue diff --git a/app/chain/user_message.py b/app/chain/user_message.py index f2dc5d29..bdb7610c 100644 --- a/app/chain/user_message.py +++ b/app/chain/user_message.py @@ -89,7 +89,7 @@ class UserMessageChain(ChainBase): return # 发送缺失的媒体信息 if no_exists: - messages = [f"第 {no_exist.get('season')} 季缺失 {no_exist.get('total_episodes')} 集" + messages = [f"第 {no_exist.get('season')} 季缺失 {len(no_exist.get('episodes'))} 集" for no_exist in no_exists.get(mediainfo.tmdb_id)] self.post_message(title=f"{mediainfo.get_title_string()}:\n" + "\n".join(messages)) logger.info(f"{mediainfo.get_title_string()} 媒体库中不存在,开始搜索 ...") @@ -109,7 +109,10 @@ class UserMessageChain(ChainBase): self._current_page = 0 # 发送种子数据 logger.info(f"搜索到 {len(contexts)} 条数据,开始发送选择消息 ...") - self.__post_torrents_message(items=contexts[:self._page_size], userid=userid, total=len(contexts)) + self.__post_torrents_message(title=mediainfo.title, + items=contexts[:self._page_size], + userid=userid, + total=len(contexts)) elif cache_type == "Subscribe": # 订阅媒体 @@ -204,10 +207,16 @@ class UserMessageChain(ChainBase): end = start + self._page_size if cache_type == "Torrent": # 发送种子数据 - self.__post_torrents_message(items=cache_list[start:end], userid=userid, total=len(cache_list)) + self.__post_torrents_message(title=self._current_media.title, + items=cache_list[start:end], + userid=userid, + total=len(cache_list)) else: # 发送媒体数据 - self.__post_medias_message(items=cache_list[start:end], userid=userid, total=len(cache_list)) + self.__post_medias_message(title=self._current_media.title, + items=cache_list[start:end], + userid=userid, + total=len(cache_list)) elif text.lower() == "n": # 下一页 @@ -229,10 +238,12 @@ class UserMessageChain(ChainBase): else: if cache_type == "Torrent": # 发送种子数据 - self.__post_torrents_message(items=cache_list, userid=userid, total=total) + self.__post_torrents_message(title=self._current_media.title, + items=cache_list, userid=userid, total=total) else: # 发送媒体数据 - self.__post_medias_message(items=cache_list, userid=userid, total=total) + self.__post_medias_message(title=self._current_media.title, + items=cache_list, userid=userid, total=total) else: # 搜索或订阅 @@ -262,6 +273,7 @@ class UserMessageChain(ChainBase): meta.begin_episode = episode_num if year: meta.year = year + # 记录当前状态 self._current_meta = meta # 开始搜索 logger.info(f"开始搜索:{meta.get_name()}") @@ -276,24 +288,26 @@ class UserMessageChain(ChainBase): self._current_page = 0 self._current_media = None # 发送媒体列表 - self.__post_medias_message(items=medias[:self._page_size], userid=userid, total=len(medias)) + self.__post_medias_message(title=meta.get_name(), + items=medias[:self._page_size], + userid=userid, total=len(medias)) - def __post_medias_message(self, items: list, userid: str, total: int): + def __post_medias_message(self, title: str, items: list, userid: str, total: int): """ 发送媒体列表消息 """ self.post_medias_message( - title=f"共找到{total}条相关信息,请回复数字选择对应媒体(p: 上一页 n: 下一页)", + title=f"【{title}】共找到{total}条相关信息,请回复数字选择对应媒体(p: 上一页 n: 下一页)", items=items, userid=userid ) - def __post_torrents_message(self, items: list, userid: str, total: int): + def __post_torrents_message(self, title: str, items: list, userid: str, total: int): """ 发送种子列表消息 """ self.post_torrents_message( - title=f"共找到{total}条相关信息,请回复数字下载对应资源(0: 自动选择 p: 上一页 n: 下一页)", + title=f"【{title}】共找到{total}条相关信息,请回复数字下载对应资源(0: 自动选择 p: 上一页 n: 下一页)", items=items, userid=userid ) diff --git a/app/core/context.py b/app/core/context.py index 9f1e76b7..a3860cc4 100644 --- a/app/core/context.py +++ b/app/core/context.py @@ -6,7 +6,7 @@ from app.core.metainfo import MetaInfo from app.utils.types import MediaType -class TorrentInfo(object): +class TorrentInfo: # 站点ID site: int = None # 站点名称 @@ -89,7 +89,7 @@ class TorrentInfo(object): return self.get_free_string(self.uploadvolumefactor, self.downloadvolumefactor) -class MediaInfo(object): +class MediaInfo: # 类型 电影、电视剧 type: MediaType = None # 媒体标题 @@ -97,7 +97,7 @@ class MediaInfo(object): # 年份 year: Optional[str] = None # TMDB ID - tmdb_id: Optional[str] = None + tmdb_id: Optional[int] = None # IMDB ID imdb_id: Optional[str] = None # TVDB ID @@ -132,6 +132,13 @@ class MediaInfo(object): actors: List[dict] = [] def __init__(self, tmdb_info: dict = None, douban_info: dict = None): + # 初始化 + self.seasons = {} + self.directors = [] + self.actors = [] + self.tmdb_info = {} + self.douban_info = {} + # 设置媒体信息 if tmdb_info: self.set_tmdb_info(tmdb_info) if douban_info: @@ -221,7 +228,7 @@ class MediaInfo(object): # 类型 self.type = info.get('media_type') # TMDBID - self.tmdb_id = str(info.get('id')) + self.tmdb_id = info.get('id') if not self.tmdb_id: return # 额外ID @@ -395,7 +402,7 @@ class MediaInfo(object): return self.seasons.get(sea) or [] -class Context(object): +class Context: """ 上下文对象 """ diff --git a/app/db/models/subscribe.py b/app/db/models/subscribe.py index 13994925..64beb98c 100644 --- a/app/db/models/subscribe.py +++ b/app/db/models/subscribe.py @@ -13,7 +13,7 @@ class Subscribe(Base): year = Column(String) type = Column(String) keyword = Column(String) - tmdbid = Column(String, index=True) + tmdbid = Column(Integer, index=True) doubanid = Column(String) season = Column(Integer) image = Column(String) @@ -28,7 +28,7 @@ class Subscribe(Base): state = Column(String, nullable=False, index=True, default='N') @staticmethod - def exists(db: Session, tmdbid: str, season: int = None): + def exists(db: Session, tmdbid: int, season: int = None): if season: return db.query(Subscribe).filter(Subscribe.tmdbid == tmdbid, Subscribe.season == season).first() diff --git a/app/modules/__init__.py b/app/modules/__init__.py index 15f53563..8badf5a4 100644 --- a/app/modules/__init__.py +++ b/app/modules/__init__.py @@ -6,7 +6,7 @@ from ruamel.yaml import CommentedMap from app.core.context import MediaInfo, TorrentInfo, Context from app.core.meta import MetaBase -from app.utils.types import TorrentStatus +from app.utils.types import TorrentStatus, MediaType class _ModuleBase(metaclass=ABCMeta): @@ -41,10 +41,12 @@ class _ModuleBase(metaclass=ABCMeta): pass def recognize_media(self, meta: MetaBase, - tmdbid: str = None) -> Optional[MediaInfo]: + mtype: MediaType = None, + tmdbid: int = None) -> Optional[MediaInfo]: """ 识别媒体信息 :param meta: 识别的元数据 + :param mtype: 媒体类型,与tmdbid配套 :param tmdbid: tmdbid :return: 识别的媒体信息,包括剧集信息 """ diff --git a/app/modules/emby/emby.py b/app/modules/emby/emby.py index 55d67ae1..1f05197d 100644 --- a/app/modules/emby/emby.py +++ b/app/modules/emby/emby.py @@ -232,7 +232,7 @@ class Emby(metaclass=Singleton): def get_tv_episodes(self, title: str = None, year: str = None, - tmdb_id: str = None, + tmdb_id: int = None, season: int = None) -> Optional[Dict[int, list]]: """ 根据标题和年份和季,返回Emby中的剧集列表 diff --git a/app/modules/jellyfin/jellyfin.py b/app/modules/jellyfin/jellyfin.py index 80bd8fb6..db55cd57 100644 --- a/app/modules/jellyfin/jellyfin.py +++ b/app/modules/jellyfin/jellyfin.py @@ -207,7 +207,7 @@ class Jellyfin(metaclass=Singleton): def get_tv_episodes(self, title: str = None, year: str = None, - tmdb_id: str = None, + tmdb_id: int = None, season: int = None) -> Optional[Dict[str, list]]: """ 根据标题和年份和季,返回Jellyfin中的剧集列表 diff --git a/app/modules/telegram/telegram.py b/app/modules/telegram/telegram.py index 06d56859..dcce07db 100644 --- a/app/modules/telegram/telegram.py +++ b/app/modules/telegram/telegram.py @@ -133,12 +133,13 @@ class Telegram(metaclass=Singleton): index, caption = 1, "*%s*" % title for context in torrents: torrent = context.torrent_info + site_name = torrent.site_name link = torrent.page_url title = torrent.title free = torrent.get_volume_factor_string() seeder = f"{torrent.seeders}↑" description = torrent.description - caption = f"{caption}\n{index}. [{title}]({link}) {free} {seeder}\n{description}" + caption = f"{caption}\n{index}. 【{site_name}】[{title}]({link}) {free} {seeder}\n_{description}_" index += 1 if userid: diff --git a/app/modules/themoviedb/__init__.py b/app/modules/themoviedb/__init__.py index 4640f679..2d766ad9 100644 --- a/app/modules/themoviedb/__init__.py +++ b/app/modules/themoviedb/__init__.py @@ -42,21 +42,23 @@ class TheMovieDb(_ModuleBase): pass def recognize_media(self, meta: MetaBase, - tmdbid: str = None) -> Optional[MediaInfo]: + mtype: MediaType = None, + tmdbid: int = None) -> Optional[MediaInfo]: """ 识别媒体信息 :param meta: 识别的元数据 + :param mtype: 识别的媒体类型,与tmdbid配套 :param tmdbid: tmdbid :return: 识别的媒体信息,包括剧集信息 """ if not meta: return None cache_info = self.cache.get(meta) - if not cache_info: + if not cache_info or cache_info.get('id') == 0: # 缓存没有或者强制不使用缓存 if tmdbid: # 直接查询详情 - info = self.tmdb.get_info(mtype=meta.type, tmdbid=tmdbid) + info = self.tmdb.get_info(mtype=mtype, tmdbid=tmdbid) else: if meta.type != MediaType.TV and not meta.year: info = self.tmdb.search_multi(meta.get_name()) diff --git a/app/modules/themoviedb/tmdb.py b/app/modules/themoviedb/tmdb.py index 5bd36dbb..1c3801b3 100644 --- a/app/modules/themoviedb/tmdb.py +++ b/app/modules/themoviedb/tmdb.py @@ -1,3 +1,4 @@ +import traceback from functools import lru_cache from typing import Optional, Tuple, List @@ -114,7 +115,7 @@ class TmdbHelper: return True return False - def __get_names(self, mtype: MediaType, tmdb_id: str) -> Tuple[Optional[dict], List[str]]: + def __get_names(self, mtype: MediaType, tmdb_id: int) -> Tuple[Optional[dict], List[str]]: """ 搜索tmdb中所有的标题和译名,用于名称匹配 :param mtype: 类型:电影、电视剧、动漫 @@ -230,7 +231,8 @@ class TmdbHelper: logger.error(f"连接TMDB出错:{err}") return None except Exception as e: - logger.error(f"连接TMDB出错:{str(e)}") + logger.error(f"连接TMDB出错:{e}") + print(traceback.print_exc()) return None logger.debug(f"API返回:{str(self.search.total_results)}") if len(movies) == 0: @@ -289,7 +291,8 @@ class TmdbHelper: logger.error(f"连接TMDB出错:{err}") return None except Exception as e: - logger.error(f"连接TMDB出错:{str(e)}") + logger.error(f"连接TMDB出错:{e}") + print(traceback.print_exc()) return None logger.debug(f"API返回:{str(self.search.total_results)}") if len(tvs) == 0: @@ -346,13 +349,14 @@ class TmdbHelper: return False try: seasons = self.__get_tv_seasons(tv_info) - for season, season_info in seasons.values(): + for season, season_info in seasons.items(): if season_info.get("air_date"): if season.get("air_date")[0:4] == str(_season_year) \ and season == int(season_number): return True except Exception as e1: logger.error(f"连接TMDB出错:{e1}") + print(traceback.print_exc()) return False return False @@ -363,6 +367,7 @@ class TmdbHelper: return None except Exception as e: logger.error(f"连接TMDB出错:{e}") + print(traceback.print_exc()) return None if len(tvs) == 0: @@ -433,7 +438,8 @@ class TmdbHelper: logger.error(f"连接TMDB出错:{err}") return None except Exception as e: - logger.error(f"连接TMDB出错:{str(e)}") + logger.error(f"连接TMDB出错:{e}") + print(traceback.print_exc()) return None logger.debug(f"API返回:{str(self.search.total_results)}") if len(multis) == 0: @@ -529,7 +535,7 @@ class TmdbHelper: def get_info(self, mtype: MediaType, - tmdbid: str) -> dict: + tmdbid: int) -> dict: """ 给定TMDB号,查询一条媒体信息 :param mtype: 类型:电影、电视剧、动漫,为空时都查(此时用不上年份) @@ -602,7 +608,7 @@ class TmdbHelper: tmdb_info['name'] = cn_title def __get_movie_detail(self, - tmdbid: str, + tmdbid: int, append_to_response: str = "images," "credits," "alternative_titles," @@ -714,7 +720,7 @@ class TmdbHelper: return None def __get_tv_detail(self, - tmdbid: str, + tmdbid: int, append_to_response: str = "images," "credits," "alternative_titles," @@ -896,7 +902,7 @@ class TmdbHelper: print(str(e)) return None - def get_tv_season_detail(self, tmdbid, season: int): + def get_tv_season_detail(self, tmdbid: int, season: int): """ 获取电视剧季的详情 :param tmdbid: TMDB ID @@ -970,7 +976,7 @@ class TmdbHelper: print(str(e)) return {} - def get_tv_episode_detail(self, tmdbid: str, season: int, episode: int): + def get_tv_episode_detail(self, tmdbid: int, season: int, episode: int): """ 获取电视剧集的详情 :param tmdbid: TMDB ID diff --git a/app/modules/themoviedb/tmdb_cache.py b/app/modules/themoviedb/tmdb_cache.py index cda15053..ba3618cf 100644 --- a/app/modules/themoviedb/tmdb_cache.py +++ b/app/modules/themoviedb/tmdb_cache.py @@ -75,12 +75,12 @@ class TmdbCache(metaclass=Singleton): with lock: return self._meta_data.pop(key, None) - def delete_by_tmdbid(self, tmdbid: str) -> None: + def delete_by_tmdbid(self, tmdbid: int) -> None: """ 清空对应TMDBID的所有缓存记录,以强制更新TMDB中最新的数据 """ for key in list(self._meta_data): - if str(self._meta_data.get(key, {}).get("id")) == str(tmdbid): + if self._meta_data.get(key, {}).get("id") == tmdbid: with lock: self._meta_data.pop(key) @@ -89,7 +89,7 @@ class TmdbCache(metaclass=Singleton): 清除未识别的缓存记录,以便重新搜索TMDB """ for key in list(self._meta_data): - if str(self._meta_data.get(key, {}).get("id")) == '0': + if self._meta_data.get(key, {}).get("id") == 0: with lock: self._meta_data.pop(key) diff --git a/app/schemas/context.py b/app/schemas/context.py index 7849c2c7..595c626f 100644 --- a/app/schemas/context.py +++ b/app/schemas/context.py @@ -54,7 +54,7 @@ class MediaInfo(BaseModel): # 年份 year: Optional[str] = None # TMDB ID - tmdb_id: Optional[str] = None + tmdb_id: Optional[int] = None # IMDB ID imdb_id: Optional[str] = None # TVDB ID diff --git a/app/schemas/subscribe.py b/app/schemas/subscribe.py index 8f233ce3..d08f1ce4 100644 --- a/app/schemas/subscribe.py +++ b/app/schemas/subscribe.py @@ -9,7 +9,7 @@ class Subscribe(BaseModel): year: str type: str keyword: Optional[str] - tmdbid: str + tmdbid: int doubanid: Optional[str] season: Optional[int] image: Optional[str] diff --git a/tests/test_recognize.py b/tests/test_recognize.py index c5220a43..4bd6f0ed 100644 --- a/tests/test_recognize.py +++ b/tests/test_recognize.py @@ -15,6 +15,6 @@ class RecognizeTest(TestCase): def test_recognize(self): result = IdentifyChain().process(title="我和我的祖国 2019") - self.assertEqual(str(result.media_info.tmdb_id), '612845') + self.assertEqual(result.media_info.tmdb_id, 612845) exists = DownloadChain().get_no_exists_info(result.media_info) self.assertTrue(exists[0])