alist/drivers/netease_music/util.go

247 lines
5.2 KiB
Go

package netease_music
import (
"io"
"net/http"
"path"
"regexp"
"strconv"
"strings"
"time"
"github.com/alist-org/alist/v3/drivers/base"
"github.com/alist-org/alist/v3/internal/errs"
"github.com/alist-org/alist/v3/internal/model"
"github.com/alist-org/alist/v3/pkg/utils"
)
func (d *NeteaseMusic) request(url, method string, opt ReqOption) ([]byte, error) {
req := base.RestyClient.R()
req.SetHeader("Cookie", d.Addition.Cookie)
if strings.Contains(url, "music.163.com") {
req.SetHeader("Referer", "https://music.163.com")
}
if opt.cookies != nil {
for _, cookie := range opt.cookies {
req.SetCookie(cookie)
}
}
if opt.headers != nil {
for header, value := range opt.headers {
req.SetHeader(header, value)
}
}
data := opt.data
if opt.crypto == "weapi" {
data = weapi(data)
re, _ := regexp.Compile(`/\w*api/`)
url = re.ReplaceAllString(url, "/weapi/")
} else if opt.crypto == "eapi" {
ch := new(Characteristic).fromDriver(d)
req.SetCookies(ch.toCookies())
data = eapi(opt.url, ch.merge(data))
re, _ := regexp.Compile(`/\w*api/`)
url = re.ReplaceAllString(url, "/eapi/")
} else if opt.crypto == "linuxapi" {
re, _ := regexp.Compile(`/\w*api/`)
data = linuxapi(map[string]interface{}{
"url": re.ReplaceAllString(url, "/api/"),
"method": method,
"params": data,
})
req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36")
url = "https://music.163.com/api/linux/forward"
}
if method == http.MethodPost {
if opt.stream != nil {
req.SetContentLength(true)
req.SetBody(io.ReadCloser(opt.stream))
} else {
req.SetFormData(data)
}
res, err := req.Post(url)
return res.Body(), err
}
if method == http.MethodGet {
res, err := req.Get(url)
return res.Body(), err
}
return nil, errs.NotImplement
}
func (d *NeteaseMusic) getSongObjs(args model.ListArgs) ([]model.Obj, error) {
body, err := d.request("https://music.163.com/weapi/v1/cloud/get", http.MethodPost, ReqOption{
crypto: "weapi",
data: map[string]string{
"limit": strconv.FormatUint(d.Addition.SongLimit, 10),
"offset": "0",
},
cookies: []*http.Cookie{
{Name: "os", Value: "pc"},
},
})
if err != nil {
return nil, err
}
var resp ListResp
err = utils.Json.Unmarshal(body, &resp)
if err != nil {
return nil, err
}
d.fileMapByName = make(map[string]model.Obj)
files := make([]model.Obj, 0, len(resp.Data))
for _, f := range resp.Data {
song := &model.ObjThumb{
Object: model.Object{
IsFolder: false,
Size: f.FileSize,
Name: f.FileName,
Modified: time.UnixMilli(f.AddTime),
ID: strconv.FormatInt(f.SongId, 10),
},
Thumbnail: model.Thumbnail{Thumbnail: f.SimpleSong.Al.PicUrl},
}
d.fileMapByName[song.Name] = song
files = append(files, song)
// map song id for lyric
lrcName := strings.Split(f.FileName, ".")[0] + ".lrc"
lrc := &model.Object{
IsFolder: false,
Name: lrcName,
Path: path.Join(args.ReqPath, lrcName),
ID: strconv.FormatInt(f.SongId, 10),
}
d.fileMapByName[lrc.Name] = lrc
}
return files, nil
}
func (d *NeteaseMusic) getSongLink(file model.Obj) (*model.Link, error) {
body, err := d.request(
"https://music.163.com/api/song/enhance/player/url", http.MethodPost, ReqOption{
crypto: "linuxapi",
data: map[string]string{
"ids": "[" + file.GetID() + "]",
"br": "999000",
},
cookies: []*http.Cookie{
{Name: "os", Value: "pc"},
},
},
)
if err != nil {
return nil, err
}
var resp SongResp
err = utils.Json.Unmarshal(body, &resp)
if err != nil {
return nil, err
}
if len(resp.Data) < 1 {
return nil, errs.ObjectNotFound
}
return &model.Link{URL: resp.Data[0].Url}, nil
}
func (d *NeteaseMusic) getLyricObj(file model.Obj) (model.Obj, error) {
if lrc, ok := file.(*LyricObj); ok {
return lrc, nil
}
body, err := d.request(
"https://music.163.com/api/song/lyric?_nmclfl=1", http.MethodPost, ReqOption{
data: map[string]string{
"id": file.GetID(),
"tv": "-1",
"lv": "-1",
"rv": "-1",
"kv": "-1",
},
cookies: []*http.Cookie{
{Name: "os", Value: "ios"},
},
},
)
if err != nil {
return nil, err
}
lyric := utils.Json.Get(body, "lrc", "lyric").ToString()
return &LyricObj{
lyric: lyric,
Object: model.Object{
IsFolder: false,
ID: file.GetID(),
Name: file.GetName(),
Path: file.GetPath(),
Size: int64(len(lyric)),
},
}, nil
}
func (d *NeteaseMusic) removeSongObj(file model.Obj) error {
_, err := d.request("http://music.163.com/weapi/cloud/del", http.MethodPost, ReqOption{
crypto: "weapi",
data: map[string]string{
"songIds": "[" + file.GetID() + "]",
},
})
return err
}
func (d *NeteaseMusic) putSongStream(stream model.FileStreamer) error {
tmp, err := stream.CacheFullInTempFile()
if err != nil {
return err
}
defer tmp.Close()
u := uploader{driver: d, file: tmp}
err = u.init(stream)
if err != nil {
return err
}
err = u.checkIfExisted()
if err != nil {
return err
}
token, err := u.allocToken()
if err != nil {
return err
}
if u.meta.needUpload {
err = u.upload(stream)
if err != nil {
return err
}
}
err = u.publishInfo(token.resourceId)
if err != nil {
return err
}
return nil
}