feat(qmc): add search interface

pull/43/head
Unlock Music Dev 2 years ago
parent 3cf542c84c
commit f60f0b3d07
No known key found for this signature in database
GPG Key ID: 95202E10D3413A1D

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

@ -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…
Cancel
Save