feat(douyu): 支持和平小店商品兑换
This commit is contained in:
@@ -826,6 +826,7 @@ class DouyuActivityClient:
|
||||
# 2026-08 抓包(8.6-和平小店)实证:本期走 xn_live_cjm 变体(旧期为 recommend_live/common)
|
||||
XPD_RECOMMEND_API = "https://apps.game.qq.com/daoju/v3/recommend_xn_live_cjm/common"
|
||||
XPD_BALANCE_API = "https://apps.game.qq.com/daoju/igw/live/"
|
||||
XPD_LIVE_BUY_API = "https://apps.game.qq.com/daoju/igw/livebuy/"
|
||||
XPD_UA = (
|
||||
"Mozilla/5.0 (Linux; Android 12; HBN-AL00 Build/V417IR; wv) "
|
||||
"AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 "
|
||||
@@ -965,7 +966,7 @@ class DouyuActivityClient:
|
||||
"iRelationGoodsid,dtModifyTime,sBuyLimitInfo,sGoodsWaterMark,dtShowBeginTime,"
|
||||
"dtShowEndTime,iSort,iGoodsId,sGoodsName,iJbPrice,iJbOrgPrice,iJb2Price,"
|
||||
"iJb2OrgPrice,iPrice,iOrgPrice,sGoodsPic,sGoodsDesc,sPayType,dtBeginTime,"
|
||||
"dtEndTime,iActionId,sExtShowInfo,sExtInfo,iCategoryId,dtRushBegin,dtRushEnd"
|
||||
"dtEndTime,iActionId,sExtShowInfo,sExtInfo,iCategoryId,iGoodsLeft,dtRushBegin,dtRushEnd"
|
||||
),
|
||||
"actionFields": "iActionId,sActionName,dtBeginTime,dtEndTime",
|
||||
"order_by": "dtShowBeginTime",
|
||||
@@ -1146,3 +1147,79 @@ class DouyuActivityClient:
|
||||
)
|
||||
info = self._xpd_parse_var(response.text, "jbInfos")
|
||||
return {"fragments": self._xpd_int(info.get("jb2")), "raw": info}
|
||||
|
||||
def xpd_exchange_goods(
|
||||
self,
|
||||
*,
|
||||
embed_query: dict[str, str],
|
||||
act_id: str,
|
||||
rid: str,
|
||||
commodity_id: str,
|
||||
price: int,
|
||||
picture: str = "",
|
||||
pay_type: int = 1,
|
||||
action_id: str = "",
|
||||
) -> dict[str, Any]:
|
||||
"""兑换和平小店商品。
|
||||
|
||||
道聚城的 code/sig 为短时授权参数,调用方必须在每次兑换前重新获取。
|
||||
该接口会实际扣除点券或扭蛋碎片,因此遇到网络错误不做自动重试。
|
||||
"""
|
||||
if pay_type not in (1, 5):
|
||||
raise DouyuActivityError("小店兑换仅支持点券或扭蛋碎片")
|
||||
if not commodity_id:
|
||||
raise DouyuActivityError("小店兑换缺少商品 ID")
|
||||
if price < 0:
|
||||
raise DouyuActivityError("小店兑换商品价格无效")
|
||||
|
||||
params = {
|
||||
"_service": "buy.plug.svr.web",
|
||||
"_plug_id": "7200",
|
||||
"_jsvar": "buyInfo",
|
||||
"acctype": "livelink",
|
||||
"_app_id": "2123",
|
||||
"iActionId": action_id or act_id,
|
||||
"propid": commodity_id,
|
||||
"paytype": str(pay_type),
|
||||
"source": rid,
|
||||
"sAnchorId": rid,
|
||||
"attach": json.dumps({"ch": "0"}, separators=(",", ":")),
|
||||
"apptype": "3",
|
||||
"_biz_code": "cjm",
|
||||
"_act_id": act_id,
|
||||
"sLiveUserInfo": json.dumps(
|
||||
{"sAnchorId": rid, "sVideoId": 0}, separators=(",", ":"),
|
||||
),
|
||||
"appext": json.dumps(
|
||||
{"user_price": price, "sGoodsPic": picture, "paytype": pay_type},
|
||||
separators=(",", ":"),
|
||||
),
|
||||
"isCode": "1",
|
||||
"authType": "delegate",
|
||||
"_sid": "8",
|
||||
"set": "8",
|
||||
}
|
||||
for key in ("gameId", "actId", "appId", "livePlatId", "code", "timestamp", "v", "sig"):
|
||||
value = str(embed_query.get(key) or "")
|
||||
if value:
|
||||
params[key] = value
|
||||
|
||||
response = self._request(
|
||||
"get",
|
||||
self.XPD_LIVE_BUY_API,
|
||||
source="兑换小店商品",
|
||||
params=params,
|
||||
headers=self._xpd_daoju_headers(),
|
||||
)
|
||||
info = self._xpd_parse_var(response.text, "buyInfo")
|
||||
if str(info.get("ret")) != "0" or str(info.get("msg") or "").lower() != "ok":
|
||||
raise DouyuActivityError(str(info.get("msg") or "小店兑换失败"))
|
||||
return {
|
||||
"commodity_id": commodity_id,
|
||||
"pay_type": pay_type,
|
||||
"price": price,
|
||||
"serial": str(info.get("serial") or info.get("sSerialNum") or ""),
|
||||
"event_id": str(info.get("event_id") or ""),
|
||||
"new_balance": self._xpd_int(info.get("newBalance")),
|
||||
"raw": info,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user