This repository has been archived by the owner on Nov 12, 2023. It is now read-only.
/
bilibili.go
106 lines (99 loc) · 2.96 KB
/
bilibili.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
package BiliBili
import (
"errors"
"fmt"
"github.com/nv4d1k/streamlink-go/app/lib"
"github.com/tidwall/gjson"
"io"
"log"
"net/http"
"net/url"
"strings"
)
type Link struct {
rid string
debug bool
client *http.Client
}
func NewBiliBiliLink(rid string, proxy *url.URL, debug bool) (bili *Link, err error) {
bili = new(Link)
bili.rid = rid
bili.debug = debug
if proxy != nil {
bili.client = &http.Client{Transport: lib.NewAddHeaderTransport(&http.Transport{Proxy: http.ProxyURL(proxy)}, true)}
} else {
bili.client = &http.Client{Transport: lib.NewAddHeaderTransport(nil, true)}
}
err = bili.getRoomStatus()
if err != nil {
return nil, fmt.Errorf("get room status error: %w", err)
}
if bili.debug {
log.Printf("real room id is %s\n", bili.rid)
}
return bili, nil
}
func (l *Link) getRoomStatus() error {
resp, err := l.client.Get(fmt.Sprintf("https://api.live.bilibili.com/room/v1/Room/room_init?id=%s", l.rid))
if err != nil {
return fmt.Errorf("get room init info error: %w", err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("parse room init info body error: %w", err)
}
if l.debug {
log.Printf("room init data: %s", string(body))
}
if gjson.ParseBytes(body).Get("code").Int() != 0 {
return errors.New("live streaming room not exist")
}
l.rid = gjson.ParseBytes(body).Get("data.room_id").String()
if gjson.ParseBytes(body).Get("data.live_status").Int() != 1 {
return errors.New("live streaming room is offline")
}
return nil
}
func (l *Link) GetLink() (string, error) {
u, err := url.Parse("https://api.live.bilibili.com/xlive/web-room/v2/index/getRoomPlayInfo")
if err != nil {
return "", fmt.Errorf("parsing room play info url error: %w", err)
}
uq := u.Query()
uq.Set("room_id", l.rid)
uq.Set("protocol", "1") // 0 = http_stream(flv), 1 = http_hls(m3u8)
uq.Set("format", "0,1,2") // 0 = flv, 1 = ts, 2 = fmp4
uq.Set("codec", "1") // 0 = avc, 1 = hevc
uq.Set("qn", "10000")
uq.Set("platform", "h5")
uq.Set("ptype", "8")
u.RawQuery = uq.Encode()
if l.debug {
log.Printf("rebuilt get room play info url: %s\n", u.String())
}
resp, err := l.client.Get(u.String())
if err != nil {
return "", fmt.Errorf("get room play info error: %w", err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("parsing room play info error: %w", err)
}
if l.debug {
log.Printf("room play info: %s\n", string(body))
}
streamsdata := gjson.ParseBytes(body).Get("data.playurl_info.playurl.stream")
if !streamsdata.Exists() {
return "", errors.New("live streams not found")
}
stream := streamsdata.Get(`#(protocol_name=="http_hls").format.0.codec.0`)
ur, err := url.Parse(stream.Get("url_info.0.host").String())
if err != nil {
return "", fmt.Errorf("parsing host to url error: %w", err)
}
ur.Path = strings.ReplaceAll(stream.Get("base_url").String(), "?", "")
ur.RawQuery = stream.Get("url_info.0.extra").String()
return ur.String(), nil
}