feat(douyu): 和平小店绑定功能(生成绑定二维码/查询绑定信息)
- activity_client: xpd_bind_qr(roleParam 签发 livelink 绑定链接, 微信扫码进小程序绑定) + xpd_bind_info(bindInfo 查询绑定状态/角色/平台), gameRole 非 dict 边界防护 - runner/service: 注册 get_xpd_bind_qr / query_xpd_bind_info 任务, 回写 xpd_game_name / xpd_bind_status - router: get_xpd_bind_qr 的 url 加入列表接口保留白名单(二维码展示) - 前端: 和平小店面板新增两个按钮, 二维码列支持 get_xpd_bind_qr 展示/放大
This commit is contained in:
@@ -819,6 +819,8 @@ class DouyuActivityClient:
|
||||
# ---- 和平小店(腾讯道聚城 H5)----
|
||||
XPD_EMBED_API = "https://www.douyu.com/japi/carnival/nc/txEmbed/getIframeUrl"
|
||||
XPD_H5_REFERER = "https://www.douyu.com/topic/h5/hpxd01"
|
||||
XPD_ROLE_PARAM_API = "https://apiv2.douyucdn.cn/japi/carnivalApi/tencent/roleParam"
|
||||
XPD_BIND_INFO_API = "https://www.douyu.com/japi/carnivalApi/v2/tencent/bindInfo"
|
||||
XPD_DAOJU_REFERER = "https://app.daoju.qq.com/"
|
||||
XPD_GET_ROLE_API = "https://apps.game.qq.com/daoju/igw/live"
|
||||
# 2026-08 抓包(8.6-和平小店)实证:本期走 xn_live_cjm 变体(旧期为 recommend_live/common)
|
||||
@@ -1002,6 +1004,67 @@ class DouyuActivityClient:
|
||||
)
|
||||
return {"goods": goods, "raw": recommend}
|
||||
|
||||
def xpd_bind_qr(self, *, act_alias: str) -> dict[str, Any]:
|
||||
"""生成和平小店绑定二维码链接(微信扫码进入 livelink 小程序绑定角色)。
|
||||
|
||||
返回 data.url(可生成二维码)与 gameRoleBindUrl(直接角色绑定页)。
|
||||
"""
|
||||
payload = self._request_json(
|
||||
"post",
|
||||
self.XPD_ROLE_PARAM_API,
|
||||
"生成小店绑定二维码",
|
||||
params={"client_sys": "android"},
|
||||
data={
|
||||
"token": self._xpd_token(),
|
||||
"uid": cookie_value(self.cookie, "acf_uid") or "",
|
||||
"client": "mobile",
|
||||
"actAlias": act_alias,
|
||||
},
|
||||
headers={
|
||||
"User-Device": "MDExZTUxMzEyYmYxMmY5MmQ3YmY1M2M4MDA3MDcxMTF8djcuOS4y",
|
||||
"aid": "android1",
|
||||
"User-Agent": "android/7.9.2 (android 9; ; M973Q)",
|
||||
"Accept-Language": "zh-CN",
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
)
|
||||
if payload.get("error") not in (0, "0", None):
|
||||
raise DouyuActivityError(payload.get("msg") or "生成小店绑定二维码失败")
|
||||
data = payload.get("data") or {}
|
||||
url = str(data.get("url") or "")
|
||||
if not url:
|
||||
raise DouyuActivityError(f"生成小店绑定二维码失败: {payload}")
|
||||
return {
|
||||
"url": url,
|
||||
"game_role_bind_url": str(data.get("gameRoleBindUrl") or ""),
|
||||
"nick_name": str((data.get("queryParams") or {}).get("nickName") or ""),
|
||||
"raw": payload,
|
||||
}
|
||||
|
||||
def xpd_bind_info(self, *, act_alias: str) -> dict[str, Any]:
|
||||
"""查询和平小店绑定信息(bindInfo)。"""
|
||||
payload = self._request_json(
|
||||
"get",
|
||||
self.XPD_BIND_INFO_API,
|
||||
"查询小店绑定信息",
|
||||
params={"actAlias": act_alias, "token": self._xpd_token()},
|
||||
)
|
||||
if payload.get("error") not in (0, "0", None):
|
||||
raise DouyuActivityError(payload.get("msg") or "查询小店绑定信息失败")
|
||||
data = payload.get("data") or {}
|
||||
game_role = data.get("gameRole") if isinstance(data.get("gameRole"), dict) else {}
|
||||
game_account = data.get("gameAccount") if isinstance(data.get("gameAccount"), dict) else {}
|
||||
return {
|
||||
"bind_account": self._xpd_int(data.get("bindAccount")),
|
||||
"bind_role": self._xpd_int(data.get("bindRole")),
|
||||
"need_bind_role": self._xpd_int(data.get("needBindRole")),
|
||||
"nick": str(game_account.get("nick") or ""),
|
||||
"role_name": str(game_role.get("roleName") or ""),
|
||||
"area_name": str(game_role.get("areaName") or ""),
|
||||
"plat_name": str(game_role.get("platName") or ""),
|
||||
"raw": payload,
|
||||
}
|
||||
|
||||
def xpd_balance(
|
||||
self,
|
||||
*,
|
||||
|
||||
Reference in New Issue
Block a user