feat(tng): 自动拉红包历史/详情,并展示发放与领取时间
从 ILoginStorage 与官方历史页缓存请求模板,级联拉详情;领取台列表用发放时间而非拉取时间。
This commit is contained in:
@@ -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 = """<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
@@ -371,7 +407,7 @@ def _mmp_html_page():
|
||||
<main class="main">
|
||||
<div id="empty" class="empty">
|
||||
暂无红包数据<br/>
|
||||
<div class="hint">打开 Money Packet 历史页可自动拉取;若没有数据,先手动点开任意一条详情一次(缓存登录模板),再回历史页</div>
|
||||
<div class="hint">登录 TNG 后停留任意页面即可自动拉历史并拉详情;也可打开 Money Packet 历史页加速。无需再手动点详情。</div>
|
||||
</div>
|
||||
<div id="panel" style="display:none">
|
||||
<h2 class="title" id="title">-</h2>
|
||||
@@ -420,7 +456,7 @@ def _mmp_html_page():
|
||||
div.onclick = () => { activeId = p.packetId; loadData(); };
|
||||
div.innerHTML = `
|
||||
<div class="pkt-id">${esc(shortId(p.packetId))} · ${esc((p.sender || '红包') + ' RM' + (p.sumClaimed ?? p.total ?? 0))}</div>
|
||||
<div class="pkt-meta">${p.claimantCount || 0} 人领取 · ${esc(p.latestAt || '')}</div>`;
|
||||
<div class="pkt-meta">${p.claimantCount || 0} 人领取 · ${esc(p.issuedAt ? ('发放 ' + p.issuedAt) : '发放时间未知')}</div>`;
|
||||
list.appendChild(div);
|
||||
}
|
||||
renderActive();
|
||||
@@ -440,6 +476,7 @@ def _mmp_html_page():
|
||||
const parts = [];
|
||||
if (p.packetId) parts.push('activityId ' + p.packetId);
|
||||
if (p.sender) parts.push('发送人 ' + p.sender);
|
||||
if (p.issuedAt) parts.push('发放 ' + p.issuedAt);
|
||||
if (p.group) parts.push('群组 ' + p.group);
|
||||
if (p.via) parts.push('来源 ' + (p.via === 'http' ? '网络' : p.via === 'gson' ? '解析' : p.via === 'rpc' ? 'RPC' : p.via));
|
||||
document.getElementById('sub').textContent = parts.join(' · ') || '单个红包领取排行';
|
||||
|
||||
Reference in New Issue
Block a user