2024-01-13 v1.0.2-b10

This commit is contained in:
ZxwyWebSite 2024-01-14 20:18:43 +08:00
parent 0bedce3bc7
commit 8d16e3be98
14 changed files with 279 additions and 92 deletions

3
.gitignore vendored
View File

@ -5,4 +5,5 @@ data/
# conf.ini # conf.ini
test.go test.go
test_test.go test_test.go
# src/sources/builtin/ # src/sources/builtin/
rsrc_windows_amd64.syso

View File

@ -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服务

36
src/env/env.go vendored
View File

@ -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`,
@ -148,8 +160,13 @@ var (
Proxy_Address: `{protocol}://({user}:{password})@{address}:{port}`, Proxy_Address: `{protocol}://({user}:{password})@{address}:{port}`,
}, },
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,
@ -157,9 +174,10 @@ var (
Script: Conf_Script{ Script: Conf_Script{
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() {
// } // }

View File

@ -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)
} }

View File

@ -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
@ -62,12 +60,12 @@ func InitRouter() *gin.Engine {
// 源信息 // 源信息
r.GET(`/`, func(c *gin.Context) { r.GET(`/`, func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{ c.JSON(http.StatusOK, gin.H{
`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,
}) })
}) })
// 静态文件 // 静态文件

View File

@ -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)

View File

@ -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"`

View File

@ -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

View File

@ -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&notrace=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&notrace=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)

View 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"`
}
)

View File

@ -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
} }

View File

@ -30,11 +30,13 @@ import (
// return // return
// } // }
func Init() { func init() {
if env.Config.Custom.Tx_Refresh_Enable { env.Inits.Add(func() {
env.Tasker.Add(`refresh_login`, func(l *logs.Logger) error { if env.Config.Custom.Tx_Refresh_Enable {
refresh(l) env.Tasker.Add(`refresh_login`, func(l *logs.Logger) error {
return nil refresh(l)
}, 86000, true) return nil
} }, 86000, true)
}
})
} }

View File

@ -24,6 +24,10 @@ const (
E_QNotSupport = `不支持的音质` E_QNotSupport = `不支持的音质`
E_QNotMatch = `实际音质不匹配` E_QNotMatch = `实际音质不匹配`
E_NoLink = `无法获取音乐链接` E_NoLink = `无法获取音乐链接`
// 内置错误
ErrHttpReq = `无法连接解析接口`
ErrNoLink = `无法获取试听链接`
ErrDisable = `该音乐源已被禁用`
) )
// 源查询接口 // 源查询接口

View File

@ -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接口