mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-11-06 15:22:05 +08:00
fix(metainfo): preserve global words for empty overrides
This commit is contained in:
@@ -411,10 +411,12 @@ def _rust_custom_parse_options(custom_words: Tuple[str, ...]) -> dict:
|
||||
def _rust_parse_options(custom_words: List[str] = None) -> dict:
|
||||
"""
|
||||
收集 Rust Meta 解析所需的运行时配置,避免 Rust 层直接访问数据库和 settings。
|
||||
|
||||
与 Python 识别词匹配器保持一致:None 或空列表沿用全局规则,非空列表覆盖全局规则。
|
||||
"""
|
||||
if custom_words is None:
|
||||
if not custom_words:
|
||||
return _rust_default_parse_options()
|
||||
return _rust_custom_parse_options(tuple(custom_words or []))
|
||||
return _rust_custom_parse_options(tuple(custom_words))
|
||||
|
||||
|
||||
def clear_rust_parse_options_cache() -> None:
|
||||
|
||||
96
tests/test_metainfo_custom_words.py
Normal file
96
tests/test_metainfo_custom_words.py
Normal file
@@ -0,0 +1,96 @@
|
||||
"""验证搜索与路径解析在两种后端下保持相同的全局识别词回退语义。"""
|
||||
|
||||
from pathlib import Path
|
||||
from unittest.mock import Mock
|
||||
|
||||
import pytest
|
||||
|
||||
from app.adapters.system import rust as rust_accel
|
||||
from app.chain.search.result import _torrent_meta
|
||||
from app.chain.search.subtitle import SearchSubtitleOwner
|
||||
from app.domain import metainfo as metainfo_module
|
||||
from app.domain.context import MediaInfo, SubtitleInfo, TorrentInfo
|
||||
from app.domain.meta import words as words_module
|
||||
from app.runtime.config import settings
|
||||
from app.schemas.types import MediaType
|
||||
|
||||
TITLE = "LINK CLICK S03 2021 2160p WEB-DL H.265 AAC-HHWEB"
|
||||
SUBTITLE = "时光代理人 / Link Click III 第三季 | 第06集"
|
||||
GLOBAL_WORD = f"{TITLE} => {TITLE.replace('S03', 'S04')}"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def recognition_words(monkeypatch):
|
||||
"""隔离全局识别词及解析配置缓存,避免规则污染其它测试。"""
|
||||
global_words = [GLOBAL_WORD]
|
||||
monkeypatch.setattr(words_module, "_custom_words_provider", lambda: global_words)
|
||||
metainfo_module.clear_rust_parse_options_cache()
|
||||
try:
|
||||
yield global_words
|
||||
finally:
|
||||
metainfo_module.clear_rust_parse_options_cache()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("backend", ["python", "rust"])
|
||||
@pytest.mark.parametrize("entry", ["title", "torrent", "subtitle", "path"])
|
||||
@pytest.mark.parametrize(
|
||||
("custom_words", "expected_season", "applied_words"),
|
||||
[
|
||||
pytest.param(None, 4, [GLOBAL_WORD], id="default-global"),
|
||||
pytest.param([], 4, [GLOBAL_WORD], id="empty-global"),
|
||||
pytest.param(["S03 => S05"], 5, ["S03 => S05"], id="explicit-override"),
|
||||
pytest.param(["UNMATCHED => OTHER"], 3, [], id="explicit-no-match"),
|
||||
],
|
||||
)
|
||||
def test_custom_words_fallback_matches_across_parsers(
|
||||
monkeypatch, recognition_words, backend, entry, custom_words,
|
||||
expected_season, applied_words,
|
||||
):
|
||||
"""空列表沿用全局规则,非空列表独立覆盖;真实 Rust 不得靠 Python 兜底通过。"""
|
||||
assert recognition_words == [GLOBAL_WORD]
|
||||
if backend == "rust":
|
||||
if not rust_accel.is_available():
|
||||
pytest.skip("moviepilot_rust 扩展未安装")
|
||||
monkeypatch.setattr(settings, "RUST_ACCEL", True)
|
||||
monkeypatch.setattr(metainfo_module, "get_metainfo_accelerator", lambda: rust_accel)
|
||||
monkeypatch.setattr(
|
||||
metainfo_module, "_build_python_meta_info",
|
||||
Mock(side_effect=AssertionError("Rust 解析不应回退到 Python")),
|
||||
)
|
||||
else:
|
||||
monkeypatch.setattr(metainfo_module, "get_metainfo_accelerator", lambda: None)
|
||||
|
||||
if entry == "torrent":
|
||||
meta = _torrent_meta(
|
||||
TorrentInfo(title=TITLE, description=SUBTITLE),
|
||||
custom_words=custom_words,
|
||||
mediainfo=MediaInfo(type=MediaType.TV),
|
||||
)
|
||||
elif entry == "subtitle":
|
||||
meta = SearchSubtitleOwner._build_subtitle_meta(
|
||||
TITLE, SubtitleInfo(title=TITLE, description=SUBTITLE),
|
||||
custom_words=custom_words,
|
||||
)
|
||||
elif entry == "path":
|
||||
meta = metainfo_module.MetaInfoPath(
|
||||
Path(f"/tv/{TITLE} E06.mkv"), custom_words=custom_words,
|
||||
)
|
||||
else:
|
||||
meta = metainfo_module.MetaInfo(TITLE, SUBTITLE, custom_words=custom_words)
|
||||
|
||||
assert meta.season_episode == f"S{expected_season:02d} E06"
|
||||
assert meta.apply_words == applied_words
|
||||
if entry != "path":
|
||||
assert meta.org_string == TITLE.replace("S03", f"S{expected_season:02d}")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("global_words", [None, []])
|
||||
@pytest.mark.parametrize("custom_words", [None, []])
|
||||
def test_empty_custom_words_without_global_rules(
|
||||
monkeypatch, recognition_words, global_words, custom_words,
|
||||
):
|
||||
"""未配置全局规则时,缺省与空列表均生成空识别词配置。"""
|
||||
recognition_words.clear()
|
||||
monkeypatch.setattr(words_module, "_custom_words_provider", lambda: global_words)
|
||||
|
||||
assert metainfo_module._rust_parse_options(custom_words)["custom_words"] == []
|
||||
Reference in New Issue
Block a user