Skip to content

Commit c5b74de

Browse files
authored
fix huya (#764)
* fix huya * fix huya 获取真实roomid
1 parent 649285c commit c5b74de

File tree

1 file changed

+65
-149
lines changed

1 file changed

+65
-149
lines changed

src/live/huya/huya.go

+65-149
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,23 @@
11
package huya
22

33
import (
4-
"bytes"
54
"crypto/md5"
6-
"encoding/base64"
75
"encoding/hex"
86
"fmt"
9-
"html/template"
10-
"math/rand"
11-
"net/http"
12-
"net/url"
13-
"strconv"
14-
"strings"
15-
"time"
16-
17-
"github.com/hr3lxphr6j/requests"
18-
"github.com/tidwall/gjson"
19-
207
"github.com/hr3lxphr6j/bililive-go/src/live"
218
"github.com/hr3lxphr6j/bililive-go/src/live/internal"
229
"github.com/hr3lxphr6j/bililive-go/src/pkg/utils"
10+
"github.com/hr3lxphr6j/requests"
11+
"github.com/tidwall/gjson"
12+
"net/http"
13+
"net/url"
2314
)
2415

2516
const (
2617
domain = "www.huya.com"
2718
cnName = "虎牙"
2819
userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
20+
uaApp = "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.49(0x18003137) NetType/WIFI Language/zh_CN WeChat/8.0.49.33 CFNetwork/1474 Darwin/23.0.0"
2921
)
3022

3123
func init() {
@@ -45,8 +37,35 @@ type Live struct {
4537
lastCdnIndex int
4638
}
4739

48-
func (l *Live) GetInfo() (info *live.Info, err error) {
49-
resp, err := requests.Get(l.Url.String(), live.CommonUserAgent)
40+
func (l *Live) getDate() (result *gjson.Result, err error) {
41+
html, err := requests.Get(l.Url.String(), live.CommonUserAgent)
42+
if err != nil {
43+
return nil, err
44+
}
45+
if html.StatusCode != http.StatusOK {
46+
return nil, live.ErrRoomNotExist
47+
}
48+
htmlBody, err := html.Text()
49+
if err != nil {
50+
return nil, err
51+
}
52+
strFilter := utils.NewStringFilterChain(utils.ParseUnicode, utils.UnescapeHTMLEntity)
53+
rjson := strFilter.Do(utils.Match1(`stream: (\{"data".*?),"iWebDefaultBitRate"`, htmlBody)) + "}"
54+
gj := gjson.Parse(rjson)
55+
56+
roomId := gj.Get("data.0.gameLiveInfo.profileRoom").String()
57+
params := make(map[string]string)
58+
params["m"] = "Live"
59+
params["do"] = "profileRoom"
60+
params["roomid"] = roomId
61+
params["showSecret"] = "1"
62+
63+
headers := make(map[string]interface{})
64+
headers["User-Agent"] = uaApp
65+
headers["xweb_xhr"] = "1"
66+
headers["referer"] = "https://servicewechat.com/wx74767bf0b684f7d3/301/page-frame.html"
67+
headers["accept-language"] = "zh-CN,zh;q=0.9"
68+
resp, err := requests.Get("https://mp.huya.com/cache.php", requests.Headers(headers), requests.Queries(params), requests.UserAgent(uaApp))
5069
if err != nil {
5170
return nil, err
5271
}
@@ -57,25 +76,32 @@ func (l *Live) GetInfo() (info *live.Info, err error) {
5776
if err != nil {
5877
return nil, err
5978
}
79+
res := gjson.Parse(body)
80+
return &res, nil
81+
}
6082

61-
if res := utils.Match1("哎呀,虎牙君找不到这个主播,要不搜索看看?", body); res != "" {
83+
func (l *Live) GetInfo() (info *live.Info, err error) {
84+
res, err := l.getDate()
85+
if err != nil {
86+
return nil, err
87+
}
88+
if res := utils.Match1("该主播不存在!", res.String()); res != "" {
6289
return nil, live.ErrRoomNotExist
6390
}
6491

65-
if strings.Contains(body, "该主播涉嫌违规,正在整改中") {
66-
return &live.Info{
67-
Live: l,
68-
HostName: "该主播涉嫌违规,正在整改中",
69-
RoomName: "该主播涉嫌违规,正在整改中",
70-
Status: false,
71-
}, nil
72-
}
92+
//if strings.Contains(body, "该主播涉嫌违规,正在整改中") {
93+
// return &live.Info{
94+
// Live: l,
95+
// HostName: "该主播涉嫌违规,正在整改中",
96+
// RoomName: "该主播涉嫌违规,正在整改中",
97+
// Status: false,
98+
// }, nil
99+
//}
73100

74101
var (
75-
strFilter = utils.NewStringFilterChain(utils.ParseUnicode, utils.UnescapeHTMLEntity)
76-
hostName = strFilter.Do(utils.Match1(`"nick":"([^"]*)"`, body))
77-
roomName = strFilter.Do(utils.Match1(`"introduction":"([^"]*)"`, body))
78-
status = strFilter.Do(utils.Match1(`"isOn":([^,]*),`, body))
102+
hostName = res.Get("data.liveData.nick").String()
103+
roomName = res.Get("data.liveData.introduction").String()
104+
status = res.Get("data.realLiveStatus").String()
79105
)
80106

81107
if hostName == "" || roomName == "" || status == "" {
@@ -86,7 +112,7 @@ func (l *Live) GetInfo() (info *live.Info, err error) {
86112
Live: l,
87113
HostName: hostName,
88114
RoomName: roomName,
89-
Status: status == "true",
115+
Status: status == "ON",
90116
}
91117
return info, nil
92118
}
@@ -96,133 +122,23 @@ func GetMD5Hash(text string) string {
96122
return hex.EncodeToString(hash[:])
97123
}
98124

99-
type urlQueryParams struct {
100-
WsSecret string
101-
WsTime string
102-
Seqid string
103-
Ctype string
104-
Ver string
105-
Fs string
106-
U string
107-
T string
108-
Sv string
109-
Sdk_sid string
110-
Codec string
111-
}
112-
113-
func parseAntiCode(anticode string, uid int64, streamName string) (string, error) {
114-
qr, err := url.ParseQuery(anticode)
115-
if err != nil {
116-
return "", err
117-
}
118-
resultTemplate := template.Must(template.New("urlQuery").Parse(
119-
"wsSecret={{.WsSecret}}" +
120-
"&wsTime={{.WsTime}}" +
121-
"&seqid={{.Seqid}}" +
122-
"&ctype={{.Ctype}}" +
123-
"&ver={{.Ver}}" +
124-
"&fs={{.Fs}}" +
125-
"&u={{.U}}" +
126-
"&t={{.T}}" +
127-
"&sv={{.Sv}}" +
128-
"&sdk_sid={{.Sdk_sid}}" +
129-
"&codec={{.Codec}}",
130-
))
131-
timeNow := time.Now().Unix() * 1000
132-
resultParams := urlQueryParams{
133-
WsSecret: "",
134-
WsTime: qr.Get("wsTime"),
135-
Seqid: strconv.FormatInt(timeNow+uid, 10),
136-
Ctype: qr.Get("ctype"),
137-
Ver: "1",
138-
Fs: qr.Get("fs"),
139-
U: strconv.FormatInt(uid, 10),
140-
T: "100",
141-
Sv: "2405220949",
142-
Sdk_sid: strconv.FormatInt(uid, 10),
143-
Codec: "264",
144-
}
145-
ss := GetMD5Hash(fmt.Sprintf("%s|%s|%s", resultParams.Seqid, resultParams.Ctype, resultParams.T))
146-
147-
decodeString, _ := base64.StdEncoding.DecodeString(qr.Get("fm"))
148-
fm := string(decodeString)
149-
fm = strings.ReplaceAll(fm, "$0", resultParams.U)
150-
fm = strings.ReplaceAll(fm, "$1", streamName)
151-
fm = strings.ReplaceAll(fm, "$2", ss)
152-
fm = strings.ReplaceAll(fm, "$3", resultParams.WsTime)
153-
154-
resultParams.WsSecret = GetMD5Hash(fm)
155-
var buf bytes.Buffer
156-
if err := resultTemplate.Execute(&buf, resultParams); err != nil {
157-
return "", err
158-
}
159-
return buf.String(), nil
160-
}
161-
162125
func (l *Live) GetStreamUrls() (us []*url.URL, err error) {
163-
resp, err := requests.Get(l.Url.String(), requests.UserAgent(userAgent))
164-
if err != nil {
165-
return nil, err
166-
}
167-
if resp.StatusCode != http.StatusOK {
168-
return nil, fmt.Errorf("status code: %d", resp.StatusCode)
169-
}
170-
body, err := resp.Text()
126+
data, err := l.getDate()
171127
if err != nil {
172128
return nil, err
173129
}
130+
sFlvUrl := data.Get("data.stream.baseSteamInfoList.0.sFlvUrl").String()
131+
sStreamName := data.Get("data.stream.baseSteamInfoList.0.sStreamName").String()
132+
sFlvUrlSuffix := data.Get("data.stream.baseSteamInfoList.0.sFlvUrlSuffix").String()
133+
sFlvAntiCode := data.Get("data.stream.baseSteamInfoList.0.sFlvAntiCode").String()
134+
streamUrl := fmt.Sprintf("%s/%s.%s?%s", sFlvUrl, sStreamName, sFlvUrlSuffix, sFlvAntiCode)
174135

175-
tmpStrings := strings.Split(body, `stream: `)
176-
if len(tmpStrings) < 2 {
177-
return nil, fmt.Errorf("stream json info not found")
178-
}
179-
tmpStreamJsonRawString := strings.Split(tmpStrings[1], `};`)
180-
if len(tmpStreamJsonRawString) < 1 {
181-
return nil, fmt.Errorf("stream json info end not found. stream text: %s", tmpStrings[1])
182-
}
183-
streamJsonRawString := tmpStreamJsonRawString[0]
184-
if !gjson.Valid(streamJsonRawString) {
185-
return nil, fmt.Errorf("streamJsonRawString not valid")
186-
}
187-
streamJson := gjson.Parse(streamJsonRawString)
188-
vMultiStreamInfoJson := streamJson.Get("vMultiStreamInfo").Array()
189-
if len(vMultiStreamInfoJson) == 0 {
190-
return nil, fmt.Errorf("vMultiStreamInfo not found")
191-
}
192-
193-
streamInfoJsons := streamJson.Get("data.0.gameStreamInfoList").Array()
194-
if len(streamInfoJsons) == 0 {
195-
return nil, fmt.Errorf("gameStreamInfoList not found")
196-
}
197-
index := l.lastCdnIndex
198-
if index >= len(streamInfoJsons) {
199-
index = 0
200-
}
201-
l.lastCdnIndex = index + 1
202-
gameStreamInfoJson := streamInfoJsons[index]
203-
return getStreamUrlsFromGameStreamInfoJson(gameStreamInfoJson)
204-
}
205-
206-
func getStreamUrlsFromGameStreamInfoJson(gameStreamInfoJson gjson.Result) (us []*url.URL, err error) {
207-
// get streamName
208-
sStreamName := gameStreamInfoJson.Get("sStreamName").String()
209-
// get sFlvAntiCode
210-
sFlvAntiCode := gameStreamInfoJson.Get("sFlvAntiCode").String()
211-
// get sFlvUrl
212-
sFlvUrl := gameStreamInfoJson.Get("sFlvUrl").String()
213-
// get random uid
214-
uid := rand.Int63n(99999999999) + 1200000000000
215-
216-
query, err := parseAntiCode(sFlvAntiCode, uid, sStreamName)
217-
if err != nil {
218-
return nil, err
219-
}
220-
tmpUrlString := fmt.Sprintf("%s/%s.flv?%s", sFlvUrl, sStreamName, query)
221-
u, err := url.Parse(tmpUrlString)
136+
res, err := utils.GenUrls(streamUrl)
222137
if err != nil {
223138
return nil, err
224139
}
225-
return []*url.URL{u}, nil
140+
return res, nil
141+
226142
}
227143

228144
func (l *Live) GetPlatformCNName() string {
@@ -231,7 +147,7 @@ func (l *Live) GetPlatformCNName() string {
231147

232148
func (l *Live) GetHeadersForDownloader() map[string]string {
233149
return map[string]string{
234-
"User-Agent": userAgent,
150+
"User-Agent": uaApp,
235151
"Accept": `text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8`,
236152
"Accept-Encoding": `gzip, deflate`,
237153
"Accept-Language": `zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3`,

0 commit comments

Comments
 (0)