2024-02-20 v1.0.3-fix

This commit is contained in:
ZxwyWebSite 2024-02-21 03:49:01 +08:00
parent 2dea36c3ce
commit 07c32ab6d4
20 changed files with 784 additions and 154 deletions

View File

@ -99,5 +99,5 @@
音乐平台不易,请尊重版权,支持正版。
本项目仅用于对技术可行性的探索及研究,不接受任何商业(包括但不限于广告等)合作及捐赠。
若对此有疑问请 mail to: admin+zxwy.tk (请将`+`替换为`@`)
若对此有疑问请 mail to: admin+zxwy.link (请将`+`替换为`@`)

23
src/env/env.go vendored
View File

@ -12,7 +12,7 @@ import (
)
const (
Version = `1.0.3-pre`
Version = `1.0.3-fix`
)
var (
@ -121,9 +121,19 @@ type (
Kw_Des_Header string `comment:"请求头 User-Agent"`
// kg
Kg_Enable bool `comment:"是否启用小枸源"`
Kg_Enable bool `comment:"是否启用小枸源"`
// kg client
Kg_Client_AppId string `comment:"酷狗音乐的appid官方安卓为1005官方PC为1001client.appid"`
Kg_Client_SignKey string `comment:"客户端signature采用的key值需要与appid对应client.signatureKey"`
Kg_Client_Version string `comment:"客户端versioncodepidversionsecret可能随此值而变化client.clientver"`
Kg_Client_PidVerSec string `comment:"获取URL时所用的key值计算验证值client.pidversionsecret"`
Kg_Client_Pid string `comment:"field client.pid"`
// kg user
Kg_token string `comment:"field user.token"`
Kg_userId string `comment:"field user.userid"`
// kg lite_sign_in
Kg_Lite_Enable bool `comment:"是否启用概念版自动签到仅在appid=3116时运行"`
Kg_Lite_Interval int64 `comment:"调用时间,自动刷新"`
// tx
Tx_Enable bool `comment:"是否启用小秋源"`
@ -227,8 +237,13 @@ var (
Kw_Des_Type: `json`,
Kw_Des_Header: `okhttp/3.10.0`,
Kg_Enable: false,
Kg_userId: `0`,
Kg_Enable: false,
Kg_Client_AppId: `1005`,
Kg_Client_SignKey: `OIlwieks28dk2k092lksi2UIkp`,
Kg_Client_Version: `12029`,
Kg_Client_PidVerSec: `57ae12eb6890223e355ccfcb74edf70d`,
Kg_Client_Pid: `2`,
Kg_userId: `0`,
Tx_Enable: false,
Tx_Refresh_Enable: false,

View File

@ -56,12 +56,12 @@ func (o *Resp) Execute(c *gin.Context) {
default:
status = http.StatusOK
}
// if o.Code != 0 {
// if o.Code == 2 /*&& o.Data == ``*/ {
// o.Data = ErrMp3
// }
// c.Abort()
// }
if o.Code != 0 {
// if o.Code == 2 /*&& o.Data == ``*/ {
// o.Data = ErrMp3
// }
c.Abort()
}
c.JSON(status, o)
}

View File

@ -3,11 +3,13 @@ package server
import (
"lx-source/src/caches"
"lx-source/src/env"
"lx-source/src/middleware/auth"
"lx-source/src/middleware/resp"
"lx-source/src/middleware/util"
"lx-source/src/sources"
"lx-source/src/sources/custom"
"strings"
"sync/atomic"
"github.com/ZxwyWebSite/ztool"
"github.com/gin-gonic/gin"
@ -23,10 +25,9 @@ import (
// }
// )
func loadMusic(api *gin.RouterGroup) {
func loadMusic(api gin.IRouter) {
// /{method}/{source}/{musicId}/{?quality}
api.GET(`/:m/:s/:id/*q`, musicHandler)
api.GET(`/:m/:s/:id/*q`, auth.InitHandler(musicHandler)...)
}
func musicHandler(c *gin.Context) {
@ -40,32 +41,36 @@ func musicHandler(c *gin.Context) {
loger.Debug(`s:'%v', m:'%v', id:'%v', q:'%v'`, ps, pm, pid, pq)
// 查询内存缓存
cquery := strings.Join([]string{pm, ps, pid, pq}, `/`)
loger.Debug(cquery)
if clink, ok := env.Cache.Get(cquery); ok {
if cstr, ok := clink.(string); ok {
loger.Debug(`MemHIT [%q]=>[%q]`, cquery, cstr)
if cstr == `` {
out.Code = 2
out.Msg = `Memory Reject`
} else {
out.Msg = `Memory HIT`
out.Data = cstr
}
return out
loger.Debug(`MemoGet: %v`, cquery)
if cdata, ok := env.Cache.Get(cquery); ok {
loger.Debug(`MemoHIT: %q`, cdata)
if cdata == `` {
out.Code = 2
out.Msg = memRej
} else {
out.Msg = memHIT
out.Data = cdata
}
return out
}
// 定位音乐源
var source custom.Source
var active bool // 是否激活(自定义账号)
switch ps {
case sources.S_wy:
active = env.Config.Custom.Wy_Enable
source = custom.WySource
case sources.S_mg:
active = env.Config.Custom.Mg_Enable
source = custom.MgSource
case sources.S_kw:
active = env.Config.Custom.Kw_Enable
source = custom.KwSource
case sources.S_kg:
active = env.Config.Custom.Kg_Enable
source = custom.KgSource
case sources.S_tx:
active = env.Config.Custom.Tx_Enable
source = custom.TxSource
case sources.S_lx:
source = custom.LxSource
@ -88,18 +93,45 @@ func musicHandler(c *gin.Context) {
switch pm {
case `url`, `link`:
// 查询文件缓存
if caches.UseCache.Stat() {
uquery := caches.NewQuery(ps, pid, pq)
defer uquery.Free()
var cstat bool
if caches.UseCache != nil {
cstat = caches.UseCache.Stat()
}
uquery := caches.NewQuery(ps, pid, pq)
defer uquery.Free()
if cstat {
loger.Debug(`FileGet: %v`, uquery.Query())
if olink := caches.UseCache.Get(uquery); olink != `` {
env.Cache.Set(cquery, olink, 3600)
out.Msg = `Cache HIT`
env.Cache.Set(cquery, olink, 7200)
out.Msg = cacheHIT
out.Data = olink
return out
}
}
out.Msg = `No Link`
// out.Data, out.Msg = source.Url(pid, pq)
// 解析歌曲外链
atomic.AddInt64(&reqnum, 1)
out.Data, out.Msg = source.Url(pid, pq)
if out.Data != `` {
// 缓存并获取直链
atomic.AddInt64(&secnum, 1)
if out.Msg == `` {
if cstat && active {
loger.Debug(`FileSet: %v`, out.Data)
if link := caches.UseCache.Set(uquery, out.Data.(string)); link != `` {
env.Cache.Set(cquery, link, 7200)
out.Msg = cacheSet
out.Data = link
return out
}
out.Msg = cacheFAIL
} else {
out.Msg = cacheMISS
}
}
// 无法获取直链 直接返回原链接
env.Cache.Set(cquery, out.Data, 1200)
return out
}
case `lrc`, `lyric`:
out.Data, out.Msg = source.Lrc(pid)
case `pic`, `cover`:
@ -107,10 +139,11 @@ func musicHandler(c *gin.Context) {
default:
out.Code = 6
out.Msg = ztool.Str_FastConcat(`无效源方法:'`, pm, `'`)
// return
return out
}
// 缓存并获取直链
if out.Data != `` {
if out.Msg != `` {
out.Code = 2
env.Cache.Set(cquery, out.Data, 600)
}
return out
})

View File

@ -3,7 +3,6 @@ package server
import (
"lx-source/src/caches"
"lx-source/src/env"
"lx-source/src/middleware/auth"
"lx-source/src/middleware/dynlink"
"lx-source/src/middleware/resp"
"lx-source/src/middleware/util"
@ -64,7 +63,8 @@ func InitRouter() *gin.Engine {
// r.StaticFile(`/favicon.ico`, `public/icon.ico`)
// r.StaticFile(`/lx-custom-source.js`, `public/lx-custom-source.js`)
// 解析接口
r.GET(`/link/:s/:id/:q`, auth.InitHandler(linkHandler)...)
loadMusic(r)
// r.GET(`/link/:s/:id/:q`, auth.InitHandler(linkHandler)...)
dynlink.LoadHandler(r)
// 动态链?
// r.GET(`/file/:t/:x/:f`, dynlink.FileHandler())
@ -75,7 +75,6 @@ func InitRouter() *gin.Engine {
// r.Static(`/file`, env.Config.Cache.Local_Path)
// }
// 功能接口
// loadMusic(r.Group(`/api`))
// api := r.Group(`/api`)
// {
// api.GET(`/:s/:m/:q`) // {source}/{method}/{query}
@ -105,6 +104,7 @@ const (
cacheHIT = `Cache HIT` // 缓存已命中
cacheMISS = `Cache MISS` // 缓存未命中
cacheSet = `Cache Seted` // 缓存已设置
cacheFAIL = `Cache FAIL` // 缓存未成功
memHIT = `Memory HIT` // 内存已命中
memRej = `Memory Reject` // 内存已拒绝

View File

@ -11,6 +11,7 @@ import (
"lx-source/src/sources/custom/tx"
"lx-source/src/sources/custom/wy"
wm "lx-source/src/sources/custom/wy/modules"
"lx-source/src/sources/example"
"net/http"
"strconv"
"sync"
@ -72,8 +73,8 @@ func (s *Source) GetLink(c *caches.Query) (outlink string, msg string) {
if env.Config.Source.MusicIdVerify {
vef := wv_pool.Get().(*wm.VerifyInfo)
defer wv_pool.Put(vef)
vurl := ztool.Str_FastConcat(`https://`, vef_wy, `&id=`, c.MusicID)
_, err := ztool.Net_HttpReq(http.MethodGet, vurl, nil, header_wy, &vef)
vurl := ztool.Str_FastConcat(`https://`, example.Vef_wy, `&id=`, c.MusicID)
_, err := ztool.Net_HttpReq(http.MethodGet, vurl, nil, example.Header_wy, &vef)
if err != nil {
jx.Error(`Wy, VefReq: %s`, err)
msg = sources.ErrHttpReq
@ -95,13 +96,13 @@ func (s *Source) GetLink(c *caches.Query) (outlink string, msg string) {
// }
// url := urls[rand.Intn(len(urls))]
url := ztool.Str_FastConcat(
`https://`, api_wy, `&id=`, c.MusicID, `&level=`, rquery,
`https://`, example.Api_wy, `&id=`, c.MusicID, `&level=`, rquery,
`&timestamp=`, strconv.FormatInt(time.Now().UnixMilli(), 10),
)
// jx.Debug(`Wy, Url: %v`, url)
// wy源增加后端重试 默认3次
for i := 0; true; i++ {
_, err := ztool.Net_HttpReq(http.MethodGet, url, nil, header_wy, &resp)
_, err := ztool.Net_HttpReq(http.MethodGet, url, nil, example.Header_wy, &resp)
if err != nil {
jx.Error(`HttpReq, Err: %s, ReTry: %v`, err, i)
if i > 3 {
@ -149,9 +150,9 @@ func (s *Source) GetLink(c *caches.Query) (outlink string, msg string) {
resp := mg_pool.Get().(*MgApi_Song)
defer mg_pool.Put(resp)
url := ztool.Str_FastConcat(`https://`, api_mg, `?copyrightId=`, c.MusicID, `&type=`, rquery)
url := ztool.Str_FastConcat(`https://`, example.Api_mg, `?copyrightId=`, c.MusicID, `&type=`, rquery)
// jx.Debug(`Mg, Url: %v`, url)
_, err := ztool.Net_HttpReq(http.MethodGet, url, nil, header_mg, &resp)
_, err := ztool.Net_HttpReq(http.MethodGet, url, nil, example.Header_mg, &resp)
if err != nil {
jx.Error(`Mg, HttpReq: %s`, err)
msg = sources.ErrHttpReq

View File

@ -1,11 +1,7 @@
package builtin
import (
"encoding/base64"
"lx-source/src/sources"
"github.com/ZxwyWebSite/ztool"
"github.com/ZxwyWebSite/ztool/zcypt"
)
type (
@ -242,18 +238,20 @@ var (
sources.S_wy: `exhigh`,
sources.S_mg: `2`,
sources.S_kw: sources.Q_320k,
// sources.S_kg: ``,
sources.S_kg: ``,
sources.S_tx: `M800`,
},
sources.Q_flac: {
sources.S_wy: `lossless`,
sources.S_mg: `3`,
sources.S_kw: `2000k`,
sources.S_kg: ``,
sources.S_tx: `F000`,
},
sources.Q_fl24: {
sources.S_wy: `hires`,
sources.S_mg: `4`,
sources.S_kg: ``,
// sources.S_tx: `RS01`,
},
// `fl24`: {
@ -262,35 +260,15 @@ var (
// },
}
// ApiAddr
api_wy string
api_mg string
// api_wy string
// api_mg string
// api_kw string
// api_kg string = `https://wwwapi.kugou.com/yy/index.php?r=play/getdata&platid=4&mid=1`
// api_tx string = `https://u.y.qq.com/cgi-bin/musicu.fcg?data=`
vef_wy string
// vef_wy string
// Headers
header_wy map[string]string
header_mg map[string]string
// header_wy map[string]string
// header_mg map[string]string
// header_kw map[string]string
// header_tx = map[string]string{`Referer`: `https://y.qq.com/`}
)
func init() {
// InitBuiltInSource
var initdata = struct {
Api_Wy *string
Api_Mg *string
Vef_Wy *string
Header_Wy *map[string]string
Header_Mg *map[string]string
}{
Api_Wy: &api_wy,
Api_Mg: &api_mg,
Vef_Wy: &vef_wy,
Header_Wy: &header_wy,
Header_Mg: &header_mg,
}
data := []byte{0x53, 0x6e, 0x38, 0x44, 0x41, 0x51, 0x4c, 0x2f, 0x67, 0x41, 0x41, 0x42, 0x42, 0x51, 0x45, 0x47, 0x51, 0x58, 0x42, 0x70, 0x58, 0x31, 0x64, 0x35, 0x41, 0x51, 0x77, 0x41, 0x41, 0x51, 0x5a, 0x42, 0x63, 0x47, 0x6c, 0x66, 0x54, 0x57, 0x63, 0x42, 0x44, 0x41, 0x41, 0x42, 0x42, 0x6c, 0x5a, 0x6c, 0x5a, 0x6c, 0x39, 0x58, 0x65, 0x51, 0x45, 0x4d, 0x41, 0x41, 0x45, 0x4a, 0x53, 0x47, 0x56, 0x68, 0x5a, 0x47, 0x56, 0x79, 0x58, 0x31, 0x64, 0x35, 0x41, 0x66, 0x2b, 0x43, 0x41, 0x41, 0x45, 0x4a, 0x53, 0x47, 0x56, 0x68, 0x5a, 0x47, 0x56, 0x79, 0x58, 0x30, 0x31, 0x6e, 0x41, 0x66, 0x2b, 0x43, 0x41, 0x41, 0x41, 0x41, 0x49, 0x66, 0x2b, 0x42, 0x42, 0x41, 0x45, 0x42, 0x45, 0x57, 0x31, 0x68, 0x63, 0x46, 0x74, 0x7a, 0x64, 0x48, 0x4a, 0x70, 0x62, 0x6d, 0x64, 0x64, 0x63, 0x33, 0x52, 0x79, 0x61, 0x57, 0x35, 0x6e, 0x41, 0x66, 0x2b, 0x43, 0x41, 0x41, 0x45, 0x4d, 0x41, 0x51, 0x77, 0x41, 0x41, 0x50, 0x34, 0x42, 0x72, 0x76, 0x2b, 0x41, 0x41, 0x53, 0x52, 0x6a, 0x63, 0x32, 0x30, 0x75, 0x63, 0x32, 0x46, 0x35, 0x63, 0x58, 0x6f, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4c, 0x32, 0x46, 0x77, 0x61, 0x53, 0x38, 0x2f, 0x64, 0x48, 0x6c, 0x77, 0x5a, 0x54, 0x31, 0x68, 0x63, 0x47, 0x6c, 0x54, 0x62, 0x32, 0x35, 0x6e, 0x56, 0x58, 0x4a, 0x73, 0x56, 0x6a, 0x45, 0x42, 0x4e, 0x6d, 0x30, 0x75, 0x62, 0x58, 0x56, 0x7a, 0x61, 0x57, 0x4d, 0x75, 0x62, 0x57, 0x6c, 0x6e, 0x64, 0x53, 0x35, 0x6a, 0x62, 0x69, 0x39, 0x74, 0x61, 0x57, 0x64, 0x31, 0x62, 0x58, 0x56, 0x7a, 0x61, 0x57, 0x4d, 0x76, 0x61, 0x44, 0x55, 0x76, 0x63, 0x47, 0x78, 0x68, 0x65, 0x53, 0x39, 0x68, 0x64, 0x58, 0x52, 0x6f, 0x4c, 0x32, 0x64, 0x6c, 0x64, 0x46, 0x4e, 0x76, 0x62, 0x6d, 0x64, 0x51, 0x62, 0x47, 0x46, 0x35, 0x53, 0x57, 0x35, 0x6d, 0x62, 0x77, 0x45, 0x6c, 0x59, 0x33, 0x4e, 0x74, 0x4c, 0x6e, 0x4e, 0x68, 0x65, 0x58, 0x46, 0x36, 0x4c, 0x6d, 0x4e, 0x76, 0x62, 0x53, 0x39, 0x68, 0x63, 0x47, 0x6b, 0x76, 0x50, 0x33, 0x52, 0x35, 0x63, 0x47, 0x55, 0x39, 0x59, 0x33, 0x4e, 0x74, 0x51, 0x32, 0x68, 0x6c, 0x59, 0x57, 0x74, 0x4e, 0x64, 0x58, 0x4e, 0x70, 0x59, 0x77, 0x45, 0x43, 0x43, 0x6c, 0x56, 0x7a, 0x5a, 0x58, 0x49, 0x74, 0x51, 0x57, 0x64, 0x6c, 0x62, 0x6e, 0x52, 0x65, 0x54, 0x57, 0x39, 0x36, 0x61, 0x57, 0x78, 0x73, 0x59, 0x53, 0x38, 0x31, 0x4c, 0x6a, 0x41, 0x67, 0x4b, 0x46, 0x64, 0x70, 0x62, 0x6d, 0x52, 0x76, 0x64, 0x33, 0x4d, 0x67, 0x54, 0x6c, 0x51, 0x67, 0x4e, 0x69, 0x34, 0x78, 0x4f, 0x79, 0x42, 0x58, 0x54, 0x31, 0x63, 0x32, 0x4e, 0x43, 0x6b, 0x67, 0x51, 0x58, 0x42, 0x77, 0x62, 0x47, 0x56, 0x58, 0x5a, 0x57, 0x4a, 0x4c, 0x61, 0x58, 0x51, 0x76, 0x4e, 0x54, 0x4d, 0x33, 0x4c, 0x6a, 0x4d, 0x32, 0x49, 0x43, 0x68, 0x4c, 0x53, 0x46, 0x52, 0x4e, 0x54, 0x43, 0x77, 0x67, 0x62, 0x47, 0x6c, 0x72, 0x5a, 0x53, 0x42, 0x48, 0x5a, 0x57, 0x4e, 0x72, 0x62, 0x79, 0x6b, 0x67, 0x51, 0x32, 0x68, 0x79, 0x62, 0x32, 0x31, 0x6c, 0x4c, 0x7a, 0x55, 0x77, 0x4c, 0x6a, 0x41, 0x75, 0x4d, 0x6a, 0x59, 0x32, 0x4d, 0x53, 0x34, 0x34, 0x4e, 0x78, 0x42, 0x59, 0x4c, 0x56, 0x4a, 0x6c, 0x63, 0x58, 0x56, 0x6c, 0x63, 0x33, 0x52, 0x6c, 0x5a, 0x43, 0x31, 0x58, 0x61, 0x58, 0x52, 0x6f, 0x44, 0x6c, 0x68, 0x4e, 0x54, 0x45, 0x68, 0x30, 0x64, 0x48, 0x42, 0x53, 0x5a, 0x58, 0x46, 0x31, 0x5a, 0x58, 0x4e, 0x30, 0x41, 0x51, 0x51, 0x48, 0x55, 0x6d, 0x56, 0x6d, 0x5a, 0x58, 0x4a, 0x6c, 0x63, 0x68, 0x74, 0x6f, 0x64, 0x48, 0x52, 0x77, 0x63, 0x7a, 0x6f, 0x76, 0x4c, 0x32, 0x30, 0x75, 0x62, 0x58, 0x56, 0x7a, 0x61, 0x57, 0x4d, 0x75, 0x62, 0x57, 0x6c, 0x6e, 0x64, 0x53, 0x35, 0x6a, 0x62, 0x69, 0x39, 0x32, 0x4e, 0x43, 0x38, 0x43, 0x51, 0x6e, 0x6b, 0x67, 0x4d, 0x44, 0x52, 0x6d, 0x4f, 0x44, 0x45, 0x30, 0x4e, 0x6a, 0x46, 0x68, 0x4f, 0x54, 0x68, 0x6a, 0x4e, 0x32, 0x46, 0x6d, 0x4e, 0x54, 0x55, 0x33, 0x5a, 0x6d, 0x56, 0x68, 0x4d, 0x32, 0x4e, 0x6d, 0x4d, 0x6a, 0x68, 0x6a, 0x4e, 0x47, 0x56, 0x68, 0x4d, 0x54, 0x55, 0x48, 0x59, 0x32, 0x68, 0x68, 0x62, 0x6d, 0x35, 0x6c, 0x62, 0x41, 0x63, 0x77, 0x4d, 0x54, 0x51, 0x77, 0x4d, 0x44, 0x42, 0x45, 0x42, 0x6b, 0x4e, 0x76, 0x62, 0x32, 0x74, 0x70, 0x5a, 0x54, 0x68, 0x54, 0x52, 0x56, 0x4e, 0x54, 0x53, 0x55, 0x39, 0x4f, 0x50, 0x56, 0x70, 0x55, 0x53, 0x58, 0x64, 0x50, 0x52, 0x47, 0x74, 0x35, 0x54, 0x55, 0x52, 0x52, 0x64, 0x45, 0x39, 0x55, 0x52, 0x54, 0x46, 0x4f, 0x55, 0x7a, 0x41, 0x77, 0x54, 0x55, 0x52, 0x6f, 0x62, 0x45, 0x78, 0x55, 0x61, 0x47, 0x68, 0x4e, 0x56, 0x30, 0x56, 0x30, 0x54, 0x57, 0x70, 0x52, 0x4d, 0x45, 0x34, 0x79, 0x57, 0x54, 0x4a, 0x4e, 0x65, 0x6d, 0x73, 0x79, 0x54, 0x31, 0x52, 0x42, 0x65, 0x67, 0x41, 0x3d}
dec, _ := zcypt.Base64Decode(base64.StdEncoding, data)
ztool.Val_GobDecode(dec, &initdata)
}

View File

@ -60,42 +60,54 @@ var (
func init() {
env.Inits.Add(func() {
WySource = &WrapSource{
UrlFunc: wy.Url,
LrcFunc: notSupport,
PicFunc: notSupport,
VefFunc: func(songMid string) bool {
_, err := strconv.ParseUint(songMid, 10, 0)
return err == nil
},
if env.Config.Source.Enable_Wy {
WySource = &WrapSource{
UrlFunc: wy.Url,
LrcFunc: notSupport,
PicFunc: notSupport,
VefFunc: func(songMid string) bool {
_, err := strconv.ParseUint(songMid, 10, 0)
return err == nil
},
}
}
MgSource = &WrapSource{
UrlFunc: mg.Url,
LrcFunc: notSupport,
PicFunc: notSupport,
VefFunc: func(songMid string) bool { return len(songMid) == 11 },
if env.Config.Source.Enable_Mg {
MgSource = &WrapSource{
UrlFunc: mg.Url,
LrcFunc: notSupport,
PicFunc: notSupport,
VefFunc: func(songMid string) bool { return len(songMid) == 11 },
}
}
KwSource = &WrapSource{
UrlFunc: kw.Url,
LrcFunc: notSupport,
PicFunc: notSupport,
VefFunc: func(songMid string) bool {
_, err := strconv.ParseUint(songMid, 10, 0)
return err == nil
},
if env.Config.Source.Enable_Kw {
KwSource = &WrapSource{
UrlFunc: kw.Url,
LrcFunc: notSupport,
PicFunc: notSupport,
VefFunc: func(songMid string) bool {
_, err := strconv.ParseUint(songMid, 10, 0)
return err == nil
},
}
}
KgSource = &WrapSource{
UrlFunc: kg.Url,
LrcFunc: notSupport,
PicFunc: notSupport,
VefFunc: func(songMid string) bool { return len(songMid) == 32 },
if env.Config.Source.Enable_Kg {
KgSource = &WrapSource{
UrlFunc: kg.Url,
LrcFunc: notSupport,
PicFunc: notSupport,
VefFunc: func(songMid string) bool { return len(songMid) == 32 },
}
}
TxSource = &WrapSource{
UrlFunc: tx.Url,
LrcFunc: notSupport,
PicFunc: notSupport,
VefFunc: func(songMid string) bool { return len(songMid) == 14 },
if env.Config.Source.Enable_Tx {
TxSource = &WrapSource{
UrlFunc: tx.Url,
LrcFunc: notSupport,
PicFunc: notSupport,
VefFunc: func(songMid string) bool { return len(songMid) == 14 },
}
}
if env.Config.Source.Enable_Lx {
LxSource = nil
}
LxSource = nil
})
}

View File

@ -3,6 +3,7 @@ package kg
import (
"lx-source/src/env"
"lx-source/src/sources"
"net/http"
"strconv"
"strings"
"time"
@ -47,9 +48,9 @@ func Url(songMid, quality string) (ourl, msg string) {
`hash`: tHash,
`module`: ``,
`mid`: mid,
`appid`: appid,
`appid`: env.Config.Custom.Kg_Client_AppId,
`ssa_flag`: `is_fromtrack`,
`clientver`: clientver,
`clientver`: env.Config.Custom.Kg_Client_Version,
`open_time`: now.Format(`20060102`),
`vipType`: `6`,
`ptype`: `0`,
@ -64,8 +65,11 @@ func Url(songMid, quality string) (ourl, msg string) {
`dfid`: `-`,
`pidversion`: `3001`,
`quality`: rquality,
`IsFreePart`: `1`,
`quality`: rquality,
// `IsFreePart`: `1`,
}
if !env.Config.Custom.Kg_Enable {
params[`IsFreePart`] = `1` // 仅游客登录时允许获取试听
}
headers := map[string]string{
`User-Agent`: `Android712-AndroidPhone-8983-18-0-NetMusic-wifi`,
@ -76,7 +80,7 @@ func Url(songMid, quality string) (ourl, msg string) {
`x-router`: `tracker.kugou.com`,
}
var resp playInfo
err := signRequest(url, params, headers, &resp)
err := signRequest(http.MethodGet, url, nil, params, headers, &resp)
if err != nil {
loger.Error(`Request: %s`, err)
msg = sources.ErrHttpReq

View File

@ -0,0 +1,149 @@
package kg
import (
"errors"
"fmt"
"lx-source/src/env"
"math/rand"
"net/http"
"strconv"
"strings"
"time"
"github.com/ZxwyWebSite/ztool"
"github.com/ZxwyWebSite/ztool/logs"
"github.com/ZxwyWebSite/ztool/zcypt"
)
// 通过TOP500榜单获取随机歌曲的mixsongmid
func randomMixSongMid() (mid string, err error) {
// 声明榜单url
const rankUrl = `http://mobilecdnbj.kugou.com/api/v3/rank/song?version=9108&ranktype=1&plat=0&pagesize=100&area_code=1&page=1&rankid=8888&with_res_tag=0&show_portrait_mv=1`
// 请求
var res rankInfo
err = ztool.Net_Request(
http.MethodGet,
rankUrl, nil,
[]ztool.Net_ReqHandlerFunc{ztool.Net_ReqAddHeaders()},
[]ztool.Net_ResHandlerFunc{ztool.Net_ResToStruct(&res)},
)
if err != nil {
return
}
// fmt.Printf("%#v\n", res)
if res.Status != 1 {
err = errors.New(res.Error)
return
}
// 随机选择一首歌曲
randomSong := res.Data.Info[rand.Intn(len(res.Data.Info))]
// fmt.Printf("%#v\n", randomSong)
// 因为排行榜api不会返回mixsongmid
// 所以需要进行一次搜索接口来获取
var body searchInfo
err = ztool.Net_Request(
http.MethodGet,
ztool.Str_FastConcat(
`https://songsearch.kugou.com/song_search_v2?`,
ztool.Net_Values(map[string]string{
`keyword`: randomSong.Filename,
`area_code`: `1`,
`page`: `1`,
`pagesize`: `1`,
`userid`: `0`,
`clientver`: ``,
`platform`: `WebFilter`,
`filter`: `2`,
`iscorrection`: `1`,
`privilege_filter`: `0`,
}),
), nil,
[]ztool.Net_ReqHandlerFunc{ztool.Net_ReqAddHeaders(map[string]string{
`Referer`: `https://www.kugou.com`,
})},
[]ztool.Net_ResHandlerFunc{ztool.Net_ResToStruct(&body)},
)
if err != nil {
return
}
// fmt.Printf("%#v\n", body)
if body.Status != 1 {
err = errors.New(body.ErrorMsg)
return
}
if body.Data.Total == 0 || len(body.Data.Lists) == 0 {
err = errors.New(`歌曲搜索失败`)
return
}
mid = body.Data.Lists[0].MixSongID
return
}
// 签到主函数传入userinfo响应None就是成功报错即为不成功
func do_account_signin(loger *logs.Logger, now int64) (err error) {
// 检查用户配置文件获取mixsongmid
mixid := `582534238`
if mixid == `auto` {
mixid, err = randomMixSongMid()
if err != nil {
return
}
}
// 声明变量
headers := map[string]string{
`User-Agent`: ztool.Str_FastConcat(
`Android712-AndroidPhone-`,
env.Config.Custom.Kg_Client_Version,
`-18-0-NetMusic-wifi`,
),
`KG-THash`: `3e5ec6b`,
`KG-Rec`: `1`,
`KG-RC`: `1`,
`x-router`: `youth.kugou.com`,
}
body := ztool.Str_FastConcat(
`{"mixsongid":"`, mixid, `"}`,
)
params := map[string]string{
`userid`: env.Config.Custom.Kg_userId,
`token`: env.Config.Custom.Kg_token,
`appid`: env.Config.Custom.Kg_Client_AppId,
`clientver`: env.Config.Custom.Kg_Client_Version,
`clienttime`: strconv.FormatInt(time.Now().Unix(), 10),
`mid`: mid,
`uuid`: zcypt.HexToString(zcypt.RandomBytes(16)),
`dfid`: `-`,
}
// 发送请求
var out refreshInfo
err = signRequest(
http.MethodPost,
`https://gateway.kugou.com/v2/report/listen_song`,
strings.NewReader(body),
params, headers, &out,
)
if err != nil {
return err
}
if out.Status != 1 {
return errors.New(out.ErrorMsg)
}
fmt.Printf("%#v\n", out)
env.Config.Custom.Kg_Lite_Interval = now + 86000
return nil
}
func init() {
env.Inits.Add(func() {
if env.Config.Custom.Kg_Lite_Enable && false {
if env.Config.Custom.Kg_Client_AppId == `3116` && env.Config.Custom.Kg_token != `` {
env.Tasker.Add(`kg_refresh`, do_account_signin, 86000, true)
}
}
})
}

View File

@ -156,3 +156,301 @@ type (
FileSize int `json:"fileSize"`
}
)
type rankInfo struct {
Data struct {
Timestamp int `json:"timestamp"`
Total int `json:"total"`
Info []struct {
LastSort int `json:"last_sort"`
Authors []struct {
SizableAvatar string `json:"sizable_avatar"`
IsPublish int `json:"is_publish"`
AuthorName string `json:"author_name"`
AuthorID int `json:"author_id"`
} `json:"authors"`
RankCount int `json:"rank_count"`
RankIDPublishDate string `json:"rank_id_publish_date"`
Songname string `json:"songname"`
TopicURL320 string `json:"topic_url_320"`
Sqhash string `json:"sqhash"`
FailProcess int `json:"fail_process"`
PayType int `json:"pay_type"`
RecommendReason string `json:"recommend_reason"`
RpType string `json:"rp_type"`
AlbumID string `json:"album_id"`
PrivilegeHigh int `json:"privilege_high"`
TopicURLSq string `json:"topic_url_sq"`
RankCid int `json:"rank_cid"`
Inlist int `json:"inlist"`
Three20Filesize int `json:"320filesize"`
PkgPrice320 int `json:"pkg_price_320"`
Feetype int `json:"feetype"`
Price320 int `json:"price_320"`
DurationHigh int `json:"duration_high"`
FailProcess320 int `json:"fail_process_320"`
Zone string `json:"zone"`
TopicURL string `json:"topic_url"`
RpPublish int `json:"rp_publish"`
TransObj struct {
RankShowSort int `json:"rank_show_sort"`
} `json:"trans_obj"`
Hash string `json:"hash"`
Sqfilesize int `json:"sqfilesize"`
Sqprivilege int `json:"sqprivilege"`
PayTypeSq int `json:"pay_type_sq"`
Bitrate int `json:"bitrate"`
PkgPriceSq int `json:"pkg_price_sq"`
HasAccompany int `json:"has_accompany"`
Musical interface{} `json:"musical"`
PayType320 int `json:"pay_type_320"`
Issue int `json:"issue"`
ExtnameSuper string `json:"extname_super"`
DurationSuper int `json:"duration_super"`
BitrateSuper int `json:"bitrate_super"`
HashHigh string `json:"hash_high"`
Duration int `json:"duration"`
Three20Hash string `json:"320hash"`
PriceSq int `json:"price_sq"`
OldCpy int `json:"old_cpy"`
AlbumAudioID int `json:"album_audio_id"`
M4Afilesize int `json:"m4afilesize"`
PkgPrice int `json:"pkg_price"`
First int `json:"first"`
AudioID int `json:"audio_id"`
HashSuper string `json:"hash_super"`
Addtime string `json:"addtime"`
FilesizeHigh int `json:"filesize_high"`
Price int `json:"price"`
Privilege int `json:"privilege"`
AlbumSizableCover string `json:"album_sizable_cover"`
Mvdata []struct {
Typ int `json:"typ"`
Trk string `json:"trk"`
Hash string `json:"hash"`
ID string `json:"id"`
} `json:"mvdata,omitempty"`
Sort int `json:"sort"`
TransParam struct {
CpyLevel int `json:"cpy_level"`
Classmap struct {
Attr0 int `json:"attr0"`
} `json:"classmap"`
CpyGrade int `json:"cpy_grade"`
Qualitymap struct {
Attr0 int `json:"attr0"`
} `json:"qualitymap"`
PayBlockTpl int `json:"pay_block_tpl"`
Cid int `json:"cid"`
Language string `json:"language"`
HashMultitrack string `json:"hash_multitrack"`
CpyAttr0 int `json:"cpy_attr0"`
Ipmap struct {
Attr0 int `json:"attr0"`
} `json:"ipmap"`
AppidBlock string `json:"appid_block"`
MusicpackAdvance int `json:"musicpack_advance"`
Display int `json:"display"`
DisplayRate int `json:"display_rate"`
} `json:"trans_param"`
FilesizeSuper int `json:"filesize_super"`
Filename string `json:"filename"`
BitrateHigh int `json:"bitrate_high"`
Remark string `json:"remark"`
Extname string `json:"extname"`
Filesize int `json:"filesize"`
Isfirst int `json:"isfirst"`
Mvhash string `json:"mvhash"`
Three20Privilege int `json:"320privilege"`
PrivilegeSuper int `json:"privilege_super"`
FailProcessSq int `json:"fail_process_sq"`
} `json:"info"`
} `json:"data"`
Errcode int `json:"errcode"`
Status int `json:"status"`
Error string `json:"error"`
}
type searchInfo struct {
Data struct {
AlgPath string `json:"AlgPath"`
Aggregation struct {
} `json:"aggregation"`
Allowerr int `json:"allowerr"`
Chinesecount int `json:"chinesecount"`
Correctionforce int `json:"correctionforce"`
Correctionrelate string `json:"correctionrelate"`
Correctionsubject string `json:"correctionsubject"`
Correctiontip string `json:"correctiontip"`
Correctiontype int `json:"correctiontype"`
From int `json:"from"`
Isshareresult int `json:"isshareresult"`
Istag int `json:"istag"`
Istagresult int `json:"istagresult"`
Lists []struct {
A320Privilege int `json:"A320Privilege"`
ASQPrivilege int `json:"ASQPrivilege"`
Accompany int `json:"Accompany"`
AlbumAux string `json:"AlbumAux"`
AlbumID string `json:"AlbumID"`
AlbumName string `json:"AlbumName"`
AlbumPrivilege int `json:"AlbumPrivilege"`
AudioCdn int `json:"AudioCdn"`
Audioid int `json:"Audioid"`
Auxiliary string `json:"Auxiliary"`
Bitrate int `json:"Bitrate"`
Category int `json:"Category"`
Duration int `json:"Duration"`
ExtName string `json:"ExtName"`
FailProcess int `json:"FailProcess"`
FileHash string `json:"FileHash"`
FileName string `json:"FileName"`
FileSize int `json:"FileSize"`
FoldType int `json:"FoldType"`
Grp []interface{} `json:"Grp"`
HQBitrate int `json:"HQBitrate"`
HQDuration int `json:"HQDuration"`
HQExtName string `json:"HQExtName"`
HQFailProcess int `json:"HQFailProcess"`
HQFileHash string `json:"HQFileHash"`
HQFileSize int `json:"HQFileSize"`
HQPayType int `json:"HQPayType"`
HQPkgPrice int `json:"HQPkgPrice"`
HQPrice int `json:"HQPrice"`
HQPrivilege int `json:"HQPrivilege"`
HasAlbum int `json:"HasAlbum"`
HeatLevel int `json:"HeatLevel"`
HiFiQuality int `json:"HiFiQuality"`
ID string `json:"ID"`
Image string `json:"Image"`
IsOriginal int `json:"IsOriginal"`
M4ASize int `json:"M4aSize"`
MatchFlag int `json:"MatchFlag"`
MixSongID string `json:"MixSongID"`
MvHash string `json:"MvHash"`
MvTrac int `json:"MvTrac"`
MvType int `json:"MvType"`
OldCpy int `json:"OldCpy"`
OriOtherName string `json:"OriOtherName"`
OriSongName string `json:"OriSongName"`
OtherName string `json:"OtherName"`
OwnerCount int `json:"OwnerCount"`
PayType int `json:"PayType"`
PkgPrice int `json:"PkgPrice"`
Price int `json:"Price"`
Privilege int `json:"Privilege"`
Publish int `json:"Publish"`
PublishAge int `json:"PublishAge"`
PublishTime string `json:"PublishTime"`
QualityLevel int `json:"QualityLevel"`
RankID int `json:"RankId"`
Res struct {
FailProcess int `json:"FailProcess"`
PayType int `json:"PayType"`
PkgPrice int `json:"PkgPrice"`
Price int `json:"Price"`
Privilege int `json:"Privilege"`
} `json:"Res"`
ResBitrate int `json:"ResBitrate"`
ResDuration int `json:"ResDuration"`
ResFileHash string `json:"ResFileHash"`
ResFileSize int `json:"ResFileSize"`
SQBitrate int `json:"SQBitrate"`
SQDuration int `json:"SQDuration"`
SQExtName string `json:"SQExtName"`
SQFailProcess int `json:"SQFailProcess"`
SQFileHash string `json:"SQFileHash"`
SQFileSize int `json:"SQFileSize"`
SQPayType int `json:"SQPayType"`
SQPkgPrice int `json:"SQPkgPrice"`
SQPrice int `json:"SQPrice"`
SQPrivilege int `json:"SQPrivilege"`
Scid int `json:"Scid"`
ShowingFlag int `json:"ShowingFlag"`
SingerID []int `json:"SingerId"`
SingerName string `json:"SingerName"`
Singers []struct {
ID int `json:"id"`
IPID int `json:"ip_id"`
Name string `json:"name"`
} `json:"Singers"`
SongLabel string `json:"SongLabel"`
SongName string `json:"SongName"`
Source string `json:"Source"`
SourceID int `json:"SourceID"`
Suffix string `json:"Suffix"`
SuperBitrate int `json:"SuperBitrate"`
SuperDuration int `json:"SuperDuration"`
SuperExtName string `json:"SuperExtName"`
SuperFileHash string `json:"SuperFileHash"`
SuperFileSize int `json:"SuperFileSize"`
TagContent string `json:"TagContent"`
TagDetails []struct {
Content string `json:"content"`
Rankid int `json:"rankid"`
Type int `json:"type"`
Version int `json:"version"`
} `json:"TagDetails"`
TopID int `json:"TopID"`
TopicRemark string `json:"TopicRemark"`
TopicURL string `json:"TopicUrl"`
Type string `json:"Type"`
Uploader string `json:"Uploader"`
UploaderContent string `json:"UploaderContent"`
MvTotal int `json:"mvTotal"`
Mvdata []struct {
Hash string `json:"hash"`
ID string `json:"id"`
Trk string `json:"trk"`
Typ int `json:"typ"`
} `json:"mvdata"`
RecommendType int `json:"recommend_type"`
TransParam struct {
AppidBlock string `json:"appid_block"`
Cid int `json:"cid"`
Classmap struct {
Attr0 int `json:"attr0"`
} `json:"classmap"`
CpyAttr0 int `json:"cpy_attr0"`
CpyGrade int `json:"cpy_grade"`
CpyLevel int `json:"cpy_level"`
Display int `json:"display"`
DisplayRate int `json:"display_rate"`
HashMultitrack string `json:"hash_multitrack"`
Ipmap struct {
Attr0 int `json:"attr0"`
} `json:"ipmap"`
Language string `json:"language"`
MusicpackAdvance int `json:"musicpack_advance"`
PayBlockTpl int `json:"pay_block_tpl"`
Qualitymap struct {
Attr0 int `json:"attr0"`
} `json:"qualitymap"`
SongnameSuffix string `json:"songname_suffix"`
} `json:"trans_param"`
Vvid string `json:"vvid"`
} `json:"lists"`
Page int `json:"page"`
Pagesize int `json:"pagesize"`
Searchfull int `json:"searchfull"`
SecAggre struct {
} `json:"sec_aggre"`
SecAggreV2 []interface{} `json:"sec_aggre_v2"`
SectagInfo struct {
IsSectag int `json:"is_sectag"`
} `json:"sectag_info"`
Size int `json:"size"`
Subjecttype int `json:"subjecttype"`
Total int `json:"total"`
} `json:"data"`
ErrorCode int `json:"error_code"`
ErrorMsg string `json:"error_msg"`
Status int `json:"status"`
}
type refreshInfo struct {
Data string `json:"data"`
ErrorCode int `json:"error_code"`
ErrorMsg string `json:"error_msg"`
Status int `json:"status"`
}

View File

@ -1,9 +1,9 @@
package kg
import (
"io"
"lx-source/src/env"
"lx-source/src/sources"
"net/http"
"slices"
"strings"
@ -28,12 +28,12 @@ var (
)
const (
signkey = `OIlwieks28dk2k092lksi2UIkp`
pidversec = `57ae12eb6890223e355ccfcb74edf70d`
clientver = `12029`
url = `https://gateway.kugou.com/v5/url`
appid = `1005`
mid = `211008`
// signkey = `OIlwieks28dk2k092lksi2UIkp`
// pidversec = `57ae12eb6890223e355ccfcb74edf70d`
// clientver = `12029`
url = `https://gateway.kugou.com/v5/url`
// appid = `1005`
mid = `211008`
)
func sortDict(dictionary map[string]string) ([]string, int) {
@ -58,7 +58,7 @@ func sortDict(dictionary map[string]string) ([]string, int) {
// return zcypt.MD5EncStr(ztool.Str_FastConcat(signkey, b.String(), signkey))
// }
func signRequest(url string, params, headers map[string]string, out any) error {
func signRequest(method string, url string, body io.Reader, params, headers map[string]string, out any) error {
// buildSignatureParams
keys, lens := sortDict(params)
var b strings.Builder
@ -77,12 +77,15 @@ func signRequest(url string, params, headers map[string]string, out any) error {
}
c.WriteString(`signature`)
c.WriteByte('=')
c.WriteString(zcypt.MD5EncStr(ztool.Str_FastConcat(signkey, b.String(), signkey)))
c.WriteString(zcypt.MD5EncStr(ztool.Str_FastConcat(
env.Config.Custom.Kg_Client_SignKey,
b.String(), env.Config.Custom.Kg_Client_SignKey,
)))
url = ztool.Str_FastConcat(url, `?`, c.String())
// ztool.Cmd_FastPrintln(url)
return ztool.Net_Request(
http.MethodGet, url, nil,
method, url, body,
[]ztool.Net_ReqHandlerFunc{ztool.Net_ReqAddHeader(headers)},
[]ztool.Net_ResHandlerFunc{ //func(res *http.Response) error {
// body, err := io.ReadAll(res.Body)
@ -96,7 +99,8 @@ func signRequest(url string, params, headers map[string]string, out any) error {
func getKey(hash_ string) string {
return zcypt.MD5EncStr(ztool.Str_FastConcat(
strings.ToLower(hash_), pidversec, appid, mid, env.Config.Custom.Kg_userId,
strings.ToLower(hash_), env.Config.Custom.Kg_Client_PidVerSec,
env.Config.Custom.Kg_Client_AppId, mid, env.Config.Custom.Kg_userId,
))
}

View File

@ -4,6 +4,7 @@ import (
"lx-source/src/env"
"lx-source/src/sources"
"lx-source/src/sources/custom/utils"
"lx-source/src/sources/example"
"net/http"
"sync"
@ -18,14 +19,12 @@ var (
func init() {
env.Inits.Add(func() {
if !env.Config.Source.Enable_Mg {
return
}
loger := env.Loger.NewGroup(`MgInit`)
switch env.Config.Custom.Mg_Mode {
case `0`, `builtin`:
loger.Debug(`use builtin`)
// Url = builtin
mg_pool = &sync.Pool{New: func() any { return new(mgApi_Song) }}
Url = builtin
case `1`, `custom`:
loger.Debug(`use custom`)
if ztool.Chk_IsNilStr(
@ -45,11 +44,35 @@ func init() {
})
}
// func builtin(songMid, quality string) (ourl, msg string) {
// loger := env.Loger.NewGroup(`Mg`)
// defer loger.Free()
// return
// }
func builtin(songMid, quality string) (ourl, msg string) {
loger := env.Loger.NewGroup(`Mg`)
rquality, ok := qualitys[quality]
if !ok {
msg = sources.E_QNotSupport
return
}
defer loger.Free()
resp := mg_pool.Get().(*mgApi_Song)
defer mg_pool.Put(resp)
url := ztool.Str_FastConcat(`https://`, example.Api_mg, `?copyrightId=`, songMid, `&type=`, rquality)
err := ztool.Net_Request(
http.MethodGet, url, nil,
[]ztool.Net_ReqHandlerFunc{ztool.Net_ReqAddHeaders(example.Header_mg)},
[]ztool.Net_ResHandlerFunc{ztool.Net_ResToStruct(&resp)},
)
if err != nil {
loger.Error(`HttpReq: %s`, err)
msg = sources.ErrHttpReq
return
}
loger.Debug(`Resp: %+v`, resp)
if resp.Data.PlayURL != `` {
ourl = `https:` + utils.DelQuery(resp.Data.PlayURL)
} else {
msg = ztool.Str_FastConcat(resp.Code, `: `, resp.Msg)
}
return
}
func mcustom(songMid, quality string) (ourl, msg string) {
loger := env.Loger.NewGroup(`Mg`)

View File

@ -42,3 +42,16 @@ type playInfo struct {
} `json:"data"`
Info string `json:"info"`
}
type mgApi_Song struct {
Code string `json:"code"`
Msg string `json:"msg"`
Data struct {
PlayURL string `json:"playUrl"`
FormatID string `json:"formatId"`
SalePrice string `json:"salePrice"`
BizType string `json:"bizType"`
BizCode string `json:"bizCode"`
AuditionsLength int `json:"auditionsLength"`
} `json:"data"`
}

View File

@ -22,4 +22,10 @@ var (
// q_flac: sources.Q_flac,
// q_fl24: sources.Q_fl24,
// }
qualitys = map[string]string{
sources.Q_128k: `1`,
sources.Q_320k: `2`,
sources.Q_flac: `3`,
sources.Q_fl24: `4`,
}
)

View File

@ -129,7 +129,7 @@ func refresh(loger *logs.Logger, now int64) error {
loger.Info(`刷新登录成功`)
env.Config.Custom.Tx_Uuin = resp.Req1.Data.StrMusicId
env.Config.Custom.Tx_Ukey = resp.Req1.Data.MusicKey
env.Config.Custom.Tx_Refresh_Interval = now + 518400 //(每6天刷新一次) //1209600 - 86000 // 14天提前一天
env.Config.Custom.Tx_Refresh_Interval = now + 432000 //(每5天刷新一次) //1209600 - 86000 // 14天提前一天
loger.Debug(`Resp: %+v`, resp)
loger.Debug(`Uuin: %v, Ukey: %v`, resp.Req1.Data.StrMusicId, resp.Req1.Data.MusicKey)
loger.Debug(`ExpiresAt: %v, Real: %v`, resp.Req1.Data.ExpiredAt, env.Config.Custom.Tx_Refresh_Interval)

View File

@ -4,17 +4,19 @@ import (
"lx-source/src/env"
"lx-source/src/sources"
"lx-source/src/sources/custom/utils"
wy "lx-source/src/sources/custom/wy/modules"
wm "lx-source/src/sources/custom/wy/modules"
"lx-source/src/sources/example"
"net/http"
"strconv"
"sync"
"time"
"github.com/ZxwyWebSite/ztool"
"github.com/ZxwyWebSite/ztool/x/cookie"
)
var (
wy_pool = &sync.Pool{New: func() any { return new(wy.PlayInfo) }}
wy_pool = &sync.Pool{New: func() any { return new(wm.PlayInfo) }}
// wv_pool *sync.Pool
Url func(string, string) (string, string)
@ -29,7 +31,7 @@ func init() {
// if env.Config.Source.MusicIdVerify {
// wv_pool = &sync.Pool{New: func() any { return new(verifyInfo) }}
// }
// Url = builtin
Url = builtin
case `1`, `163api`:
if env.Config.Custom.Wy_Api_Cookie == `` {
loger.Fatal(`使用163api且Cookie参数为空`)
@ -58,11 +60,49 @@ func init() {
})
}
// func builtin(songMid, quality string) (ourl, msg string) {
// loger := env.Loger.NewGroup(`Wy`)
// defer loger.Free()
// return
// }
func builtin(songMid, quality string) (ourl, msg string) {
loger := env.Loger.NewGroup(`Wy`)
defer loger.Free()
rquality, ok := qualityMap[quality]
if !ok {
msg = sources.E_QNotSupport
return
}
resp := wy_pool.Get().(*wm.PlayInfo)
defer wy_pool.Put(resp)
url := ztool.Str_FastConcat(
`https://`, example.Api_wy, `&id=`, songMid, `&level=`, rquality,
`&timestamp=`, strconv.FormatInt(time.Now().UnixMilli(), 10),
)
err := ztool.Net_Request(
http.MethodGet, url, nil,
[]ztool.Net_ReqHandlerFunc{ztool.Net_ReqAddHeaders(example.Header_wy)},
[]ztool.Net_ResHandlerFunc{ztool.Net_ResToStruct(&resp)},
)
if err != nil {
loger.Error(`HttpReq: %s`, err)
msg = sources.ErrHttpReq
return
}
loger.Debug(`Resp: %+v`, resp)
if len(resp.Data) == 0 {
msg = `No DataApi接口忙请稍后重试`
return
}
var data = resp.Data[0]
if data.Code != 200 || data.FreeTrialInfo != nil {
msg = `触发风控或专辑单独收费: ` + strconv.Itoa(data.Code)
return
}
if data.Level != rquality {
msg = ztool.Str_FastConcat(`实际音质不匹配: `, rquality, ` <= `, data.Level)
if !env.Config.Source.ForceFallback {
return
}
}
ourl = data.URL
return
}
func nmModule(songMid, quality string) (ourl, msg string) {
loger := env.Loger.NewGroup(`Wy`)
@ -73,13 +113,13 @@ func nmModule(songMid, quality string) (ourl, msg string) {
return
}
cookies := cookie.Parse(env.Config.Custom.Wy_Api_Cookie)
answer, err := wy.SongUrlV1(wy.ReqQuery{
answer, err := wm.SongUrlV1(wm.ReqQuery{
Cookie: cookie.ToMap(cookies),
Ids: songMid,
// Br: rquality,
Level: rquality,
})
body := wy_pool.Get().(*wy.PlayInfo)
body := wy_pool.Get().(*wm.PlayInfo)
defer wy_pool.Put(body)
if err == nil {
err = ztool.Val_MapToStruct(answer.Body, &body)
@ -122,7 +162,7 @@ func nmCustom(songMid, quality string) (ourl, msg string) {
msg = sources.E_QNotSupport
return
}
body := wy_pool.Get().(*wy.PlayInfo)
body := wy_pool.Get().(*wm.PlayInfo)
defer wy_pool.Put(body)
err := ztool.Net_Request(
http.MethodGet,

View File

@ -22,6 +22,12 @@ import (
2024-02-15:
MUSIC_U 改变 6 继续执行
MUSIC_U 不变 1 继续执行
原理
听说隔壁某解析群的账号经常使用Token快一年了也没过期
所以模拟正常使用每天调用一次刷新接口
证明这个Token还在使用类似于给它"续期"
就像SPlayer客户端一样Cookie变了就合并
(这是我随便猜的未经测试仅供参考)
*/
func refresh(loger *logs.Logger, now int64) error {
@ -44,15 +50,16 @@ func refresh(loger *logs.Logger, now int64) error {
maps.Copy(cookies, cmap)
env.Config.Custom.Wy_Api_Cookie = cookie.Marshal(cookies)
loger.Debug(`Cookie: %#v`, cookies)
if _, ok := cmap[`MUSIC_U`]; ok {
// MUSIC_U 改变 则 6天 后 继续执行
env.Config.Custom.Wy_Refresh_Interval = now + 518400 //2147483647 - 86000
loger.Debug(`MUSIC_U 改变, 6天 后 继续执行`)
} else {
// MUSIC_U 不变 则 1天 后 继续执行
env.Config.Custom.Wy_Refresh_Interval = now + 86000
loger.Debug(`MUSIC_U 不变, 1天 后 继续执行`) //`未发现有效结果,将在下次检测时再次尝试`
}
// if _, ok := cmap[`MUSIC_U`]; ok {
// // MUSIC_U 改变 则 6天 后 继续执行
// env.Config.Custom.Wy_Refresh_Interval = now + 518400 //2147483647 - 86000
// loger.Debug(`MUSIC_U 改变, 6天 后 继续执行`)
// } else {
// // MUSIC_U 不变 则 1天 后 继续执行
// env.Config.Custom.Wy_Refresh_Interval = now + 86000
// loger.Debug(`MUSIC_U 不变, 1天 后 继续执行`) //`未发现有效结果,将在下次检测时再次尝试`
// }
env.Config.Custom.Wy_Refresh_Interval = now + 86000
err = env.Cfg.Save(``)
if err == nil {
loger.Info(`配置更新成功`)

View File

@ -0,0 +1,38 @@
package example
import (
"encoding/base64"
"github.com/ZxwyWebSite/ztool"
"github.com/ZxwyWebSite/ztool/zcypt"
)
var (
Api_wy string
Api_mg string
Vef_wy string
Header_wy map[string]string
Header_mg map[string]string
)
func init() {
// InitBuiltInData
var initdata = struct {
Api_Wy *string
Api_Mg *string
Vef_Wy *string
Header_Wy *map[string]string
Header_Mg *map[string]string
}{
Api_Wy: &Api_wy,
Api_Mg: &Api_mg,
Vef_Wy: &Vef_wy,
Header_Wy: &Header_wy,
Header_Mg: &Header_mg,
}
data := []byte{0x53, 0x6e, 0x38, 0x44, 0x41, 0x51, 0x4c, 0x2f, 0x67, 0x41, 0x41, 0x42, 0x42, 0x51, 0x45, 0x47, 0x51, 0x58, 0x42, 0x70, 0x58, 0x31, 0x64, 0x35, 0x41, 0x51, 0x77, 0x41, 0x41, 0x51, 0x5a, 0x42, 0x63, 0x47, 0x6c, 0x66, 0x54, 0x57, 0x63, 0x42, 0x44, 0x41, 0x41, 0x42, 0x42, 0x6c, 0x5a, 0x6c, 0x5a, 0x6c, 0x39, 0x58, 0x65, 0x51, 0x45, 0x4d, 0x41, 0x41, 0x45, 0x4a, 0x53, 0x47, 0x56, 0x68, 0x5a, 0x47, 0x56, 0x79, 0x58, 0x31, 0x64, 0x35, 0x41, 0x66, 0x2b, 0x43, 0x41, 0x41, 0x45, 0x4a, 0x53, 0x47, 0x56, 0x68, 0x5a, 0x47, 0x56, 0x79, 0x58, 0x30, 0x31, 0x6e, 0x41, 0x66, 0x2b, 0x43, 0x41, 0x41, 0x41, 0x41, 0x49, 0x66, 0x2b, 0x42, 0x42, 0x41, 0x45, 0x42, 0x45, 0x57, 0x31, 0x68, 0x63, 0x46, 0x74, 0x7a, 0x64, 0x48, 0x4a, 0x70, 0x62, 0x6d, 0x64, 0x64, 0x63, 0x33, 0x52, 0x79, 0x61, 0x57, 0x35, 0x6e, 0x41, 0x66, 0x2b, 0x43, 0x41, 0x41, 0x45, 0x4d, 0x41, 0x51, 0x77, 0x41, 0x41, 0x50, 0x34, 0x42, 0x72, 0x76, 0x2b, 0x41, 0x41, 0x53, 0x52, 0x6a, 0x63, 0x32, 0x30, 0x75, 0x63, 0x32, 0x46, 0x35, 0x63, 0x58, 0x6f, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4c, 0x32, 0x46, 0x77, 0x61, 0x53, 0x38, 0x2f, 0x64, 0x48, 0x6c, 0x77, 0x5a, 0x54, 0x31, 0x68, 0x63, 0x47, 0x6c, 0x54, 0x62, 0x32, 0x35, 0x6e, 0x56, 0x58, 0x4a, 0x73, 0x56, 0x6a, 0x45, 0x42, 0x4e, 0x6d, 0x30, 0x75, 0x62, 0x58, 0x56, 0x7a, 0x61, 0x57, 0x4d, 0x75, 0x62, 0x57, 0x6c, 0x6e, 0x64, 0x53, 0x35, 0x6a, 0x62, 0x69, 0x39, 0x74, 0x61, 0x57, 0x64, 0x31, 0x62, 0x58, 0x56, 0x7a, 0x61, 0x57, 0x4d, 0x76, 0x61, 0x44, 0x55, 0x76, 0x63, 0x47, 0x78, 0x68, 0x65, 0x53, 0x39, 0x68, 0x64, 0x58, 0x52, 0x6f, 0x4c, 0x32, 0x64, 0x6c, 0x64, 0x46, 0x4e, 0x76, 0x62, 0x6d, 0x64, 0x51, 0x62, 0x47, 0x46, 0x35, 0x53, 0x57, 0x35, 0x6d, 0x62, 0x77, 0x45, 0x6c, 0x59, 0x33, 0x4e, 0x74, 0x4c, 0x6e, 0x4e, 0x68, 0x65, 0x58, 0x46, 0x36, 0x4c, 0x6d, 0x4e, 0x76, 0x62, 0x53, 0x39, 0x68, 0x63, 0x47, 0x6b, 0x76, 0x50, 0x33, 0x52, 0x35, 0x63, 0x47, 0x55, 0x39, 0x59, 0x33, 0x4e, 0x74, 0x51, 0x32, 0x68, 0x6c, 0x59, 0x57, 0x74, 0x4e, 0x64, 0x58, 0x4e, 0x70, 0x59, 0x77, 0x45, 0x43, 0x43, 0x6c, 0x56, 0x7a, 0x5a, 0x58, 0x49, 0x74, 0x51, 0x57, 0x64, 0x6c, 0x62, 0x6e, 0x52, 0x65, 0x54, 0x57, 0x39, 0x36, 0x61, 0x57, 0x78, 0x73, 0x59, 0x53, 0x38, 0x31, 0x4c, 0x6a, 0x41, 0x67, 0x4b, 0x46, 0x64, 0x70, 0x62, 0x6d, 0x52, 0x76, 0x64, 0x33, 0x4d, 0x67, 0x54, 0x6c, 0x51, 0x67, 0x4e, 0x69, 0x34, 0x78, 0x4f, 0x79, 0x42, 0x58, 0x54, 0x31, 0x63, 0x32, 0x4e, 0x43, 0x6b, 0x67, 0x51, 0x58, 0x42, 0x77, 0x62, 0x47, 0x56, 0x58, 0x5a, 0x57, 0x4a, 0x4c, 0x61, 0x58, 0x51, 0x76, 0x4e, 0x54, 0x4d, 0x33, 0x4c, 0x6a, 0x4d, 0x32, 0x49, 0x43, 0x68, 0x4c, 0x53, 0x46, 0x52, 0x4e, 0x54, 0x43, 0x77, 0x67, 0x62, 0x47, 0x6c, 0x72, 0x5a, 0x53, 0x42, 0x48, 0x5a, 0x57, 0x4e, 0x72, 0x62, 0x79, 0x6b, 0x67, 0x51, 0x32, 0x68, 0x79, 0x62, 0x32, 0x31, 0x6c, 0x4c, 0x7a, 0x55, 0x77, 0x4c, 0x6a, 0x41, 0x75, 0x4d, 0x6a, 0x59, 0x32, 0x4d, 0x53, 0x34, 0x34, 0x4e, 0x78, 0x42, 0x59, 0x4c, 0x56, 0x4a, 0x6c, 0x63, 0x58, 0x56, 0x6c, 0x63, 0x33, 0x52, 0x6c, 0x5a, 0x43, 0x31, 0x58, 0x61, 0x58, 0x52, 0x6f, 0x44, 0x6c, 0x68, 0x4e, 0x54, 0x45, 0x68, 0x30, 0x64, 0x48, 0x42, 0x53, 0x5a, 0x58, 0x46, 0x31, 0x5a, 0x58, 0x4e, 0x30, 0x41, 0x51, 0x51, 0x48, 0x55, 0x6d, 0x56, 0x6d, 0x5a, 0x58, 0x4a, 0x6c, 0x63, 0x68, 0x74, 0x6f, 0x64, 0x48, 0x52, 0x77, 0x63, 0x7a, 0x6f, 0x76, 0x4c, 0x32, 0x30, 0x75, 0x62, 0x58, 0x56, 0x7a, 0x61, 0x57, 0x4d, 0x75, 0x62, 0x57, 0x6c, 0x6e, 0x64, 0x53, 0x35, 0x6a, 0x62, 0x69, 0x39, 0x32, 0x4e, 0x43, 0x38, 0x43, 0x51, 0x6e, 0x6b, 0x67, 0x4d, 0x44, 0x52, 0x6d, 0x4f, 0x44, 0x45, 0x30, 0x4e, 0x6a, 0x46, 0x68, 0x4f, 0x54, 0x68, 0x6a, 0x4e, 0x32, 0x46, 0x6d, 0x4e, 0x54, 0x55, 0x33, 0x5a, 0x6d, 0x56, 0x68, 0x4d, 0x32, 0x4e, 0x6d, 0x4d, 0x6a, 0x68, 0x6a, 0x4e, 0x47, 0x56, 0x68, 0x4d, 0x54, 0x55, 0x48, 0x59, 0x32, 0x68, 0x68, 0x62, 0x6d, 0x35, 0x6c, 0x62, 0x41, 0x63, 0x77, 0x4d, 0x54, 0x51, 0x77, 0x4d, 0x44, 0x42, 0x45, 0x42, 0x6b, 0x4e, 0x76, 0x62, 0x32, 0x74, 0x70, 0x5a, 0x54, 0x68, 0x54, 0x52, 0x56, 0x4e, 0x54, 0x53, 0x55, 0x39, 0x4f, 0x50, 0x56, 0x70, 0x55, 0x53, 0x58, 0x64, 0x50, 0x52, 0x47, 0x74, 0x35, 0x54, 0x55, 0x52, 0x52, 0x64, 0x45, 0x39, 0x55, 0x52, 0x54, 0x46, 0x4f, 0x55, 0x7a, 0x41, 0x77, 0x54, 0x55, 0x52, 0x6f, 0x62, 0x45, 0x78, 0x55, 0x61, 0x47, 0x68, 0x4e, 0x56, 0x30, 0x56, 0x30, 0x54, 0x57, 0x70, 0x52, 0x4d, 0x45, 0x34, 0x79, 0x57, 0x54, 0x4a, 0x4e, 0x65, 0x6d, 0x73, 0x79, 0x54, 0x31, 0x52, 0x42, 0x65, 0x67, 0x41, 0x3d}
dec, _ := zcypt.Base64Decode(base64.StdEncoding, data)
ztool.Val_GobDecode(dec, &initdata)
}

View File

@ -3,11 +3,20 @@
<!-- #### \# 2024-02-14 v1.0.3-rel (release)
+ **停止更新:感谢这三个月的陪伴,现因无力维护,停止后续更新,发布最后版本,大家有缘再见** -->
#### \# 2024-02-20 v1.0.3-fix (fix)
+ 修复新版Wraper在Code不为0时未能正常结束Handler的问题
+ zTool: 修复计划任务模块一处计时bug "时间倒流"
+ Tx源刷新登录间隔时间降至5天
+ Wy源刷新登录间隔时间固定为1天
+ Kg源暴露更多配置项
+ 使用新版MusicRouter处理器(beta)兼容Python版**调用**方式?
<!-- + 为不同来源自定义直链缓存时间 -->
#### \# 2024-02-15 v1.0.3-pre (pre)
+ Wy源刷新登录模式确定每天执行一次合并Cookie
+ zTool: task: 增加传参 now(int64): 执行时间(Unix)
+ 优化Tx源刷新登录函数兼容计划任务错误处理模式
+ 对源脚本进行部分更改建议重新下载导入http://127.0.0.1:1011/lx-custom-source.js
+ 对源脚本进行部分更改,建议重新下载导入(<http://127.0.0.1:1011/lx-custom-source.js>
+ 简单优化旧版LinkHandler
+ 支持Mg源自定义账号