diff --git a/internal/client/client.go b/internal/client/client.go index e69474f..b875e66 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -656,10 +656,7 @@ func (c *DouyuClient) XiaodianAssets(cookie string) (types.XiaodianAssets, error if areaID <= 0 { areaID = 1 } - platID := parseXiaodianInt(string(role.PlatID)) - if platID <= 0 { - platID = 1 - } + platID := parseXiaodianOptionalInt(string(role.PlatID), 1) coupons, err := c.xiaodianAsset(cookie, role, areaID, platID, "banlanceInfo", "pay.midas.dq.get.ttpp", "balance", true) if err != nil { return types.XiaodianAssets{}, err @@ -694,10 +691,7 @@ func (c *DouyuClient) XiaodianRole(cookie string) (types.XiaodianRole, error) { if areaID <= 0 { areaID = 1 } - platID := parseXiaodianInt(string(role.PlatID)) - if platID <= 0 { - platID = 1 - } + platID := parseXiaodianOptionalInt(string(role.PlatID), 1) result := types.XiaodianRole{ Success: true, RoleID: string(role.RoleID), @@ -908,7 +902,7 @@ func (c *DouyuClient) xiaodianAsset(cookie string, role xiaodianRoleContext, are query.Set("_act_id", c.Activity.ActID) query.Set("_sid", "6") if withTime { - query.Set("_time", strconv.FormatInt(time.Now().Unix(), 10)) + query.Set("_time", strconv.FormatInt(time.Now().UnixMilli(), 10)) } else { query.Set("coin_type", "1") } @@ -938,6 +932,20 @@ func parseXiaodianInt(value string) int { return parsed } +// parseXiaodianOptionalInt 保留接口明确返回的 0;只有缺失或非法值才回退。 +// platId=0 是合法的 iOS 平台标识,不能用 <=0 判断为缺失。 +func parseXiaodianOptionalInt(value string, fallback int) int { + value = strings.TrimSpace(value) + if value == "" { + return fallback + } + parsed, err := strconv.Atoi(value) + if err != nil { + return fallback + } + return parsed +} + // Score 查询账号积分余额。不同活动的积分接口方法/路径不同: // 和平手册用 POST /japi/oms/web/peace/credit/balance; // 电竞手册用 GET /wgapi/ordnc/activity/peacematch/score/balance。 diff --git a/internal/client/client_test.go b/internal/client/client_test.go index fe3180d..e77f4c9 100644 --- a/internal/client/client_test.go +++ b/internal/client/client_test.go @@ -147,10 +147,16 @@ func TestProductsAutomaticallyResolvesXiaodianRoleAndPaginates(t *testing.T) { if got := r.URL.Query().Get("_act_id"); got != "46195" { t.Errorf("_act_id = %q", got) } - _, _ = w.Write([]byte(`var info = {"gameOpenId":"openid","roleId":1192083858,"roleName":"测试角色","type":"qq","area":1};`)) + _, _ = w.Write([]byte(`var info = {"gameOpenId":"openid","roleId":1192083858,"roleName":"测试角色","type":"qq","area":1,"platId":0};`)) case "/role/": + if got := r.URL.Query().Get("plat"); got != "0" { + t.Errorf("plat = %q, want iOS platform 0", got) + } switch r.URL.Query().Get("_jsvar") { case "banlanceInfo": + if got := r.URL.Query().Get("_time"); len(got) != 13 { + t.Errorf("_time = %q, want millisecond timestamp", got) + } _, _ = w.Write([]byte(`var banlanceInfo={"balance":8800};`)) case "jbInfos": _, _ = w.Write([]byte(`var jbInfos={"jb2":"36"};`)) @@ -236,7 +242,7 @@ func TestProductsAutomaticallyResolvesXiaodianRoleAndPaginates(t *testing.T) { t.Fatalf("资产 = %#v", assets) } role, err := cli.XiaodianRole("acf_uid=uid; acf_stk=stk; acf_ltkid=ltkid") - if err != nil || role.RoleName != "测试角色" || role.AreaID != 2 { + if err != nil || role.RoleName != "测试角色" || role.AreaID != 2 || role.PlatID != 0 { t.Fatalf("角色 = %#v, err=%v", role, err) } } diff --git a/internal/types/types.go b/internal/types/types.go index b2cb020..fbb0cb9 100644 --- a/internal/types/types.go +++ b/internal/types/types.go @@ -31,8 +31,8 @@ type XiaodianRole struct { RoleName string `json:"roleName,omitempty"` OpenID string `json:"openId,omitempty"` Type string `json:"type,omitempty"` - PlatID int `json:"platId,omitempty"` - AreaID int `json:"areaId,omitempty"` + PlatID int `json:"platId"` + AreaID int `json:"areaId"` Error string `json:"error,omitempty"` }