Skip to content

Commit 9db1fc4

Browse files
CopilotCuteReimu
andauthored
解决B站开播问题 (#122)
Co-authored-by: 奇葩の灵梦 <[email protected]>
1 parent 8c9c40d commit 9db1fc4

File tree

3 files changed

+74
-7
lines changed

3 files changed

+74
-7
lines changed

client.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ func (c *Client) GetCookies() []*http.Cookie {
124124
}
125125

126126
// 根据key获取指定的cookie值
127-
func (c *Client) getCookie(name string) string {
127+
func (c *Client) getCookie(name string) string { //nolint:unparam
128128
now := time.Now()
129129
// 查找指定name的cookie
130130
for _, cookie := range c.resty.Cookies {

live.go

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package bilibili
22

33
import (
4+
"strconv"
5+
"time"
6+
47
"github.com/go-resty/resty/v2"
58
)
69

@@ -117,13 +120,13 @@ type StartLiveParam struct {
117120
AreaV2 int `json:"area_v2"` // 直播分区id(子分区id)。详见[直播分区]
118121
Platform string `json:"platform"` // 直播平台。直播姬(pc):pc_link。web在线直播:web_link(已下线)。bililink:android_link。
119122

120-
// 下面四个参数详见:https://github.com/SocialSisterYi/bilibili-API-collect/pull/1351/files
121-
Version string `json:"version"` // 直播姬版本号
122-
Build int `json:"build"` // 直播姬构建号
123-
Appkey string `json:"appkey"` // APP密钥
124-
Sign string `json:"sign"` // APP API签名得到的sign
123+
// 下面四个参数详见:https://github.com/SocialSisterYi/bilibili-API-collect/pull/1351/files 。
124+
// 可以调用 GetHomePageLiveVersion 方法获取 Version 和 Build 参数。
125+
Version string `json:"version"` // 直播姬版本号,2025.7.20后对于某些用户必填
126+
Build int `json:"build"` // 直播姬构建号,2025.7.20后对于某些用户必填
127+
Appkey string `json:"appkey,omitempty"` // APP密钥,不填会自动计算
128+
Sign string `json:"sign,omitempty"` // APP API签名得到的sign,不填会自动计算
125129

126-
// 还需要一个ts,详见:https://github.com/SocialSisterYi/bilibili-API-collect/issues/1349
127130
Ts int `json:"ts,omitempty" request:"query,omitempty"` // 10位时间戳
128131
}
129132

@@ -163,11 +166,41 @@ type StartLiveResult struct {
163166
}
164167

165168
// StartLive 开始直播
169+
//
170+
// 注意:为了方便使用,这个函数的很多参数做了自动填入,使用例子可以参考:https://github.com/CuteReimu/bilibili/issues/121
166171
func (c *Client) StartLive(param StartLiveParam) (*StartLiveResult, error) {
167172
const (
168173
method = resty.MethodPost
169174
url = "https://api.live.bilibili.com/room/v1/Room/startLive"
170175
)
176+
177+
// 如果没有提供签名,自动计算
178+
if param.Sign == "" && param.Appkey == "" {
179+
// 已知的 Bilibili 直播姬的密钥和对应的秘钥
180+
// 这些是公开的常量,用于计算 API 签名
181+
const (
182+
appKey = "aae92bc66f3edfab"
183+
appSecret = "af125a0d5279fd576c1b4418a3e8276d" //nolint:gosec
184+
)
185+
if param.Ts == 0 {
186+
param.Ts = int(time.Now().Unix())
187+
}
188+
param.Appkey = appKey
189+
csrf := c.getCookie("bili_jct")
190+
signParams := map[string]string{
191+
"appkey": param.Appkey,
192+
"build": strconv.Itoa(param.Build),
193+
"platform": param.Platform,
194+
"room_id": strconv.Itoa(param.RoomId),
195+
"area_v2": strconv.Itoa(param.AreaV2),
196+
"ts": strconv.Itoa(param.Ts),
197+
"version": param.Version,
198+
"csrf": csrf,
199+
"csrf_token": csrf,
200+
}
201+
param.Sign = calculateAppSign(signParams, appSecret)
202+
}
203+
171204
return execute[*StartLiveResult](c, method, url, param, fillCsrf(c))
172205
}
173206

util.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
package bilibili
22

33
import (
4+
"crypto/md5"
5+
"encoding/hex"
46
"encoding/json"
57
"fmt"
68
"net/http"
9+
"net/url"
710
"reflect"
11+
"sort"
812
"strings"
913
"time"
1014
"unicode"
@@ -231,3 +235,33 @@ type Error struct {
231235
func (e Error) Error() string {
232236
return fmt.Sprintf("错误码: %d, 错误信息: %s", e.Code, e.Message)
233237
}
238+
239+
// calculateAppSign 计算 APP API 签名
240+
// 按照 Bilibili APP API 签名算法:参数按 key 排序后拼接,加上秘钥后计算 MD5
241+
func calculateAppSign(params map[string]string, appSecret string) string {
242+
// 收集所有非空参数
243+
keys := make([]string, 0, len(params))
244+
for k, v := range params {
245+
if v != "" {
246+
keys = append(keys, k)
247+
}
248+
}
249+
250+
// 按 key 排序
251+
sort.Strings(keys)
252+
253+
// 构建查询字符串
254+
query := url.Values{}
255+
for _, k := range keys {
256+
if params[k] != "" {
257+
query.Set(k, params[k])
258+
}
259+
}
260+
261+
// 拼接参数和秘钥
262+
signStr := query.Encode() + appSecret
263+
264+
// 计算 MD5
265+
hash := md5.Sum([]byte(signStr))
266+
return hex.EncodeToString(hash[:])
267+
}

0 commit comments

Comments
 (0)