From 1517ff46711dd47d2f1a7332bd1b6c7a182ea5b2 Mon Sep 17 00:00:00 2001 From: mars <3361409208@qq.com> Date: Tue, 4 Aug 2026 16:20:13 +0800 Subject: [PATCH] =?UTF-8?q?feat(tng):=20=E8=87=AA=E5=8A=A8=E6=8B=89?= =?UTF-8?q?=E7=BA=A2=E5=8C=85=E5=8E=86=E5=8F=B2/=E8=AF=A6=E6=83=85?= =?UTF-8?q?=EF=BC=8C=E5=B9=B6=E5=B1=95=E7=A4=BA=E5=8F=91=E6=94=BE=E4=B8=8E?= =?UTF-8?q?=E9=A2=86=E5=8F=96=E6=97=B6=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 从 ILoginStorage 与官方历史页缓存请求模板,级联拉详情;领取台列表用发放时间而非拉取时间。 --- debug-server/server.py | 65 +- docs/TNG_MoneyPacket领取台.md | 41 +- docs/TNG_开放问题与抓包能力.md | 5 +- .../xposed/hook/TngMoneyPacketHook.java | 890 ++++++++++++++++-- 4 files changed, 873 insertions(+), 128 deletions(-) diff --git a/debug-server/server.py b/debug-server/server.py index 8352e0a..2658d05 100644 --- a/debug-server/server.py +++ b/debug-server/server.py @@ -2,6 +2,7 @@ """notiMessage 本地调试转发服务 — 在 PC 浏览器查看手机抓取的消息。""" import json +import re import threading import time from collections import deque @@ -178,6 +179,11 @@ def _parse_mmp_content(content): if "total" in meta: total_num = _normalize_money(meta["total"]) meta["total"] = ("{0:.2f}".format(total_num) if total_num is not None else meta["total"]) + # 发放时间:issued= / createTime= / issuedAt= + for key in ("issued", "createTime", "issuedAt", "create"): + if meta.get(key): + meta["issued"] = meta[key] + break for line in lines[1:]: line = line.strip() if not line or "->" not in line: @@ -212,22 +218,28 @@ def _claims_fingerprint(claims): def _aggregate_claims(claims): - """同一快照内同昵称合并;跨快照不应再混加(外层只取最新快照)。""" + """同一快照内同昵称只保留一笔(取较大金额),红包每人只领一次,禁止累加导致翻倍。""" buckets = {} order = [] for c in claims: nick = c.get("nickname") or "?" + try: + amt = float(c.get("amountValue") if c.get("amountValue") is not None + else _normalize_money(c.get("amount")) or 0.0) + except (TypeError, ValueError): + amt = 0.0 if nick not in buckets: - buckets[nick] = {"nickname": nick, "amount": 0.0, "count": 0, "claimTime": ""} + buckets[nick] = {"nickname": nick, "amount": amt, "count": 1, + "claimTime": c.get("claimTime") or ""} order.append(nick) + continue b = buckets[nick] b["count"] += 1 - try: - b["amount"] += float(c.get("amountValue") if c.get("amountValue") is not None - else _normalize_money(c.get("amount")) or 0.0) - except (TypeError, ValueError): - pass - if c.get("claimTime") and not b["claimTime"]: + if amt >= b["amount"]: + b["amount"] = amt + if c.get("claimTime"): + b["claimTime"] = c.get("claimTime") or b["claimTime"] + elif c.get("claimTime") and not b["claimTime"]: b["claimTime"] = c.get("claimTime") or "" result = [] for nick in order: @@ -259,6 +271,7 @@ def _mmp_packets(): # 用领取名单指纹区分不同红包 packet_id = "红包-" + _claims_fingerprint(claims)[:48] key = str(packet_id) + issued = meta.get("issued") or "" item = { "packetId": key, "title": msg.get("title") or "TNG 红包", @@ -266,7 +279,9 @@ def _mmp_packets(): "group": meta.get("group") or "", "total": meta.get("total") or "", "via": meta.get("via") or "", - "latestAt": msg.get("receivedAt") or "", + "issuedAt": issued, + "fetchedAt": msg.get("receivedAt") or "", + "latestAt": issued or (msg.get("receivedAt") or ""), "snapshots": 1, "claims": claims, "rawMessages": [{ @@ -277,15 +292,27 @@ def _mmp_packets(): }], } existing = packets.get(key) - if existing is None or (item["latestAt"] or "") >= (existing.get("latestAt") or ""): + # 优先保留「有发放时间 + 领取更全」的快照;时间戳用发放时间排序 + def _score(it): + return ( + 1 if it.get("issuedAt") else 0, + len(it.get("claims") or []), + it.get("fetchedAt") or "", + ) + if existing is None or _score(item) >= _score(existing): if existing is not None: item["snapshots"] = int(existing.get("snapshots") or 1) + 1 - # 保留历史原始报文,但排行只用最新 claims item["rawMessages"] = existing.get("rawMessages", []) + item["rawMessages"] + if not item.get("issuedAt") and existing.get("issuedAt"): + item["issuedAt"] = existing["issuedAt"] + item["latestAt"] = item["issuedAt"] or item.get("fetchedAt") or "" packets[key] = item else: existing["snapshots"] = int(existing.get("snapshots") or 1) + 1 existing["rawMessages"].append(item["rawMessages"][0]) + if not existing.get("issuedAt") and issued: + existing["issuedAt"] = issued + existing["latestAt"] = issued result = [] for p in packets.values(): ranked = _aggregate_claims(p.get("claims") or []) @@ -305,10 +332,19 @@ def _mmp_packets(): p["total"] = "{0:.2f}".format(total_num) del p["claims"] result.append(p) - result.sort(key=lambda x: x.get("latestAt") or "", reverse=True) + result.sort(key=lambda x: _mmp_time_sort_key(x.get("issuedAt") or x.get("latestAt") or ""), reverse=True) return result +def _mmp_time_sort_key(text): + """把 13/07/2026 11:54:44 / ISO 等统一成可比较字符串。""" + s = (text or "").strip() + m = re.match(r"^(\d{2})/(\d{2})/(\d{4})(?:\s+(\d{2}:\d{2}(?::\d{2})?))?", s) + if m: + return "{0}-{1}-{2} {3}".format(m.group(3), m.group(2), m.group(1), m.group(4) or "") + return s + + def _mmp_html_page(): html = """ @@ -371,7 +407,7 @@ def _mmp_html_page():
暂无红包数据
-
打开 Money Packet 历史页可自动拉取;若没有数据,先手动点开任意一条详情一次(缓存登录模板),再回历史页
+
登录 TNG 后停留任意页面即可自动拉历史并拉详情;也可打开 Money Packet 历史页加速。无需再手动点详情。