mirror of
https://github.com/ZxwyWebSite/lx-source.git
synced 2025-05-23 21:37:42 +08:00
2024-01-07 v1.0.2-b0.9
This commit is contained in:
parent
b500fca79a
commit
d086e2934b
7
main.go
7
main.go
@ -10,6 +10,7 @@ import (
|
||||
"lx-source/src/router"
|
||||
"lx-source/src/sources"
|
||||
"lx-source/src/sources/builtin"
|
||||
"lx-source/src/sources/custom/tx"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"os"
|
||||
@ -166,9 +167,13 @@ func main() {
|
||||
ise.Error(`未定义的音乐源,请检查配置 [Source].Mode,本次启动禁用内置源`)
|
||||
}
|
||||
|
||||
// 启动Http服务
|
||||
// 载入必要模块
|
||||
env.Loger.NewGroup(`ServStart`).Info(`服务端启动, 监听地址 %s`, env.Config.Main.Listen)
|
||||
loadFileLoger()
|
||||
tx.Init()
|
||||
env.Defer.Add(env.Tasker.Run(env.Loger)) // wait
|
||||
|
||||
// 启动Http服务
|
||||
r := router.InitRouter() //InitRouter()
|
||||
server := &http.Server{
|
||||
Addr: env.Config.Main.Listen,
|
||||
|
33
src/env/env.go
vendored
33
src/env/env.go
vendored
@ -2,14 +2,17 @@
|
||||
package env
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/ZxwyWebSite/ztool"
|
||||
"github.com/ZxwyWebSite/ztool/cache/memo"
|
||||
"github.com/ZxwyWebSite/ztool/conf"
|
||||
"github.com/ZxwyWebSite/ztool/logs"
|
||||
"github.com/ZxwyWebSite/ztool/task"
|
||||
)
|
||||
|
||||
const (
|
||||
Version = `1.0.2-b0.8`
|
||||
Version = `1.0.2-b0.9`
|
||||
)
|
||||
|
||||
var (
|
||||
@ -46,7 +49,8 @@ type (
|
||||
RateLimit_Block uint32 `comment:"检测范围,每分区为x秒"` // 每x秒一个分区
|
||||
RateLimit_Global uint32 `comment:"全局速率限制,单位次每x秒(暂未开放)"`
|
||||
RateLimit_Single uint32 `comment:"单IP速率限制,单位次每x秒"`
|
||||
// RateLimit_BanNum uint32 `commemt:"容忍限度,超出限制N倍后封禁"`
|
||||
RateLimit_BanNum uint32 `comment:"容忍限度,超出限制N次后封禁"`
|
||||
RateLimit_BanTim uint32 `comment:"封禁后每次延长时间"`
|
||||
// 黑白名单
|
||||
BanList_Mode string `comment:"名单模式 0: off(关闭), 1: white(白名单), 2: black(黑名单)"`
|
||||
BanList_White []string `comment:"host白名单"`
|
||||
@ -64,17 +68,20 @@ type (
|
||||
// ...(待实现)
|
||||
} // `comment:""`
|
||||
Conf_Custom struct {
|
||||
// wy (暂未实现)
|
||||
Wy_Enable bool `comment:"是否开启小芸源"`
|
||||
// Wy_Cookie string `comment:"账号cookie数据"`
|
||||
// mg (暂未实现)
|
||||
// Mg_Enable bool `comment:"是否开启小蜜源"`
|
||||
// kg (暂未实现)
|
||||
// Kg_Enable bool `comment:"是否开启小枸源"`
|
||||
// tx
|
||||
Tx_Enable bool `comment:"是否开启小秋源"`
|
||||
Tx_Ukey string `comment:"Cookie中/客户端的请求体中的(comm.authst)"`
|
||||
Tx_Uuin string `comment:"key对应的QQ号"`
|
||||
// wy (暂未实现)
|
||||
// Wy_Enable bool `comment:"是否开启小芸源"`
|
||||
// Wy_Cookie string `comment:"账号cookie数据"`
|
||||
// mg (暂未实现)
|
||||
// Mg_Enable bool `comment:"是否开启小蜜源"`
|
||||
// tx refresh_login
|
||||
Tx_Refresh_Enable bool `comment:"是否启动刷新登录"`
|
||||
Tx_Refresh_Interval int64 `comment:"刷新间隔 (由程序维护,非必要无需修改)"`
|
||||
}
|
||||
Conf_Script struct {
|
||||
Ver string `comment:"自定义脚本版本" json:"ver"`
|
||||
@ -111,7 +118,7 @@ var (
|
||||
defCfg = Conf{
|
||||
Main: Conf_Main{
|
||||
Debug: false,
|
||||
Listen: `0.0.0.0:1011`,
|
||||
Listen: `127.0.0.1:1011`,
|
||||
Gzip: false,
|
||||
LogPath: `/data/logfile.log`,
|
||||
Print: true,
|
||||
@ -126,6 +133,8 @@ var (
|
||||
RateLimit_Block: 30,
|
||||
RateLimit_Global: 1,
|
||||
RateLimit_Single: 15,
|
||||
RateLimit_BanNum: 5,
|
||||
RateLimit_BanTim: 10,
|
||||
BanList_Mode: `off`,
|
||||
BanList_White: []string{`127.0.0.1`},
|
||||
},
|
||||
@ -136,6 +145,12 @@ var (
|
||||
Proxy_Enable: false,
|
||||
Proxy_Address: `{protocol}://({user}:{password})@{address}:{port}`,
|
||||
},
|
||||
Custom: Conf_Custom{
|
||||
Wy_Enable: true,
|
||||
Tx_Enable: false,
|
||||
Tx_Refresh_Enable: false,
|
||||
Tx_Refresh_Interval: 86000,
|
||||
},
|
||||
Script: Conf_Script{
|
||||
Log: `发布更新 (请删除旧源后重新导入):进行了部分优化,修复了部分Bug`, // 更新日志
|
||||
|
||||
@ -166,6 +181,8 @@ var (
|
||||
})
|
||||
Defer = new(ztool.Err_DeferList)
|
||||
Cache = memo.NewMemoStoreConf(Loger, 300) // 内存缓存 默认每5分钟进行一次GC //memo.NewMemoStore()
|
||||
|
||||
Tasker = task.New(time.Hour, 2) // 定时任务 (暂时没有什么快速任务,默认每小时检测一次)
|
||||
)
|
||||
|
||||
// func init() {
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
|
||||
type (
|
||||
RateLimit struct {
|
||||
Tim int64 // 创建时间
|
||||
Tim int64 // 创建时间 (注:原子操作64位数据需放在结构体第一位或保证8字节对齐,否则不兼容32位平台 https://pkg.go.dev/sync/atomic#pkg-note-BUG)
|
||||
Num uint32 // 请求次数
|
||||
}
|
||||
)
|
||||
@ -40,6 +40,7 @@ func InitHandler(h gin.HandlerFunc) (out []gin.HandlerFunc) {
|
||||
// 判断ip是否在白名单内,是则直接放行
|
||||
判断请求数+1是否大于限制,True: 429 请求过快,请稍后重试
|
||||
// 判断是否超出容忍限度,是则封禁ip (暂未实现)
|
||||
// 超过容忍限度每次请求增加一个Block的时间
|
||||
继续执行后续Handler
|
||||
*/
|
||||
if env.Config.Auth.RateLimit_Enable {
|
||||
@ -47,7 +48,9 @@ func InitHandler(h gin.HandlerFunc) (out []gin.HandlerFunc) {
|
||||
loger.Info(`已启用速率限制,当前配置 %v/%v`, env.Config.Auth.RateLimit_Single, env.Config.Auth.RateLimit_Block)
|
||||
newRateLimit := func() *RateLimit { return &RateLimit{Tim: time.Now().Unix(), Num: 1} }
|
||||
block_int64 := int64(env.Config.Auth.RateLimit_Block)
|
||||
block_int := int(env.Config.Auth.RateLimit_Block)
|
||||
block_mem := int(env.Config.Auth.RateLimit_Block * env.Config.Auth.RateLimit_BanNum)
|
||||
bannum := env.Config.Auth.RateLimit_Single + env.Config.Auth.RateLimit_BanNum
|
||||
bantim := int64(env.Config.Auth.RateLimit_BanTim)
|
||||
out = append(out, func(c *gin.Context) {
|
||||
resp.Wrap(c, func() *resp.Resp {
|
||||
rip := c.RemoteIP()
|
||||
@ -62,6 +65,9 @@ func InitHandler(h gin.HandlerFunc) (out []gin.HandlerFunc) {
|
||||
if oip.Tim+block_int64 > time.Now().Unix() {
|
||||
oi := atomic.AddUint32(&oip.Num, 1)
|
||||
if oi > env.Config.Auth.RateLimit_Single {
|
||||
if oi > bannum {
|
||||
atomic.AddInt64(&oip.Tim, bantim)
|
||||
}
|
||||
return &resp.Resp{Code: 5, Msg: `请求过快,请稍后重试`}
|
||||
}
|
||||
return nil
|
||||
@ -69,7 +75,7 @@ func InitHandler(h gin.HandlerFunc) (out []gin.HandlerFunc) {
|
||||
}
|
||||
}
|
||||
val := newRateLimit()
|
||||
if err := env.Cache.Set(rip, val, block_int); err != nil {
|
||||
if err := env.Cache.Set(rip, val, block_mem); err != nil {
|
||||
loger.Error(`写入内存: %s`, err)
|
||||
return &resp.Resp{Code: 4, Msg: `速率限制内部异常,请联系网站管理员`}
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ const httpRequest = (url, options) => new Promise((resolve, reject) => {
|
||||
const musicUrl = async (source, info, quality) => {
|
||||
const start = new Date().getTime();
|
||||
const id = info.hash ?? info.copyrightId ?? info.songmid // 音乐id kg源为hash, mg源为copyrightId
|
||||
const ext = source == 'kg' ? info.albumId : source == 'tx' ? info.strMediaMid : ''
|
||||
const ext = source == 'kg' ? info.albumId : '' //source == 'tx' ? info.strMediaMid
|
||||
const query = `${source}/${id}${(ext != '' && ext != void 0) ? '-' + ext : ''}/${quality}`
|
||||
console.log('创建任务: %s, 音乐信息: %O', query, info)
|
||||
const body = await httpRequest(`${apiaddr}link/${query}`, { method: 'get' });
|
||||
|
@ -21,22 +21,26 @@ var (
|
||||
defQuality = []string{`128k`, `320k`, `flac`, `flac24bit`}
|
||||
// 试听音质
|
||||
tstQuality = []string{`128k`}
|
||||
// 标准音质
|
||||
stdQuality = []string{`128k`, `320k`, `flac`}
|
||||
)
|
||||
|
||||
// 自动生成支持的音质表
|
||||
func loadQMap() [][]string {
|
||||
m := make([][]string, 6)
|
||||
// 0.wy
|
||||
m[0] = defQuality
|
||||
if env.Config.Custom.Wy_Enable {
|
||||
m[0] = defQuality
|
||||
}
|
||||
// 1.mg
|
||||
m[1] = defQuality
|
||||
// 2.kw
|
||||
m[2] = []string{`128k`, `320k`, `flac`}
|
||||
m[2] = stdQuality
|
||||
// 3.kg
|
||||
m[3] = tstQuality
|
||||
// 4.tx
|
||||
if env.Config.Custom.Tx_Enable {
|
||||
m[4] = defQuality
|
||||
m[4] = stdQuality
|
||||
} else {
|
||||
m[4] = tstQuality
|
||||
}
|
||||
@ -64,11 +68,11 @@ func InitRouter() *gin.Engine {
|
||||
`github`: `https://github.com/ZxwyWebSite/lx-source`,
|
||||
// 可用平台
|
||||
`source`: gin.H{
|
||||
`wy`: qmap[0], //true,
|
||||
`mg`: qmap[1], //true,
|
||||
`kw`: qmap[2], //true,
|
||||
`kg`: qmap[3], //[]string{`128k`, `320k`}, // 测试结构2, 启用时返回音质列表, 禁用为false
|
||||
`tx`: qmap[4], //gin.H{ // "测试结构 不代表最终方式"
|
||||
sources.S_wy: qmap[0], //true,
|
||||
sources.S_mg: qmap[1], //true,
|
||||
sources.S_kw: qmap[2], //true,
|
||||
sources.S_kg: qmap[3], //[]string{`128k`, `320k`}, // 测试结构2, 启用时返回音质列表, 禁用为false
|
||||
sources.S_tx: qmap[4], //gin.H{ // "测试结构 不代表最终方式"
|
||||
// `enable`: false,
|
||||
// `qualitys`: []string{`128k`, `320k`, `flac`, `flac24bit`},
|
||||
// },
|
||||
@ -177,8 +181,8 @@ func linkHandler(c *gin.Context) {
|
||||
env.Cache.Set(cquery.Query(), ``, 600) // 发生错误的10分钟内禁止再次查询
|
||||
return &resp.Resp{Code: 2, Msg: emsg}
|
||||
}
|
||||
// 缓存并获取直链
|
||||
if outlink != `` && cstat && !ztool.Chk_IsMatch(cquery.Source, `kg`, `tx`) {
|
||||
// 缓存并获取直链 !(s == `kg` || (s == `tx` && !tx_en)) => (s != `kg` && (s != `tx` || tx_en))
|
||||
if outlink != `` && cstat && cquery.Source != sources.S_kg && (cquery.Source != sources.S_tx || env.Config.Custom.Tx_Enable) {
|
||||
sc.Debug(`Method: Set, Link: %v`, outlink)
|
||||
if link := caches.UseCache.Set(cquery, outlink); link != `` {
|
||||
env.Cache.Set(cquery.Query(), link, 3600)
|
||||
|
@ -25,7 +25,7 @@ func (s *Source) Verify(c *caches.Query) (rquery string, ok bool) {
|
||||
|
||||
var (
|
||||
// 并发对象池 (用户限制在Router处实现)
|
||||
wy_pool = &sync.Pool{New: func() any { return new(FyApi_Song) }}
|
||||
wy_pool = &sync.Pool{New: func() any { return new(WyApi_Song) }}
|
||||
mg_pool = &sync.Pool{New: func() any { return new(MgApi_Song) }}
|
||||
kw_pool = &sync.Pool{New: func() any { return new(KwApi_Song) }}
|
||||
kg_pool = &sync.Pool{New: func() any { return new(KgApi_Song) }}
|
||||
@ -35,12 +35,13 @@ var (
|
||||
const (
|
||||
errHttpReq = `无法连接解析接口`
|
||||
errNoLink = `无法获取试听链接`
|
||||
errDisable = `该音乐源已被禁用`
|
||||
)
|
||||
|
||||
// 查询
|
||||
func (s *Source) GetLink(c *caches.Query) (outlink string, msg string) {
|
||||
rquery, ok := s.Verify(c)
|
||||
if !ok {
|
||||
if !ok /*&& c.Source != `tx`*/ {
|
||||
msg = sources.Err_Verify //`Verify Failed`
|
||||
return
|
||||
}
|
||||
@ -48,14 +49,20 @@ func (s *Source) GetLink(c *caches.Query) (outlink string, msg 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)
|
||||
if !env.Config.Custom.Wy_Enable {
|
||||
msg = errDisable
|
||||
return
|
||||
}
|
||||
resp := wy_pool.Get().(*WyApi_Song)
|
||||
defer wy_pool.Put(resp)
|
||||
|
||||
url := ztool.Str_FastConcat(`http://`, api_wy, `?id=`, c.MusicID, `&level=`, rquery, `&noCookie=true`)
|
||||
// url := ztool.Str_FastConcat(`http://`, api_wy, `?id=`, c.MusicID, `&level=`, rquery, `&noCookie=true`)
|
||||
url := ztool.Str_FastConcat(`https://`, api_wy, `&id=`, c.MusicID, `&level=`, rquery, `&encodeType=`, c.Extname)
|
||||
// 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, header_wy, &resp)
|
||||
_, err := ztool.Net_HttpReq(http.MethodGet, url, nil, nil, &resp)
|
||||
if err != nil {
|
||||
jx.Error(`HttpReq, Err: %s, ReTry: %v`, err, i)
|
||||
if i > 3 {
|
||||
|
File diff suppressed because one or more lines are too long
@ -1,5 +1,11 @@
|
||||
package tx
|
||||
|
||||
import (
|
||||
"lx-source/src/env"
|
||||
|
||||
"github.com/ZxwyWebSite/ztool/logs"
|
||||
)
|
||||
|
||||
// func Info(songMid string) (info any, msg string) {
|
||||
// req, emsg := getMusicInfo(songMid)
|
||||
// if emsg != `` {
|
||||
@ -23,3 +29,12 @@ package tx
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
|
||||
func Init() {
|
||||
if env.Config.Custom.Tx_Refresh_Enable {
|
||||
env.Tasker.Add(`refresh_login`, func(l *logs.Logger) error {
|
||||
refresh(l)
|
||||
return nil
|
||||
}, 86000, true)
|
||||
}
|
||||
}
|
||||
|
@ -218,30 +218,3 @@ func getMusicInfo(songMid string) (infoBody musicInfo, emsg string) {
|
||||
infoBody = infoResp.Req.Data
|
||||
return //infoBody.Req.Data, ``
|
||||
}
|
||||
|
||||
// func (infoBody *musicInfo) GetLink(songMid, strFileName string) (ourl, msg string) {
|
||||
// var uauthst, uuin string = env.Config.Custom.Tx_Ukey, env.Config.Custom.Tx_Uuin
|
||||
// if uuin == `` {
|
||||
// uuin = `1535153710`
|
||||
// }
|
||||
// requestBody := ztool.Str_FastConcat(`{"comm":{"authst":"`, uauthst, `","ct":"26","cv":"2010101","qq":"`, uuin, `","v":"2010101"},"req_0":{"method":"CgiGetVkey","module":"vkey.GetVkeyServer","param":{"filename":["`, strFileName, `"],"guid":"114514","loginflag":1,"platform":"20","songmid":["`, songMid, `"],"songtype":[0],"uin":"10086"}}}`)
|
||||
// var infoResp struct {
|
||||
// Code int `json:"code"`
|
||||
// // Ts int64 `json:"ts"`
|
||||
// // StartTs int64 `json:"start_ts"`
|
||||
// // Traceid string `json:"traceid"`
|
||||
// Req0 playInfo `json:"req_0"`
|
||||
// }
|
||||
// err := signRequest(bytesconv.StringToBytes(requestBody), &infoResp)
|
||||
// if err != nil {
|
||||
// msg = err.Error()
|
||||
// return
|
||||
// }
|
||||
// infoData := infoResp.Req0.Data.Midurlinfo[0]
|
||||
// if infoData.Purl == `` {
|
||||
// msg = `无法获取音乐链接`
|
||||
// return
|
||||
// }
|
||||
// ourl = infoData.Purl
|
||||
// return
|
||||
// }
|
||||
|
@ -2,6 +2,7 @@ package tx
|
||||
|
||||
import (
|
||||
"lx-source/src/env"
|
||||
"lx-source/src/sources"
|
||||
"strings"
|
||||
|
||||
"github.com/ZxwyWebSite/ztool"
|
||||
@ -85,21 +86,25 @@ type playInfo struct {
|
||||
if没有链接:
|
||||
报错
|
||||
返回结果
|
||||
更新:
|
||||
可通过 goto loop 实现,但可能会导致逻辑混乱 (想使用账号获取正常链接却返回试听链接)
|
||||
*/
|
||||
|
||||
func Url(songMid, quality string) (ourl, msg string) {
|
||||
loger := env.Loger.NewGroup(`Tx`)
|
||||
infoFile, ok := fileInfo[quality]
|
||||
if !ok {
|
||||
if !ok || (!env.Config.Custom.Tx_Enable && quality != sources.Q_128k) {
|
||||
msg = `不支持的音质`
|
||||
return
|
||||
}
|
||||
infoBody, emsg := getMusicInfo(songMid)
|
||||
loger.Debug(`infoBody: %+v`, infoBody)
|
||||
if emsg != `` {
|
||||
msg = emsg
|
||||
return
|
||||
}
|
||||
var uauthst, uuin string = env.Config.Custom.Tx_Ukey, env.Config.Custom.Tx_Uuin
|
||||
if uuin == `` {
|
||||
if uuin == `` || !env.Config.Custom.Tx_Enable {
|
||||
uuin = `1535153710`
|
||||
}
|
||||
var strFileName string
|
||||
@ -122,6 +127,7 @@ func Url(songMid, quality string) (ourl, msg string) {
|
||||
msg = err.Error()
|
||||
return
|
||||
}
|
||||
loger.Debug(`infoResp: %+v`, infoResp)
|
||||
infoData := infoResp.Req0.Data.Midurlinfo[0]
|
||||
if infoData.Purl == `` {
|
||||
msg = `无法获取音乐链接`
|
||||
|
147
src/sources/custom/tx/refresh_login.go
Normal file
147
src/sources/custom/tx/refresh_login.go
Normal file
@ -0,0 +1,147 @@
|
||||
package tx
|
||||
|
||||
import (
|
||||
"lx-source/src/env"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ZxwyWebSite/ztool"
|
||||
"github.com/ZxwyWebSite/ztool/logs"
|
||||
"github.com/ZxwyWebSite/ztool/x/bytesconv"
|
||||
)
|
||||
|
||||
/*type AutoGenerated struct {
|
||||
Code int `json:"code"`
|
||||
Ts int64 `json:"ts"`
|
||||
StartTs int64 `json:"start_ts"`
|
||||
Traceid string `json:"traceid"`
|
||||
Req1 struct {
|
||||
Code int `json:"code"`
|
||||
Data struct {
|
||||
Openid string `json:"openid"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
AccessToken string `json:"access_token"`
|
||||
ExpiredAt int `json:"expired_at"`
|
||||
Musicid int `json:"musicid"`
|
||||
MusicKey string `json:"musickey"`
|
||||
MusickeyCreateTime int `json:"musickeyCreateTime"`
|
||||
FirstLogin int `json:"first_login"`
|
||||
ErrMsg string `json:"errMsg"`
|
||||
SessionKey string `json:"sessionKey"`
|
||||
Unionid string `json:"unionid"`
|
||||
StrMusicId string `json:"str_musicid"`
|
||||
Errtip string `json:"errtip"`
|
||||
Nick string `json:"nick"`
|
||||
Logo string `json:"logo"`
|
||||
FeedbackURL string `json:"feedbackURL"`
|
||||
EncryptUin string `json:"encryptUin"`
|
||||
Userip string `json:"userip"`
|
||||
LastLoginTime int `json:"lastLoginTime"`
|
||||
KeyExpiresIn int `json:"keyExpiresIn"`
|
||||
RefreshKey string `json:"refresh_key"`
|
||||
LoginType int `json:"loginType"`
|
||||
Prompt2Bind int `json:"prompt2bind"`
|
||||
LogoffStatus int `json:"logoffStatus"`
|
||||
OtherAccounts []interface{} `json:"otherAccounts"`
|
||||
OtherPhoneNo string `json:"otherPhoneNo"`
|
||||
Token string `json:"token"`
|
||||
IsPrized int `json:"isPrized"`
|
||||
IsShowDevManage int `json:"isShowDevManage"`
|
||||
ErrTip2 string `json:"errTip2"`
|
||||
Tip3 string `json:"tip3"`
|
||||
EncryptedPhoneNo string `json:"encryptedPhoneNo"`
|
||||
PhoneNo string `json:"phoneNo"`
|
||||
} `json:"data"`
|
||||
} `json:"req1"`
|
||||
}*/
|
||||
|
||||
type refreshData struct {
|
||||
Req1 struct {
|
||||
Code int `json:"code"`
|
||||
Data struct {
|
||||
ExpiredAt int64 `json:"expired_at"` // 过期时间 (Unix)
|
||||
// MusicId int `json:"musicid"` // 数字uid
|
||||
MusicKey string `json:"musickey"` // 账号Key
|
||||
StrMusicId string `json:"str_musicid"` // 字符串uid
|
||||
// KeyExpiresIn int `json:"keyExpiresIn"` // 过期时间 (秒)
|
||||
} `json:"data"`
|
||||
} `json:"req1"`
|
||||
}
|
||||
|
||||
/*
|
||||
刷新登录模块 (移植自Python版)
|
||||
逻辑:
|
||||
1. 使用内存缓存设置过期时间,每次获取链接时取值检查,若没有设置或已过期则尝试刷新Key
|
||||
2. 以计划任务方式运行,每隔一段时间自动执行
|
||||
注:
|
||||
第一次载入时会刷新一次测试可用性&同步过期时间 (默认7天)
|
||||
*/
|
||||
|
||||
func refresh(loger *logs.Logger) {
|
||||
// loger := env.Loger.NewGroup(`refresh_login`)
|
||||
if env.Config.Custom.Tx_Ukey == `` || !env.Config.Custom.Tx_Refresh_Enable {
|
||||
return
|
||||
}
|
||||
if time.Now().Unix() < env.Config.Custom.Tx_Refresh_Interval {
|
||||
loger.Debug(`Key未过期,跳过...`)
|
||||
return
|
||||
}
|
||||
var body, surl string
|
||||
if strings.HasPrefix(env.Config.Custom.Tx_Ukey, `W_X`) {
|
||||
body = ztool.Str_FastConcat(
|
||||
`{"comm":{"authst":"","ct":"11","cv":"12080008","fPersonality":"0","qq":"","tmeAppID":"qqmusic","tmeLoginMethod":"1","tmeLoginType":"1","v":"12080008"},"req1":{"method":"Login","module":"music.login.LoginServer","param":{"code":"","loginMode":2,"musickey":"`,
|
||||
env.Config.Custom.Tx_Ukey,
|
||||
`","openid":"","refresh_key":"","refresh_token":"","str_musicid":"`,
|
||||
env.Config.Custom.Tx_Uuin,
|
||||
`","unionid":""}}}`,
|
||||
)
|
||||
} else if strings.HasPrefix(env.Config.Custom.Tx_Ukey, `Q_H_L`) {
|
||||
body = ztool.Str_FastConcat(
|
||||
`{"req1":{"method":"QQLogin","module":"QQConnectLogin.LoginServer","param":{"expired_in":7776000,"musicid":`,
|
||||
env.Config.Custom.Tx_Uuin,
|
||||
`,"musickey":"`,
|
||||
env.Config.Custom.Tx_Ukey,
|
||||
`"}}}`,
|
||||
)
|
||||
surl = `6`
|
||||
} else {
|
||||
loger.Error(`未知的qqmusic_key格式`)
|
||||
env.Config.Custom.Tx_Refresh_Enable = false // 本次启动阻止继续执行
|
||||
return
|
||||
}
|
||||
loger.Debug(`Body: %v`, body)
|
||||
var resp refreshData
|
||||
signature := sign(bytesconv.StringToBytes(body))
|
||||
err := ztool.Net_Request(http.MethodPost,
|
||||
ztool.Str_FastConcat(`https://u`, surl, `.y.qq.com/cgi-bin/musics.fcg?sign=`, signature),
|
||||
strings.NewReader(body),
|
||||
[]ztool.Net_ReqHandlerFunc{
|
||||
ztool.Net_ReqAddHeaders(header),
|
||||
},
|
||||
[]ztool.Net_ResHandlerFunc{
|
||||
ztool.Net_ResToStruct(&resp),
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
loger.Error(`请求Api失败: %s`, err)
|
||||
return
|
||||
}
|
||||
if resp.Req1.Code != 0 {
|
||||
loger.Warn("刷新登录失败, code: %v\n响应体: %+v", resp.Req1.Code, resp)
|
||||
return
|
||||
}
|
||||
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 = resp.Req1.Data.ExpiredAt - 86000 // 提前一天
|
||||
loger.Debug(`Resp: %+v`, resp)
|
||||
loger.Debug(`Uuin: %v, Ukey: %v`, resp.Req1.Data.StrMusicId, resp.Req1.Data.MusicKey)
|
||||
loger.Debug(`ExpiresAt: %v`, resp.Req1.Data.ExpiredAt)
|
||||
err = env.Cfg.Save(``)
|
||||
if err != nil {
|
||||
loger.Error(`%s`, err)
|
||||
return
|
||||
}
|
||||
loger.Info(`数据更新成功`) // 已通过相应数据更新uin和qqmusic_key
|
||||
}
|
@ -46,6 +46,9 @@ var (
|
||||
`Q000`: `dolby`,
|
||||
`AI00`: `master`,
|
||||
}
|
||||
header = map[string]string{
|
||||
`Referer`: `https://y.qq.com/`,
|
||||
}
|
||||
)
|
||||
|
||||
func signRequest(data []byte, out any) error {
|
||||
@ -54,9 +57,7 @@ func signRequest(data []byte, out any) error {
|
||||
ztool.Str_FastConcat(`https://u.y.qq.com/cgi-bin/musics.fcg?format=json&sign=`, s),
|
||||
bytes.NewReader(data),
|
||||
[]ztool.Net_ReqHandlerFunc{
|
||||
ztool.Net_ReqAddHeaders(map[string]string{
|
||||
`Referer`: `https://y.qq.com/`,
|
||||
}),
|
||||
ztool.Net_ReqAddHeaders(header),
|
||||
},
|
||||
[]ztool.Net_ResHandlerFunc{
|
||||
ztool.Net_ResToStruct(out),
|
||||
|
14
update.md
14
update.md
@ -1,5 +1,19 @@
|
||||
## Lx-Source/更新日志
|
||||
|
||||
#### \# 2024-01-07 v1.0.2-b0.9 (beta)
|
||||
<!-- + 不再导出 `public` 目录,源脚本统一到 `/lx-custom-source.js` 获取
|
||||
+ 为每个源单独设置直链缓存时间 -->
|
||||
+ 开启tx源账号解析时启用文件缓存
|
||||
+ 移植tx源刷新登录功能
|
||||
+ 注:之前没有登录过手机qq音乐的账号签到可免费领绿钻会员
|
||||
+ **已知问题:生成直链会暴露uin且无法移除,共享时请务必使用缓存**
|
||||
+ 完善速率限制功能:增加容忍限度、封禁时间,详见配置注释
|
||||
+ 准备弃用"MusicId-字符串"传附加参数的方式
|
||||
+ 计划:重构音质对应表部分,每个源使用独立音质表
|
||||
+ 更换wy内置接口为qz源
|
||||
+ 默认监听地址改为127.0.0.1
|
||||
<!-- + *内置接口失效,暂时禁用wy源 (如恢复可修改 [Custom].Wy_Enable=true)* -->
|
||||
|
||||
#### \# 2024-01-01 v1.0.2-b0.8 (beta)
|
||||
+ 注:新年第一次更新,祝大家听歌愉快
|
||||
- 根据源启用状态生成支持音质表
|
||||
|
Loading…
x
Reference in New Issue
Block a user