From 549658e8716e2cdd99d3450e21cb333dfeb9c210 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Wed, 28 Feb 2024 14:18:23 +0800 Subject: [PATCH] fix #1553 fix #1496 --- app/chain/search.py | 107 ++++------------------------------------- app/chain/subscribe.py | 75 ++++++----------------------- app/helper/torrent.py | 100 +++++++++++++++++++++++++++++++++++++- 3 files changed, 123 insertions(+), 159 deletions(-) diff --git a/app/chain/search.py b/app/chain/search.py index e3766884..a61d3621 100644 --- a/app/chain/search.py +++ b/app/chain/search.py @@ -3,7 +3,7 @@ import re import traceback from concurrent.futures import ThreadPoolExecutor, as_completed from datetime import datetime -from typing import Dict, Tuple +from typing import Dict from typing import List, Optional from app.chain import ChainBase @@ -352,102 +352,13 @@ class SearchChain(ChainBase): filter_rule = self.systemconfig.get(SystemConfigKey.DefaultSearchFilterRules) if not filter_rule: return torrents - # 包含 - include = filter_rule.get("include") - # 排除 - exclude = filter_rule.get("exclude") - # 质量 - quality = filter_rule.get("quality") - # 分辨率 - resolution = filter_rule.get("resolution") - # 特效 - effect = filter_rule.get("effect") - # 电影大小 - movie_size = filter_rule.get("movie_size") - # 剧集单集大小 - tv_size = filter_rule.get("tv_size") - - def __get_size_range(size_str: str) -> Tuple[float, float]: - """ - 获取大小范围 - """ - if not size_str: - return 0, 0 - try: - size_range = size_str.split("-") - if len(size_range) == 1: - return 0, float(size_range[0]) - elif len(size_range) == 2: - return float(size_range[0]), float(size_range[1]) - except Exception as e: - logger.error(f"解析大小范围失败:{str(e)} - {traceback.format_exc()}") - return 0, 0 - - def __filter_torrent(t: TorrentInfo) -> bool: - """ - 过滤种子 - """ - # 包含 - if include: - if not re.search(r"%s" % include, - f"{t.title} {t.description}", re.I): - logger.info(f"{t.title} 不匹配包含规则 {include}") - return False - # 排除 - if exclude: - if re.search(r"%s" % exclude, - f"{t.title} {t.description}", re.I): - logger.info(f"{t.title} 匹配排除规则 {exclude}") - return False - # 质量 - if quality: - if not re.search(r"%s" % quality, t.title, re.I): - logger.info(f"{t.title} 不匹配质量规则 {quality}") - return False - - # 分辨率 - if resolution: - if not re.search(r"%s" % resolution, t.title, re.I): - logger.info(f"{t.title} 不匹配分辨率规则 {resolution}") - return False - - # 特效 - if effect: - if not re.search(r"%s" % effect, t.title, re.I): - logger.info(f"{t.title} 不匹配特效规则 {effect}") - return False - - # 大小 - if movie_size or tv_size: - if mediainfo.type == MediaType.TV: - size = tv_size - else: - size = movie_size - # 大小范围 - begin_size, end_size = __get_size_range(size) - if begin_size or end_size: - meta = MetaInfo(title=t.title, subtitle=t.description) - # 集数 - if mediainfo.type == MediaType.TV: - # 电视剧 - season = meta.begin_season or 1 - if meta.total_episode: - # 识别的总集数 - episodes_num = meta.total_episode - else: - # 整季集数 - episodes_num = len(mediainfo.seasons.get(season) or [1]) - # 比较大小 - if not (begin_size * 1024 ** 3 <= (t.size / episodes_num) <= end_size * 1024 ** 3): - logger.info(f"{t.title} {StringUtils.str_filesize(t.size)} " - f"共{episodes_num}集,不匹配大小规则 {size}") - return False - else: - # 电影比较大小 - if not (begin_size * 1024 ** 3 <= t.size <= end_size * 1024 ** 3): - logger.info(f"{t.title} {StringUtils.str_filesize(t.size)} 不匹配大小规则 {size}") - return False - return True # 使用默认过滤规则再次过滤 - return list(filter(lambda t: __filter_torrent(t), torrents)) + return list(filter( + lambda t: self.torrenthelper.filter_torrent( + torrent_info=t, + filter_rule=filter_rule, + mediainfo=mediainfo + ), + torrents + )) diff --git a/app/chain/subscribe.py b/app/chain/subscribe.py index 8f315dd8..4defeb68 100644 --- a/app/chain/subscribe.py +++ b/app/chain/subscribe.py @@ -1,6 +1,5 @@ import json import random -import re import time from datetime import datetime from typing import Dict, List, Optional, Union, Tuple @@ -18,6 +17,7 @@ from app.db.models.subscribe import Subscribe from app.db.subscribe_oper import SubscribeOper from app.db.systemconfig_oper import SystemConfigOper from app.helper.message import MessageHelper +from app.helper.torrent import TorrentHelper from app.log import logger from app.schemas import NotExistMediaInfo, Notification from app.schemas.types import MediaType, SystemConfigKey, MessageChannel, NotificationType @@ -37,6 +37,7 @@ class SubscribeChain(ChainBase): self.mediachain = MediaChain() self.message = MessageHelper() self.systemconfig = SystemConfigOper() + self.torrenthelper = TorrentHelper() def add(self, title: str, year: str, mtype: MediaType = None, @@ -446,64 +447,19 @@ class SubscribeChain(ChainBase): def get_filter_rule(self, subscribe: Subscribe): """ - 获取订阅过滤规则,没有则返回默认规则 + 获取订阅过滤规则,同时组合默认规则 """ # 默认过滤规则 - if (subscribe.include - or subscribe.exclude - or subscribe.quality - or subscribe.resolution - or subscribe.effect): - return { - "include": subscribe.include, - "exclude": subscribe.exclude, - "quality": subscribe.quality, - "resolution": subscribe.resolution, - "effect": subscribe.effect, - } - # 订阅默认过滤规则 - return self.systemconfig.get(SystemConfigKey.DefaultFilterRules) or {} - - @staticmethod - def check_filter_rule(torrent_info: TorrentInfo, filter_rule: Dict[str, str]) -> bool: - """ - 检查种子是否匹配订阅过滤规则 - """ - if not filter_rule: - return True - # 包含 - include = filter_rule.get("include") - if include: - if not re.search(r"%s" % include, - f"{torrent_info.title} {torrent_info.description}", re.I): - logger.info(f"{torrent_info.title} 不匹配包含规则 {include}") - return False - # 排除 - exclude = filter_rule.get("exclude") - if exclude: - if re.search(r"%s" % exclude, - f"{torrent_info.title} {torrent_info.description}", re.I): - logger.info(f"{torrent_info.title} 匹配排除规则 {exclude}") - return False - # 质量 - quality = filter_rule.get("quality") - if quality: - if not re.search(r"%s" % quality, torrent_info.title, re.I): - logger.info(f"{torrent_info.title} 不匹配质量规则 {quality}") - return False - # 分辨率 - resolution = filter_rule.get("resolution") - if resolution: - if not re.search(r"%s" % resolution, torrent_info.title, re.I): - logger.info(f"{torrent_info.title} 不匹配分辨率规则 {resolution}") - return False - # 特效 - effect = filter_rule.get("effect") - if effect: - if not re.search(r"%s" % effect, torrent_info.title, re.I): - logger.info(f"{torrent_info.title} 不匹配特效规则 {effect}") - return False - return True + default_rule = self.systemconfig.get(SystemConfigKey.DefaultFilterRules) + return { + "include": subscribe.include or default_rule.get("include"), + "exclude": subscribe.exclude or default_rule.get("exclude"), + "quality": subscribe.quality or default_rule.get("quality"), + "resolution": subscribe.resolution or default_rule.get("resolution"), + "effect": subscribe.effect or default_rule.get("effect"), + "tv_size": subscribe.tv_size or default_rule.get("tv_size"), + "movie_size": subscribe.movie_size or default_rule.get("movie_size"), + } def match(self, torrents: Dict[str, List[Context]]): """ @@ -662,8 +618,9 @@ class SubscribeChain(ChainBase): continue # 过滤规则 - if not self.check_filter_rule(torrent_info=torrent_info, - filter_rule=filter_rule): + if not self.torrenthelper.filter_torrent(torrent_info=torrent_info, + filter_rule=filter_rule, + mediainfo=torrent_mediainfo): continue # 洗版时,优先级小于已下载优先级的不要 diff --git a/app/helper/torrent.py b/app/helper/torrent.py index 5970f782..2d07e2f7 100644 --- a/app/helper/torrent.py +++ b/app/helper/torrent.py @@ -1,20 +1,22 @@ import datetime import re +import traceback from pathlib import Path -from typing import Tuple, Optional, List, Union +from typing import Tuple, Optional, List, Union, Dict from urllib.parse import unquote from requests import Response from torrentool.api import Torrent from app.core.config import settings -from app.core.context import Context +from app.core.context import Context, TorrentInfo, MediaInfo from app.core.metainfo import MetaInfo from app.db.systemconfig_oper import SystemConfigOper from app.log import logger from app.utils.http import RequestUtils from app.schemas.types import MediaType, SystemConfigKey from app.utils.singleton import Singleton +from app.utils.string import StringUtils class TorrentHelper(metaclass=Singleton): @@ -295,3 +297,97 @@ class TorrentHelper(metaclass=Singleton): """ if url not in self._invalid_torrents: self._invalid_torrents.append(url) + + @staticmethod + def filter_torrent(torrent_info: TorrentInfo, + filter_rule: Dict[str, str], + mediainfo: MediaInfo) -> bool: + """ + 检查种子是否匹配订阅过滤规则 + """ + + def __get_size_range(size_str: str) -> Tuple[float, float]: + """ + 获取大小范围 + """ + if not size_str: + return 0, 0 + try: + size_range = size_str.split("-") + if len(size_range) == 1: + return 0, float(size_range[0]) + elif len(size_range) == 2: + return float(size_range[0]), float(size_range[1]) + except Exception as e: + logger.error(f"解析大小范围失败:{str(e)} - {traceback.format_exc()}") + return 0, 0 + + if not filter_rule: + return True + # 包含 + include = filter_rule.get("include") + if include: + if not re.search(r"%s" % include, + f"{torrent_info.title} {torrent_info.description}", re.I): + logger.info(f"{torrent_info.title} 不匹配包含规则 {include}") + return False + # 排除 + exclude = filter_rule.get("exclude") + if exclude: + if re.search(r"%s" % exclude, + f"{torrent_info.title} {torrent_info.description}", re.I): + logger.info(f"{torrent_info.title} 匹配排除规则 {exclude}") + return False + # 质量 + quality = filter_rule.get("quality") + if quality: + if not re.search(r"%s" % quality, torrent_info.title, re.I): + logger.info(f"{torrent_info.title} 不匹配质量规则 {quality}") + return False + # 分辨率 + resolution = filter_rule.get("resolution") + if resolution: + if not re.search(r"%s" % resolution, torrent_info.title, re.I): + logger.info(f"{torrent_info.title} 不匹配分辨率规则 {resolution}") + return False + # 特效 + effect = filter_rule.get("effect") + if effect: + if not re.search(r"%s" % effect, torrent_info.title, re.I): + logger.info(f"{torrent_info.title} 不匹配特效规则 {effect}") + return False + + # 大小 + tv_size = filter_rule.get("tv_size") + movie_size = filter_rule.get("movie_size") + if movie_size or tv_size: + if mediainfo.type == MediaType.TV: + size = tv_size + else: + size = movie_size + # 大小范围 + begin_size, end_size = __get_size_range(size) + if begin_size or end_size: + meta = MetaInfo(title=torrent_info.title, subtitle=torrent_info.description) + # 集数 + if mediainfo.type == MediaType.TV: + # 电视剧 + season = meta.begin_season or 1 + if meta.total_episode: + # 识别的总集数 + episodes_num = meta.total_episode + else: + # 整季集数 + episodes_num = len(mediainfo.seasons.get(season) or [1]) + # 比较大小 + if not (begin_size * 1024 ** 3 <= (torrent_info.size / episodes_num) <= end_size * 1024 ** 3): + logger.info(f"{torrent_info.title} {StringUtils.str_filesize(torrent_info.size)} " + f"共{episodes_num}集,不匹配大小规则 {size}") + return False + else: + # 电影比较大小 + if not (begin_size * 1024 ** 3 <= torrent_info.size <= end_size * 1024 ** 3): + logger.info( + f"{torrent_info.title} {StringUtils.str_filesize(torrent_info.size)} 不匹配大小规则 {size}") + return False + return True