diff --git a/app/chain/__init__.py b/app/chain/__init__.py index 092b5cc0..8f0675dc 100644 --- a/app/chain/__init__.py +++ b/app/chain/__init__.py @@ -223,16 +223,19 @@ class ChainBase(metaclass=ABCMeta): def filter_torrents(self, rule_string: str, torrent_list: List[TorrentInfo], - season_episodes: Dict[int, list] = None) -> List[TorrentInfo]: + season_episodes: Dict[int, list] = None, + mediainfo: MediaInfo = None) -> List[TorrentInfo]: """ 过滤种子资源 :param rule_string: 过滤规则 :param torrent_list: 资源列表 :param season_episodes: 季集数过滤 {season:[episodes]} + :param mediainfo: 识别的媒体信息 :return: 过滤后的资源列表,添加资源优先级 """ return self.run_module("filter_torrents", rule_string=rule_string, - torrent_list=torrent_list, season_episodes=season_episodes) + torrent_list=torrent_list, season_episodes=season_episodes, + mediainfo=mediainfo) def download(self, content: Union[Path, str], download_dir: Path, cookie: str, episodes: Set[int] = None, category: str = None diff --git a/app/chain/download.py b/app/chain/download.py index 3ae393ea..cda85569 100644 --- a/app/chain/download.py +++ b/app/chain/download.py @@ -225,7 +225,7 @@ class DownloadChain(ChainBase): self.downloadhis.add_files(files_to_add) # 发送消息 - self.post_download_message(meta=_meta, mediainfo=_media, torrent=_torrent, channel=channel) + self.post_download_message(meta=_meta, mediainfo=_media, torrent=_torrent, channel=channel, userid=userid) # 下载成功后处理 self.download_added(context=context, download_dir=download_dir, torrent_path=torrent_file) # 广播事件 diff --git a/app/chain/search.py b/app/chain/search.py index 2c390dbc..413279e1 100644 --- a/app/chain/search.py +++ b/app/chain/search.py @@ -135,7 +135,8 @@ class SearchChain(ChainBase): logger.info(f'开始过滤资源,当前规则:{filter_rule} ...') result: List[TorrentInfo] = self.filter_torrents(rule_string=filter_rule, torrent_list=torrents, - season_episodes=season_episodes) + season_episodes=season_episodes, + mediainfo=mediainfo) if result is not None: torrents = result if not torrents: diff --git a/app/chain/subscribe.py b/app/chain/subscribe.py index be86557f..d3e57e00 100644 --- a/app/chain/subscribe.py +++ b/app/chain/subscribe.py @@ -512,7 +512,8 @@ class SubscribeChain(ChainBase): filter_rule = self.systemconfig.get(SystemConfigKey.FilterRules) result: List[TorrentInfo] = self.filter_torrents( rule_string=filter_rule, - torrent_list=[torrent_info]) + torrent_list=[torrent_info], + mediainfo=torrent_mediainfo) if result is not None and not result: # 不符合过滤规则 logger.info(f"{torrent_info.title} 不匹配当前过滤规则") diff --git a/app/chain/transfer.py b/app/chain/transfer.py index e31cefc6..12236fee 100644 --- a/app/chain/transfer.py +++ b/app/chain/transfer.py @@ -1,3 +1,4 @@ +import glob import re import shutil import threading @@ -601,8 +602,10 @@ class TransferChain(ChainBase): if not path.exists(): return if path.is_file(): - # 删除文件 - path.unlink() + # 删除文件、nfo、jpg + files = glob.glob(f"{Path(path.parent).joinpath(path.stem)}*") + for file in files: + Path(file).unlink() logger.warn(f"文件 {path} 已删除") # 需要删除父目录 elif str(path.parent) == str(path.root): @@ -615,11 +618,24 @@ class TransferChain(ChainBase): # 删除目录 logger.warn(f"目录 {path} 已删除") # 需要删除父目录 - # 判断父目录是否为空, 为空则删除 - for parent_path in path.parents: - if str(parent_path.parent) != str(path.root): - # 父目录非根目录,才删除父目录 - files = SystemUtils.list_files(parent_path, settings.RMT_MEDIAEXT) - if not files: - shutil.rmtree(parent_path) - logger.warn(f"目录 {parent_path} 已删除") + + # 判断当前媒体父路径下是否有媒体文件,如有则无需遍历父级 + if not SystemUtils.exits_files(path.parent, settings.RMT_MEDIAEXT): + # 媒体库二级分类根路径 + library_root_names = [ + settings.LIBRARY_MOVIE_NAME or '电影', + settings.LIBRARY_TV_NAME or '电视剧', + settings.LIBRARY_ANIME_NAME or '动漫', + ] + + # 判断父目录是否为空, 为空则删除 + for parent_path in path.parents: + # 遍历父目录到媒体库二级分类根路径 + if str(parent_path.name) in library_root_names: + break + if str(parent_path.parent) != str(path.root): + # 父目录非根目录,才删除父目录 + if not SystemUtils.exits_files(path.parent, settings.RMT_MEDIAEXT): + # 当前路径下没有媒体文件则删除 + shutil.rmtree(parent_path) + logger.warn(f"目录 {parent_path} 已删除") diff --git a/app/modules/filter/__init__.py b/app/modules/filter/__init__.py index a8e3303a..d17ea96a 100644 --- a/app/modules/filter/__init__.py +++ b/app/modules/filter/__init__.py @@ -1,7 +1,7 @@ import re from typing import List, Tuple, Union, Dict, Optional -from app.core.context import TorrentInfo +from app.core.context import TorrentInfo, MediaInfo from app.core.metainfo import MetaInfo from app.log import logger from app.modules import _ModuleBase @@ -9,9 +9,10 @@ from app.modules.filter.RuleParser import RuleParser class FilterModule(_ModuleBase): - # 规则解析器 parser: RuleParser = None + # 媒体信息 + media: MediaInfo = None # 内置规则集 rule_set: Dict[str, dict] = { @@ -37,8 +38,13 @@ class FilterModule(_ModuleBase): }, # 中字 "CNSUB": { - "include": [r'[中国國繁简](/|\s|\\|\|)?[繁简英粤]|[英简繁](/|\s|\\|\|)?[中繁简]|繁體|简体|[中国國][字配]|国语|國語|中文|中字'], - "exclude": [] + "include": [ + r'[中国國繁简](/|\s|\\|\|)?[繁简英粤]|[英简繁](/|\s|\\|\|)?[中繁简]|繁體|简体|[中国國][字配]|国语|國語|中文|中字'], + "exclude": [], + # 只处理对应TMDB信息的数据 + "tmdb": { + "original_language": "zh,cn" + } }, # 特效字幕 "SPECSUB": { @@ -107,16 +113,19 @@ class FilterModule(_ModuleBase): def filter_torrents(self, rule_string: str, torrent_list: List[TorrentInfo], - season_episodes: Dict[int, list] = None) -> List[TorrentInfo]: + season_episodes: Dict[int, list] = None, + mediainfo: MediaInfo = None) -> List[TorrentInfo]: """ 过滤种子资源 :param rule_string: 过滤规则 :param torrent_list: 资源列表 :param season_episodes: 季集数过滤 {season:[episodes]} + :param mediainfo: 媒体信息 :return: 过滤后的资源列表,添加资源优先级 """ if not rule_string: return torrent_list + self.media = mediainfo # 返回种子列表 ret_torrents = [] for torrent in torrent_list: @@ -215,6 +224,11 @@ class FilterModule(_ModuleBase): if not self.rule_set.get(rule_name): # 规则不存在 return False + # TMDB规则 + tmdb = self.rule_set[rule_name].get("tmdb") + # 不符合TMDB规则的直接返回True,即不过滤 + if tmdb and not self.__match_tmdb(tmdb): + return True # 包含规则项 includes = self.rule_set[rule_name].get("include") or [] # 排除规则项 @@ -236,3 +250,44 @@ class FilterModule(_ModuleBase): # FREE规则不匹配 return False return True + + def __match_tmdb(self, tmdb: dict) -> bool: + """ + 判断种子是否匹配TMDB规则 + """ + def __get_media_value(key: str): + try: + return getattr(self.media, key) + except ValueError: + return "" + + if not self.media: + return False + + for attr, value in tmdb.items(): + if not value: + continue + # 获取media信息的值 + info_value = __get_media_value(attr) + if not info_value: + # 没有该值,不匹配 + return False + elif attr == "production_countries": + # 国家信息 + info_values = [str(val.get("iso_3166_1")).upper() for val in info_value] + else: + # media信息转化为数组 + if isinstance(info_value, list): + info_values = [str(val).upper() for val in info_value] + else: + info_values = [str(info_value).upper()] + # 过滤值转化为数组 + if value.find(",") != -1: + values = [str(val).upper() for val in value.split(",")] + else: + values = [str(value).upper()] + # 没有交集为不匹配 + if not set(values).intersection(set(info_values)): + return False + + return True diff --git a/app/modules/transmission/__init__.py b/app/modules/transmission/__init__.py index b81e06c9..78eb6456 100644 --- a/app/modules/transmission/__init__.py +++ b/app/modules/transmission/__init__.py @@ -131,7 +131,7 @@ class TransmissionModule(_ModuleBase): title=torrent.name, path=Path(torrent.download_dir) / torrent.name, hash=torrent.hashString, - tags=torrent.labels + tags=",".join(torrent.labels or []) )) elif status == TorrentStatus.DOWNLOADING: # 获取正在下载的任务 diff --git a/app/plugins/rsssubscribe/__init__.py b/app/plugins/rsssubscribe/__init__.py index 08c6f4b7..bce06b73 100644 --- a/app/plugins/rsssubscribe/__init__.py +++ b/app/plugins/rsssubscribe/__init__.py @@ -593,7 +593,8 @@ class RssSubscribe(_PluginBase): if self._filter: result = self.chain.filter_torrents( rule_string=filter_rule, - torrent_list=[torrentinfo] + torrent_list=[torrentinfo], + mediainfo=mediainfo ) if not result: logger.info(f"{title} {description} 不匹配过滤规则") diff --git a/app/utils/system.py b/app/utils/system.py index 36b553bd..2776ccf3 100644 --- a/app/utils/system.py +++ b/app/utils/system.py @@ -106,7 +106,7 @@ class SystemUtils: if directory.is_file(): return [directory] - + if not min_filesize: min_filesize = 0 @@ -122,6 +122,36 @@ class SystemUtils: return files + @staticmethod + def exits_files(directory: Path, extensions: list, min_filesize: int = 0) -> bool: + """ + 判断目录下是否存在指定扩展名的文件 + :return True存在 False不存在 + """ + + if not min_filesize: + min_filesize = 0 + + if not directory.exists(): + return False + + if directory.is_file(): + return True + + if not min_filesize: + min_filesize = 0 + + pattern = r".*(" + "|".join(extensions) + ")$" + + # 遍历目录及子目录 + for path in directory.rglob('**/*'): + if path.is_file() \ + and re.match(pattern, path.name, re.IGNORECASE) \ + and path.stat().st_size >= min_filesize * 1024 * 1024: + return True + + return False + @staticmethod def list_sub_files(directory: Path, extensions: list) -> List[Path]: """