diff --git a/app/chain/__init__.py b/app/chain/__init__.py index 41b2a12d..42ce40d3 100644 --- a/app/chain/__init__.py +++ b/app/chain/__init__.py @@ -1,7 +1,7 @@ import traceback from abc import abstractmethod from pathlib import Path -from typing import Optional, Any, Tuple, List, Set, Union +from typing import Optional, Any, Tuple, List, Set, Union, Dict from ruamel.yaml import CommentedMap @@ -71,7 +71,7 @@ class ChainBase(AbstractSingleton, metaclass=Singleton): def recognize_media(self, meta: MetaBase, mtype: MediaType = None, tmdbid: int = None) -> Optional[MediaInfo]: - return self.run_module("recognize_media", meta=meta, tmdbid=tmdbid) + return self.run_module("recognize_media", meta=meta, mtype=mtype, tmdbid=tmdbid) def douban_info(self, doubanid: str) -> Optional[dict]: return self.run_module("douban_info", doubanid=doubanid) @@ -95,8 +95,10 @@ class ChainBase(AbstractSingleton, metaclass=Singleton): def refresh_torrents(self, sites: List[CommentedMap]) -> Optional[List[TorrentInfo]]: return self.run_module("refresh_torrents", sites=sites) - def filter_torrents(self, torrent_list: List[TorrentInfo]) -> List[TorrentInfo]: - return self.run_module("filter_torrents", torrent_list=torrent_list) + def filter_torrents(self, torrent_list: List[TorrentInfo], + season_episodes: Dict[int, list] = None) -> List[TorrentInfo]: + return self.run_module("filter_torrents", torrent_list=torrent_list, + season_episodes=season_episodes) def download(self, torrent_path: Path, cookie: str, episodes: Set[int] = None) -> Optional[Tuple[Optional[str], str]]: diff --git a/app/chain/search.py b/app/chain/search.py index b6139ee8..3e8e4a03 100644 --- a/app/chain/search.py +++ b/app/chain/search.py @@ -1,4 +1,4 @@ -from typing import Optional, List +from typing import Optional, List, Dict from app.chain import ChainBase from app.core.config import settings @@ -19,12 +19,14 @@ class SearchChain(ChainBase): self.siteshelper = SitesHelper() def process(self, meta: MetaBase, mediainfo: MediaInfo, - keyword: str = None) -> Optional[List[Context]]: + keyword: str = None, + season_episodes: Dict[int, list] = None) -> Optional[List[Context]]: """ 根据媒体信息,执行搜索 :param meta: 元数据 :param mediainfo: 媒体信息 :param keyword: 搜索关键词 + :param season_episodes: 媒体季度集数 """ logger.info(f'开始搜索资源,关键词:{keyword or mediainfo.title} ...') # 未开启的站点不搜索 @@ -46,7 +48,8 @@ class SearchChain(ChainBase): logger.warn(f'{keyword or mediainfo.title} 未搜索到资源') return [] # 过滤种子 - result: List[TorrentInfo] = self.filter_torrents(torrent_list=torrents) + result: List[TorrentInfo] = self.filter_torrents(torrent_list=torrents, + season_episodes=season_episodes) if result is not None: torrents = result if not torrents: diff --git a/app/chain/subscribe.py b/app/chain/subscribe.py index 4c3b92ee..1eaf0ef9 100644 --- a/app/chain/subscribe.py +++ b/app/chain/subscribe.py @@ -59,7 +59,7 @@ class SubscribeChain(ChainBase): self.obtain_image(mediainfo=mediainfo) # 添加订阅 state, err_msg = self.subscribes.add(mediainfo, season=season, **kwargs) - if state: + if not state: logger.info(f'{mediainfo.get_title_string()} {err_msg}') # 发回原用户 self.post_message(title=f"{mediainfo.get_title_string()}{metainfo.get_season_string()} " diff --git a/app/chain/user_message.py b/app/chain/user_message.py index be1e1946..baf37f5f 100644 --- a/app/chain/user_message.py +++ b/app/chain/user_message.py @@ -89,14 +89,23 @@ class UserMessageChain(ChainBase): return # 发送缺失的媒体信息 if no_exists: + # 过滤剧集 + season_episodes = {info.get('season'): info.get('episodes') + for info in no_exists.get(mediainfo.tmdb_id)} + # 发送消息 messages = [f"第 {no_exist.get('season')} 季缺失 {len(no_exist.get('episodes'))} 集" for no_exist in no_exists.get(mediainfo.tmdb_id)] + logger.info(f"{mediainfo.get_title_string()}:" + "\n".join(messages)) self.post_message(title=f"{mediainfo.get_title_string()}:\n" + "\n".join(messages)) + else: + season_episodes = None + # 搜索种子,过滤掉不需要的剧集,以便选择 logger.info(f"{mediainfo.get_title_string()} 媒体库中不存在,开始搜索 ...") self.post_message( title=f"开始搜索 {mediainfo.type.value} {mediainfo.get_title_string()} ...", userid=userid) - # 搜索种子 - contexts = self.searchchain.process(meta=self._current_meta, mediainfo=mediainfo) + contexts = self.searchchain.process(meta=self._current_meta, + mediainfo=mediainfo, + season_episodes=season_episodes) if not contexts: # 没有数据 self.post_message(title=f"{mediainfo.title} 未搜索到资源!", userid=userid) diff --git a/app/modules/__init__.py b/app/modules/__init__.py index 8badf5a4..ec96229c 100644 --- a/app/modules/__init__.py +++ b/app/modules/__init__.py @@ -1,6 +1,6 @@ from abc import abstractmethod, ABCMeta from pathlib import Path -from typing import Optional, List, Tuple, Union, Set, Any +from typing import Optional, List, Tuple, Union, Set, Any, Dict from ruamel.yaml import CommentedMap @@ -116,10 +116,12 @@ class _ModuleBase(metaclass=ABCMeta): """ pass - def filter_torrents(self, torrent_list: List[TorrentInfo]) -> List[TorrentInfo]: + def filter_torrents(self, torrent_list: List[TorrentInfo], + season_episodes: Dict[int, dict] = None) -> List[TorrentInfo]: """ 过滤资源 :param torrent_list: 资源列表 + :param season_episodes: 过滤的剧集信息 :return: 过滤后的资源列表,注意如果返回None,有可能是没有对应的处理模块,应无视结果 """ pass diff --git a/app/modules/filter/__init__.py b/app/modules/filter/__init__.py index fcf849bd..9d6b67ab 100644 --- a/app/modules/filter/__init__.py +++ b/app/modules/filter/__init__.py @@ -3,6 +3,8 @@ from typing import List, Tuple, Union, Dict, Optional from app.core.context import TorrentInfo from app.core.config import settings +from app.core.metainfo import MetaInfo +from app.log import logger from app.modules import _ModuleBase from app.modules.filter.RuleParser import RuleParser @@ -70,21 +72,57 @@ class FilterModule(_ModuleBase): def init_setting(self) -> Tuple[str, Union[str, bool]]: return "FILTER_RULE", True - def filter_torrents(self, torrent_list: List[TorrentInfo]) -> List[TorrentInfo]: + def filter_torrents(self, torrent_list: List[TorrentInfo], + season_episodes: Dict[int, list] = None) -> List[TorrentInfo]: """ 过滤种子资源 :param torrent_list: 资源列表 + :param season_episodes: 季集数过滤 {season:[episodes]} :return: 过滤后的资源列表,添加资源优先级 """ # 返回种子列表 ret_torrents = [] for torrent in torrent_list: # 能命中优先级的才返回 - if self.__get_order(torrent, settings.FILTER_RULE): - ret_torrents.append(torrent) + if not self.__get_order(torrent, settings.FILTER_RULE): + continue + # 季集数过滤 + if season_episodes \ + and not self.__match_season_episodes(torrent, season_episodes): + continue + ret_torrents.append(torrent) return ret_torrents + @staticmethod + def __match_season_episodes(torrent: TorrentInfo, season_episodes: Dict[int, list]): + """ + 判断种子是否匹配季集数 + """ + # 匹配季 + seasons = season_episodes.keys() + meta = MetaInfo(title=torrent.title, subtitle=torrent.description) + # 种子季 + torrent_seasons = meta.get_season_list() + if not torrent_seasons: + # 按第一季处理 + torrent_seasons = [1] + # 种子集 + torrent_episodes = meta.get_episode_list() + if not set(torrent_seasons).issubset(set(seasons)): + # 种子季不在过滤季中 + logger.info(f"种子 {torrent.title} 不是需要的季") + return False + if not torrent_episodes: + # 整季按匹配处理 + return True + if len(torrent_episodes) == 1 \ + and not set(torrent_seasons).issubset(set(season_episodes.get(torrent_seasons[0]))): + # 单季不是子集的种子不要 + logger.info(f"种子 {torrent.title} 集 {torrent_episodes} 不是需要的集") + return False + return True + def __get_order(self, torrent: TorrentInfo, rule_str: str) -> Optional[TorrentInfo]: """ 获取种子匹配的规则优先级,值越大越优先,未匹配时返回None diff --git a/app/modules/themoviedb/tmdb.py b/app/modules/themoviedb/tmdb.py index 1c3801b3..f26d857d 100644 --- a/app/modules/themoviedb/tmdb.py +++ b/app/modules/themoviedb/tmdb.py @@ -351,7 +351,7 @@ class TmdbHelper: seasons = self.__get_tv_seasons(tv_info) for season, season_info in seasons.items(): if season_info.get("air_date"): - if season.get("air_date")[0:4] == str(_season_year) \ + if season_info.get("air_date")[0:4] == str(_season_year) \ and season == int(season_number): return True except Exception as e1: