diff --git a/src/env/env.go b/src/env/env.go index 4b13283..b158026 100644 --- a/src/env/env.go +++ b/src/env/env.go @@ -12,7 +12,7 @@ import ( ) const ( - Version = `1.0.2-b11` + Version = `1.0.2-b12` ) var ( @@ -70,8 +70,8 @@ type ( } // `comment:""` Conf_Custom struct { // wy (暂未实现) - Wy_Enable bool `comment:"是否开启小芸源"` - // Wy_Cookie string `comment:"账号cookie数据"` + Wy_Enable bool `comment:"是否开启小芸源"` + Wy_Cookie string `comment:"账号cookie数据"` // mg (暂未实现) // Mg_Enable bool `comment:"是否开启小蜜源"` @@ -80,9 +80,9 @@ type ( Kw_Enable bool `comment:"是否开启小蜗源"` Kw_Mode string `comment:"接口模式 0: bdapi(需验证), 1: kwdes"` // kw bdapi - Kw_Bd_Uid string `comment:"user.uid"` - Kw_Bd_Token string `comment:"user.token"` - Kw_Bd_DevId string `comment:"user.device_id"` + Kw_Bd_Uid string `comment:"field user.uid"` + Kw_Bd_Token string `comment:"field user.token"` + Kw_Bd_DevId string `comment:"field user.device_id"` // kw kwdes Kw_Des_Type string `comment:"返回格式 0: text, 1: json"` Kw_Des_Header string `comment:"请求头 User-Agent"` diff --git a/src/router/router.go b/src/router/router.go index fd43c16..bbc1f39 100644 --- a/src/router/router.go +++ b/src/router/router.go @@ -31,6 +31,8 @@ func loadQMap() [][]string { // 0.wy if env.Config.Custom.Wy_Enable { m[0] = defQuality + } else { + m[0] = tstQuality } // 1.mg m[1] = defQuality diff --git a/src/sources/custom/kw/player.go b/src/sources/custom/kw/player.go index 77e5c4a..4ab2366 100644 --- a/src/sources/custom/kw/player.go +++ b/src/sources/custom/kw/player.go @@ -4,9 +4,9 @@ import ( "io" "lx-source/src/env" "lx-source/src/sources" + "lx-source/src/sources/custom/utils" "net/http" "strconv" - "strings" "sync" "github.com/ZxwyWebSite/ztool" @@ -94,7 +94,7 @@ func bdapi(songMid, quality string) (ourl, msg string) { msg = ztool.Str_FastConcat(`failed: `, resp.Msg) return } - ourl = strings.Split(resp.Data.URL, `?`)[0] + ourl = utils.DelQuery(resp.Data.URL) //strings.Split(resp.Data.URL, `?`)[0] return } @@ -136,11 +136,11 @@ func kwdes(songMid, quality string) (ourl, msg string) { return } realQuality := strconv.Itoa(resp.Data.Bitrate) - if qualityMapReverse[realQuality] != quality { + if realQuality != infoFile.H[:len(infoFile.H)-1] { msg = sources.E_QNotMatch return } - ourl = resp.Data.URL[:strings.Index(resp.Data.URL, `?`)] + ourl = utils.DelQuery(resp.Data.URL) //resp.Data.URL[:strings.Index(resp.Data.URL, `?`)] return } ztool.Net_Request(http.MethodGet, target_url, nil, @@ -161,12 +161,12 @@ func kwdes(songMid, quality string) (ourl, msg string) { } infoData := mkMap(data) loger.Debug(`infoData: %+v`, infoData) - realQuality := qualityMapReverse[infoData[`bitrate`]] - if realQuality != quality { + realQuality := infoData[`bitrate`] + if realQuality != infoFile.H[:len(infoFile.H)-1] { msg = sources.E_QNotMatch return } - ourl = infoData[`url`][:strings.Index(infoData[`url`], `?`)] + ourl = utils.DelQuery(infoData[`url`]) //infoData[`url`][:strings.Index(infoData[`url`], `?`)] return }, }, diff --git a/src/sources/custom/kw/utils.go b/src/sources/custom/kw/utils.go index a13d25f..7dc838a 100644 --- a/src/sources/custom/kw/utils.go +++ b/src/sources/custom/kw/utils.go @@ -29,12 +29,13 @@ var ( H: `4000k`, }, } - qualityMapReverse = map[string]string{ - `128`: sources.Q_128k, - `320`: sources.Q_320k, - `2000`: sources.Q_flac, - `4000`: sources.Q_fl24, - } + // 注:这个还是有规律的,加上或去掉k即可直接比较 + // qualityMapReverse = map[string]string{ + // `128`: sources.Q_128k, + // `320`: sources.Q_320k, + // `2000`: sources.Q_flac, + // `4000`: sources.Q_fl24, + // } desheader = map[string]string{ // `User-Agent`: `okhttp/3.10.0`, } diff --git a/src/sources/custom/tx/QMWSign.go b/src/sources/custom/tx/encrypt.go similarity index 86% rename from src/sources/custom/tx/QMWSign.go rename to src/sources/custom/tx/encrypt.go index 633e993..eb55e1d 100644 --- a/src/sources/custom/tx/QMWSign.go +++ b/src/sources/custom/tx/encrypt.go @@ -1,13 +1,12 @@ package tx import ( - "crypto/md5" - "encoding/hex" "regexp" "strings" "github.com/ZxwyWebSite/ztool" "github.com/ZxwyWebSite/ztool/x/bytesconv" + "github.com/ZxwyWebSite/ztool/zcypt" ) func v(b string) string { @@ -106,14 +105,14 @@ func t(b string) (res []int) { return //res } -func createMD5(s []byte) string { - hash := md5.New() - hash.Write(s) - return hex.EncodeToString(hash.Sum(nil)) -} +// func createMD5(s []byte) string { +// hash := md5.New() +// hash.Write(s) +// return hex.EncodeToString(hash.Sum(nil)) +// } func sign(params []byte) string { - md5Str := strings.ToUpper(createMD5(params)) + md5Str := strings.ToUpper(zcypt.CreateMD5(params)) h := v(md5Str) e := c(md5Str) ls := t(md5Str) diff --git a/src/sources/custom/tx/player.go b/src/sources/custom/tx/player.go index 6059cae..9a8b00c 100644 --- a/src/sources/custom/tx/player.go +++ b/src/sources/custom/tx/player.go @@ -3,7 +3,6 @@ package tx import ( "lx-source/src/env" "lx-source/src/sources" - "strings" "github.com/ZxwyWebSite/ztool" "github.com/ZxwyWebSite/ztool/x/bytesconv" @@ -133,9 +132,13 @@ func Url(songMid, quality string) (ourl, msg string) { msg = sources.E_NoLink //`无法获取音乐链接` return } - realQuality := strings.Split(infoData.Filename, `.`)[0][:4] - if qualityMapReverse[realQuality] != quality && /*infoBody.TrackInfo.Pay.PayPlay == 0*/ !tryLink { - msg = sources.E_QNotMatch //`实际音质不匹配` + realQuality := ztool.Str_Before(infoData.Filename, `.`)[:4] //strings.Split(infoData.Filename, `.`)[0][:4] + // if qualityMapReverse[realQuality] != quality && /*infoBody.TrackInfo.Pay.PayPlay == 0*/ !tryLink { + // msg = sources.E_QNotMatch //`实际音质不匹配` + // return + // } + if realQuality != infoFile.H && !tryLink { + msg = sources.E_QNotMatch return } ourl = ztool.Str_FastConcat(`https://ws.stream.qqmusic.qq.com/`, infoData.Purl) diff --git a/src/sources/custom/tx/utils.go b/src/sources/custom/tx/utils.go index fbe9fde..0139062 100644 --- a/src/sources/custom/tx/utils.go +++ b/src/sources/custom/tx/utils.go @@ -10,8 +10,8 @@ import ( var ( fileInfo = map[string]struct { - E string - H string + E string // 扩展名 + H string // 专用音质 }{ sources.Q_128k: { E: `.mp3`, @@ -38,14 +38,14 @@ var ( H: `AI00`, }, } - qualityMapReverse = map[string]string{ - `M500`: sources.Q_128k, - `M800`: sources.Q_320k, - `F000`: sources.Q_flac, - `RS01`: sources.Q_fl24, - `Q000`: `dolby`, - `AI00`: `master`, - } + // qualityMapReverse = map[string]string{ + // `M500`: sources.Q_128k, + // `M800`: sources.Q_320k, + // `F000`: sources.Q_flac, + // `RS01`: sources.Q_fl24, + // `Q000`: `dolby`, + // `AI00`: `master`, + // } header = map[string]string{ `Referer`: `https://y.qq.com/`, } diff --git a/src/sources/custom/utils/utils.go b/src/sources/custom/utils/utils.go index 1cb76a5..17aa8c0 100644 --- a/src/sources/custom/utils/utils.go +++ b/src/sources/custom/utils/utils.go @@ -1,5 +1,9 @@ package utils +import ( + "github.com/ZxwyWebSite/ztool" +) + // func SizeFormat(size int) string { // if size < 1024 { // return ztool.Str_FastConcat(strconv.Itoa(size), `B`) @@ -10,3 +14,8 @@ package utils // } // return `` // } + +// 删除?号后尾随内容 +func DelQuery(str string) string { + return ztool.Str_Before(str, `?`) +} diff --git a/src/sources/custom/wy/encrypt.go b/src/sources/custom/wy/encrypt.go new file mode 100644 index 0000000..fe50a00 --- /dev/null +++ b/src/sources/custom/wy/encrypt.go @@ -0,0 +1,98 @@ +package wy + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "encoding/base64" + + "github.com/ZxwyWebSite/ztool" + "github.com/ZxwyWebSite/ztool/x/bytesconv" + "github.com/ZxwyWebSite/ztool/x/json" + "github.com/ZxwyWebSite/ztool/zcypt" +) + +var ( + // __all__ = []string{`weEncrypt`, `linuxEncrypt`, `eEncrypt`} + // MODULUS = ztool.Str_FastConcat( + // `00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7`, + // `b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280`, + // `104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932`, + // `575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b`, + // `3ece0462db0a22b8e7`, + // ) + // PUBKEY = `010001` + // NONCE = bytesconv.StringToBytes(`0CoJUm6Qyw8W8jud`) + // LINUXKEY = bytesconv.StringToBytes(`rFgB&h#%2?^eDg:Q`) + eapiKey = bytesconv.StringToBytes(`e82ckenh8dichen8`) + ivKey = bytesconv.StringToBytes(`0102030405060708`) +) + +func eapiEncrypt(url, text string) map[string][]string { + digest := zcypt.CreateMD5(bytesconv.StringToBytes(ztool.Str_FastConcat( + `nobody`, url, `use`, text, `md5forencrypt`, + ))) + data := ztool.Str_FastConcat( + url, `-36cd479b6b5-`, text, `-36cd479b6b5-`, digest, + ) + // 注:JSON编码时会自动将[]byte转为string,这里省去一步转换 + return map[string][]string{ + `params`: {bytesconv.BytesToString(aesEncrypt(bytesconv.StringToBytes(data), eapiKey, false))}, + } +} + +// crypto.js + +func aesEncrypt(text, key []byte, iv bool) []byte { + pad := 16 - len(text)%16 + text = append(text, bytes.Repeat([]byte{byte(pad)}, pad)...) + block, _ := aes.NewCipher(key) + // if err != nil { + // panic(err) + // } + var encryptor cipher.BlockMode + if iv { + encryptor = cipher.NewCBCEncrypter(block, ivKey) + } else { + encryptor = zcypt.NewECBEncrypter(block) + } + ciphertext := make([]byte, len(text)) + encryptor.CryptBlocks(ciphertext, text) + if iv { + return zcypt.Base64Encode(base64.StdEncoding, ciphertext) + } + return bytes.ToUpper(zcypt.HexEncode(ciphertext)) +} + +func eapi(url string, object map[string]any) map[string][]string { + text, err := json.Marshal(object) + if err != nil { + panic(err) + } + message := ztool.Str_FastConcat( + `nobody`, url, `use`, bytesconv.BytesToString(text), `md5forencrypt`, + ) + digest := zcypt.CreateMD5(bytesconv.StringToBytes(message)) + data := bytes.Join( + [][]byte{ + bytesconv.StringToBytes(url), + text, + bytesconv.StringToBytes(digest), + }, + []byte{45, 51, 54, 99, 100, 52, 55, 57, 98, 54, 98, 53, 45}, + ) + return map[string][]string{ + `params`: {bytesconv.BytesToString(aesEncrypt(data, eapiKey, false))}, + } +} + +func decrypt(data []byte) (out []byte) { + dec, err := zcypt.HexDecode(data) + if err == nil { + out, err = zcypt.AesDecrypt(dec, eapiKey) + } + if err != nil { + panic(err) + } + return out +} diff --git a/src/sources/custom/wy/player.go b/src/sources/custom/wy/player.go new file mode 100644 index 0000000..656a9b0 --- /dev/null +++ b/src/sources/custom/wy/player.go @@ -0,0 +1,107 @@ +package wy + +import ( + "io" + "lx-source/src/env" + "lx-source/src/sources" + "lx-source/src/sources/builtin" + "lx-source/src/sources/custom/utils" + "net/http" + "net/url" + "strconv" + "strings" + + "github.com/ZxwyWebSite/ztool" + "github.com/ZxwyWebSite/ztool/x/cookie" +) + +func Url(songMid, quality string) (ourl, msg string) { + loger := env.Loger.NewGroup(`Wy`) + rquality, ok := brMap[quality] + if !ok { + msg = sources.E_QNotSupport + return + } + cookies := cookie.Parse(env.Config.Custom.Wy_Cookie) + answer, err := SongUrl(song_url_query{ + Cookie: cookie.ToMap(cookies), + Ids: songMid, + Br: rquality, + }) + var body builtin.WyApi_Song + if err == nil { + err = ztool.Val_MapToStruct(answer.Body, &body) + } + if err != nil { + loger.Error(`SongUrl: %s`, err) + msg = sources.ErrHttpReq + return + } + loger.Debug(`Resp: %+v`, body) + if len(body.Data) == 0 { + msg = `No Data:无返回数据` + return + } + data := body.Data[0] + br := strconv.Itoa(data.Br) // 注:由于flac返回br值不固定,暂无法进行比较 + if br != rquality && !ztool.Chk_IsMatch(br, sources.Q_flac, sources.Q_fl24) { + msg = sources.E_QNotMatch + return + } + ourl = utils.DelQuery(data.URL) + return +} + +func PyUrl(songMid, quality string) (ourl, msg string) { + loger := env.Loger.NewGroup(`Wy`) + rquality, ok := qualityMap[quality] + if !ok { + msg = sources.E_QNotSupport + return + } + path := `/api/song/enhance/player/url/v1` + requestUrl := `https://interface.music.163.com/eapi/song/enhance/player/url/v1` + var body builtin.WyApi_Song + text := ztool.Str_FastConcat( + `{"encodeType":"flac","ids":["`, songMid, `"],"level":"`, rquality, `"}`, + ) + var form url.Values = eapiEncrypt(path, text) + // form, err := json.Marshal(eapiEncrypt(path, text)) + // if err == nil { + err := ztool.Net_Request( + http.MethodPost, requestUrl, + strings.NewReader(form.Encode()), //bytes.NewReader(form), + []ztool.Net_ReqHandlerFunc{ztool.Net_ReqAddHeader(map[string]string{ + `Cookie`: env.Config.Custom.Wy_Cookie, + })}, + []ztool.Net_ResHandlerFunc{ + func(res *http.Response) error { + body, err := io.ReadAll(res.Body) + if err != nil { + return err + } + loger.Info(`%s`, body) + return ztool.Err_EsContinue + }, + ztool.Net_ResToStruct(&body), + }, + ) + // } + if err != nil { + loger.Error(`Request: %s`, err) + msg = sources.ErrHttpReq + return + } + loger.Debug(`Resp: %+v`, body) + if len(body.Data) == 0 { + msg = `No Data:无返回数据` + return + } + data := body.Data[0] + if data.Level != rquality { + msg = sources.E_QNotMatch + return + } + ourl = utils.DelQuery(data.URL) + return +} diff --git a/src/sources/custom/wy/song_url.go b/src/sources/custom/wy/song_url.go new file mode 100644 index 0000000..8acbe75 --- /dev/null +++ b/src/sources/custom/wy/song_url.go @@ -0,0 +1,42 @@ +package wy + +import ( + "net/http" + "strings" + + "github.com/ZxwyWebSite/ztool" +) + +type song_url_query struct { + Cookie map[string]string + Ids string + Br string + RealIP string +} + +func SongUrl(query song_url_query) (*reqAnswer, error) { + query.Cookie[`os`] = `pc` + if query.Br == `` { + query.Br = `999000` + } + ids := strings.Split(query.Ids, `,`) + // idj, err := json.Marshal(ids) + // if err != nil { + // return nil, err + // } + data := map[string]any{ + `ids`: ztool.Str_FastConcat(`["`, strings.Join(ids, `","`), `"]`), //bytesconv.BytesToString(idj), //`["1998644237"]`, + `br`: query.Br, //ztool.Str_Select(query.Br, `999000`), + } + return createRequest( + http.MethodPost, + `https://interface3.music.163.com/eapi/song/enhance/player/url`, + data, + reqOptions{ + Crypto: `eapi`, + Cookie: query.Cookie, + RealIP: query.RealIP, + Url: `/api/song/enhance/player/url`, + }, + ) +} diff --git a/src/sources/custom/wy/types.go b/src/sources/custom/wy/types.go new file mode 100644 index 0000000..02c5f26 --- /dev/null +++ b/src/sources/custom/wy/types.go @@ -0,0 +1,31 @@ +package wy + +import "lx-source/src/sources" + +var ( + brMap = map[string]string{ + sources.Q_128k: `128000`, + sources.Q_320k: `320000`, + sources.Q_flac: `1000000`, //`743625`,`915752` + sources.Q_fl24: `2000000`, //`1453955`,`1683323` + } + qualityMap = map[string]string{ + sources.Q_128k: `standard`, + sources.Q_320k: `exhigh`, + sources.Q_flac: `lossless`, + sources.Q_fl24: `hires`, + `dolby`: `jyeffect`, + `sky`: `jysky`, + `master`: `jymaster`, + } + // 优化:返回音质与查询音质相同,完全可以直接比较,不用多一步Reverse + // qualityMapReverse = map[string]string{ + // `standard`: sources.Q_128k, + // `exhigh`: sources.Q_320k, + // `lossless`: sources.Q_flac, + // `hires`: sources.Q_fl24, + // `jyeffect`: `dolby`, + // `jysky`: `sky`, + // `jymaster`: `master`, + // } +) diff --git a/src/sources/custom/wy/utils.go b/src/sources/custom/wy/utils.go new file mode 100644 index 0000000..26d0b9e --- /dev/null +++ b/src/sources/custom/wy/utils.go @@ -0,0 +1,223 @@ +package wy + +import ( + "errors" + "io" + "math/rand" + "net/http" + stdurl "net/url" + "regexp" + "strconv" + "strings" + "time" + + "github.com/ZxwyWebSite/ztool" + "github.com/ZxwyWebSite/ztool/x/json" + "github.com/ZxwyWebSite/ztool/zcypt" +) + +// request.js + +const anonymous_token = `1f5fa7b6a6a9f81a11886e5186fde7fb98e25cf0036d7afd055b980b2261f5464b7f5273fc3921d1262bfec66a19a30c41d8da00c3685f5ace96f0d5a48b6db334d974731083682e3324751bcc9aaf44c3061cd1` + +var wapiReg = regexp.MustCompile(`\w*api`) + +var userAgentMap = map[string]string{ + `mobile`: `Mozilla/5.0 (iPhone; CPU iPhone OS 17_2_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Mobile/15E148 Safari/604.1`, + `pc`: `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0`, +} + +type ( + // reqCookie struct{} + reqOptions struct { + UA string + Headers map[string]string + RealIP string + IP string + Cookie interface{} + Crypto string + Url string + } + reqAnswer struct { + Status int + Body map[string]any + Cookie []string + } +) + +func createRequest(method, url string, data map[string]any, options reqOptions) (*reqAnswer, error) { + if options.Headers == nil { + options.Headers = make(map[string]string) + } + options.Headers[`User-Agent`] = userAgentMap[options.UA] + if method == http.MethodPost { + options.Headers[`Content-Type`] = `application/x-www-form-urlencoded` + } + if strings.Contains(url, `music.163.com`) { + options.Headers[`Referer`] = `https://music.163.com` + } + ip := ztool.Str_Select(options.RealIP, options.IP, ``) + if ip != `` { + options.Headers[`X-Real-IP`] = ip + options.Headers[`X-Forwarded-For`] = ip + } + if obj, ok := options.Cookie.(map[string]string); ok { + obj[`__remember_me`] = `true` + obj[`_ntes_nuid`] = zcypt.HexToString(zcypt.RandomBytes(16)) + if !strings.Contains(url, `login`) { + obj[`NMTID`] = zcypt.HexToString(zcypt.RandomBytes(16)) + } + if _, ok := obj[`MUSIC_U`]; !ok { + // 游客 + if _, ok := obj[`MUSIC_A`]; !ok { + obj[`MUSIC_A`] = anonymous_token + if obj[`os`] == `` { + obj[`os`] = `ios` + } + if obj[`appver`] == `` { + obj[`appver`] = `8.20.21` + } + } + } + keys, i := make([]string, len(obj)), 0 + for k, v := range obj { + keys[i] = ztool.Str_FastConcat( + stdurl.QueryEscape(k), `=`, stdurl.QueryEscape(v), + ) + i++ + } + options.Headers[`Cookie`] = strings.Join(keys, `; `) + options.Cookie = obj + } else if str, ok := options.Cookie.(string); ok && str != `` { + options.Headers[`Cookie`] = str + } else { + options.Headers[`Cookie`] = `__remember_me=true; NMTID=xxx` + } + var form stdurl.Values + switch options.Crypto { + case `weapi`: + panic(`not support`) + // options.Headers[`User-Agent`] = `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 Edg/116.0.1938.69` + // reg := regexp.MustCompile(`_csrf=([^(;|$)]+)`) + // csrfToken := reg.FindStringSubmatch(options.Headers[`Cookie`]) + // if len(csrfToken) > 1 { + // data[`csrf_token`] = csrfToken[1] + // } else { + // data[`csrf_token`] = `` + // } + // data = weapi(data) + // url = wapiReg.ReplaceAllString(url, `weapi`) + case `linuxapi`: + panic(`not support`) + // data = linuxapi( + // method, + // wapiReg.ReplaceAllString(url, `weapi`), + // data, + // ) + // options.Headers[`User-Agent`] = `Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36` + // url = `https://music.163.com/api/linux/forward` + case `eapi`: + cookie, ok := options.Cookie.(map[string]string) + if !ok { + cookie = make(map[string]string) + } + // csrfToken := cookie[`__csrf`] + now := time.Now() + reqid := strconv.Itoa(rand.Intn(1000)) + header := map[string]string{ + `osver`: ztool.Str_Select(cookie[`osver`], `17,1,2`), //系统版本 + `deviceId`: cookie[`deviceId`], //zcypt.Base64ToString(base64.StdEncoding, bytesconv.StringToBytes(imei+"'\t02:00:00:00:00:00\t5106025eb79a5247\t70ffbaac7'")) + `appver`: ztool.Str_Select(cookie[`appver`], `8.9.70`), // app版本 + `versioncode`: ztool.Str_Select(cookie[`versioncode`], `140`), //版本号 + `mobilename`: cookie[`mobilename`], //设备model + `buildver`: ztool.Str_Select(cookie[`buildver`], strconv.FormatInt(now.Unix(), 10)), + `resolution`: ztool.Str_Select(cookie[`resolution`], `1920x1080`), //设备分辨率 + `__csrf`: cookie[`__csrf`], //csrfToken, + `os`: ztool.Str_Select(cookie[`os`], `ios`), + `channel`: cookie[`channel`], + `requestId`: ztool.Str_FastConcat( + strconv.FormatInt(now.UnixMilli(), 10), `_`, + strings.Repeat(`0`, 4-len(reqid)), reqid, + ), + } + if cookie[`MUSIC_U`] != `` { + header[`MUSIC_U`] = cookie[`MUSIC_U`] + } + if cookie[`MUSIC_A`] != `` { + header[`MUSIC_A`] = cookie[`MUSIC_A`] + } + keys, i := make([]string, len(header)), 0 + for k, v := range header { + keys[i] = ztool.Str_FastConcat( + stdurl.QueryEscape(k), `=`, stdurl.QueryEscape(v), + ) + i++ + } + options.Headers[`Cookie`] = strings.Join(keys, `; `) + out, err := json.Marshal(header) + if err != nil { + panic(err) + } + data[`header`] = out //bytesconv.BytesToString(out) + form = eapi(options.Url, data) + url = wapiReg.ReplaceAllString(url, `eapi`) + default: + return nil, errors.New(`not support`) + } + // values := stdurl.Values{} + // for k, v := range data { + // values.Add(k, v) + // } + answer := reqAnswer{Status: 500, Body: map[string]any{} /*, Cookie: []string{}*/} + err := ztool.Net_Request(method, url, + strings.NewReader(form.Encode()), + []ztool.Net_ReqHandlerFunc{ + ztool.Net_ReqAddHeader(options.Headers), + }, + []ztool.Net_ResHandlerFunc{ + func(res *http.Response) error { + body, err := io.ReadAll(res.Body) + if err == nil { + answer.Cookie = res.Header[`Set-Cookie`] + reg := regexp.MustCompile(`\s*Domain=[^(;|$)]+;*`) + for i, v := range answer.Cookie { + answer.Cookie[i] = reg.ReplaceAllString(v, ``) + } + if options.Crypto == `eapi` && body[0] != '{' { + err = json.Unmarshal(decrypt(body), &answer.Body) + } else { + err = json.Unmarshal(body, &answer.Body) + } + if err == nil { + if code, ok := answer.Body[`code`].(string); ok { + answer.Body[`code`], err = strconv.Atoi(code) + } else { + answer.Body[`code`] = res.StatusCode + } + if err == nil { + if code, ok := answer.Body[`code`].(int); ok { + if !ztool.Chk_IsMatchInt(code, 201, 302, 400, 502, 800, 801, 802, 803) { + // 特殊状态码 + answer.Status = 200 + } + } + if answer.Status < 100 || answer.Status >= 600 { + answer.Status = 400 + } + if answer.Status != 200 { + err = errors.New(strconv.Itoa(answer.Status)) + } + } + } + } + if err != nil { + answer.Status = 502 + answer.Body = map[string]any{`code`: 502, `msg`: err} + return err + } + return nil + }, + }, + ) + return &answer, err +} diff --git a/update.md b/update.md index c94c4ec..71e54b8 100644 --- a/update.md +++ b/update.md @@ -1,5 +1,11 @@ ## Lx-Source/更新日志 +#### \# 2024-01-18 v1.0.2-b12-d1 (dev) ++ 对部分功能实现方式进行优化,去除qualityMapReverse依赖 ++ 由于wy修改api验证方式,python版逻辑已不可用,现参考NeteaseCloudMusicApi项目进行修改 ++ 实现wy外链获取逻辑(暂未实装) + + #### \# 2024-01-15 v1.0.2-b11 (beta) + 测试版MusicId验证