优化和平小店碎片兑换链路

This commit is contained in:
yml2213
2026-08-09 10:07:36 +08:00
parent c6f16dfbee
commit feb72196c1
6 changed files with 54 additions and 18 deletions
+22 -5
View File
@@ -256,6 +256,7 @@ type xiaodianRecommendation struct {
type xiaodianItem struct {
GoodsID string `json:"iGoodsId"`
GoodsName string `json:"sGoodsName"`
ActionID xiaodianFlexibleString `json:"iActionId"`
Category xiaodianFlexibleString `json:"iCategoryId"`
Price string `json:"iPrice"`
JB2Price string `json:"iJb2Price"`
@@ -264,7 +265,6 @@ type xiaodianItem struct {
GoodsPic string `json:"sGoodsPic"`
ShowBegin string `json:"dtShowBeginTime"`
ShowEnd string `json:"dtShowEndTime"`
ActionID string `json:"iActionId"`
}
type xiaodianFlexibleString string
@@ -328,6 +328,16 @@ type xiaodianBuyInfo struct {
// xiaodianEmbedQuery 获取斗鱼为当前账号签发的短时道具城参数。
func (c *DouyuClient) xiaodianEmbedQuery(cookie string) (url.Values, error) {
return c.xiaodianEmbedQueryWithCache(cookie, true)
}
// xiaodianEmbedQueryFresh 每次调用都重新获取 H5 授权,供会真实扣款的兑换请求使用。
// code/sig/timestamp 是短时凭证,不应跨兑换轮次长期复用。
func (c *DouyuClient) xiaodianEmbedQueryFresh(cookie string) (url.Values, error) {
return c.xiaodianEmbedQueryWithCache(cookie, false)
}
func (c *DouyuClient) xiaodianEmbedQueryWithCache(cookie string, useCache bool) (url.Values, error) {
uid := cookieValue(cookie, "acf_uid")
stk := cookieValue(cookie, "acf_stk")
ltkid := cookieValue(cookie, "acf_ltkid")
@@ -335,8 +345,10 @@ func (c *DouyuClient) xiaodianEmbedQuery(cookie string) (url.Values, error) {
return nil, errors.New("斗鱼 Cookie 缺少 acf_uid、acf_stk 或 acf_ltkid,无法获取和平小店授权")
}
cacheKey := uid + ":" + c.Activity.ActAlias + ":" + c.Activity.RoomID
if cached, ok := c.getXiaodianEmbedCache(cacheKey); ok {
return cached, nil
if useCache {
if cached, ok := c.getXiaodianEmbedCache(cacheKey); ok {
return cached, nil
}
}
endpoint, err := url.Parse(c.Activity.RoleParamURL)
if err != nil {
@@ -539,6 +551,7 @@ func (c *DouyuClient) xiaodianProducts(cookie string, options types.XiaodianProd
products = append(products, types.Product{
CommodityID: item.GoodsID,
CommodityName: item.GoodsName,
ActionID: string(item.ActionID),
Category: string(item.Category),
Score: price,
PayType: payType,
@@ -1231,7 +1244,7 @@ func (c *DouyuClient) xiaodianExchange(cookie string, product types.Product) (st
if strings.TrimSpace(product.CommodityID) == "" {
return "", errors.New("商品 ID 为空")
}
embedQuery, err := c.xiaodianEmbedQuery(cookie)
embedQuery, err := c.xiaodianEmbedQueryFresh(cookie)
if err != nil {
return "", err
}
@@ -1254,7 +1267,11 @@ func (c *DouyuClient) xiaodianExchange(cookie string, product types.Product) (st
query.Set("_jsvar", "buyInfo")
query.Set("acctype", "livelink")
query.Set("_app_id", "2123")
query.Set("iActionId", c.Activity.ActID)
actionID := strings.TrimSpace(product.ActionID)
if actionID == "" {
actionID = c.Activity.ActID
}
query.Set("iActionId", actionID)
query.Set("propid", product.CommodityID)
query.Set("paytype", strconv.Itoa(payType))
query.Set("source", c.Activity.RoomID)
+4 -1
View File
@@ -177,7 +177,7 @@ func TestProductsAutomaticallyResolvesXiaodianRoleAndPaginates(t *testing.T) {
} else {
switch offset {
case "0":
items = []map[string]string{{"iGoodsId": "g1", "sGoodsName": "商品一", "iCategoryId": "1", "iPrice": "10", "sPayType": "qpqb", "iGoodsLeft": "-1"}, {"iGoodsId": "g2", "sGoodsName": "特惠商品", "iCategoryId": "45", "iPrice": "0", "iJb2Price": "20", "sPayType": "jb2", "iGoodsLeft": "3"}}
items = []map[string]string{{"iGoodsId": "g1", "iActionId": "act-g1", "sGoodsName": "商品一", "iCategoryId": "1", "iPrice": "10", "sPayType": "qpqb", "iGoodsLeft": "-1"}, {"iGoodsId": "g2", "sGoodsName": "特惠商品", "iCategoryId": "45", "iPrice": "0", "iJb2Price": "20", "sPayType": "jb2", "iGoodsLeft": "3"}}
case "2":
items = []map[string]string{{"iGoodsId": "g2", "sGoodsName": "重复商品", "iCategoryId": "45", "iPrice": "0", "iJb2Price": "20", "sPayType": "jb2", "iGoodsLeft": "3"}, {"iGoodsId": "g4", "sGoodsName": "商品四", "iCategoryId": "1", "iPrice": "40", "sPayType": "qpqb", "iGoodsLeft": "0"}}
}
@@ -219,6 +219,9 @@ func TestProductsAutomaticallyResolvesXiaodianRoleAndPaginates(t *testing.T) {
if products[1].Category != "45" || products[3].Score != 30 {
t.Fatalf("商品字段 = %#v", products)
}
if products[0].ActionID != "act-g1" {
t.Fatalf("商品动作 ID = %q", products[0].ActionID)
}
if products[0].PayType != 1 || products[0].PayLabel != "点券" || products[1].PayType != 5 || products[1].PayLabel != "扭蛋碎片" || products[1].Score != 20 {
t.Fatalf("支付字段 = %#v", products)
}