Fix: bilibili wbi

pull/24/head
zijiren233 2 years ago
parent b213ede66d
commit b299e12a40

@ -812,3 +812,16 @@ type pgcURLInfo struct {
Status int `json:"status"` Status int `json:"status"`
} `json:"result"` } `json:"result"`
} }
type wbi struct {
Code int `json:"code"`
Message string `json:"message"`
TTL int `json:"ttl"`
Data struct {
IsLogin bool `json:"isLogin"`
WbiImg struct {
ImgURL string `json:"img_url"`
SubURL string `json:"sub_url"`
} `json:"wbi_img"`
} `json:"data"`
}

@ -32,6 +32,10 @@ func NewClient(cookies []*http.Cookie, conf ...ClientConfig) *Client {
} }
func (c *Client) NewRequest(method, url string, body io.Reader) (*http.Request, error) { func (c *Client) NewRequest(method, url string, body io.Reader) (*http.Request, error) {
url, err := signAndGenerateURL(url)
if err != nil {
return nil, err
}
req, err := http.NewRequest(method, url, body) req, err := http.NewRequest(method, url, body)
if err != nil { if err != nil {
return nil, err return nil, err
@ -40,6 +44,6 @@ func (c *Client) NewRequest(method, url string, body io.Reader) (*http.Request,
req.AddCookie(cookie) req.AddCookie(cookie)
} }
req.Header.Set("User-Agent", utils.UA) req.Header.Set("User-Agent", utils.UA)
req.Header.Set("Referer", "https://www.bilibili.com/") req.Header.Set("Referer", "https://www.bilibili.com")
return req, nil return req, nil
} }

@ -227,7 +227,7 @@ func (c *Client) GetPGCURL(ep_id, cid uint, conf ...GetVideoURLConfig) (*VideoUR
for _, v := range conf { for _, v := range conf {
v(config) v(config)
} }
url := fmt.Sprintf("https://api.bilibili.com/pgc/player/web/playurl?ep_id=%d&cid=%d&qn=%d&fourk=1", ep_id, cid, config.Quality) url := fmt.Sprintf("https://api.bilibili.com/pgc/player/web/playurl?ep_id=%d&cid=%d&qn=%d&fourk=1&fnval=0", ep_id, cid, config.Quality)
req, err := c.NewRequest(http.MethodGet, url, nil) req, err := c.NewRequest(http.MethodGet, url, nil)
if err != nil { if err != nil {
return nil, err return nil, err
@ -248,5 +248,4 @@ func (c *Client) GetPGCURL(ep_id, cid uint, conf ...GetVideoURLConfig) (*VideoUR
CurrentQuality: info.Result.Quality, CurrentQuality: info.Result.Quality,
URL: info.Result.Durl[0].URL, URL: info.Result.Durl[0].URL,
}, nil }, nil
} }

@ -0,0 +1,139 @@
package bilibili
import (
"crypto/md5"
"encoding/hex"
"net/http"
"net/url"
"sort"
"strconv"
"strings"
"sync"
"time"
json "github.com/json-iterator/go"
"github.com/synctv-org/synctv/utils"
)
var (
mixinKeyEncTab = []int{
46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49,
33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40,
61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11,
36, 20, 34, 44, 52,
}
lock sync.RWMutex
imgKey, subKey string
lastUpdateTime time.Time
)
func signAndGenerateURL(urlStr string) (string, error) {
urlObj, err := url.Parse(urlStr)
if err != nil {
return "", err
}
imgKey, subKey, err := getWbiKeysCached()
if err != nil {
return "", err
}
query := urlObj.Query()
params := map[string]string{}
for k, v := range query {
params[k] = v[0]
}
newParams := encWbi(params, imgKey, subKey)
for k, v := range newParams {
query.Set(k, v)
}
urlObj.RawQuery = query.Encode()
return urlObj.String(), nil
}
func encWbi(params map[string]string, imgKey, subKey string) map[string]string {
mixinKey := getMixinKey(imgKey + subKey)
currTime := strconv.FormatInt(time.Now().Unix(), 10)
params["wts"] = currTime
keys := make([]string, 0, len(params))
for k := range params {
keys = append(keys, k)
}
sort.Strings(keys)
for k, v := range params {
v = sanitizeString(v)
params[k] = v
}
query := url.Values{}
for _, k := range keys {
query.Set(k, params[k])
}
queryStr := query.Encode()
hash := md5.Sum([]byte(queryStr + mixinKey))
params["w_rid"] = hex.EncodeToString(hash[:])
return params
}
func getMixinKey(orig string) string {
var str strings.Builder
for _, v := range mixinKeyEncTab {
if v < len(orig) {
str.WriteByte(orig[v])
}
}
return str.String()[:32]
}
func sanitizeString(s string) string {
unwantedChars := []string{"!", "'", "(", ")", "*"}
for _, char := range unwantedChars {
s = strings.ReplaceAll(s, char, "")
}
return s
}
func getWbiKeysCached() (string, string, error) {
lock.RLock()
if time.Since(lastUpdateTime).Minutes() < 10 {
defer lock.RUnlock()
return imgKey, subKey, nil
}
lock.RUnlock()
lock.Lock()
defer lock.Unlock()
if time.Since(lastUpdateTime).Minutes() < 10 {
return imgKey, subKey, nil
}
var err error
imgKey, subKey, err = getWbiKeys()
if err != nil {
return "", "", err
}
lastUpdateTime = time.Now()
return imgKey, subKey, nil
}
func getWbiKeys() (string, string, error) {
req, err := http.NewRequest(http.MethodGet, "https://api.bilibili.com/x/web-interface/nav", nil)
if err != nil {
return "", "", err
}
req.Header.Set("User-Agent", utils.UA)
req.Header.Set("Referer", "https://www.bilibili.com")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return "", "", err
}
defer resp.Body.Close()
info := wbi{}
err = json.NewDecoder(resp.Body).Decode(&info)
if err != nil {
return "", "", err
}
imgKey := strings.Split(strings.Split(info.Data.WbiImg.ImgURL, "/")[len(strings.Split(info.Data.WbiImg.ImgURL, "/"))-1], ".")[0]
subKey := strings.Split(strings.Split(info.Data.WbiImg.SubURL, "/")[len(strings.Split(info.Data.WbiImg.SubURL, "/"))-1], ".")[0]
return imgKey, subKey, nil
}
Loading…
Cancel
Save