mirror of
https://github.com/ZxwyWebSite/lx-source.git
synced 2025-05-23 21:37:42 +08:00
2024-01-13 v1.0.2-b10
This commit is contained in:
parent
0bedce3bc7
commit
8d16e3be98
1
.gitignore
vendored
1
.gitignore
vendored
@ -6,3 +6,4 @@ data/
|
|||||||
test.go
|
test.go
|
||||||
test_test.go
|
test_test.go
|
||||||
# src/sources/builtin/
|
# src/sources/builtin/
|
||||||
|
rsrc_windows_amd64.syso
|
3
main.go
3
main.go
@ -10,7 +10,6 @@ import (
|
|||||||
"lx-source/src/router"
|
"lx-source/src/router"
|
||||||
"lx-source/src/sources"
|
"lx-source/src/sources"
|
||||||
"lx-source/src/sources/builtin"
|
"lx-source/src/sources/builtin"
|
||||||
"lx-source/src/sources/custom/tx"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@ -168,9 +167,9 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 载入必要模块
|
// 载入必要模块
|
||||||
|
env.Inits.Do()
|
||||||
env.Loger.NewGroup(`ServStart`).Info(`服务端启动, 监听地址 %s`, env.Config.Main.Listen)
|
env.Loger.NewGroup(`ServStart`).Info(`服务端启动, 监听地址 %s`, env.Config.Main.Listen)
|
||||||
loadFileLoger()
|
loadFileLoger()
|
||||||
tx.Init()
|
|
||||||
env.Defer.Add(env.Tasker.Run(env.Loger)) // wait
|
env.Defer.Add(env.Tasker.Run(env.Loger)) // wait
|
||||||
|
|
||||||
// 启动Http服务
|
// 启动Http服务
|
||||||
|
26
src/env/env.go
vendored
26
src/env/env.go
vendored
@ -71,12 +71,24 @@ type (
|
|||||||
// wy (暂未实现)
|
// wy (暂未实现)
|
||||||
Wy_Enable bool `comment:"是否开启小芸源"`
|
Wy_Enable bool `comment:"是否开启小芸源"`
|
||||||
// Wy_Cookie string `comment:"账号cookie数据"`
|
// Wy_Cookie string `comment:"账号cookie数据"`
|
||||||
|
|
||||||
// mg (暂未实现)
|
// mg (暂未实现)
|
||||||
// Mg_Enable bool `comment:"是否开启小蜜源"`
|
// Mg_Enable bool `comment:"是否开启小蜜源"`
|
||||||
|
|
||||||
// kw
|
// kw
|
||||||
Kw_Enable bool `comment:"是否开启小蜗源"`
|
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 kwdes
|
||||||
|
Kw_Des_Type string `comment:"返回格式 0: text, 1: json"`
|
||||||
|
Kw_Des_Header string `comment:"请求头 User-Agent"`
|
||||||
|
|
||||||
// kg (暂未实现)
|
// kg (暂未实现)
|
||||||
// Kg_Enable bool `comment:"是否开启小枸源"`
|
// Kg_Enable bool `comment:"是否开启小枸源"`
|
||||||
|
|
||||||
// tx
|
// tx
|
||||||
Tx_Enable bool `comment:"是否开启小秋源"`
|
Tx_Enable bool `comment:"是否开启小秋源"`
|
||||||
Tx_Ukey string `comment:"Cookie中/客户端的请求体中的(comm.authst)"`
|
Tx_Ukey string `comment:"Cookie中/客户端的请求体中的(comm.authst)"`
|
||||||
@ -117,7 +129,7 @@ type (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
// 默认配置
|
// 默认配置
|
||||||
defCfg = Conf{
|
DefCfg = Conf{
|
||||||
Main: Conf_Main{
|
Main: Conf_Main{
|
||||||
Debug: false,
|
Debug: false,
|
||||||
Listen: `127.0.0.1:1011`,
|
Listen: `127.0.0.1:1011`,
|
||||||
@ -149,7 +161,12 @@ var (
|
|||||||
},
|
},
|
||||||
Custom: Conf_Custom{
|
Custom: Conf_Custom{
|
||||||
Wy_Enable: true,
|
Wy_Enable: true,
|
||||||
|
|
||||||
Kw_Enable: true,
|
Kw_Enable: true,
|
||||||
|
Kw_Mode: `kwdes`,
|
||||||
|
Kw_Des_Type: `json`,
|
||||||
|
Kw_Des_Header: `okhttp/3.10.0`,
|
||||||
|
|
||||||
Tx_Enable: false,
|
Tx_Enable: false,
|
||||||
Tx_Refresh_Enable: false,
|
Tx_Refresh_Enable: false,
|
||||||
Tx_Refresh_Interval: 86000,
|
Tx_Refresh_Interval: 86000,
|
||||||
@ -158,8 +175,9 @@ var (
|
|||||||
Log: `发布更新 (请删除旧源后重新导入):进行了部分优化,修复了部分Bug`, // 更新日志
|
Log: `发布更新 (请删除旧源后重新导入):进行了部分优化,修复了部分Bug`, // 更新日志
|
||||||
|
|
||||||
Ver: `1.0.3`, // 自定义脚本版本
|
Ver: `1.0.3`, // 自定义脚本版本
|
||||||
Url: `lx-custom-source.js`, // 脚本下载地址
|
|
||||||
Force: true, // 强制推送更新
|
Force: true, // 强制推送更新
|
||||||
|
|
||||||
|
Url: `public/lx-custom-source.js`, // 脚本下载地址
|
||||||
},
|
},
|
||||||
Cache: Conf_Cache{
|
Cache: Conf_Cache{
|
||||||
Mode: `local`, // 缓存模式
|
Mode: `local`, // 缓存模式
|
||||||
@ -173,7 +191,7 @@ var (
|
|||||||
Cloud_Path: `/Lx-Source/cache`,
|
Cloud_Path: `/Lx-Source/cache`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
Config = defCfg
|
Config = DefCfg
|
||||||
// 通用对象
|
// 通用对象
|
||||||
Loger = logs.NewLogger(`LX-SOURCE`)
|
Loger = logs.NewLogger(`LX-SOURCE`)
|
||||||
Cfg, _ = conf.New(&Config, &conf.Confg{
|
Cfg, _ = conf.New(&Config, &conf.Confg{
|
||||||
@ -184,10 +202,10 @@ var (
|
|||||||
})
|
})
|
||||||
Defer = new(ztool.Err_DeferList)
|
Defer = new(ztool.Err_DeferList)
|
||||||
Cache = memo.NewMemoStoreConf(Loger, 300) // 内存缓存 默认每5分钟进行一次GC //memo.NewMemoStore()
|
Cache = memo.NewMemoStoreConf(Loger, 300) // 内存缓存 默认每5分钟进行一次GC //memo.NewMemoStore()
|
||||||
|
Inits = new(ztool.Err_DeferList)
|
||||||
|
|
||||||
Tasker = task.New(time.Hour, 2) // 定时任务 (暂时没有什么快速任务,默认每小时检测一次)
|
Tasker = task.New(time.Hour, 2) // 定时任务 (暂时没有什么快速任务,默认每小时检测一次)
|
||||||
)
|
)
|
||||||
|
|
||||||
// func init() {
|
// func init() {
|
||||||
|
|
||||||
// }
|
// }
|
||||||
|
@ -20,9 +20,9 @@ var publicEM embed.FS // 打包默认Public目录 src/router/router.go
|
|||||||
// 载入Public目录并设置路由
|
// 载入Public目录并设置路由
|
||||||
func LoadPublic(r *gin.Engine) {
|
func LoadPublic(r *gin.Engine) {
|
||||||
pf := env.Loger.NewGroup(`PublicFS`)
|
pf := env.Loger.NewGroup(`PublicFS`)
|
||||||
var httpFS http.FileSystem
|
|
||||||
dir := ztool.Str_FastConcat(env.RunPath, `/data/public`)
|
dir := ztool.Str_FastConcat(env.RunPath, `/data/public`)
|
||||||
publicFS, err := fs.Sub(publicEM, `public`)
|
publicFS, err := fs.Sub(publicEM, `public`)
|
||||||
|
var httpFS http.FileSystem = http.FS(publicFS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pf.Fatal(`内置Public目录载入错误: %s, 请尝试重新编译`, err)
|
pf.Fatal(`内置Public目录载入错误: %s, 请尝试重新编译`, err)
|
||||||
}
|
}
|
||||||
@ -38,7 +38,7 @@ func LoadPublic(r *gin.Engine) {
|
|||||||
return fmt.Errorf(`无法创建文件[%q]: %s`, relPath, err)
|
return fmt.Errorf(`无法创建文件[%q]: %s`, relPath, err)
|
||||||
}
|
}
|
||||||
defer out.Close()
|
defer out.Close()
|
||||||
pf.Info(`导出 [%q]...`, relPath)
|
pf.Debug(`导出 [%q]...`, relPath)
|
||||||
obj, err := publicFS.Open(relPath)
|
obj, err := publicFS.Open(relPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf(`无法打开文件[%q]: %s`, relPath, err)
|
return fmt.Errorf(`无法打开文件[%q]: %s`, relPath, err)
|
||||||
@ -50,23 +50,26 @@ func LoadPublic(r *gin.Engine) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if err := fs.WalkDir(publicFS, `.`, walk); err != nil {
|
if err := fs.WalkDir(publicFS, `.`, walk); err != nil {
|
||||||
pf.Fatal(`无法释放静态文件: %s`, err)
|
pf.Error(`无法释放静态文件: %s`, err)
|
||||||
// pf.Warn(`正在使用内置Public目录, 将无法自定义静态文件`)
|
// pf.Warn(`正在使用内置Public目录, 将无法自定义静态文件`)
|
||||||
// httpFS = http.FS(publicFS)
|
// httpFS = http.FS(publicFS)
|
||||||
} else {
|
} else {
|
||||||
pf.Info(`全部静态资源导出完成, 祝你使用愉快 ^_^`)
|
pf.Info(`全部静态资源导出完成, 祝你使用愉快 ^_^`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
httpFS = gin.Dir(dir, false)
|
// httpFS = gin.Dir(dir, false)
|
||||||
r.GET(`/:file`, func(c *gin.Context) {
|
// r.GET(`/:file`, func(c *gin.Context) {
|
||||||
file := c.Param(`file`)
|
// file := c.Param(`file`)
|
||||||
switch file {
|
// switch file {
|
||||||
case `favicon.ico`:
|
// case `favicon.ico`:
|
||||||
c.FileFromFS(`icon.ico`, httpFS)
|
// c.FileFromFS(`icon.ico`, httpFS)
|
||||||
case `lx-custom-source.js`:
|
// // case `lx-custom-source.js`:
|
||||||
c.FileFromFS(`lx-custom-source.js`, http.FS(publicFS))
|
// // c.FileFromFS(`lx-custom-source.js`, http.FS(publicFS))
|
||||||
default:
|
// default:
|
||||||
c.FileFromFS(file, httpFS)
|
// c.FileFromFS(file, httpFS)
|
||||||
}
|
// }
|
||||||
})
|
// })
|
||||||
|
r.StaticFileFS(`/favicon.ico`, `icon.ico`, httpFS)
|
||||||
|
r.StaticFileFS(`/lx-custom-source.js`, `lx-custom-source.js`, httpFS)
|
||||||
|
r.StaticFS(`/public`, httpFS)
|
||||||
}
|
}
|
||||||
|
@ -35,9 +35,7 @@ func loadQMap() [][]string {
|
|||||||
// 1.mg
|
// 1.mg
|
||||||
m[1] = defQuality
|
m[1] = defQuality
|
||||||
// 2.kw
|
// 2.kw
|
||||||
// if env.Config.Custom.Kw_Enable {
|
m[2] = defQuality
|
||||||
m[2] = stdQuality
|
|
||||||
// }
|
|
||||||
// 3.kg
|
// 3.kg
|
||||||
m[3] = tstQuality
|
m[3] = tstQuality
|
||||||
// 4.tx
|
// 4.tx
|
||||||
@ -65,9 +63,9 @@ func InitRouter() *gin.Engine {
|
|||||||
`version`: env.Version, // 服务端程序版本
|
`version`: env.Version, // 服务端程序版本
|
||||||
`name`: `lx-music-source`, // 名称
|
`name`: `lx-music-source`, // 名称
|
||||||
`msg`: `Hello~::^-^::~v1~`, // Api大版本
|
`msg`: `Hello~::^-^::~v1~`, // Api大版本
|
||||||
`developer`: []string{`Zxwy`}, // 开发者列表, 可在保留原作者的基础上添加你自己的名字?
|
// `developer`: []string{`Zxwy`}, // 开发者列表, 可在保留原作者的基础上添加你自己的名字?
|
||||||
// 仓库地址
|
// 仓库地址
|
||||||
`github`: `https://github.com/ZxwyWebSite/lx-source`,
|
// `github`: `https://github.com/ZxwyWebSite/lx-source`,
|
||||||
// 可用平台
|
// 可用平台
|
||||||
`source`: gin.H{
|
`source`: gin.H{
|
||||||
sources.S_wy: qmap[0], //true,
|
sources.S_wy: qmap[0], //true,
|
||||||
@ -81,7 +79,7 @@ func InitRouter() *gin.Engine {
|
|||||||
sources.S_lx: qmap[5],
|
sources.S_lx: qmap[5],
|
||||||
},
|
},
|
||||||
// 自定义源脚本更新
|
// 自定义源脚本更新
|
||||||
`script`: env.Config.Script,
|
`script`: env.DefCfg.Script, //env.Config.Script,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
// 静态文件
|
// 静态文件
|
||||||
|
@ -27,7 +27,7 @@ var (
|
|||||||
// 并发对象池 (用户限制在Router处实现)
|
// 并发对象池 (用户限制在Router处实现)
|
||||||
wy_pool = &sync.Pool{New: func() any { return new(WyApi_Song) }}
|
wy_pool = &sync.Pool{New: func() any { return new(WyApi_Song) }}
|
||||||
mg_pool = &sync.Pool{New: func() any { return new(MgApi_Song) }}
|
mg_pool = &sync.Pool{New: func() any { return new(MgApi_Song) }}
|
||||||
kw_pool = &sync.Pool{New: func() any { return new(KwApi_Song) }}
|
// kw_pool = &sync.Pool{New: func() any { return new(KwApi_Song) }}
|
||||||
kg_pool = &sync.Pool{New: func() any { return new(KgApi_Song) }}
|
kg_pool = &sync.Pool{New: func() any { return new(KgApi_Song) }}
|
||||||
// tx_pool = &sync.Pool{New: func() any { return new(res_tx) }}
|
// tx_pool = &sync.Pool{New: func() any { return new(res_tx) }}
|
||||||
)
|
)
|
||||||
@ -56,7 +56,11 @@ func (s *Source) GetLink(c *caches.Query) (outlink string, msg string) {
|
|||||||
resp := wy_pool.Get().(*WyApi_Song)
|
resp := wy_pool.Get().(*WyApi_Song)
|
||||||
defer wy_pool.Put(resp)
|
defer wy_pool.Put(resp)
|
||||||
|
|
||||||
// url := ztool.Str_FastConcat(`http://`, api_wy, `?id=`, c.MusicID, `&level=`, rquery, `&noCookie=true`)
|
// urls := [...]string{
|
||||||
|
// ztool.Str_FastConcat(`http://`, api_wy, `?id=`, c.MusicID, `&level=`, rquery, `&noCookie=true`),
|
||||||
|
// ztool.Str_FastConcat(`https://`, api_wy, `&id=`, c.MusicID, `&level=`, rquery, `&encodeType=`, c.Extname),
|
||||||
|
// }
|
||||||
|
// url := urls[rand.Intn(len(urls))]
|
||||||
url := ztool.Str_FastConcat(`https://`, api_wy, `&id=`, c.MusicID, `&level=`, rquery, `&encodeType=`, c.Extname)
|
url := ztool.Str_FastConcat(`https://`, api_wy, `&id=`, c.MusicID, `&level=`, rquery, `&encodeType=`, c.Extname)
|
||||||
// jx.Debug(`Wy, Url: %v`, url)
|
// jx.Debug(`Wy, Url: %v`, url)
|
||||||
// wy源增加后端重试 默认3次
|
// wy源增加后端重试 默认3次
|
||||||
@ -121,25 +125,6 @@ func (s *Source) GetLink(c *caches.Query) (outlink string, msg string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
outlink = ourl
|
outlink = ourl
|
||||||
// case s_kw:
|
|
||||||
// resp := kw_pool.Get().(*KwApi_Song)
|
|
||||||
// defer kw_pool.Put(resp)
|
|
||||||
|
|
||||||
// url := ztool.Str_FastConcat(`https://`, api_kw, `/`, c.MusicID, `?isMv=0&format=`, c.Extname, `&br=`, rquery, c.Extname, `&level=`)
|
|
||||||
// // jx.Debug(`Kw, Url: %s`, url)
|
|
||||||
// _, err := ztool.Net_HttpReq(http.MethodGet, url, nil, header_kw, &resp)
|
|
||||||
// if err != nil {
|
|
||||||
// jx.Error(`Kw, HttpReq: %s`, err)
|
|
||||||
// msg = errHttpReq //err.Error()
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// jx.Debug(`Kw, Resp: %+v`, resp)
|
|
||||||
// if resp.Code != 200 || resp.Data.AudioInfo.Bitrate == `1` {
|
|
||||||
// // jx.Debug(`Kw, Err: %#v`, resp)
|
|
||||||
// msg = ztool.Str_FastConcat(`failed: `, resp.Msg)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// outlink = strings.Split(resp.Data.URL, `?`)[0]
|
|
||||||
case s_kg:
|
case s_kg:
|
||||||
resp := kg_pool.Get().(*KgApi_Song)
|
resp := kg_pool.Get().(*KgApi_Song)
|
||||||
defer kg_pool.Put(resp)
|
defer kg_pool.Put(resp)
|
||||||
|
@ -59,23 +59,23 @@ type (
|
|||||||
} `json:"data"`
|
} `json:"data"`
|
||||||
}
|
}
|
||||||
// 酷我音乐接口 (波点)
|
// 酷我音乐接口 (波点)
|
||||||
KwApi_Song struct {
|
// KwApi_Song struct {
|
||||||
Code int `json:"code"`
|
// Code int `json:"code"`
|
||||||
Msg string `json:"msg"`
|
// Msg string `json:"msg"`
|
||||||
ReqID string `json:"reqId"`
|
// ReqID string `json:"reqId"`
|
||||||
Data struct {
|
// Data struct {
|
||||||
Duration int `json:"duration"`
|
// Duration int `json:"duration"`
|
||||||
AudioInfo struct {
|
// AudioInfo struct {
|
||||||
Bitrate string `json:"bitrate"`
|
// Bitrate string `json:"bitrate"`
|
||||||
Format string `json:"format"`
|
// Format string `json:"format"`
|
||||||
Level string `json:"level"`
|
// Level string `json:"level"`
|
||||||
Size string `json:"size"`
|
// Size string `json:"size"`
|
||||||
} `json:"audioInfo"`
|
// } `json:"audioInfo"`
|
||||||
URL string `json:"url"`
|
// URL string `json:"url"`
|
||||||
} `json:"data"`
|
// } `json:"data"`
|
||||||
ProfileID string `json:"profileId"`
|
// ProfileID string `json:"profileId"`
|
||||||
CurTime int64 `json:"curTime"`
|
// CurTime int64 `json:"curTime"`
|
||||||
}
|
// }
|
||||||
// 酷狗试听接口
|
// 酷狗试听接口
|
||||||
KgApi_Song struct {
|
KgApi_Song struct {
|
||||||
Status int `json:"status"`
|
Status int `json:"status"`
|
||||||
|
@ -122,7 +122,7 @@ var (
|
|||||||
15, 1, 5, 12, 3, 10, 14, 5,
|
15, 1, 5, 12, 3, 10, 14, 5,
|
||||||
8, 7, 11, 0, 4, 13, 2, 11},
|
8, 7, 11, 0, 4, 13, 2, 11},
|
||||||
}
|
}
|
||||||
SECRET_KEY = bytesconv.StringToBytes(`ylzsxkwm`) //[]byte("ylzsxkwm")
|
SECRET_KEY = []byte{0x79, 0x6c, 0x7a, 0x73, 0x78, 0x6b, 0x77, 0x6d} //bytesconv.StringToBytes(`ylzsxkwm`)
|
||||||
)
|
)
|
||||||
|
|
||||||
// 初始化arrayMask
|
// 初始化arrayMask
|
||||||
|
@ -5,12 +5,100 @@ import (
|
|||||||
"lx-source/src/env"
|
"lx-source/src/env"
|
||||||
"lx-source/src/sources"
|
"lx-source/src/sources"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/ZxwyWebSite/ztool"
|
"github.com/ZxwyWebSite/ztool"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Url(songMid, quality string) (ourl, msg string) {
|
var (
|
||||||
|
kw_pool *sync.Pool
|
||||||
|
|
||||||
|
Url func(string, string) (string, string)
|
||||||
|
|
||||||
|
parsemod bool
|
||||||
|
convtype string
|
||||||
|
// desParse func([]byte, *playInfo) error
|
||||||
|
// desParse func(any) ztool.Net_ResHandlerFunc
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
env.Inits.Add(func() {
|
||||||
|
loger := env.Loger.NewGroup(`KwInit`)
|
||||||
|
switch env.Config.Custom.Kw_Mode {
|
||||||
|
case `0`, `bdapi`:
|
||||||
|
loger.Debug(`Use bdapi`)
|
||||||
|
if ztool.Chk_IsNilStr(
|
||||||
|
env.Config.Custom.Kw_Bd_Uid,
|
||||||
|
env.Config.Custom.Kw_Bd_Token,
|
||||||
|
env.Config.Custom.Kw_Bd_DevId,
|
||||||
|
) {
|
||||||
|
loger.Fatal(`使用bdapi且验证参数为空`)
|
||||||
|
}
|
||||||
|
bdheader[`uid`] = env.Config.Custom.Kw_Bd_Uid
|
||||||
|
bdheader[`devId`] = env.Config.Custom.Kw_Bd_DevId
|
||||||
|
kw_pool = &sync.Pool{New: func() any { return new(kwApi_Song) }}
|
||||||
|
Url = bdapi
|
||||||
|
case `1`, `kwdes`:
|
||||||
|
switch env.Config.Custom.Kw_Des_Type {
|
||||||
|
case `0`, `text`:
|
||||||
|
loger.Debug(`Use kwdes_text`)
|
||||||
|
convtype = `convert_url2`
|
||||||
|
// desParse = txtParse
|
||||||
|
case `1`, `json`:
|
||||||
|
loger.Debug(`Use kwdes_json`)
|
||||||
|
convtype = `convert_url_with_sign`
|
||||||
|
// desParse = ztool.Net_ResToStruct
|
||||||
|
parsemod = true
|
||||||
|
default:
|
||||||
|
loger.Fatal(`未定义的返回格式,请检查配置 [Custom].Kw_Des_Type`)
|
||||||
|
}
|
||||||
|
desheader[`User-Agent`] = env.Config.Custom.Kw_Des_Header
|
||||||
|
kw_pool = &sync.Pool{New: func() any { return new(playInfo) }}
|
||||||
|
Url = kwdes
|
||||||
|
default:
|
||||||
|
loger.Fatal(`未定义的接口模式,请检查配置 [Custom].Kw_Mode`)
|
||||||
|
}
|
||||||
|
loger = nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func bdapi(songMid, quality string) (ourl, msg string) {
|
||||||
|
loger := env.Loger.NewGroup(`Kw`)
|
||||||
|
info, ok := fileInfo[quality]
|
||||||
|
if !ok {
|
||||||
|
msg = sources.E_QNotSupport
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp := kw_pool.Get().(*kwApi_Song)
|
||||||
|
defer kw_pool.Put(resp)
|
||||||
|
|
||||||
|
url := ztool.Str_FastConcat(
|
||||||
|
`https://bd-api.kuwo.cn/api/service/music/downloadInfo/`, songMid,
|
||||||
|
`?isMv=0&format=`, info.E,
|
||||||
|
`&br=`, info.H, info.E, //`&level=`,
|
||||||
|
`&uin=`, env.Config.Custom.Kw_Bd_Uid,
|
||||||
|
`&token=`, env.Config.Custom.Kw_Bd_Token,
|
||||||
|
)
|
||||||
|
// jx.Debug(`Kw, Url: %s`, url)
|
||||||
|
_, err := ztool.Net_HttpReq(http.MethodGet, url, nil, bdheader, &resp)
|
||||||
|
if err != nil {
|
||||||
|
loger.Error(`HttpReq: %s`, err)
|
||||||
|
msg = sources.ErrHttpReq
|
||||||
|
return
|
||||||
|
}
|
||||||
|
loger.Debug(`Resp: %+v`, resp)
|
||||||
|
if resp.Code != 200 || resp.Data.AudioInfo.Bitrate == `1` {
|
||||||
|
// jx.Debug(`Kw, Err: %#v`, resp)
|
||||||
|
msg = ztool.Str_FastConcat(`failed: `, resp.Msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ourl = strings.Split(resp.Data.URL, `?`)[0]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func kwdes(songMid, quality string) (ourl, msg string) {
|
||||||
loger := env.Loger.NewGroup(`Kw`)
|
loger := env.Loger.NewGroup(`Kw`)
|
||||||
infoFile, ok := fileInfo[quality]
|
infoFile, ok := fileInfo[quality]
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -20,16 +108,44 @@ func Url(songMid, quality string) (ourl, msg string) {
|
|||||||
target_url := ztool.Str_FastConcat(
|
target_url := ztool.Str_FastConcat(
|
||||||
`https://mobi.kuwo.cn/mobi.s?f=kuwo&q=`,
|
`https://mobi.kuwo.cn/mobi.s?f=kuwo&q=`,
|
||||||
Base64_encrypt(ztool.Str_FastConcat(
|
Base64_encrypt(ztool.Str_FastConcat(
|
||||||
`user=0&android_id=0&prod=kwplayer_ar_8.5.5.0&corp=kuwo&newver=3&vipver=8.5.5.0&source=kwplayer_ar_8.5.5.0_apk_keluze.apk&p2p=1¬race=0&type=convert_url2`,
|
`user=0&android_id=0&prod=kwplayer_ar_8.5.5.0&corp=kuwo&newver=3&vipver=8.5.5.0&source=kwplayer_ar_8.5.5.0_apk_keluze.apk&p2p=1¬race=0`,
|
||||||
|
`&type=`, convtype,
|
||||||
`&br=`, infoFile.H, infoFile.E,
|
`&br=`, infoFile.H, infoFile.E,
|
||||||
`&format=`, infoFile.E,
|
`&format=`, infoFile.E,
|
||||||
`&rid=`, songMid,
|
`&rid=`, songMid,
|
||||||
`&priority=bitrate&loginUid=0&network=WIFI&loginSid=0&mode=down`,
|
`&priority=bitrate&loginUid=0&network=WIFI&loginSid=0&mode=down`,
|
||||||
)),
|
)),
|
||||||
)
|
)
|
||||||
|
if parsemod {
|
||||||
|
resp := kw_pool.Get().(*playInfo)
|
||||||
|
defer kw_pool.Put(resp)
|
||||||
|
|
||||||
|
err := ztool.Net_Request(http.MethodGet, target_url, nil,
|
||||||
|
[]ztool.Net_ReqHandlerFunc{ztool.Net_ReqAddHeader(desheader)},
|
||||||
|
[]ztool.Net_ResHandlerFunc{ztool.Net_ResToStruct(&resp)},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
loger.Error(`Request: %s`, err)
|
||||||
|
msg = sources.ErrHttpReq
|
||||||
|
return
|
||||||
|
}
|
||||||
|
loger.Debug(`Resp: %+v`, resp)
|
||||||
|
if resp.Code != http.StatusOK {
|
||||||
|
msg = ztool.Str_FastConcat(`failed: `, resp.Msg)
|
||||||
|
loger.Debug(msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
realQuality := strconv.Itoa(resp.Data.Bitrate)
|
||||||
|
if qualityMapReverse[realQuality] != quality {
|
||||||
|
msg = sources.E_QNotMatch
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ourl = resp.Data.URL[:strings.Index(resp.Data.URL, `?`)]
|
||||||
|
return
|
||||||
|
}
|
||||||
ztool.Net_Request(http.MethodGet, target_url, nil,
|
ztool.Net_Request(http.MethodGet, target_url, nil,
|
||||||
[]ztool.Net_ReqHandlerFunc{
|
[]ztool.Net_ReqHandlerFunc{
|
||||||
ztool.Net_ReqAddHeader(header),
|
ztool.Net_ReqAddHeader(desheader),
|
||||||
},
|
},
|
||||||
[]ztool.Net_ResHandlerFunc{
|
[]ztool.Net_ResHandlerFunc{
|
||||||
func(res *http.Response) (err error) {
|
func(res *http.Response) (err error) {
|
||||||
@ -39,8 +155,8 @@ func Url(songMid, quality string) (ourl, msg string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if res.StatusCode != http.StatusOK {
|
if res.StatusCode != http.StatusOK {
|
||||||
msg = res.Status
|
msg = ztool.Str_FastConcat(`failed: `, res.Status)
|
||||||
loger.Debug(`failed: %v`, res.Status)
|
loger.Debug(msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
infoData := mkMap(data)
|
infoData := mkMap(data)
|
||||||
|
39
src/sources/custom/kw/types.go
Normal file
39
src/sources/custom/kw/types.go
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package kw
|
||||||
|
|
||||||
|
type (
|
||||||
|
// KwDES json
|
||||||
|
playInfo struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Locationid string `json:"locationid"`
|
||||||
|
Data struct {
|
||||||
|
Bitrate int `json:"bitrate"`
|
||||||
|
User string `json:"user"`
|
||||||
|
Sig string `json:"sig"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Format string `json:"format"`
|
||||||
|
P2PAudiosourceid string `json:"p2p_audiosourceid"`
|
||||||
|
Rid int `json:"rid"`
|
||||||
|
Source string `json:"source"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
} `json:"data"`
|
||||||
|
Msg string `json:"msg"`
|
||||||
|
}
|
||||||
|
// 酷我音乐接口 (波点)
|
||||||
|
kwApi_Song struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Msg string `json:"msg"`
|
||||||
|
ReqID string `json:"reqId"`
|
||||||
|
Data struct {
|
||||||
|
Duration int `json:"duration"`
|
||||||
|
AudioInfo struct {
|
||||||
|
Bitrate string `json:"bitrate"`
|
||||||
|
Format string `json:"format"`
|
||||||
|
Level string `json:"level"`
|
||||||
|
Size string `json:"size"`
|
||||||
|
} `json:"audioInfo"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
} `json:"data"`
|
||||||
|
ProfileID string `json:"profileId"`
|
||||||
|
CurTime int64 `json:"curTime"`
|
||||||
|
}
|
||||||
|
)
|
@ -9,8 +9,8 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
fileInfo = map[string]struct {
|
fileInfo = map[string]struct {
|
||||||
E string
|
E string // 扩展名
|
||||||
H string
|
H string // 专用音质
|
||||||
}{
|
}{
|
||||||
sources.Q_128k: {
|
sources.Q_128k: {
|
||||||
E: `mp3`,
|
E: `mp3`,
|
||||||
@ -24,14 +24,27 @@ var (
|
|||||||
E: sources.Q_flac,
|
E: sources.Q_flac,
|
||||||
H: `2000k`,
|
H: `2000k`,
|
||||||
},
|
},
|
||||||
|
sources.Q_fl24: {
|
||||||
|
E: sources.Q_flac,
|
||||||
|
H: `4000k`,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
qualityMapReverse = map[string]string{
|
qualityMapReverse = map[string]string{
|
||||||
`128`: sources.Q_128k,
|
`128`: sources.Q_128k,
|
||||||
`320`: sources.Q_320k,
|
`320`: sources.Q_320k,
|
||||||
`2000`: sources.Q_flac,
|
`2000`: sources.Q_flac,
|
||||||
|
`4000`: sources.Q_fl24,
|
||||||
}
|
}
|
||||||
header = map[string]string{
|
desheader = map[string]string{
|
||||||
`User-Agent`: `okhttp/3.10.0`,
|
// `User-Agent`: `okhttp/3.10.0`,
|
||||||
|
}
|
||||||
|
bdheader = map[string]string{
|
||||||
|
`channel`: `qq`,
|
||||||
|
`plat`: `ar`,
|
||||||
|
`net`: `wifi`,
|
||||||
|
`ver`: `3.1.2`,
|
||||||
|
// `uid`: ``,
|
||||||
|
// `devId`: `0`,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -44,7 +57,7 @@ func mkMap(data []byte) map[string]string {
|
|||||||
out[bytesconv.BytesToString(pat[0])] = bytesconv.BytesToString(pat[1])
|
out[bytesconv.BytesToString(pat[0])] = bytesconv.BytesToString(pat[1])
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
out[`_etc`] += bytesconv.BytesToString(pat[0]) + `; `
|
out[`_`] += bytesconv.BytesToString(pat[0]) + `;`
|
||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
@ -30,11 +30,13 @@ import (
|
|||||||
// return
|
// return
|
||||||
// }
|
// }
|
||||||
|
|
||||||
func Init() {
|
func init() {
|
||||||
|
env.Inits.Add(func() {
|
||||||
if env.Config.Custom.Tx_Refresh_Enable {
|
if env.Config.Custom.Tx_Refresh_Enable {
|
||||||
env.Tasker.Add(`refresh_login`, func(l *logs.Logger) error {
|
env.Tasker.Add(`refresh_login`, func(l *logs.Logger) error {
|
||||||
refresh(l)
|
refresh(l)
|
||||||
return nil
|
return nil
|
||||||
}, 86000, true)
|
}, 86000, true)
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,10 @@ const (
|
|||||||
E_QNotSupport = `不支持的音质`
|
E_QNotSupport = `不支持的音质`
|
||||||
E_QNotMatch = `实际音质不匹配`
|
E_QNotMatch = `实际音质不匹配`
|
||||||
E_NoLink = `无法获取音乐链接`
|
E_NoLink = `无法获取音乐链接`
|
||||||
|
// 内置错误
|
||||||
|
ErrHttpReq = `无法连接解析接口`
|
||||||
|
ErrNoLink = `无法获取试听链接`
|
||||||
|
ErrDisable = `该音乐源已被禁用`
|
||||||
)
|
)
|
||||||
|
|
||||||
// 源查询接口
|
// 源查询接口
|
||||||
|
@ -1,5 +1,14 @@
|
|||||||
## Lx-Source/更新日志
|
## Lx-Source/更新日志
|
||||||
|
|
||||||
|
#### \# 2024-01-13 v1.0.2-b10 (beta)
|
||||||
|
+ 不再支持自定义Public目录,默认使用内置embedFS提供服务
|
||||||
|
+ 修改脚本更新路径为 `public/lx-custom-source.js`
|
||||||
|
+ 优化kw内置源获取方式
|
||||||
|
+ 强制使用默认Script配置
|
||||||
|
+ 隐藏服务端信息中的`developer,github`字段
|
||||||
|
+ 为Windows构建添加文件属性
|
||||||
|
<!-- + 添加wy源接口分流功能 -->
|
||||||
|
|
||||||
#### \# 2024-01-10 v1.0.2-b10-d1 (dev)
|
#### \# 2024-01-10 v1.0.2-b10-d1 (dev)
|
||||||
<!-- + 内置kw接口失效,暂时禁用kw源 -->
|
<!-- + 内置kw接口失效,暂时禁用kw源 -->
|
||||||
+ 修复内置kw接口
|
+ 修复内置kw接口
|
||||||
|
Loading…
x
Reference in New Issue
Block a user