fix(indexer): parse PTTTime user data correctly

This commit is contained in:
moviepilot-codex[bot]
2026-09-21 18:55:59 +08:00
parent 3c516ddbe1
commit 1ab94877d7
2 changed files with 77 additions and 2 deletions

View File

@@ -76,6 +76,10 @@ class NexusPhpSiteUserInfo(SiteParserBase):
if not DomUtils.has_child_elements(html):
return
user_level = self._parse_user_level_marker(html.xpath("string(.)"), self.userid)
if user_level:
self.user_level = user_level
ret = html.xpath(f'//a[contains(@href, "userdetails") and contains(@href, "{self.userid}")]//b//text()')
if ret:
self.username = str(ret[0])
@@ -125,12 +129,24 @@ class NexusPhpSiteUserInfo(SiteParserBase):
if bonus_match and bonus_match.group(1).strip():
self.bonus = text_tools.parse_float(bonus_match.group(1))
return
# PTT-NP 的 mybonus 链接文本只有“使用&说明”,数值位于同一容器的文本中。
bonus_links = html.xpath('//a[contains(@href,"mybonus")]') if html is not None else []
for bonus_link in bonus_links:
bonus_containers = bonus_link.xpath('ancestor::*[contains(., "魔力值")][1]')
if not bonus_containers:
bonus_containers = bonus_link.xpath('parent::*')
for bonus_container in bonus_containers:
bonus_text = bonus_container.xpath("string(.)")
bonus_match = re.search(r"魔力值.*?[::]\s*([\d,.]+)", bonus_text, flags=re.S)
if bonus_match and bonus_match.group(1).strip():
self.bonus = text_tools.parse_float(bonus_match.group(1))
return
bonus_match = re.search(r"mybonus.[\[\]::<>/a-zA-Z_\-=\"'\s#;.(使用魔力值豆]+\s*([\d,.]+)[<()&\s]", html_text)
try:
if bonus_match and bonus_match.group(1).strip():
self.bonus = text_tools.parse_float(bonus_match.group(1))
return
bonus_match = re.search(r"[魔力值|\]][\[\]::<>/a-zA-Z_\-=\"'\s#;]+\s*([\d,.]+|\"[\d,.]+\")[<>()&\s]",
bonus_match = re.search(r"(?:魔力值|\])[\[\]::<>/a-zA-Z_\-=\"'\s#;]+\s*([\d,.]+|\"[\d,.]+\")[<>()&\s]",
html_text,
flags=re.S)
if bonus_match and bonus_match.group(1).strip():
@@ -365,8 +381,24 @@ class NexusPhpSiteUserInfo(SiteParserBase):
# if seeding_url_text:
# self._torrent_seeding_page = seeding_url_text
@staticmethod
def _parse_user_level_marker(page_text: str, userid: Optional[str]) -> Optional[str]:
"""
解析 PTT-NP 首页中的 UID 与用户等级标记。
"""
user_id_pattern = re.escape(str(userid)) if userid else r"\d+"
user_level_match = re.search(
rf"\[\s*UID\s*=\s*{user_id_pattern}\s*\]\s*\[\(\s*([^\)\]]+?)\s*\)",
page_text,
flags=re.IGNORECASE,
)
return user_level_match.group(1).strip() if user_level_match else None
def _get_user_level(self, html):
# 等级 获取同一行等级数据,图片格式等级,取title信息,否则取文本信息
"""
从用户详情页或首页中解析用户等级。
"""
# 等级获取同一行等级数据,图片格式等级取 title 信息,否则取文本信息。
user_levels_text = html.xpath('//tr/td[text()="等級" or text()="等级" or *[text()="等级"]]/'
'following-sibling::td[1]/img[1]/@title')
if user_levels_text:
@@ -395,6 +427,10 @@ class NexusPhpSiteUserInfo(SiteParserBase):
self.user_level = user_level_match.group(1).strip()
break
user_level = self._parse_user_level_marker(html.xpath("string(.)"), self.userid)
if user_level:
self.user_level = user_level
def _parse_message_unread_links(self, html_text: str, msg_links: list) -> Optional[str]:
html = etree.HTML(html_text)
try:

View File

@@ -61,3 +61,42 @@ def test_nexus_php_seeding_next_page_checks_userid_parameter_name():
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&gt;=20||h&lt;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">使用&amp;说明</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 == "初中"
def test_nexus_php_bonus_fallback_ignores_unrelated_script_numbers():
"""
魔力值兜底解析不得把页面脚本中的无关数字当作积分。
"""
parser = _build_parser()
parser._parse_user_traffic_info(
"<html><body><script>if(h&gt;=20||h&lt;5)return 'night';</script></body></html>"
)
assert parser.bonus == 0