summaryrefslogtreecommitdiff
path: root/bilibili
diff options
context:
space:
mode:
authorKeuin <[email protected]>2023-07-29 19:43:27 +0800
committerKeuin <[email protected]>2023-07-29 20:21:17 +0800
commit9b5c3913989754370bd7d03ac8cf2e32a6172afb (patch)
tree9e2caca8feb9ca5a9c14a96424d23e20db4314bc /bilibili
parenta153bf02d1cf05f020d263e9670a76ae99cfeb02 (diff)
Simulate real web app cookies & WebSocket fields
Diffstat (limited to 'bilibili')
-rw-r--r--bilibili/client.go8
-rw-r--r--bilibili/connect.go13
-rw-r--r--bilibili/danmaku_server_info.go43
-rw-r--r--bilibili/request.go14
4 files changed, 73 insertions, 5 deletions
diff --git a/bilibili/client.go b/bilibili/client.go
index 4abad60..f4b64fd 100644
--- a/bilibili/client.go
+++ b/bilibili/client.go
@@ -10,6 +10,7 @@ import (
"github.com/keuin/slbr/types"
"net"
"net/http"
+ "net/http/cookiejar"
)
const (
@@ -39,10 +40,15 @@ func NewBilibiliWithContext(ctx context.Context, netTypes []types.IpNetType, log
transport.DialTLSContext = nil
transport.DialContext, _ = np.NextNetworkType(dialer)
+ cookieJar, _ := cookiejar.New(nil)
+ httpClient := &http.Client{
+ Jar: cookieJar,
+ }
+
return &Bilibili{
logger: logger,
userAgent: userAgent,
- http: http.DefaultClient,
+ http: httpClient,
ctx: ctx,
netTypes: nets,
}
diff --git a/bilibili/connect.go b/bilibili/connect.go
new file mode 100644
index 0000000..472c979
--- /dev/null
+++ b/bilibili/connect.go
@@ -0,0 +1,13 @@
+package bilibili
+
+import (
+ "context"
+ "nhooyr.io/websocket"
+)
+
+func (b Bilibili) DialWebSocket(ctx context.Context, url string) (*websocket.Conn, error) {
+ ws, _, err := websocket.Dial(ctx, url, &websocket.DialOptions{
+ HTTPClient: b.http,
+ })
+ return ws, err
+}
diff --git a/bilibili/danmaku_server_info.go b/bilibili/danmaku_server_info.go
index 4d26873..8c79d51 100644
--- a/bilibili/danmaku_server_info.go
+++ b/bilibili/danmaku_server_info.go
@@ -1,11 +1,50 @@
package bilibili
import (
+ "errors"
"fmt"
"github.com/keuin/slbr/types"
+ "net/url"
)
+type WebBannerResponse = BaseResponse[interface{}]
+
+const apiUrlPrefix = "https://api.live.bilibili.com"
+
func (b *Bilibili) GetDanmakuServerInfo(roomId types.RoomId) (resp types.DanmakuServerInfoResponse, err error) {
- url := fmt.Sprintf("https://api.live.bilibili.com/xlive/web-room/v1/index/getDanmuInfo?id=%d&type=0", roomId)
- return callGet[types.DanmakuServerInfoResponse](b, url)
+ u := fmt.Sprintf("https://api.live.bilibili.com/xlive/web-room/v1/index/getDanmuInfo?id=%d&type=0", roomId)
+ return callGet[types.DanmakuServerInfoResponse](b, u)
+}
+
+// GetBUVID initializes cookie `buvid3`. If success, returns its value.
+func (b *Bilibili) GetBUVID() (string, error) {
+ const u = "https://data.bilibili.com/v/web/web_page_view"
+ _, _, err := callGetRaw(b, u)
+ if err != nil {
+ return "", err
+ }
+ uu, _ := url.Parse(apiUrlPrefix)
+ cookies := b.http.Jar.Cookies(uu)
+ var buvid3 *string
+ for _, c := range cookies {
+ if c.Name == "buvid3" {
+ buvid3 = &c.Value
+ }
+ }
+ if buvid3 == nil {
+ return "", errors.New("failed to get buvid3")
+ }
+ return *buvid3, nil
+}
+
+// GetLiveBUVID initializes cookie `LIVE_BUVID`. This should be called before GetDanmakuServerInfo.
+func (b *Bilibili) GetLiveBUVID(roomId types.RoomId) (resp WebBannerResponse, err error) {
+ u := fmt.Sprintf("https://api.live.bilibili.com/activity/v1/Common/webBanner?"+
+ "platform=web&position=6&roomid=%d&area_v2_parent_id=0&area_v2_id=0&from=", roomId)
+ resp, err = callGet[WebBannerResponse](b, u)
+ if err == nil {
+ uu, _ := url.Parse(apiUrlPrefix)
+ b.logger.Info("Cookie info: %v", b.http.Jar.Cookies(uu))
+ }
+ return resp, err
}
diff --git a/bilibili/request.go b/bilibili/request.go
index 11ff995..613530c 100644
--- a/bilibili/request.go
+++ b/bilibili/request.go
@@ -29,8 +29,8 @@ func (b *Bilibili) newGet(url string) (req *http.Request, err error) {
return b.newRequest("GET", url, strings.NewReader(""))
}
-// callGet make a GET request and parse response as a JSON document with given model.
-func callGet[T types.BaseResponse[V], V any](b *Bilibili, url string) (resp T, err error) {
+// callGetRaw make a GET request and returns the raw response body.
+func callGetRaw(b *Bilibili, url string) (resp *http.Response, respBody []byte, err error) {
req, err := b.newGet(url)
if err != nil {
b.logger.Error("Cannot create HTTP request instance on API %v: %v", url, err)
@@ -56,6 +56,16 @@ func callGet[T types.BaseResponse[V], V any](b *Bilibili, url string) (resp T, e
return
}
+ return r, data, err
+}
+
+// callGet make a GET request and parse response as a JSON document with given model.
+func callGet[T BaseResponse[V], V any](b Bilibili, url string) (resp T, err error) {
+ r, data, err := callGetRaw(b, url)
+ if err != nil {
+ return
+ }
+
err = json.Unmarshal(data, &resp)
if err != nil {
b.logger.Error("Invalid JSON body of HTTP response on API %v: %v. Text: \"%v\"",