From 4bbecd392ef7164ca0d1d6dc690e6fcc6ae26d04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=82=A5=E7=BE=8A?= Date: Thu, 1 Jun 2023 16:43:08 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E8=99=8E=E7=89=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Golang/README.md | 17 +++- Golang/liveurls/huya.go | 188 ++++++++++++++++++++++++++++++---------- Golang/main.go | 11 ++- 3 files changed, 167 insertions(+), 49 deletions(-) diff --git a/Golang/README.md b/Golang/README.md index a48e953..e8bfdbe 100644 --- a/Golang/README.md +++ b/Golang/README.md @@ -60,9 +60,22 @@ http://你的IP:35455/douyu/xxxxx(?stream=flv&cdn=hw-tct) ``` http://你的IP:35455/bilibili/xxxxxx(?platform=h5&line=first&quality=10000) ``` -## **虎牙`(huya.com/)xxxxxx`:** +## **虎牙`(huya.com/)xxxxxx`:** +### 1,查看可用CDN: ``` -http://你的IP:35455/huya/xxxxx +http://你的IP:35455/huya/xxxxx?type=display +``` +### 2,切换媒体类型(默认flv,可选flv、hls): +``` +http://你的IP:35455/huya/xxxxx?media=hls +``` +### 3,切换CDN(默认hwcdn,可选hycdn、alicdn、txcdn、hwcdn、hscdn、wscdn,具体可先访问1获取): +``` +http://你的IP:35455/huya/xxxxx?cdn=alicdn +``` +### 4,最后的代理链接示例: +``` +http://你的IP:35455/huya/xxxxx(?media=xxx&cdn=xxx) ``` ## **YouTube:** ``` diff --git a/Golang/liveurls/huya.go b/Golang/liveurls/huya.go index 399ea05..fb196a6 100644 --- a/Golang/liveurls/huya.go +++ b/Golang/liveurls/huya.go @@ -8,10 +8,14 @@ package liveurls import ( + "bytes" "crypto/md5" "encoding/base64" + "encoding/hex" + "encoding/json" "fmt" "io" + "math/rand" "net/http" "net/url" "regexp" @@ -21,48 +25,118 @@ import ( ) type Huya struct { - Rid string + Rid string + Media string + Type string + Cdn string } -func md5huya(str string) string { - w := md5.New() - io.WriteString(w, str) - md5str := fmt.Sprintf("%x", w.Sum(nil)) - return md5str +type Data struct { } -func format(realstr string) string { - i := strings.Split(realstr, "?")[0] - b := strings.Split(realstr, "?")[1] - r := strings.Split(i, "/") - reg := regexp.MustCompile(".(flv|m3u8)") - s := reg.ReplaceAllString(r[len(r)-1], "") - c := strings.SplitN(b, "&", 4) - cnil := c[:0] - n := make(map[string]string) - for _, v := range c { - if len(v) > 0 { - cnil = append(cnil, v) - narr := strings.Split(v, "=") - n[narr[0]] = narr[1] +type Payload struct { + AppId int `json:"appId"` + ByPass int `json:"byPass"` + Context string `json:"context"` + Version string `json:"version"` + Data Data `json:"data"` +} + +type ResponseData struct { + Data struct { + Uid string `json:"uid"` + } `json:"data"` +} + +func getContent(apiUrl string) ([]byte, error) { + payload := Payload{ + AppId: 5002, + ByPass: 3, + Context: "", + Version: "2.4", + Data: Data{}, + } + jsonPayload, err := json.Marshal(payload) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", apiUrl, bytes.NewBuffer(jsonPayload)) + if err != nil { + return nil, err + } + + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Content-Length", fmt.Sprintf("%d", len(jsonPayload))) + req.Header.Set("upgrade-insecure-requests", "1") + req.Header.Set("user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36") + + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + return io.ReadAll(resp.Body) +} + +func getUid() string { + content, _ := getContent("https://udblgn.huya.com/web/anonymousLogin") + var responseData ResponseData + json.Unmarshal(content, &responseData) + uid := responseData.Data.Uid + return uid +} + +var uid, _ = strconv.Atoi(getUid()) + +func getUUID() int64 { + now := time.Now().UnixNano() / int64(time.Millisecond) + randNum := rand.Intn(1000) + return ((now % 10000000000 * 1000) + int64(randNum)) % 4294967295 +} + +func processAntiCode(antiCode string, uid int, streamName string) string { + q, _ := url.ParseQuery(antiCode) + q.Set("ver", "1") + q.Set("sv", "2110211124") + seqId := strconv.Itoa(uid + int(time.Now().UnixNano()/int64(time.Millisecond))) + q.Set("seqid", seqId) + q.Set("uid", strconv.Itoa(uid)) + q.Set("uuid", strconv.FormatInt(getUUID(), 10)) + h := md5.New() + h.Write([]byte(seqId + "|" + q.Get("ctype") + "|" + q.Get("t"))) + ss := hex.EncodeToString(h.Sum(nil)) + fm, _ := base64.StdEncoding.DecodeString(q.Get("fm")) + q.Set("fm", strings.Replace(strings.Replace(strings.Replace(strings.Replace(string(fm), "$0", q.Get("uid"), -1), "$1", streamName, -1), "$2", ss, -1), "$3", q.Get("wsTime"), -1)) + h.Reset() + h.Write([]byte(q.Get("fm"))) + q.Set("wsSecret", hex.EncodeToString(h.Sum(nil))) + q.Del("fm") + if _, ok := q["txyp"]; ok { + q.Del("txyp") + } + return q.Encode() +} + +func format(liveArr map[string]any, uid int) map[string]any { + streamInfo := map[string]any{"flv": make(map[string]string), "hls": make(map[string]string)} + cdnType := map[string]string{"HY": "hycdn", "AL": "alicdn", "TX": "txcdn", "HW": "hwcdn", "HS": "hscdn", "WS": "wscdn"} + for _, s := range liveArr["roomInfo"].(map[string]any)["tLiveInfo"].(map[string]any)["tLiveStreamInfo"].(map[string]any)["vStreamInfo"].(map[string]any)["value"].([]any) { + sMap := s.(map[string]any) + if sMap["sFlvUrl"] != nil { + streamInfo["flv"].(map[string]string)[cdnType[sMap["sCdnType"].(string)]] = sMap["sFlvUrl"].(string) + "/" + sMap["sStreamName"].(string) + "." + sMap["sFlvUrlSuffix"].(string) + "?" + processAntiCode(sMap["sFlvAntiCode"].(string), uid, sMap["sStreamName"].(string)) + } + if sMap["sHlsUrl"] != nil { + streamInfo["hls"].(map[string]string)[cdnType[sMap["sCdnType"].(string)]] = sMap["sHlsUrl"].(string) + "/" + sMap["sStreamName"].(string) + "." + sMap["sHlsUrlSuffix"].(string) + "?" + processAntiCode(sMap["sHlsAntiCode"].(string), uid, sMap["sStreamName"].(string)) } } - c = cnil - fm, _ := url.QueryUnescape(n["fm"]) - ub64, _ := base64.StdEncoding.DecodeString(fm) - u := string(ub64) - p := strings.Split(u, "_")[0] - f := strconv.FormatInt(time.Now().UnixNano()/100, 10) - l := n["wsTime"] - t := "0" - h := p + "_" + t + "_" + s + "_" + f + "_" + l - m := md5huya(h) - y := c[len(c)-1] - url := fmt.Sprintf("%s?wsSecret=%s&wsTime=%s&u=%s&seqid=%s&%s", i, m, l, t, f, y) - return url + return streamInfo } func (h *Huya) GetLiveUrl() any { + var liveArr map[string]any liveurl := "https://m.huya.com/" + h.Rid client := &http.Client{} r, _ := http.NewRequest("GET", liveurl, nil) @@ -72,18 +146,42 @@ func (h *Huya) GetLiveUrl() any { defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) str := string(body) - freg := regexp.MustCompile(`"(?i)liveLineUrl":"([\s\S]*?)",`) + freg := regexp.MustCompile(`(?i)`) res := freg.FindStringSubmatch(str) - if res == nil || res[1] == "" { - return nil - } - nstr, _ := base64.StdEncoding.DecodeString(res[1]) - realstr := string(nstr) - if strings.Contains(realstr, "replay") { - return "https:" + realstr - } else { - liveurl := format(realstr) - realurl := strings.Replace(strings.Replace(strings.Replace(liveurl, "hls", "flv", -1), "m3u8", "flv", -1), "&ctype=tars_mobile", "", -1) - return "https:" + realurl + + json.Unmarshal([]byte(res[1]), &liveArr) + var mediaurl any + if roomInfo, ok := liveArr["roomInfo"].(map[string]any); ok { + if liveStatus, ok := roomInfo["eLiveStatus"].(float64); ok && liveStatus == 2 { + realurl := format(liveArr, uid) + if h.Type == "display" { + return realurl + } + for k, v := range realurl { + switch k { + case h.Media: + if urlarr, ok := v.(map[string]string); ok { + for k, v := range urlarr { + switch k { + case h.Cdn: + mediaurl = v + } + } + } + } + } + + } else if liveStatus, ok := roomInfo["eLiveStatus"].(float64); ok && liveStatus == 3 { + if roomProfile, ok := liveArr["roomProfile"].(map[string]any); ok { + if liveLineUrl, ok := roomProfile["liveLineUrl"].(string); ok { + decodedLiveLineUrl, _ := base64.StdEncoding.DecodeString(liveLineUrl) + mediaurl = "http:" + string(decodedLiveLineUrl) + } + } + } else { + mediaurl = nil + } } + return mediaurl + } diff --git a/Golang/main.go b/Golang/main.go index 9f9e387..38b6c67 100644 --- a/Golang/main.go +++ b/Golang/main.go @@ -1,5 +1,5 @@ // Package Golang -// @Time:2023/02/03 02:29 +// @Time:2023/02/03 02:28 // @File:main.go // @SoftWare:Goland // @Author:feiyang @@ -53,7 +53,14 @@ func setupRouter(adurl string) *gin.Engine { case "huya": huyaobj := &liveurls.Huya{} huyaobj.Rid = rid - c.Redirect(http.StatusMovedPermanently, duanyan(adurl, huyaobj.GetLiveUrl())) + huyaobj.Cdn = c.DefaultQuery("cdn", "hwcdn") + huyaobj.Media = c.DefaultQuery("media", "flv") + huyaobj.Type = c.DefaultQuery("type", "nodisplay") + if huyaobj.Type == "display" { + c.JSON(200, huyaobj.GetLiveUrl()) + } else { + c.Redirect(http.StatusMovedPermanently, duanyan(adurl, huyaobj.GetLiveUrl())) + } case "bilibili": biliobj := &liveurls.BiliBili{} biliobj.Rid = rid