update kugou playlist

This commit is contained in:
aynakeya
2024-12-06 01:34:23 -08:00
parent ad1c0c2427
commit 7beb87edff
6 changed files with 185 additions and 12 deletions

View File

@@ -213,7 +213,7 @@ func (k *Kugou) GetMediaUrl(meta miaosic.MetaData, quality miaosic.Quality) ([]m
if err != nil {
return nil, err
}
fmt.Println(urlResp.String())
//fmt.Println(urlResp.String())
urlJson := gjson.ParseBytes(urlResp.Body())
if !urlJson.Get("url").Exists() {
return nil, errors.New("kugou: failed to get media url, might be vip only")

View File

@@ -1,11 +1,138 @@
package kugou
import "github.com/AynaLivePlayer/miaosic"
import (
"encoding/json"
"errors"
"fmt"
"github.com/AynaLivePlayer/miaosic"
"github.com/aynakeya/deepcolor"
"github.com/tidwall/gjson"
"net/http"
"strings"
)
func (k *Kugou) MatchPlaylist(uri string) (miaosic.MetaData, bool) {
return miaosic.MetaData{}, false
}
func (k *Kugou) GetPlaylist(meta miaosic.MetaData) (*miaosic.Playlist, error) {
return nil, miaosic.ErrNotImplemented
func (k *Kugou) getCollectionId(gcid string) (string, error) {
data := map[string]interface{}{
"data": []map[string]interface{}{
{
"id": gcid, "id_type": "1",
},
},
"ret_info": 1,
}
dataBytes, _ := json.Marshal(data)
param := k.addAndroidParams(map[string]interface{}{}, string(dataBytes))
urlReq, _ := deepcolor.NewGetRequestWithQuery(
"https://t.kugou.com/v1/songlist/batch_decode",
param, map[string]string{},
)
urlReq.Method = http.MethodPost
urlReq.Data = dataBytes
resp, err := miaosic.Requester.HTTP(urlReq)
if err != nil {
return "", err
}
collId := gjson.Get(resp.String(), "data.list.0.global_collection_id").String()
if collId == "" {
return "", fmt.Errorf("kugou: failed to get collection id")
}
return collId, nil
}
func (k *Kugou) getPlaylistTitle(collId string) (string, error) {
data := map[string]interface{}{
"data": []map[string]interface{}{
{
"global_collection_id": collId,
},
},
"userid": "0",
"token": "",
}
dataBytes, _ := json.Marshal(data)
param := k.addAndroidParams(map[string]interface{}{}, string(dataBytes))
urlReq, _ := deepcolor.NewGetRequestWithQuery(
"https://gateway.kugou.com/v3/get_list_info",
param, map[string]string{
"x-router": "pubsongs.kugou.com",
},
)
urlReq.Method = http.MethodPost
urlReq.Data = dataBytes
resp, err := miaosic.Requester.HTTP(urlReq)
if err != nil {
return "", err
}
title := gjson.Get(resp.String(), "data.0.name").String()
if title == "" {
return "", fmt.Errorf("kugou: failed to get playlist title")
}
return title, nil
}
func (k *Kugou) GetPlaylist(meta miaosic.MetaData) (*miaosic.Playlist, error) {
collId := meta.Identifier
if !strings.HasPrefix(collId, "collection_") {
var err error
collId, err = k.getCollectionId(collId)
if err != nil {
return nil, err
}
}
params := map[string]interface{}{
"global_collection_id": collId,
"pagesize": 100,
"plat": 1,
"type": 1,
"area_code": 1,
"begin_idx": 0,
}
playlist := &miaosic.Playlist{
Meta: meta,
Title: "Kugou Collection " + collId,
Medias: make([]miaosic.MediaInfo, 0),
}
title, err := k.getPlaylistTitle(collId)
if err == nil {
playlist.Title = title
}
for page := 0; page < 25; page++ {
params["begin_idx"] = page * 100
params = k.addAndroidParams(params, "")
urlReq, _ := deepcolor.NewGetRequestWithQuery(
"https://gateway.kugou.com/pubsongs/v2/get_other_list_file_nofilt",
params, map[string]string{},
)
resp, err := miaosic.Requester.HTTP(urlReq)
if err != nil {
return nil, err
}
result := gjson.ParseBytes(resp.Body())
if result.Get("error_code").Int() != 0 {
return nil, errors.New("kugou: get playlist error")
}
count := int(result.Get("data.count").Int())
medias := result.Get("data.songs")
medias.ForEach(func(key, value gjson.Result) bool {
playlist.Medias = append(playlist.Medias, miaosic.MediaInfo{
Title: value.Get("name").String(),
Cover: miaosic.Picture{Url: strings.Replace(value.Get("cover").String(), "{size}", "128", 1)},
Artist: value.Get("singerinfo.0.name").String(),
Album: value.Get("albuminfo.name").String(),
Meta: miaosic.MetaData{
Provider: k.GetName(),
Identifier: value.Get("hash").String(),
},
})
return true
})
if page*100+100 >= count {
break
}
}
return playlist, nil
}

View File

@@ -0,0 +1,26 @@
package kugou
import (
"fmt"
"github.com/AynaLivePlayer/miaosic"
"github.com/stretchr/testify/require"
"testing"
)
func TestKugou_GetPlaylist(t *testing.T) {
playlist, err := testApi.GetPlaylist(miaosic.MetaData{Identifier: "gcid_3zfcfgjcz31z06d"})
require.NoError(t, err)
fmt.Println(playlist.Medias)
}
func TestKugou_getCollectionId(t *testing.T) {
val, err := testApi.getCollectionId("gcid_3zfcfgjcz31z06d")
require.NoError(t, err)
require.Equal(t, "collection_3_806499027_106_0", val)
}
func TestKugou_getPlaylistTitle(t *testing.T) {
val, err := testApi.getPlaylistTitle("collection_3_806499027_106_0")
require.NoError(t, err)
require.Equal(t, "emo伤感天花板来自0.8×的孤独与失恋", val)
}

View File

@@ -0,0 +1,5 @@
part of code is inspired by
https://github.com/MakcRe/KuGouMusicApi
under MIT License

View File

@@ -6,8 +6,8 @@ import (
"encoding/json"
"fmt"
"sort"
"strconv"
"strings"
"time"
)
const (
@@ -26,12 +26,6 @@ func signKey(appid string, hash, mid, userid string) string {
return getMD5Hash(data)
}
// signParamsKey encrypts the given parameters and returns the encrypted signParams.
func signParamsKey(data int64) string {
dataStr := appid + signkeyLite + clientver + strconv.FormatInt(data, 10)
return getMD5Hash(dataStr)
}
func signatureAndroidParams(signkey string, params map[string]interface{}, data string) string {
// Sort the keys of the params map
keys := make([]string, 0, len(params))
@@ -56,7 +50,7 @@ func signatureAndroidParams(signkey string, params map[string]interface{}, data
}
// Generate the MD5 hash
hash := md5.Sum([]byte(signkey + paramsString.String() + string(data) + signkey))
hash := md5.Sum([]byte(signkey + paramsString.String() + data + signkey))
return hex.EncodeToString(hash[:])
}
@@ -81,3 +75,24 @@ func signatureWebParams(params map[string]string) string {
hash := md5.Sum([]byte(str + paramsString.String() + str))
return strings.ToUpper(hex.EncodeToString(hash[:]))
}
func (k *Kugou) addAndroidParams(params map[string]interface{}, data string) map[string]interface{} {
if token, ok := k.cookie["token"]; ok {
params["token"] = token
} else {
params["token"] = ""
}
if userId, ok := k.cookie["userid"]; ok {
params["userid"] = userId
} else {
params["userid"] = "0"
}
params["appid"] = k.appid
params["clientver"] = k.clientver
params["dfid"] = k.dfid
params["mid"] = getMD5Hash(k.dfid)
params["uuid"] = getMD5Hash(k.dfid)
params["clienttime"] = fmt.Sprintf("%d", time.Now().Unix())
params["signature"] = signatureAndroidParams(k.signkey, params, data)
return params
}