fix(metainfo): 副标题中被否定的季集号不再识别为资源季集

与 MoviePilot-Rust 同步 Python 兜底解析:副标题季/集正则增加「不包含/不包括/不含」
否定前缀的反向断言,避免「不包含 第二季」被识别为第 2 季,导致未标季号的第一季合集
命中第二季订阅并将订阅判定完成。补充 Python 兜底解析单测。
This commit is contained in:
flippedyizheng
2026-10-20 12:44:59 +08:00
parent 1b62418caa
commit 4df028d49f
2 changed files with 51 additions and 4 deletions

View File

@@ -19,9 +19,9 @@ logger = logging.getLogger(__name__)
TITLE_EPISODE_RE = re.compile(r"Episode\s+(\d{1,4})", re.IGNORECASE)
SUBTITLE_HAS_SEASON_EPISODE_RE = re.compile(r"[全第季集话話期幕]", re.IGNORECASE)
SUBTITLE_SEASON_RE = re.compile(r"(?<![全共]\s*)[第\s]+([0-9一二三四五六七八九十S\-]+)\s*季(?!\s*[全共])", re.IGNORECASE)
SUBTITLE_SEASON_RE = re.compile(r"(?<!(?:不包含|不包括|不含)\s*)(?<![全共]\s*)[第\s]+([0-9一二三四五六七八九十S\-]+)\s*季(?!\s*[全共])", re.IGNORECASE)
SUBTITLE_SEASON_ALL_RE = re.compile(r"[全共]\s*([0-9一二三四五六七八九十]+)\s*季", re.IGNORECASE)
SUBTITLE_EPISODE_RE = re.compile(r"(?<![全共]\s*)[第\s]+([0-9一二三四五六七八九十百零EP]+)\s*[集话話期幕](?!\s*[全共])", re.IGNORECASE)
SUBTITLE_EPISODE_RE = re.compile(r"(?<!(?:不包含|不包括|不含)\s*)(?<![全共]\s*)[第\s]+([0-9一二三四五六七八九十百零EP]+)\s*[集话話期幕](?!\s*[全共])", re.IGNORECASE)
SUBTITLE_EPISODE_BETWEEN_RE = re.compile(
r"[第]*\s*([0-9一二三四五六七八九十百零]+)\s*[集话話期幕]?\s*-\s*第*\s*"
r"([0-9一二三四五六七八九十百零]+)\s*[集话話期幕]",
@@ -245,9 +245,9 @@ class MetaBase(object):
_subtitle_flag = False
_title_episodel_re = r"Episode\s+(\d{1,4})"
_subtitle_season_re = r"(?<![全共]\s*)[第\s]+([0-9一二三四五六七八九十S\-]+)\s*季(?!\s*[全共])"
_subtitle_season_re = r"(?<!(?:不包含|不包括|不含)\s*)(?<![全共]\s*)[第\s]+([0-9一二三四五六七八九十S\-]+)\s*季(?!\s*[全共])"
_subtitle_season_all_re = r"[全共]\s*([0-9一二三四五六七八九十]+)\s*季"
_subtitle_episode_re = r"(?<![全共]\s*)[第\s]+([0-9一二三四五六七八九十百零EP]+)\s*[集话話期幕](?!\s*[全共])"
_subtitle_episode_re = r"(?<!(?:不包含|不包括|不含)\s*)(?<![全共]\s*)[第\s]+([0-9一二三四五六七八九十百零EP]+)\s*[集话話期幕](?!\s*[全共])"
_subtitle_episode_between_re = r"[第]*\s*([0-9一二三四五六七八九十百零]+)\s*[集话話期幕]?\s*-\s*第*\s*([0-9一二三四五六七八九十百零]+)\s*[集话話期幕]"
_subtitle_episode_all_re = r"([0-9一二三四五六七八九十百零]+)\s*集\s*全|[全共]\s*([0-9一二三四五六七八九十百零]+)\s*[集话話期幕]"

View File

@@ -536,6 +536,53 @@ def test_python_subtitle_episode_range_end_variant():
assert meta_cn.end_episode == 12
@pytest.mark.parametrize(
"subtitle",
[
"【赛博朋克:边缘行者】 转载 不包含 第二季",
"赛博朋克:边缘行者 不含第2季",
"赛博朋克:边缘行者 不包括 第二季",
],
)
def test_python_subtitle_negated_season_is_ignored(subtitle):
"""
副标题中被“不包含/不含/不包括”否定的季号不应作为资源季号。
"""
with patch("app.adapters.system.rust.parse_metainfo", return_value=None):
meta = MetaInfo(
title="[Nekomoe kissaten&VCB-Studio] Cyberpunk Edgerunners [Ma10p_1080p]",
subtitle=subtitle,
)
assert meta.begin_season is None
def test_python_subtitle_negated_season_keeps_affirmed_season():
"""
副标题同时声明包含与不包含的季时,只采用未被否定的季号。
"""
with patch("app.adapters.system.rust.parse_metainfo", return_value=None):
meta = MetaInfo(
title="Cyberpunk Edgerunners 2022 1080p NF WEB-DL x264 DDP5.1-GRP",
subtitle="赛博朋克:边缘行者 第一季 不包含第二季",
)
assert meta.begin_season == 1
def test_python_subtitle_negated_episode_is_ignored():
"""
副标题中被否定的集号不应作为资源集号。
"""
with patch("app.adapters.system.rust.parse_metainfo", return_value=None):
meta = MetaInfo(
title="Some Show S01 2022 1080p WEB-DL H264-GRP",
subtitle="某剧 不含第13集",
)
assert meta.begin_episode is None
def test_python_subtitle_year_range_not_treated_as_episodes():
"""
年份范围(如 2019-2020)不得误识别为集数。