mirror of
https://github.com/ZxwyWebSite/lx-source.git
synced 2025-07-03 10:42:18 +08:00
2023-12-22 v1.0.2-b0.4
This commit is contained in:
parent
72cdfd081e
commit
2535319005
2
.gitignore
vendored
2
.gitignore
vendored
@ -5,4 +5,4 @@ outdated/
|
||||
# conf.ini
|
||||
test.go
|
||||
test_test.go
|
||||
src/sources/builtin/
|
||||
# src/sources/builtin/
|
@ -1,7 +1,7 @@
|
||||
package caches
|
||||
|
||||
import (
|
||||
"lx-source/src/env"
|
||||
"sync"
|
||||
|
||||
"github.com/ZxwyWebSite/ztool"
|
||||
)
|
||||
@ -39,13 +39,16 @@ func (*Nullcache) Stat() bool { return false }
|
||||
func (*Nullcache) Init() error { return nil }
|
||||
|
||||
var (
|
||||
Loger = env.Loger.NewGroup(`Caches`)
|
||||
|
||||
// Loger = env.Loger.NewGroup(`Caches`)
|
||||
UseCache Cache = &Nullcache{}
|
||||
|
||||
// ErrNotInited = errors.New(`缓存策略未初始化`)
|
||||
query_pool = sync.Pool{New: func() any { return new(Query) }}
|
||||
)
|
||||
|
||||
// 对象池相关 (注:结构体释放时一定要清理未导出字段)
|
||||
func newQuery() *Query { return query_pool.Get().(*Query) }
|
||||
func (c *Query) Free() { c.query = ``; query_pool.Put(c) }
|
||||
|
||||
// 根据音质判断文件后缀
|
||||
func rext(q string) string {
|
||||
if q == `128k` || q == `320k` {
|
||||
@ -56,12 +59,18 @@ func rext(q string) string {
|
||||
|
||||
// 生成查询参数 (必须使用此函数初始化)
|
||||
func NewQuery(s, id, q string) *Query {
|
||||
return &Query{
|
||||
Source: s,
|
||||
MusicID: id,
|
||||
Quality: q,
|
||||
Extname: rext(q),
|
||||
}
|
||||
out := newQuery()
|
||||
out.Source = s
|
||||
out.MusicID = id
|
||||
out.Quality = q
|
||||
out.Extname = rext(q)
|
||||
return out
|
||||
// return &Query{
|
||||
// Source: s,
|
||||
// MusicID: id,
|
||||
// Quality: q,
|
||||
// Extname: rext(q),
|
||||
// }
|
||||
}
|
||||
|
||||
// 获取旧版查询字符串
|
||||
|
@ -3,6 +3,7 @@ package localcache
|
||||
import (
|
||||
"errors"
|
||||
"lx-source/src/caches"
|
||||
"lx-source/src/env"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
@ -16,7 +17,7 @@ type Cache struct {
|
||||
state bool // 激活状态
|
||||
}
|
||||
|
||||
var loger = caches.Loger.AppGroup(`local`)
|
||||
var loger = env.Loger.NewGroup(`Caches`) //caches.Loger.AppGroup(`local`)
|
||||
|
||||
func (c *Cache) getLink(q string) string {
|
||||
return ztool.Str_FastConcat(c.Bind, `/file/`, q) // c.Addr + `file/` + q
|
||||
|
2
src/env/env.go
vendored
2
src/env/env.go
vendored
@ -9,7 +9,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
Version = `1.0.2-β0.3`
|
||||
Version = `1.0.2-β0.4`
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -8,6 +8,24 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func InitHandler(h gin.HandlerFunc) (out []gin.HandlerFunc) {
|
||||
loger := env.Loger.NewGroup(`AuthHandler`)
|
||||
// ApiKey
|
||||
if env.Config.Auth.ApiKey_Enable {
|
||||
loger.Debug(`ApiKeyAuth Enabled`)
|
||||
out = append(out, func(c *gin.Context) {
|
||||
resp.Wrap(c, func() *resp.Resp {
|
||||
if auth := c.Request.Header.Get(`X-LxM-Auth`); auth != env.Config.Auth.ApiKey_Value {
|
||||
loger.Debug(`验证失败: %q`, auth)
|
||||
return &resp.Resp{Code: 3, Msg: `验证Key失败, 请联系网站管理员`}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
})
|
||||
}
|
||||
return append(out, h)
|
||||
}
|
||||
|
||||
// 请求验证
|
||||
func AuthHandler(c *gin.Context) {
|
||||
loger := env.Loger.NewGroup(`AuthHandler`)
|
||||
|
@ -26,6 +26,32 @@ func LoadHandler(r *gin.Engine) {
|
||||
// 动态链暂未完成...
|
||||
}
|
||||
|
||||
// Doc 动态链
|
||||
/*
|
||||
0. 链接格式
|
||||
- (Mode: 链接模式 0:本地/1:远程, Link: 真实链接), id(uint32 4294967295)
|
||||
- yyyymmdd/unixsecond/hex(:s/:id/:q).format(flac24bit->fl24)
|
||||
1. 传入参数 (得到音乐链接后生成随机链并写入缓存)
|
||||
+ Data1 查询缓存
|
||||
- key: "lx/0000000001/320k"
|
||||
- val: "`{cache.Path}/file/`20231221/1703176257/6c782f303030303030303030312f3332306b.mp3"
|
||||
+ Data2 直链缓存
|
||||
- key: "20231221/1703176257/6c782f303030303030303030312f3332306b.mp3"
|
||||
- val: "&DynLink{Mode: 0, Link: 'cache/lx/0000000001/320k'}"
|
||||
2. 查询缓存
|
||||
- key: "20231221/1703176257/6c782f303030303030303030312f3332306b.mp3"
|
||||
- val: "&DynLink{Mode: 0, Link: 'cache/lx/0000000001/320k'}"
|
||||
- va2: "&DynLink{Mode: 1, Link: 'http://127.0.0.1/file/lx/0000000001/320k.mp3'}"
|
||||
3. 实际数据 (访问 /file/:t/:x/:f)
|
||||
+ if Mode==0 本地数据直接发送
|
||||
- c.File(Link)
|
||||
+ if Mode==1 远程数据302跳转
|
||||
- c.Redirect(Link)
|
||||
|
||||
0. 实现思路
|
||||
|
||||
*/
|
||||
|
||||
// func FileHandler() gin.HandlerFunc {
|
||||
// loger := env.Loger.NewGroup(`DynLink`)
|
||||
// // 为了兼容原静态链,必须设置3个参数
|
||||
|
@ -52,7 +52,7 @@ 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.AuthHandler, linkHandler)
|
||||
r.GET(`/link/:s/:id/:q`, auth.InitHandler(linkHandler)...)
|
||||
dynlink.LoadHandler(r)
|
||||
// r.GET(`/file/:t/:x/:f`, dynlink.FileHandler())
|
||||
// if cache, ok := caches.UseCache.(*localcache.Cache); ok {
|
||||
@ -86,21 +86,18 @@ const (
|
||||
func linkHandler(c *gin.Context) {
|
||||
resp.Wrap(c, func() *resp.Resp {
|
||||
// 获取传入参数 检查合法性
|
||||
// parmlen := len(c.Params)
|
||||
// parms := make(map[string]string, parmlen)
|
||||
// for i := 0; i < parmlen; i++ {
|
||||
// parms[c.Params[i].Key] = c.Params[i].Value
|
||||
// }
|
||||
parms := util.ParaMap(c)
|
||||
// getParam := func(p string) string { return strings.TrimSuffix(strings.TrimPrefix(c.Param(p), `/`), `/`) } //strings.Trim(c.Param(p), `/`)
|
||||
s := parms[`s`] //c.Param(`s`) //getParam(`s`) // source 平台 wy, mg, kw
|
||||
id := parms[`id`] //c.Param(`id`) //getParam(`id`) // sid 音乐ID wy: songmid, mg: copyrightId
|
||||
q := parms[`q`] //c.Param(`q`) //getParam(`q`) // quality 音质 128k / 320k / flac / flac24bit
|
||||
env.Loger.NewGroup(`LinkQuery`).Debug(`s: %v, id: %v, q: %v`, s, id, q)
|
||||
if ztool.Chk_IsNil(s, q, id) {
|
||||
if ztool.Chk_IsNilStr(s, q, id) {
|
||||
return &resp.Resp{Code: 6, Msg: `参数不全`} // http.StatusBadRequest
|
||||
}
|
||||
cquery := caches.NewQuery(s, id, q)
|
||||
// fmt.Printf("%+v\n", cquery)
|
||||
defer cquery.Free()
|
||||
// _, ok := sources.UseSource.Verify(cquery) // 获取请求音质 同时检测是否支持(如kw源没有flac24bit) qualitys[q][s]rquery
|
||||
// if !ok {
|
||||
// return &resp.Resp{Code: 6, Msg: `不支持的平台或音质`}
|
||||
@ -110,6 +107,7 @@ func linkHandler(c *gin.Context) {
|
||||
clink, ok := env.Cache.Get(cquery.Query())
|
||||
if ok {
|
||||
if str, ok := clink.(string); ok {
|
||||
env.Loger.NewGroup(`MemCache`).Debug(`MemHIT [%q]=>[%q]`, cquery.Query(), str)
|
||||
if str == `` {
|
||||
return &resp.Resp{Code: 2, Msg: `MemCache Reject`} // 拒绝请求,当前一段时间内解析出错
|
||||
}
|
||||
@ -149,6 +147,7 @@ func linkHandler(c *gin.Context) {
|
||||
}
|
||||
}
|
||||
// 无法获取直链 直接返回原链接
|
||||
env.Cache.Set(cquery.Query(), outlink, 1200)
|
||||
return &resp.Resp{Msg: CacheMISS, Data: outlink}
|
||||
})
|
||||
}
|
||||
|
118
src/sources/builtin/driver.go
Normal file
118
src/sources/builtin/driver.go
Normal file
@ -0,0 +1,118 @@
|
||||
// 内置解析源
|
||||
package builtin
|
||||
|
||||
import (
|
||||
"lx-source/src/caches"
|
||||
"lx-source/src/env"
|
||||
"lx-source/src/sources"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ZxwyWebSite/ztool"
|
||||
)
|
||||
|
||||
type Source struct{}
|
||||
|
||||
// 预检 (兼容旧接口)
|
||||
func (s *Source) Verify(c *caches.Query) (rquery string, ok bool) {
|
||||
rquery, ok = qualitys[c.Quality][c.Source]
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
// 并发对象池 (用户限制在Router处实现)
|
||||
wy_pool = &sync.Pool{New: func() any { return new(FyApi_Song) }}
|
||||
mg_pool = &sync.Pool{New: func() any { return new(MgApi_Song) }}
|
||||
kw_pool = &sync.Pool{New: func() any { return new(KwApi_Song) }}
|
||||
)
|
||||
|
||||
// 查询
|
||||
func (s *Source) GetLink(c *caches.Query) (outlink string, msg string) {
|
||||
rquery, ok := s.Verify(c)
|
||||
if !ok {
|
||||
msg = sources.Err_Verify //`Verify Failed`
|
||||
return
|
||||
}
|
||||
// var outlink string
|
||||
jx := env.Loger.NewGroup(`Sources`) //sources.Loger.AppGroup(`builtin`) //env.Loger.NewGroup(`JieXiApis`)
|
||||
switch c.Source {
|
||||
case s_wy:
|
||||
resp := wy_pool.Get().(*FyApi_Song)
|
||||
defer wy_pool.Put(resp)
|
||||
|
||||
url := ztool.Str_FastConcat(`http://`, api_wy, `?id=`, c.MusicID, `&level=`, rquery, `&noCookie=true`)
|
||||
// jx.Debug(`Wy, Url: %v`, url)
|
||||
// wy源增加后端重试 默认3次
|
||||
for i := 0; true; i++ {
|
||||
_, err := ztool.Net_HttpReq(http.MethodGet, url, nil, header_wy, &resp)
|
||||
if err != nil {
|
||||
jx.Error(`HttpReq, Err: %s, ReTry: %v`, err, i)
|
||||
if i > 3 {
|
||||
msg = err.Error()
|
||||
return
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
jx.Debug(`Wy, Resp: %+v`, resp)
|
||||
if len(resp.Data) == 0 {
|
||||
msg = `No Data:Api接口忙,请稍后重试`
|
||||
return
|
||||
}
|
||||
var data = resp.Data[0]
|
||||
if data.FreeTrialInfo != nil {
|
||||
// jx.Error("发生错误, 返回数据:\n%#v", resp)
|
||||
msg = `触发风控或专辑单独收费`
|
||||
return
|
||||
}
|
||||
if data.Level != rquery {
|
||||
msg = `实际音质不匹配`
|
||||
return
|
||||
}
|
||||
// jx.Info(`WyLink, RealQuality: %v`, data.Level)
|
||||
outlink = data.URL
|
||||
case s_mg:
|
||||
resp := mg_pool.Get().(*MgApi_Song)
|
||||
defer mg_pool.Put(resp)
|
||||
|
||||
url := ztool.Str_FastConcat(`https://`, api_mg, `?copyrightId=`, c.MusicID, `&type=`, rquery)
|
||||
// jx.Debug(`Mg, Url: %v`, url)
|
||||
_, err := ztool.Net_HttpReq(http.MethodGet, url, nil, header_mg, &resp)
|
||||
if err != nil {
|
||||
msg = err.Error()
|
||||
return
|
||||
}
|
||||
jx.Debug(`Mg, Resp: %+v`, resp)
|
||||
if link := resp.Data.PlayURL; link != `` {
|
||||
outlink = `https:` + link
|
||||
} // else {
|
||||
// jx.Debug(`Mg, Err: %#v`, resp)
|
||||
// }
|
||||
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 {
|
||||
msg = 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]
|
||||
default:
|
||||
msg = `不支持的平台`
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
147
src/sources/builtin/types.go
Normal file
147
src/sources/builtin/types.go
Normal file
File diff suppressed because one or more lines are too long
@ -2,10 +2,9 @@ package sources
|
||||
|
||||
import (
|
||||
"lx-source/src/caches"
|
||||
"lx-source/src/env"
|
||||
)
|
||||
|
||||
var Loger = env.Loger.NewGroup(`Sources`) // JieXiApis
|
||||
// var Loger = env.Loger.NewGroup(`Sources`) // JieXiApis
|
||||
const (
|
||||
Err_Verify = `Verify Failed`
|
||||
)
|
||||
|
15
update.md
15
update.md
@ -1,5 +1,20 @@
|
||||
## Lx-Source/更新日志
|
||||
|
||||
#### 2023-12-22 v1.0.2-b0.4 (beta)
|
||||
<!-- + 没有功能更新,几个未来的想法
|
||||
- 利用缓存信息制作数据库,可通过api搜索音乐
|
||||
- 修改Lx-Music支持通过脚本新增搜索源 -->
|
||||
+ update 更新:
|
||||
- 给CacheQuery加个sync.Pool,提高并发分配效率
|
||||
- 请求验证改为在初始化时载入,降低每次判断性能损耗
|
||||
<!-- - (现在内存缓存和文件缓存的响应速度差距约为200µs) -->
|
||||
+ feature 功能:
|
||||
- 临时链生成仍将推迟
|
||||
+ bugfix 修复:
|
||||
- 临时解决预定义(*Loger).NewGroup()无法输出到FileLoger问题
|
||||
+ 注:
|
||||
- 如果非调试使用建议关闭控制台日志输出 [Main].Print=false,可少量提升io性能 (不影响文件日志记录)
|
||||
|
||||
#### 2023-12-19 1.0.2-b0.3 (dev)
|
||||
+ 增加dev分支,日常开发,稳定了再合main,防止临时补充更新情况
|
||||
+ 上次补充更新内容:将error.mp3换成远程连接
|
||||
|
Loading…
x
Reference in New Issue
Block a user