mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-10-29 03:18:14 +08:00
308 lines
10 KiB
Python
308 lines
10 KiB
Python
# -*- coding: utf-8 -*-
|
||
from urllib.parse import parse_qs, urlsplit
|
||
|
||
from lxml import etree
|
||
|
||
from app.modules.indexer.parser.nexus_php import NexusPhpSiteUserInfo
|
||
|
||
|
||
def _build_parser() -> NexusPhpSiteUserInfo:
|
||
"""
|
||
构造 NexusPHP 解析器测试实例。
|
||
"""
|
||
return NexusPhpSiteUserInfo(
|
||
site_name="NexusPHP",
|
||
url="https://example.com/",
|
||
site_cookie="",
|
||
apikey=None,
|
||
token=None,
|
||
)
|
||
|
||
|
||
def test_nexus_php_seeding_next_page_stops_when_userid_missing():
|
||
"""
|
||
userid 未识别且下一页也缺少 userid 时应停止翻页而不是抛出异常。
|
||
"""
|
||
parser = _build_parser()
|
||
html_text = """
|
||
<html>
|
||
<body>
|
||
<table class="torrents">
|
||
<tr><td>标题</td><td>大小</td><td>在做种</td></tr>
|
||
</table>
|
||
<a href="getusertorrentlistajax.php?page=2">下一页</a>
|
||
</body>
|
||
</html>
|
||
"""
|
||
|
||
next_page = parser._parse_user_torrent_seeding_info(html_text, multi_page=True)
|
||
|
||
assert next_page is None
|
||
|
||
|
||
def test_nexus_php_seeding_next_page_checks_userid_parameter_name():
|
||
"""
|
||
下一页链接缺少 userid 参数时,即使链接中包含用户 ID 字符串也应补齐 userid。
|
||
"""
|
||
parser = _build_parser()
|
||
parser.userid = "12"
|
||
html_text = """
|
||
<html>
|
||
<body>
|
||
<table class="torrents">
|
||
<tr><td>标题</td><td>大小</td><td>在做种</td></tr>
|
||
</table>
|
||
<a href="getusertorrentlistajax.php?page=12&type=seeding">下一页</a>
|
||
</body>
|
||
</html>
|
||
"""
|
||
|
||
next_page = parser._parse_user_torrent_seeding_info(html_text, multi_page=True)
|
||
query_params = parse_qs(urlsplit(next_page).query)
|
||
|
||
assert query_params["page"] == ["12"]
|
||
assert query_params["type"] == ["seeding"]
|
||
assert query_params["userid"] == ["12"]
|
||
|
||
|
||
def test_nexus_php_pttime_homepage_parses_bonus_and_user_level():
|
||
"""
|
||
PTT-NP 首页应从魔力值容器和 UID 标记中解析魔力值、通用用户等级。
|
||
"""
|
||
parser = _build_parser()
|
||
html_text = """
|
||
<html>
|
||
<body>
|
||
<script>if(h>=20||h<5)return 'night';</script>
|
||
<a href="userdetails.php?id=67537" class="EliteUser_Name"><b>Opportunity</b></a>
|
||
[UID=67537][(初中)Elite User]
|
||
<span class="mr5">
|
||
<font class="fwb">魔力值(96.67魔力/小时)</font>
|
||
[<a href="mybonus.php" class="fcb">使用&说明</a>]:14419.2
|
||
</span>
|
||
</body>
|
||
</html>
|
||
"""
|
||
|
||
parser._parse_site_page(html_text)
|
||
parser._parse_user_base_info(html_text)
|
||
|
||
assert parser.bonus == 14419.2
|
||
assert parser.user_level == "Elite User"
|
||
|
||
|
||
def test_nexus_php_pttime_marker_requires_common_level_for_current_user():
|
||
"""UID 标记缺少通用等级或属于其他用户时,不应解析站点专用等级。"""
|
||
parse_marker = NexusPhpSiteUserInfo._parse_user_level_marker
|
||
|
||
assert parse_marker("[UID=67537][(初中)]", "67537") is None
|
||
assert parse_marker("[UID=123][(初中)Elite User]", "67537") is None
|
||
|
||
|
||
def test_nexus_php_bonus_fallback_ignores_unrelated_script_numbers():
|
||
"""
|
||
魔力值兜底解析不得把页面脚本中的无关数字当作积分。
|
||
"""
|
||
parser = _build_parser()
|
||
|
||
parser._parse_user_traffic_info(
|
||
"<html><body><script>if(h>=20||h<5)return 'night';</script></body></html>"
|
||
)
|
||
|
||
assert parser.bonus == 0
|
||
|
||
|
||
def test_nexus_php_bonus_reads_value_nested_in_mybonus_link():
|
||
"""
|
||
憨憨等站点将魔力值嵌在 mybonus 链接内的元素中,且页面公告里存在无关的“魔力值…:数字”文本。
|
||
"""
|
||
parser = _build_parser()
|
||
html_text = """
|
||
<html>
|
||
<body>
|
||
<div>
|
||
视工作情况会给予魔力值、邀请码等奖励。具体处理措施如下:
|
||
1、补偿所有用户100000憨豆;(已经发放完成)
|
||
</div>
|
||
<div class="flex flex-row items-center">
|
||
<img src="styles/HHan/icons/icon-bean.svg" alt="憨豆">
|
||
<a href="mybonus.php">
|
||
<div class="text-sm flex flex-wrap break-all">13,853,582</div>
|
||
</a>
|
||
</div>
|
||
</body>
|
||
</html>
|
||
"""
|
||
|
||
parser._parse_user_traffic_info(html_text)
|
||
|
||
assert parser.bonus == 13853582.0
|
||
|
||
|
||
def test_nexus_php_uuid_user_details_link_parses_uuid_user():
|
||
"""
|
||
NexusPHP v1.10+ 使用 UUID 标识用户的站点应解析用户详情链接,并使用 useruuid 请求做种列表。
|
||
"""
|
||
parser = _build_parser()
|
||
html_text = """
|
||
<html>
|
||
<body>
|
||
<table id="info_block"><tr><td>
|
||
欢迎回来, <span class="nowrap"><a href="https://mua.xloli.cc/userdetails.php?uuid=53d25816-f7b7-4372-b58d-6f445acfe090" class='User_Name'><b>Andreas</b></a></span>
|
||
<font class='color_bonus'>魔力值 </font>[<a href="mybonus.php">使用</a>]: 105.5
|
||
</td></tr></table>
|
||
</body>
|
||
</html>
|
||
"""
|
||
|
||
parser._parse_site_page(html_text)
|
||
parser._parse_user_base_info(html_text)
|
||
|
||
assert parser.userid == "53d25816-f7b7-4372-b58d-6f445acfe090"
|
||
assert parser._user_detail_page == "userdetails.php?uuid=53d25816-f7b7-4372-b58d-6f445acfe090"
|
||
assert parser._torrent_seeding_page == (
|
||
"getusertorrentlistajax.php?useruuid=53d25816-f7b7-4372-b58d-6f445acfe090&type=seeding"
|
||
)
|
||
assert parser.username == "Andreas"
|
||
assert parser.bonus == 105.5
|
||
|
||
|
||
def test_nexus_php_numeric_user_details_link_keeps_userid_param():
|
||
"""
|
||
传统数字用户 ID 的站点应继续使用 userid 请求做种列表。
|
||
"""
|
||
parser = _build_parser()
|
||
html_text = '<html><body><a href="userdetails.php?id=67537"><b>Opportunity</b></a></body></html>'
|
||
|
||
parser._parse_site_page(html_text)
|
||
|
||
assert parser.userid == "67537"
|
||
assert parser._torrent_seeding_page == "getusertorrentlistajax.php?userid=67537&type=seeding"
|
||
|
||
|
||
def test_nexus_php_uuid_seeding_js_link_uses_useruuid():
|
||
"""
|
||
用户详情页的做种 JS 调用携带 UUID 时,应改用 useruuid 参数请求做种列表。
|
||
"""
|
||
parser = _build_parser()
|
||
# 首页未解析到用户链接时,做种地址为空,需要从用户详情页的 JS 调用中补齐
|
||
parser._torrent_seeding_page = None
|
||
html_text = """
|
||
<html>
|
||
<body>
|
||
<a href="javascript: getusertorrentlistajax('53d25816-f7b7-4372-b58d-6f445acfe090', 'seeding', 'ka1'); klappe_news('a1')">[显示/隐藏]</a>
|
||
</body>
|
||
</html>
|
||
"""
|
||
|
||
parser._fixup_torrent_seeding_page(etree.HTML(html_text))
|
||
|
||
assert parser.userid == "53d25816-f7b7-4372-b58d-6f445acfe090"
|
||
assert parser._torrent_seeding_page == (
|
||
"getusertorrentlistajax.php?useruuid=53d25816-f7b7-4372-b58d-6f445acfe090&type=seeding"
|
||
)
|
||
|
||
|
||
def test_nexus_php_uuid_seeding_next_page_uses_useruuid():
|
||
"""
|
||
UUID 站点的做种下一页地址缺少用户标识时,应补齐 useruuid 而不是 userid。
|
||
"""
|
||
parser = _build_parser()
|
||
parser.userid = "53d25816-f7b7-4372-b58d-6f445acfe090"
|
||
html_text = """
|
||
<html>
|
||
<body>
|
||
<table class="torrents">
|
||
<tr><td>标题</td><td>大小</td><td>在做种</td></tr>
|
||
</table>
|
||
<a href="getusertorrentlistajax.php?page=2&type=seeding">下一页</a>
|
||
</body>
|
||
</html>
|
||
"""
|
||
|
||
next_page = parser._parse_user_torrent_seeding_info(html_text, multi_page=True)
|
||
query_params = parse_qs(urlsplit(next_page).query)
|
||
|
||
assert query_params["useruuid"] == ["53d25816-f7b7-4372-b58d-6f445acfe090"]
|
||
assert "userid" not in query_params
|
||
assert query_params["type"] == ["seeding"]
|
||
|
||
|
||
def test_nexus_php_pterclub_profile_parses_current_seeding_table():
|
||
"""
|
||
猫站用户详情页的“当前做种”表应按第 4、5 列统计做种体积和做种人数。
|
||
"""
|
||
parser = _build_parser()
|
||
parser.userid = "123"
|
||
html_text = """
|
||
<html><body>
|
||
<table><tr>
|
||
<td>当前做种</td>
|
||
<td><table><tbody>
|
||
<tr><td>详情</td><td><a>种子一</a></td><td>分类</td><td>1.5 TB</td><td><a>12</a></td></tr>
|
||
<tr><td>详情</td><td><a>种子二</a></td><td>分类</td><td>700 GB</td><td><a>3</a></td></tr>
|
||
</tbody></table></td>
|
||
</tr></table>
|
||
</body></html>
|
||
"""
|
||
|
||
parser._parse_user_detail_info(html_text)
|
||
|
||
assert parser.seeding == 2
|
||
assert parser.seeding_size == 1.5 * 1024**4 + 700 * 1024**3
|
||
assert parser.seeding_info == [[12, int(1.5 * 1024**4)], [3, 700 * 1024**3]]
|
||
|
||
|
||
def test_nexus_php_pterclub_full_seeding_list_uses_site_columns():
|
||
"""
|
||
猫站完整做种页即使没有表头,也应读取第 4 列体积和第 5 列做种人数。
|
||
"""
|
||
parser = _build_parser()
|
||
parser._site_domain = "pterclub.net"
|
||
parser.userid = "123"
|
||
html_text = """
|
||
<html><body>
|
||
<div id="outer"><table><tbody>
|
||
<tr><td>详情</td><td><a href="details.php?id=1">种子一</a></td><td>分类</td><td>1.5 TB</td><td><a>12</a></td></tr>
|
||
</tbody></table>
|
||
<p class="np-pager"><font class="gray">1</font><a href="getusertorrentlist.php?userid=123&type=seeding&page=2">下一页</a></p></div>
|
||
</body></html>
|
||
"""
|
||
|
||
next_page = parser._parse_user_torrent_seeding_info(html_text)
|
||
|
||
assert parser.seeding == 1
|
||
assert parser.seeding_size == int(1.5 * 1024**4)
|
||
assert parser.seeding_info == [[12, int(1.5 * 1024**4)]]
|
||
assert next_page == "getusertorrentlist.php?userid=123&type=seeding&page=2"
|
||
|
||
|
||
def test_nexus_php_seeding_list_replaces_profile_fallback_without_double_counting(monkeypatch):
|
||
"""
|
||
做种列表成功时应覆盖详情页中的部分做种统计,避免重复累加。
|
||
"""
|
||
parser = _build_parser()
|
||
parser.userid = "123"
|
||
parser._torrent_seeding_page = "getusertorrentlistajax.php?userid=123&type=seeding"
|
||
parser._parse_user_detail_info("""
|
||
<html><body><table><tr>
|
||
<td>当前做种</td>
|
||
<td><table><tbody>
|
||
<tr><td>详情</td><td>种子一</td><td>分类</td><td>1.5 TB</td><td>12</td></tr>
|
||
</tbody></table></td>
|
||
</tr></table></body></html>
|
||
""")
|
||
list_html = """
|
||
<html><body><table class="torrents">
|
||
<tr><td>标题</td><td>分类</td><td>大小</td><td>在做种</td></tr>
|
||
<tr><td>种子一</td><td>分类</td><td>500 GB</td><td><b><a>7</a></b></td></tr>
|
||
</table></body></html>
|
||
"""
|
||
monkeypatch.setattr(parser, "_get_page_content", lambda **_: list_html)
|
||
|
||
parser._parse_seeding_pages()
|
||
|
||
assert parser.seeding == 1
|
||
assert parser.seeding_size == 500 * 1024**3
|
||
assert parser.seeding_info == [[7, 500 * 1024**3]]
|