From 39a95297dfa94ddded5bf24deaca89196e2c4d83 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Tue, 1 Sep 2026 20:51:17 +0800 Subject: [PATCH 1/2] test(site): cover DIC complete music titles --- tests/test_dicmusic_indexer.py | 116 +++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 tests/test_dicmusic_indexer.py diff --git a/tests/test_dicmusic_indexer.py b/tests/test_dicmusic_indexer.py new file mode 100644 index 000000000..dc6ca1f47 --- /dev/null +++ b/tests/test_dicmusic_indexer.py @@ -0,0 +1,116 @@ +from unittest.mock import patch + +import pytest + +from app.adapters.system import rust as rust_accel +from app.modules.indexer.spider import SiteSpider +from app.schemas.types import MediaType + +DICMUSIC_HTML = """ + + + + + + + + + + +
+ + DL + + BTS - ARIRANG + today1.00 GiB2482
+ +""" + + +def _dicmusic_indexer() -> dict: + """构造与 DIC Music 资源配置一致的非分组 Gazelle 索引器。""" + detail_selector = 'a[href*="torrents.php?id="][href*="torrentid="]' + return { + "id": "dicmusic", + "name": "海豚", + "domain": "https://dicmusic.com/", + "media_type": "music", + "schema": "Gazelle", + "search": { + "paths": [{"path": "torrents.php", "method": "get"}], + "params": { + "searchsubmit": 1, + "group_results": 0, + "searchstr": "{keyword}", + }, + }, + "torrents": { + "list": {"selector": "table#torrent_table > tbody > tr.torrent"}, + "fields": { + "id": { + "selector": detail_selector, + "attribute": "href", + "filters": [ + {"name": "re_search", "args": [r"torrentid=(\d+)", 1]} + ], + }, + "title": {"selector": detail_selector}, + "details": {"selector": detail_selector, "attribute": "href"}, + "download": { + "selector": 'a[href*="torrents.php?action=download"]', + "attribute": "href", + }, + "size": {"selector": "td.td_size"}, + "seeders": {"selector": "td.td_seeders"}, + "leechers": {"selector": "td.td_leechers"}, + "grabs": {"selector": "td.td_snatched"}, + "date_elapsed": { + "selector": "td.td_time > span", + "attribute": "title", + "optional": True, + }, + "date": { + "text": "{% if fields['date_elapsed'] %}{{ fields['date_elapsed'] }}{% else %}now{% endif %}", + "filters": [{"name": "dateparse", "args": "%b %d %Y, %H:%M"}], + }, + }, + }, + } + + +def test_dicmusic_search_uses_complete_music_title_in_python_fallback(): + """DIC Music Python 兜底解析应从非分组行保留完整音乐名。""" + with patch( + "app.modules.indexer.spider.rust_accel.parse_indexer_torrents", + return_value=None, + ): + results = SiteSpider( + _dicmusic_indexer(), keyword="ARIRANG", mtype=MediaType.MUSIC + ).parse(DICMUSIC_HTML) + + assert len(results) == 1 + assert results[0]["title"] == "BTS - ARIRANG" + assert results[0]["page_url"].endswith("torrents.php?id=123&torrentid=456") + assert results[0]["enclosure"].endswith("torrents.php?action=download&id=456") + + +@pytest.mark.skipif( + not rust_accel.is_available(), + reason="moviepilot_rust 扩展未安装", +) +def test_dicmusic_search_uses_complete_music_title_in_rust_parser(monkeypatch): + """DIC Music Rust 解析应与 Python 解析共享完整音乐名。""" + monkeypatch.setattr(rust_accel, "is_enabled", lambda: True) + + def fail_python_fallback(*_args, **_kwargs): + """Rust 解析异常回退时让测试显式失败。""" + raise AssertionError("DIC Music Rust 解析不应回退 Python") + + monkeypatch.setattr(SiteSpider, "get_info", fail_python_fallback) + + results = SiteSpider( + _dicmusic_indexer(), keyword="ARIRANG", mtype=MediaType.MUSIC + ).parse(DICMUSIC_HTML) + + assert len(results) == 1 + assert results[0]["title"] == "BTS - ARIRANG" From bdb2d0d7e28a0df9d384e5128ad5e79c9aa22954 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Tue, 1 Sep 2026 21:03:39 +0800 Subject: [PATCH 2/2] test(site): satisfy mypy for DIC regression --- tests/test_dicmusic_indexer.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/tests/test_dicmusic_indexer.py b/tests/test_dicmusic_indexer.py index dc6ca1f47..36e1b88b8 100644 --- a/tests/test_dicmusic_indexer.py +++ b/tests/test_dicmusic_indexer.py @@ -1,3 +1,4 @@ +from typing import Any, NoReturn from unittest.mock import patch import pytest @@ -27,7 +28,7 @@ DICMUSIC_HTML = """ """ -def _dicmusic_indexer() -> dict: +def _dicmusic_indexer() -> dict[str, Any]: """构造与 DIC Music 资源配置一致的非分组 Gazelle 索引器。""" detail_selector = 'a[href*="torrents.php?id="][href*="torrentid="]' return { @@ -78,7 +79,7 @@ def _dicmusic_indexer() -> dict: } -def test_dicmusic_search_uses_complete_music_title_in_python_fallback(): +def test_dicmusic_search_uses_complete_music_title_in_python_fallback() -> None: """DIC Music Python 兜底解析应从非分组行保留完整音乐名。""" with patch( "app.modules.indexer.spider.rust_accel.parse_indexer_torrents", @@ -94,15 +95,16 @@ def test_dicmusic_search_uses_complete_music_title_in_python_fallback(): assert results[0]["enclosure"].endswith("torrents.php?action=download&id=456") -@pytest.mark.skipif( - not rust_accel.is_available(), - reason="moviepilot_rust 扩展未安装", -) -def test_dicmusic_search_uses_complete_music_title_in_rust_parser(monkeypatch): +def test_dicmusic_search_uses_complete_music_title_in_rust_parser( + monkeypatch: pytest.MonkeyPatch, +) -> None: """DIC Music Rust 解析应与 Python 解析共享完整音乐名。""" + if not rust_accel.is_available(): + pytest.skip("moviepilot_rust 扩展未安装") + monkeypatch.setattr(rust_accel, "is_enabled", lambda: True) - def fail_python_fallback(*_args, **_kwargs): + def fail_python_fallback(*_args: object, **_kwargs: object) -> NoReturn: """Rust 解析异常回退时让测试显式失败。""" raise AssertionError("DIC Music Rust 解析不应回退 Python")