perf: optimize torrent filtering

This commit is contained in:
jxxghp
2026-05-15 16:55:42 +08:00
parent 2831eecbeb
commit 51229204c9
3 changed files with 243 additions and 46 deletions
+47 -15
View File
@@ -1,5 +1,6 @@
import datetime
import re
from functools import lru_cache
from pathlib import Path
from typing import Tuple, Optional, List, Union, Dict, Any
from urllib.parse import unquote
@@ -19,6 +20,40 @@ from app.utils.http import RequestUtils
from app.utils.string import StringUtils
_SIZE_UNIT = 1024 * 1024
@lru_cache(maxsize=512)
def _compile_filter_pattern(pattern: str) -> re.Pattern:
"""
编译订阅/工作流附加过滤正则。
用户输入沿用原本的正则语义,缓存只减少同一规则反复匹配大量种子时的编译成本。
"""
return re.compile(r"%s" % pattern, re.I)
def _filter_pattern_search(pattern: Union[str, int, float], content: str) -> bool:
"""
按原有字符串插值语义执行过滤正则匹配。
"""
return bool(_compile_filter_pattern(str(pattern)).search(content))
@lru_cache(maxsize=256)
def _parse_filter_size_range(size_range: str) -> Tuple[str, float, Optional[float]]:
"""
解析附加过滤的大小范围,单位为 MB。
"""
if size_range.find("-") != -1:
size_min, size_max = size_range.split("-")
return "between", float(size_min.strip()) * _SIZE_UNIT, float(size_max.strip()) * _SIZE_UNIT
if size_range.startswith(">"):
return "gte", float(size_range[1:].strip()) * _SIZE_UNIT, None
if size_range.startswith("<"):
return "lte", 0, float(size_range[1:].strip()) * _SIZE_UNIT
return "unknown", 0, None
class TorrentHelper:
"""
种子帮助类
@@ -460,52 +495,48 @@ class TorrentHelper:
# 包含
include = filter_params.get("include")
if include:
if not re.search(r"%s" % include, content, re.I):
if not _filter_pattern_search(include, content):
logger.info(f"{content} 不匹配包含规则 {include}")
return False
# 排除
exclude = filter_params.get("exclude")
if exclude:
if re.search(r"%s" % exclude, content, re.I):
if _filter_pattern_search(exclude, content):
logger.info(f"{content} 匹配排除规则 {exclude}")
return False
# 质量
quality = filter_params.get("quality")
if quality:
if not re.search(r"%s" % quality, torrent_info.title, re.I):
if not _filter_pattern_search(quality, torrent_info.title):
logger.info(f"{torrent_info.title} 不匹配质量规则 {quality}")
return False
# 分辨率
resolution = filter_params.get("resolution")
if resolution:
if not re.search(r"%s" % resolution, torrent_info.title, re.I):
if not _filter_pattern_search(resolution, torrent_info.title):
logger.info(f"{torrent_info.title} 不匹配分辨率规则 {resolution}")
return False
# 特效
effect = filter_params.get("effect")
if effect:
if not re.search(r"%s" % effect, torrent_info.title, re.I):
if not _filter_pattern_search(effect, torrent_info.title):
logger.info(f"{torrent_info.title} 不匹配特效规则 {effect}")
return False
# 大小
size_range = filter_params.get("size")
if size_range:
if size_range.find("-") != -1:
size_rule, size_min, size_max = _parse_filter_size_range(size_range)
if size_rule == "between":
# 区间
size_min, size_max = size_range.split("-")
size_min = float(size_min.strip()) * 1024 * 1024
size_max = float(size_max.strip()) * 1024 * 1024
if torrent_info.size < size_min or torrent_info.size > size_max:
return False
elif size_range.startswith(">"):
elif size_rule == "gte":
# 大于
size_min = float(size_range[1:].strip()) * 1024 * 1024
if torrent_info.size < size_min:
return False
elif size_range.startswith("<"):
elif size_rule == "lte":
# 小于
size_max = float(size_range[1:].strip()) * 1024 * 1024
if torrent_info.size > size_max:
return False
@@ -521,6 +552,7 @@ class TorrentHelper:
"""
# 匹配季
seasons = season_episodes.keys()
seasons_set = set(seasons)
# 种子季
torrent_seasons = meta.season_list
if not torrent_seasons:
@@ -528,7 +560,7 @@ class TorrentHelper:
torrent_seasons = [1]
# 种子集
torrent_episodes = meta.episode_list
if not set(torrent_seasons).issubset(set(seasons)):
if not set(torrent_seasons).issubset(seasons_set):
# 种子季不在过滤季中
logger.debug(
f"种子 {torrent.site_name} - {torrent.title} 包含季 {torrent_seasons} 不是需要的季 {list(seasons)}")
@@ -539,7 +571,7 @@ class TorrentHelper:
if len(torrent_seasons) == 1:
need_episodes = season_episodes.get(torrent_seasons[0])
if need_episodes \
and not set(torrent_episodes).intersection(set(need_episodes)):
and not set(torrent_episodes).intersection(need_episodes):
# 单季集没有交集的不要
logger.debug(f"种子 {torrent.site_name} - {torrent.title} "
f"{torrent_episodes} 没有需要的集:{need_episodes}")