mirror of https://github.com/Xhofe/alist
247 lines
5.2 KiB
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
|
|
}
|