Feat: 获取&写入 音频文件的 Metadata #43
@ -10,28 +10,23 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const endpointURL = "https://u.y.qq.com/cgi-bin/musicu.fcg"
|
|
||||||
|
|
||||||
type QQMusic struct {
|
type QQMusic struct {
|
||||||
http *http.Client
|
http *http.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *QQMusic) doRequest(ctx context.Context, reqBody any) ([]byte, error) {
|
func (c *QQMusic) rpcDoRequest(ctx context.Context, reqBody any) ([]byte, error) {
|
||||||
reqBodyBuf, ok := reqBody.([]byte)
|
reqBodyBuf, err := json.Marshal(reqBody)
|
||||||
if !ok {
|
|
||||||
var err error
|
|
||||||
reqBodyBuf, err = json.Marshal(reqBody)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("qqMusicClient[doRequest] marshal request: %w", err)
|
return nil, fmt.Errorf("qqMusicClient[rpcDoRequest] marshal request: %w", err)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const endpointURL = "https://u.y.qq.com/cgi-bin/musicu.fcg"
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost,
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost,
|
||||||
endpointURL+fmt.Sprintf("?pcachetime=%d", time.Now().Unix()),
|
endpointURL+fmt.Sprintf("?pcachetime=%d", time.Now().Unix()),
|
||||||
bytes.NewReader(reqBodyBuf),
|
bytes.NewReader(reqBodyBuf),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("qqMusicClient[doRequest] create request: %w", err)
|
return nil, fmt.Errorf("qqMusicClient[rpcDoRequest] create request: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Header.Set("Accept", "*/*")
|
req.Header.Set("Accept", "*/*")
|
||||||
@ -42,13 +37,13 @@ func (c *QQMusic) doRequest(ctx context.Context, reqBody any) ([]byte, error) {
|
|||||||
|
|
||||||
reqp, err := c.http.Do(req)
|
reqp, err := c.http.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("qqMusicClient[doRequest] send request: %w", err)
|
return nil, fmt.Errorf("qqMusicClient[rpcDoRequest] send request: %w", err)
|
||||||
}
|
}
|
||||||
defer reqp.Body.Close()
|
defer reqp.Body.Close()
|
||||||
|
|
||||||
respBodyBuf, err := io.ReadAll(reqp.Body)
|
respBodyBuf, err := io.ReadAll(reqp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("qqMusicClient[doRequest] read response: %w", err)
|
return nil, fmt.Errorf("qqMusicClient[rpcDoRequest] read response: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return respBodyBuf, nil
|
return respBodyBuf, nil
|
||||||
@ -82,7 +77,7 @@ func (c *QQMusic) rpcCall(ctx context.Context,
|
|||||||
Param: param,
|
Param: param,
|
||||||
}}
|
}}
|
||||||
|
|
||||||
respBodyBuf, err := c.doRequest(ctx, reqBody)
|
respBodyBuf, err := c.rpcDoRequest(ctx, reqBody)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("qqMusicClient[rpcCall] do request: %w", err)
|
return nil, fmt.Errorf("qqMusicClient[rpcCall] do request: %w", err)
|
||||||
}
|
}
|
||||||
|
52
algo/qmc/client/search.go
Normal file
52
algo/qmc/client/search.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type searchParams struct {
|
||||||
|
Grp int `json:"grp"`
|
||||||
|
NumPerPage int `json:"num_per_page"`
|
||||||
|
PageNum int `json:"page_num"`
|
||||||
|
Query string `json:"query"`
|
||||||
|
RemotePlace string `json:"remoteplace"`
|
||||||
|
SearchType int `json:"search_type"`
|
||||||
|
//SearchID string `json:"searchid"` // todo: it seems generated randomly
|
||||||
|
}
|
||||||
|
|
||||||
|
type searchResponse struct {
|
||||||
|
Body struct {
|
||||||
|
Song struct {
|
||||||
|
List []*TrackInfo `json:"list"`
|
||||||
|
} `json:"song"`
|
||||||
|
} `json:"body"`
|
||||||
|
Code int `json:"code"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *QQMusic) Search(ctx context.Context, keyword string) ([]*TrackInfo, error) {
|
||||||
|
|
||||||
|
resp, err := c.rpcCall(ctx,
|
||||||
|
"music.search.SearchCgiService",
|
||||||
|
"DoSearchForQQMusicDesktop",
|
||||||
|
"music.search.SearchCgiService",
|
||||||
|
&searchParams{
|
||||||
|
SearchType: 0, Query: keyword,
|
||||||
|
PageNum: 1, NumPerPage: 40,
|
||||||
|
|
||||||
|
// static values
|
||||||
|
Grp: 1, RemotePlace: "sizer.newclient.song",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("qqMusicClient[Search] rpc call: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
respData := searchResponse{}
|
||||||
|
if err := json.Unmarshal(resp, &respData); err != nil {
|
||||||
|
return nil, fmt.Errorf("qqMusicClient[Search] unmarshal response: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return respData.Body.Song.List, nil
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user