Files
dygou_go/internal/activity/activity.go
T
yml2213 599f9d71f0 fix: 电竞手册用 ctn(acf_ccn) 鉴权替代 csrfToken
peacematch 与 peace 的兑换接口鉴权机制完全不同:
- peace: 表单发 csrfToken 字段,multipart 格式
- peacematch: 表单发 ctn 字段(值=acf_ccn),urlencoded 格式,
  cvl_csrf_token 只放 Cookie,不需要 batchExchangeLimit/preExchange

改动:
- Activity 加 UseCTN/CTNURL 字段
- GenerateCSRF 对 UseCTN 活动额外 FetchCTN 获取 acf_ccn,组合返回
- 新增 postForm(urlencoded) 方法用于 peacematch 兑换
- Exchange 按 UseCTN 分流:peacematch 发 ctn 字段,peace 发 csrfToken
- BatchExchangeLimit/PreExchange 对 UseCTN 活动跳过(返回默认值)
- 参考 /Users/yml/codes/douyu_login_py 中 Python 实现
2026-07-29 11:05:46 +08:00

121 lines
4.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package activity
import "douyu_go/internal/constants"
// Activity 描述一个斗鱼手册活动的全部接口参数。
//
// 不同活动(精英手册 / 电竞手册)的 manualID、roomID、actAlias 以及接口路径段都不同,
// 集中在这里可以让调度核心逻辑保持活动无关,新增活动只需在 registry 中加一项。
//
// 注意:peacematch 的 exchange / preExchange / batchExchangeLimit / storedetail 端点
// 没有出现在抓包里,这里按 peace 的 1:1 路径映射推断(storehome、exchangeList 已验证
// 确实落在 peacematch 路径下)。若实际抢购报错,优先核对这几个端点。
type Activity struct {
ID string // 注册表 key,例如 "peace" / "peacematch"
DisplayName string // 前端展示名
ManualID string
RoomID string
ActAlias string
BaseURL string
ShopReferer string
StoreHomeURL string
CSRFURL string
BatchLimitURL string
PreExchangeURL string
ExchangeURL string
ExchangeListURL string
BindInfoURL string
ScoreURL string
ScoreMethod string // "POST" 或 "GET"
// UseCTN 为 true 时(电竞手册),兑换接口用 ctn(acf_ccn) 鉴权而非 csrfToken:
// - 表单发 ctn 字段(值=acf_ccn),不发 csrfToken
// - cvl_csrf_token 只放 Cookie 头
// - 跳过 batchExchangeLimit / preExchange(Python 实现直接调 exchange)
// - Content-Type 用 application/x-www-form-urlencoded
UseCTN bool
CTNURL string // 获取 acf_ccn 的接口(UseCTN=true 时必填)
}
const douyuBase = constants.BaseURL
// peace 精英手册(旧活动,ActAlias=20260120QYOOB)。
var peace = &Activity{
ID: "peace",
DisplayName: "精英手册",
ManualID: "G4KA4Qnz4LDp7",
RoomID: "9263298",
ActAlias: "20260120QYOOB",
BaseURL: douyuBase,
ShopReferer: douyuBase + "/pages/live-peace-handbook/web/shop?ditchname=pass0&roomId=9263298",
StoreHomeURL: douyuBase + "/wgapi/ordnc/activity/peace/storehome?manualID=G4KA4Qnz4LDp7&rid=9263298",
CSRFURL: douyuBase + "/japi/carnival/nc/common/generateCsrf",
BatchLimitURL: douyuBase + "/wgapi/ordnc/activity/peace/batchExchangeLimit",
PreExchangeURL: douyuBase + "/wgapi/ordnc/activity/peace/preExchange",
ExchangeURL: douyuBase + "/wgapi/ordnc/activity/peace/exchange",
ExchangeListURL: douyuBase + "/wgapi/ordnc/activity/peace/exchangeList?manualID=G4KA4Qnz4LDp7&limit=100&offset=0",
BindInfoURL: douyuBase + "/japi/carnivalApi/v2/tencent/bindInfo?actAlias=20260120QYOOB",
ScoreURL: douyuBase + "/japi/oms/web/peace/credit/balance",
ScoreMethod: "POST",
UseCTN: false,
}
// peacematch 电竞手册(新活动,ActAlias=20260226ZMGDG)。
// 数据来源:/Users/yml/Desktop/抓包/douyu/7.29/电竞手册-基础信息.har 及 7.28 系列抓包。
var peacematch = &Activity{
ID: "peacematch",
DisplayName: "电竞手册",
ManualID: "1W0yGkOdDbAXb",
RoomID: "9263298",
ActAlias: "20260226ZMGDG",
BaseURL: douyuBase,
ShopReferer: douyuBase + "/pages/live-peace-pel/web/shop?roomId=9263298&isAnchorSide=0",
StoreHomeURL: douyuBase + "/wgapi/ordnc/activity/peacematch/storehome?manualID=1W0yGkOdDbAXb&rid=9263298",
// generateCsrf 为嘉年华平台级接口,抓包未单独出现,沿用 peace 同款端点。
CSRFURL: douyuBase + "/japi/carnival/nc/common/generateCsrf",
// 以下 4 个兑换类端点未在抓包中捕获,按 peace 的 1:1 路径映射推断,待实跑验证。
BatchLimitURL: douyuBase + "/wgapi/ordnc/activity/peacematch/batchExchangeLimit",
PreExchangeURL: douyuBase + "/wgapi/ordnc/activity/peacematch/preExchange",
ExchangeURL: douyuBase + "/wgapi/ordnc/activity/peacematch/exchange",
ExchangeListURL: douyuBase + "/wgapi/ordnc/activity/peacematch/exchangeList?manualID=1W0yGkOdDbAXb&limit=100&offset=0",
BindInfoURL: douyuBase + "/wgapi/ordnc/live/memberthird/tencent/bindInfo?actAlias=20260226ZMGDG",
ScoreURL: douyuBase + "/wgapi/ordnc/activity/peacematch/score/balance",
ScoreMethod: "GET",
UseCTN: true,
CTNURL: douyuBase + "/curl/csrfNlApi/getCsrfCookie",
}
var registry = map[string]*Activity{
peace.ID: peace,
peacematch.ID: peacematch,
}
// DefaultActivityID 默认活动,新分支默认启用「电竞手册」。
const DefaultActivityID = "peacematch"
// List 返回所有注册活动,按注册顺序(精英手册在前)。
func List() []*Activity {
return []*Activity{peace, peacematch}
}
// Get 按 ID 获取活动;不存在时返回 nil。
func Get(id string) *Activity {
if id == "" {
return nil
}
return registry[id]
}
// Default 返回默认活动。
func Default() *Activity {
if a := registry[DefaultActivityID]; a != nil {
return a
}
return peace
}