mirror of
https://github.com/AynaLivePlayer/miaosic.git
synced 2025-12-12 07:48:12 +08:00
update api
This commit is contained in:
@@ -1,77 +1,41 @@
|
||||
package bilibili
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/AynaLivePlayer/miaosic"
|
||||
"github.com/AynaLivePlayer/miaosic/providers"
|
||||
"github.com/aynakeya/deepcolor"
|
||||
"github.com/aynakeya/deepcolor/dphttp"
|
||||
"github.com/tidwall/gjson"
|
||||
"miaosic"
|
||||
"miaosic/providers"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
var _ = (miaosic.MediaProvider)(&Bilibili{})
|
||||
|
||||
type Bilibili struct {
|
||||
providers.DeepcolorProvider
|
||||
requester dphttp.IRequester
|
||||
IdRegex0 *regexp.Regexp
|
||||
IdRegex1 *regexp.Regexp
|
||||
header map[string]string
|
||||
IdRegex0 *regexp.Regexp
|
||||
IdRegex1 *regexp.Regexp
|
||||
header map[string]string
|
||||
}
|
||||
|
||||
func NewBilibili(requester dphttp.IRequester) *Bilibili {
|
||||
func NewBilibili() *Bilibili {
|
||||
bili := &Bilibili{
|
||||
requester: requester,
|
||||
IdRegex0: regexp.MustCompile("^[0-9]+"),
|
||||
IdRegex1: regexp.MustCompile("^au[0-9]+"),
|
||||
IdRegex0: regexp.MustCompile("^[0-9]+"),
|
||||
IdRegex1: regexp.MustCompile("^au[0-9]+"),
|
||||
header: map[string]string{
|
||||
"user-agent": "BiliMusic/2.233.3",
|
||||
},
|
||||
}
|
||||
bili.initHeader()
|
||||
bili.InfoFunc = bili.buildInfoApi()
|
||||
bili.FileFunc = bili.buildFileApi()
|
||||
bili.SearchFunc = bili.buildSearchApi()
|
||||
return bili
|
||||
}
|
||||
|
||||
func (b *Bilibili) GetName() string {
|
||||
return "bilibili"
|
||||
}
|
||||
|
||||
func (b *Bilibili) MatchMedia(keyword string) *miaosic.Media {
|
||||
if id := b.IdRegex0.FindString(keyword); id != "" {
|
||||
return &miaosic.Media{
|
||||
Meta: miaosic.MediaMeta{
|
||||
Provider: b.GetName(),
|
||||
Identifier: id,
|
||||
},
|
||||
}
|
||||
}
|
||||
if id := b.IdRegex1.FindString(keyword); id != "" {
|
||||
return &miaosic.Media{
|
||||
Meta: miaosic.MediaMeta{
|
||||
Provider: b.GetName(),
|
||||
Identifier: id[2:],
|
||||
},
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Bilibili) MatchPlaylist(keyword string) *miaosic.Playlist {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Bilibili) initHeader() {
|
||||
b.header = map[string]string{
|
||||
"user-agent": "BiliMusic/2.233.3",
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Bilibili) buildInfoApi() dphttp.ApiFunc[*miaosic.Media, *miaosic.Media] {
|
||||
return deepcolor.CreateApiFunc(
|
||||
b.requester,
|
||||
func(media *miaosic.Media) (*dphttp.Request, error) {
|
||||
return deepcolor.NewGetRequestWithSingleQuery("https://www.bilibili.com/audio/music-service-c/web/song/info", "sid", b.header)(media.Meta.Identifier)
|
||||
bili.InfoApi = deepcolor.CreateApiResultFunc(
|
||||
func(meta miaosic.MediaMeta) (*dphttp.Request, error) {
|
||||
return deepcolor.NewGetRequestWithSingleQuery(
|
||||
"https://www.bilibili.com/audio/music-service-c/web/song/info",
|
||||
"sid", meta.Identifier,
|
||||
bili.header)
|
||||
},
|
||||
deepcolor.ParserGJson,
|
||||
func(resp *gjson.Result, media *miaosic.Media) error {
|
||||
func(resp *gjson.Result, media *miaosic.MediaInfo) error {
|
||||
if resp.Get("data.title").String() == "" {
|
||||
return miaosic.ErrorExternalApi
|
||||
}
|
||||
@@ -80,41 +44,47 @@ func (b *Bilibili) buildInfoApi() dphttp.ApiFunc[*miaosic.Media, *miaosic.Media]
|
||||
media.Artist = resp.Get("data.author").String()
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (b *Bilibili) buildFileApi() dphttp.ApiFunc[*miaosic.Media, *miaosic.Media] {
|
||||
return deepcolor.CreateApiFunc(
|
||||
b.requester,
|
||||
func(media *miaosic.Media) (*dphttp.Request, error) {
|
||||
// Assuming the endpoint and query are similar for file details
|
||||
return deepcolor.NewGetRequestWithSingleQuery("https://api.bilibili.com/audio/music-service-c/url?device=phone&mid=8047632&mobi_app=iphone&platform=ios&privilege=2&quality=2", "songid", b.header)(media.Meta.Identifier)
|
||||
bili.FileApi = deepcolor.CreateApiResultFunc(
|
||||
func(param providers.FileApiParam) (*dphttp.Request, error) {
|
||||
// todo: handle quality
|
||||
return deepcolor.NewGetRequestWithSingleQuery(
|
||||
"https://api.bilibili.com/audio/music-service-c/url?device=phone&mid=8047632&mobi_app=iphone&platform=ios&privilege=2&quality=2",
|
||||
"songid", param.Meta.Identifier,
|
||||
bili.header)
|
||||
},
|
||||
deepcolor.ParserGJson,
|
||||
func(resp *gjson.Result, media *miaosic.Media) error {
|
||||
func(resp *gjson.Result, media *[]miaosic.MediaUrl) error {
|
||||
fmt.Println(resp.String())
|
||||
if resp.Get("data.cdns.0").String() == "" {
|
||||
return miaosic.ErrorExternalApi
|
||||
}
|
||||
media.Url = resp.Get("data.cdns.0").String()
|
||||
resp.Get("data.cdns").ForEach(func(key, value gjson.Result) bool {
|
||||
*media = append(*media, miaosic.NewMediaUrl(value.String(), miaosic.QualityUnk))
|
||||
return true
|
||||
})
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (b *Bilibili) buildSearchApi() dphttp.ApiFuncResult[string, []*miaosic.Media] {
|
||||
return deepcolor.CreateApiResultFunc(
|
||||
b.requester,
|
||||
func(query string) (*dphttp.Request, error) {
|
||||
return deepcolor.NewGetRequestWithSingleQuery("https://api.bilibili.com/audio/music-service-c/s?search_type=music&page=1&pagesize=100", "keyword", b.header)(query)
|
||||
bili.SearchApi = deepcolor.CreateApiResultFunc(
|
||||
func(param providers.MediaSearchParam) (*dphttp.Request, error) {
|
||||
return deepcolor.NewGetRequestWithQuery(
|
||||
"https://api.bilibili.com/audio/music-service-c/s?search_type=music",
|
||||
map[string]any{
|
||||
"keyword": param.Keyword,
|
||||
"page": param.Page,
|
||||
"pagesize": param.PageSize,
|
||||
},
|
||||
bili.header)
|
||||
},
|
||||
deepcolor.ParserGJson,
|
||||
func(resp *gjson.Result, result *[]*miaosic.Media) error {
|
||||
func(resp *gjson.Result, result *[]miaosic.MediaInfo) error {
|
||||
// Assuming data contains a list of search results
|
||||
for _, r := range resp.Get("data.result").Array() {
|
||||
media := &miaosic.Media{
|
||||
media := miaosic.MediaInfo{
|
||||
Title: r.Get("title").String(),
|
||||
Cover: miaosic.Picture{Url: r.Get("cover").String()},
|
||||
Artist: r.Get("author").String(),
|
||||
Meta: miaosic.MediaMeta{
|
||||
Provider: b.GetName(),
|
||||
Provider: bili.GetName(),
|
||||
Identifier: r.Get("id").String(),
|
||||
},
|
||||
}
|
||||
@@ -122,4 +92,25 @@ func (b *Bilibili) buildSearchApi() dphttp.ApiFuncResult[string, []*miaosic.Medi
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return bili
|
||||
}
|
||||
|
||||
func (b *Bilibili) GetName() string {
|
||||
return "bilibili"
|
||||
}
|
||||
|
||||
func (b *Bilibili) MatchMedia(keyword string) (miaosic.MediaMeta, bool) {
|
||||
if id := b.IdRegex0.FindString(keyword); id != "" {
|
||||
return miaosic.MediaMeta{
|
||||
Provider: b.GetName(),
|
||||
Identifier: id,
|
||||
}, true
|
||||
}
|
||||
if id := b.IdRegex1.FindString(keyword); id != "" {
|
||||
return miaosic.MediaMeta{
|
||||
Provider: b.GetName(),
|
||||
Identifier: id[2:],
|
||||
}, true
|
||||
}
|
||||
return miaosic.MediaMeta{}, false
|
||||
}
|
||||
|
||||
@@ -1,28 +1,27 @@
|
||||
package bilibili
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/AynaLivePlayer/miaosic"
|
||||
"github.com/stretchr/testify/require"
|
||||
"miaosic"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var api miaosic.MediaProvider = NewBilibili(miaosic.Requester)
|
||||
var api miaosic.MediaProvider = NewBilibili()
|
||||
|
||||
func TestBilibili_Search(t *testing.T) {
|
||||
result, err := api.Search("染 reol")
|
||||
result, err := api.Search("染 reol", 1, 100)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, result)
|
||||
}
|
||||
|
||||
func TestBilibili_GetMusic(t *testing.T) {
|
||||
media := miaosic.Media{
|
||||
Meta: miaosic.MediaMeta{
|
||||
Provider: api.GetName(),
|
||||
Identifier: "1560601",
|
||||
},
|
||||
meta := miaosic.MediaMeta{
|
||||
Provider: api.GetName(),
|
||||
Identifier: "1560601",
|
||||
}
|
||||
require.NoError(t, api.UpdateMedia(&media))
|
||||
require.NoError(t, api.UpdateMediaUrl(&media))
|
||||
fmt.Println(media.Url)
|
||||
_, err := api.GetMediaInfo(meta)
|
||||
require.NoError(t, err)
|
||||
urls, err := api.GetMediaUrl(meta, miaosic.QualityAny)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, urls)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package bilibili
|
||||
|
||||
import (
|
||||
"miaosic"
|
||||
"github.com/AynaLivePlayer/miaosic"
|
||||
)
|
||||
|
||||
func init() {
|
||||
miaosic.RegisterProvider(NewBilibili(miaosic.Requester))
|
||||
miaosic.RegisterProvider(NewBilibili())
|
||||
}
|
||||
|
||||
@@ -3,13 +3,13 @@ package bilivideo
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/AynaLivePlayer/miaosic"
|
||||
"github.com/AynaLivePlayer/miaosic/providers"
|
||||
"github.com/aynakeya/deepcolor"
|
||||
"github.com/aynakeya/deepcolor/dphttp"
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/spf13/cast"
|
||||
"github.com/tidwall/gjson"
|
||||
"miaosic"
|
||||
"miaosic/providers"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
@@ -17,14 +17,14 @@ var _ = (miaosic.MediaProvider)(&BilibiliVideo{})
|
||||
|
||||
type BilibiliVideo struct {
|
||||
providers.DeepcolorProvider
|
||||
requester dphttp.IRequester
|
||||
BVRegex *regexp.Regexp
|
||||
IdRegex *regexp.Regexp
|
||||
PageRegex *regexp.Regexp
|
||||
header map[string]string
|
||||
cidApi dphttp.ApiResultFunc[string, []string]
|
||||
}
|
||||
|
||||
func NewBilibiliViedo(requester dphttp.IRequester) *BilibiliVideo {
|
||||
func NewBilibiliViedo() *BilibiliVideo {
|
||||
headers := map[string]string{
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0",
|
||||
"Referer": "https://www.bilibili.com/",
|
||||
@@ -32,17 +32,76 @@ func NewBilibiliViedo(requester dphttp.IRequester) *BilibiliVideo {
|
||||
"Cookie": "buvid3=9A8B3564-BDA9-407F-B45F-D5C40786CA49167618infoc;",
|
||||
}
|
||||
pvdr := &BilibiliVideo{
|
||||
requester: requester,
|
||||
BVRegex: regexp.MustCompile("^BV[0-9A-Za-z]+"),
|
||||
IdRegex: regexp.MustCompile("^BV[0-9A-Za-z]+(\\?p=[0-9]+)?"),
|
||||
PageRegex: regexp.MustCompile("p=[0-9]+"),
|
||||
header: headers,
|
||||
}
|
||||
pvdr.InfoFunc = pvdr.buildInfoApi()
|
||||
pvdr.InfoApi = deepcolor.CreateApiResultFunc(
|
||||
func(meta miaosic.MediaMeta) (*dphttp.Request, error) {
|
||||
return deepcolor.NewGetRequestWithQuery(
|
||||
"https://api.bilibili.com/x/web-interface/view/detail?&aid=&jsonp=jsonp",
|
||||
map[string]any{
|
||||
"bvid": pvdr.getBv(meta.Identifier),
|
||||
}, pvdr.header,
|
||||
)
|
||||
},
|
||||
deepcolor.ParserGJson,
|
||||
func(result *gjson.Result, media *miaosic.MediaInfo) error {
|
||||
if result.Get("data.View.title").String() == "" {
|
||||
return errors.New("failed to find required data")
|
||||
}
|
||||
media.Title = result.Get("data.View.title").String()
|
||||
media.Artist = result.Get("data.View.owner.name").String()
|
||||
media.Cover.Url = result.Get("data.View.pic").String()
|
||||
return nil
|
||||
})
|
||||
|
||||
pvdr.cidApi = deepcolor.CreateApiResultFunc(
|
||||
deepcolor.NewGetRequestFuncWithSingleQuery(
|
||||
"https://api.bilibili.com/x/web-interface/view/detail?&aid=&jsonp=jsonp", "bvid", pvdr.header),
|
||||
deepcolor.ParserGJson,
|
||||
func(resp *gjson.Result, result *[]string) error {
|
||||
for _, r := range resp.Get("data.View.pages.#.cid").Array() {
|
||||
*result = append(*result, r.String())
|
||||
}
|
||||
if len(*result) == 0 {
|
||||
return errors.New("failed to find cid data")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
//pvdr.FileFunc = buildFileApi(requester, headers)
|
||||
pvdr.LyricFunc = nil
|
||||
//pvdr.PlaylistFunc = buildPlaylistApi(requester, headers)
|
||||
pvdr.SearchFunc = pvdr.buildSearchApi()
|
||||
pvdr.SearchApi = deepcolor.CreateApiResultFunc(
|
||||
func(param providers.MediaSearchParam) (*dphttp.Request, error) {
|
||||
return deepcolor.NewGetRequestWithQuery(
|
||||
"https://api.bilibili.com/x/web-interface/wbi/search/type?search_type=video",
|
||||
map[string]any{
|
||||
"keyword": param.Keyword,
|
||||
"page": param.Page,
|
||||
"page_size": param.PageSize,
|
||||
}, pvdr.header)
|
||||
},
|
||||
deepcolor.ParserGJson,
|
||||
func(resp *gjson.Result, result *[]miaosic.MediaInfo) error {
|
||||
if resp.Get("code").String() != "0" {
|
||||
return errors.New("failed to find required data")
|
||||
}
|
||||
r := regexp.MustCompile("</?em[^>]*>")
|
||||
resp.Get("data.result").ForEach(func(key, value gjson.Result) bool {
|
||||
*result = append(*result, miaosic.MediaInfo{
|
||||
Title: r.ReplaceAllString(value.Get("title").String(), ""),
|
||||
Cover: miaosic.Picture{Url: "https:" + value.Get("pic").String()},
|
||||
Artist: value.Get("author").String(),
|
||||
Meta: miaosic.MediaMeta{
|
||||
Provider: pvdr.GetName(),
|
||||
Identifier: value.Get("bvid").String(),
|
||||
},
|
||||
})
|
||||
return true
|
||||
})
|
||||
return nil
|
||||
})
|
||||
return pvdr
|
||||
}
|
||||
|
||||
@@ -61,120 +120,48 @@ func (b *BilibiliVideo) GetName() string {
|
||||
return "bilibili-video"
|
||||
}
|
||||
|
||||
func (b *BilibiliVideo) MatchMedia(keyword string) *miaosic.Media {
|
||||
func (b *BilibiliVideo) MatchMedia(keyword string) (miaosic.MediaMeta, bool) {
|
||||
if id := b.IdRegex.FindString(keyword); id != "" {
|
||||
return &miaosic.Media{
|
||||
Meta: miaosic.MediaMeta{
|
||||
Provider: b.GetName(),
|
||||
Identifier: id,
|
||||
},
|
||||
}
|
||||
return miaosic.MediaMeta{
|
||||
Provider: b.GetName(),
|
||||
Identifier: id,
|
||||
}, true
|
||||
}
|
||||
return nil
|
||||
return miaosic.MediaMeta{}, false
|
||||
}
|
||||
|
||||
func (b *BilibiliVideo) MatchPlaylist(keyword string) *miaosic.Playlist {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *BilibiliVideo) UpdateMediaLyric(media *miaosic.Media) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *BilibiliVideo) buildInfoApi() dphttp.ApiFunc[*miaosic.Media, *miaosic.Media] {
|
||||
return deepcolor.CreateApiFunc(
|
||||
b.requester,
|
||||
func(params *miaosic.Media) (*dphttp.Request, error) {
|
||||
return deepcolor.NewGetRequestWithSingleQuery(
|
||||
"https://api.bilibili.com/x/web-interface/view/detail?&aid=&jsonp=jsonp",
|
||||
"bvid", b.header,
|
||||
)(b.getBv(params.Meta.Identifier))
|
||||
},
|
||||
deepcolor.ParserGJson,
|
||||
func(result *gjson.Result, media *miaosic.Media) error {
|
||||
if result.Get("data.View.title").String() == "" {
|
||||
return errors.New("failed to find required data")
|
||||
}
|
||||
media.Title = result.Get("data.View.title").String()
|
||||
media.Artist = result.Get("data.View.owner.name").String()
|
||||
media.Cover.Url = result.Get("data.View.pic").String()
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (b *BilibiliVideo) buildSearchApi() dphttp.ApiFuncResult[string, []*miaosic.Media] {
|
||||
return deepcolor.CreateApiResultFunc(
|
||||
b.requester,
|
||||
deepcolor.NewGetRequestWithSingleQuery(
|
||||
"https://api.bilibili.com/x/web-interface/wbi/search/type?search_type=video&page=1",
|
||||
"keyword", b.header),
|
||||
deepcolor.ParserGJson,
|
||||
func(resp *gjson.Result, result *[]*miaosic.Media) error {
|
||||
if resp.Get("code").String() != "0" {
|
||||
return errors.New("failed to find required data")
|
||||
}
|
||||
r := regexp.MustCompile("</?em[^>]*>")
|
||||
resp.Get("data.result").ForEach(func(key, value gjson.Result) bool {
|
||||
*result = append(*result, &miaosic.Media{
|
||||
Title: r.ReplaceAllString(value.Get("title").String(), ""),
|
||||
Cover: miaosic.Picture{Url: "https:" + value.Get("pic").String()},
|
||||
Artist: value.Get("author").String(),
|
||||
Meta: miaosic.MediaMeta{
|
||||
Provider: b.GetName(),
|
||||
Identifier: value.Get("bvid").String(),
|
||||
},
|
||||
})
|
||||
return true
|
||||
})
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (b *BilibiliVideo) cidApi(bvid string) ([]string, error) {
|
||||
return deepcolor.CreateApiResultFunc(
|
||||
b.requester,
|
||||
deepcolor.NewGetRequestWithSingleQuery(
|
||||
"https://api.bilibili.com/x/web-interface/view/detail?&aid=&jsonp=jsonp", "bvid", b.header),
|
||||
deepcolor.ParserGJson,
|
||||
func(resp *gjson.Result, result *[]string) error {
|
||||
for _, r := range resp.Get("data.View.pages.#.cid").Array() {
|
||||
*result = append(*result, r.String())
|
||||
}
|
||||
if len(*result) == 0 {
|
||||
return errors.New("failed to find cid data")
|
||||
}
|
||||
return nil
|
||||
})(bvid)
|
||||
}
|
||||
|
||||
func (b *BilibiliVideo) UpdateMediaUrl(media *miaosic.Media) error {
|
||||
page := b.getPage(media.Meta.Identifier) - 1
|
||||
cids, err := b.cidApi(b.getBv(media.Meta.Identifier))
|
||||
func (b *BilibiliVideo) GetMediaUrl(meta miaosic.MediaMeta, quality miaosic.Quality) ([]miaosic.MediaUrl, error) {
|
||||
page := b.getPage(meta.Identifier) - 1
|
||||
cids, err := b.cidApi(b.getBv(meta.Identifier))
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
if err != nil || page >= len(cids) {
|
||||
return miaosic.ErrorExternalApi
|
||||
return nil, miaosic.ErrorExternalApi
|
||||
}
|
||||
return deepcolor.CreateApiFunc(
|
||||
b.requester,
|
||||
func(params *miaosic.Media) (*dphttp.Request, error) {
|
||||
return deepcolor.CreateApiResultFunc(
|
||||
func(param string) (*dphttp.Request, error) {
|
||||
return deepcolor.NewGetRequestWithQuery(
|
||||
"https://api.bilibili.com/x/player/playurl?type=&otype=json&fourk=1&qn=32&avid=",
|
||||
[]string{"bvid", "cid"}, b.header,
|
||||
)([]string{b.getBv(media.Meta.Identifier), cids[page]})
|
||||
map[string]any{
|
||||
"bvid": b.getBv(meta.Identifier),
|
||||
"cid": cids[page],
|
||||
}, b.header)
|
||||
},
|
||||
deepcolor.ParserGJson,
|
||||
func(result *gjson.Result, container *miaosic.Media) error {
|
||||
func(result *gjson.Result, container *[]miaosic.MediaUrl) error {
|
||||
uri := result.Get("data.durl.0.url").String()
|
||||
if uri == "" {
|
||||
return miaosic.ErrorExternalApi
|
||||
}
|
||||
container.Url = uri
|
||||
header := make(map[string]string)
|
||||
_ = copier.Copy(&header, &b.header)
|
||||
header["Referer"] = fmt.Sprintf("https://www.bilibili.com/video/%s", b.getBv(container.Meta.Identifier))
|
||||
container.Header = header
|
||||
header["Referer"] = fmt.Sprintf("https://www.bilibili.com/video/%s", b.getBv(meta.Identifier))
|
||||
*container = append(*container, miaosic.MediaUrl{
|
||||
Quality: miaosic.QualityUnk,
|
||||
Url: uri,
|
||||
Header: header,
|
||||
})
|
||||
return nil
|
||||
})(media, media)
|
||||
})("")
|
||||
}
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
package bilivideo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/aynakeya/deepcolor"
|
||||
"github.com/AynaLivePlayer/miaosic"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"miaosic"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var api miaosic.MediaProvider = NewBilibiliViedo(deepcolor.NewRestyRequester())
|
||||
var api miaosic.MediaProvider = NewBilibiliViedo()
|
||||
|
||||
func TestBV_GetMusicMeta(t *testing.T) {
|
||||
media := api.MatchMedia("BV1434y1q71P")
|
||||
require.NotNil(t, media)
|
||||
require.NoError(t, api.UpdateMedia(media))
|
||||
assert.Equal(t, "卦者那啥子靈風", media.Artist)
|
||||
meta, ok := api.MatchMedia("BV1434y1q71P")
|
||||
require.True(t, ok)
|
||||
media, err := api.GetMediaInfo(meta)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "卦者那啥子靈風", media.Artist)
|
||||
}
|
||||
|
||||
func TestBV_GetMusic(t *testing.T) {
|
||||
media := api.MatchMedia("BV1434y1q71P")
|
||||
require.NoError(t, api.UpdateMedia(media))
|
||||
require.NoError(t, api.UpdateMediaUrl(media))
|
||||
assert.True(t, strings.Contains(media.Url, "bilivideo"), media.Url)
|
||||
meta, _ := api.MatchMedia("BV1434y1q71P")
|
||||
urls, err := api.GetMediaUrl(meta, miaosic.QualityAny)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, urls)
|
||||
assert.True(t, strings.Contains(urls[0].Url, "http"))
|
||||
}
|
||||
|
||||
func TestBV_Regex(t *testing.T) {
|
||||
@@ -32,22 +32,23 @@ func TestBV_Regex(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBV_GetMusicMeta2(t *testing.T) {
|
||||
media := api.MatchMedia("BV1gA411P7ir?p=3")
|
||||
require.NotNil(t, media)
|
||||
require.NoError(t, api.UpdateMedia(media))
|
||||
meta, ok := api.MatchMedia("BV1gA411P7ir?p=3")
|
||||
require.True(t, ok)
|
||||
media, err := api.GetMediaInfo(meta)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "沈默沈默", media.Artist)
|
||||
}
|
||||
|
||||
func TestBV_GetMusic2(t *testing.T) {
|
||||
media := api.MatchMedia("BV1gA411P7ir?p=3")
|
||||
require.NoError(t, api.UpdateMedia(media))
|
||||
require.NoError(t, api.UpdateMediaUrl(media))
|
||||
assert.Equal(t, "沈默沈默", media.Artist)
|
||||
fmt.Println(media.Url)
|
||||
meta, _ := api.MatchMedia("BV1gA411P7ir?p=3")
|
||||
urls, err := api.GetMediaUrl(meta, miaosic.QualityAny)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, urls)
|
||||
assert.True(t, strings.Contains(urls[0].Url, "http"))
|
||||
}
|
||||
|
||||
func TestBV_Search(t *testing.T) {
|
||||
result, err := api.Search("家有女友op")
|
||||
result, err := api.Search("家有女友op", 1, 20)
|
||||
require.NoError(t, err, "Search Error")
|
||||
require.NotEmpty(t, result, "Search Result Empty")
|
||||
t.Log(result[0])
|
||||
|
||||
7
providers/bilivideo/init.go
Normal file
7
providers/bilivideo/init.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package bilivideo
|
||||
|
||||
import "github.com/AynaLivePlayer/miaosic"
|
||||
|
||||
func init() {
|
||||
miaosic.RegisterProvider(NewBilibiliViedo())
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package kuwo
|
||||
|
||||
import "miaosic"
|
||||
import "github.com/AynaLivePlayer/miaosic"
|
||||
|
||||
func init() {
|
||||
miaosic.RegisterProvider(NewKuwo(miaosic.Requester))
|
||||
miaosic.RegisterProvider(NewKuwo())
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package kuwo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/AynaLivePlayer/miaosic"
|
||||
"github.com/AynaLivePlayer/miaosic/providers"
|
||||
"github.com/aynakeya/deepcolor"
|
||||
"github.com/aynakeya/deepcolor/dphttp"
|
||||
"github.com/spf13/cast"
|
||||
@@ -9,8 +11,6 @@ import (
|
||||
"html"
|
||||
"math"
|
||||
"math/rand"
|
||||
"miaosic"
|
||||
"miaosic/providers"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -18,7 +18,6 @@ import (
|
||||
|
||||
type Kuwo struct {
|
||||
providers.DeepcolorProvider
|
||||
requester dphttp.IRequester
|
||||
PlaylistRegex0 *regexp.Regexp
|
||||
PlaylistRegex1 *regexp.Regexp
|
||||
IdRegex0 *regexp.Regexp
|
||||
@@ -26,20 +25,89 @@ type Kuwo struct {
|
||||
header map[string]string
|
||||
}
|
||||
|
||||
func NewKuwo(requester dphttp.IRequester) *Kuwo {
|
||||
func NewKuwo() *Kuwo {
|
||||
kw := &Kuwo{
|
||||
requester: requester,
|
||||
PlaylistRegex0: regexp.MustCompile("[0-9]+"),
|
||||
PlaylistRegex1: regexp.MustCompile("playlist/[0-9]+"),
|
||||
IdRegex0: regexp.MustCompile("^[0-9]+"),
|
||||
IdRegex1: regexp.MustCompile("^kw[0-9]+"),
|
||||
}
|
||||
kw.initToken()
|
||||
kw.InfoFunc = kw.buildInfoApi()
|
||||
kw.FileFunc = kw.buildFileApi()
|
||||
kw.LyricFunc = kw.buildLyricApi()
|
||||
kw.PlaylistFunc = kw.playlistApi
|
||||
kw.SearchFunc = kw.buildSearchApi()
|
||||
kw.InfoApi = deepcolor.CreateApiResultFunc(
|
||||
func(meta miaosic.MediaMeta) (*dphttp.Request, error) {
|
||||
return deepcolor.NewGetRequestWithSingleQuery(
|
||||
"http://www.kuwo.cn/api/www/music/musicInfo",
|
||||
"mid", meta.Identifier, kw.header)
|
||||
},
|
||||
deepcolor.ParserGJson,
|
||||
func(resp *gjson.Result, media *miaosic.MediaInfo) error {
|
||||
if resp.Get("data.musicrid").String() == "" {
|
||||
return miaosic.ErrorExternalApi
|
||||
}
|
||||
media.Title = html.UnescapeString(resp.Get("data.name").String())
|
||||
media.Cover.Url = resp.Get("data.pic").String()
|
||||
media.Artist = resp.Get("data.artist").String()
|
||||
media.Album = resp.Get("data.album").String()
|
||||
return nil
|
||||
})
|
||||
kw.FileApi = deepcolor.CreateApiResultFunc(
|
||||
func(param providers.FileApiParam) (*dphttp.Request, error) {
|
||||
return deepcolor.NewGetRequestWithSingleQuery(
|
||||
"http://antiserver.kuwo.cn/anti.s?type=convert_url&format=mp3&response=url",
|
||||
"rid", "MUSIC_"+param.Meta.Identifier, kw.header)
|
||||
},
|
||||
deepcolor.ParserText,
|
||||
func(resp string, urls *[]miaosic.MediaUrl) error {
|
||||
*urls = []miaosic.MediaUrl{miaosic.NewMediaUrl(resp, miaosic.QualityUnk)}
|
||||
return nil
|
||||
})
|
||||
kw.LyricApi = deepcolor.CreateApiResultFunc(
|
||||
func(meta miaosic.MediaMeta) (*dphttp.Request, error) {
|
||||
return deepcolor.NewGetRequestWithSingleQuery(
|
||||
"http://m.kuwo.cn/newh5/singles/songinfoandlrc",
|
||||
"musicId", meta.Identifier, kw.header)
|
||||
},
|
||||
deepcolor.ParserGJson,
|
||||
func(resp *gjson.Result, lyrics *[]miaosic.Lyrics) error {
|
||||
lrcs := make([]string, 0)
|
||||
resp.Get("data.lrclist").ForEach(func(key, value gjson.Result) bool {
|
||||
lrcs = append(lrcs, fmt.Sprintf("[00:%s]%s", value.Get("time").String(), value.Get("lineLyric").String()))
|
||||
return true
|
||||
})
|
||||
if len(lrcs) == 0 {
|
||||
return miaosic.ErrorExternalApi
|
||||
}
|
||||
*lyrics = []miaosic.Lyrics{miaosic.ParseLyrics("default", strings.Join(lrcs, "\n"))}
|
||||
return nil
|
||||
})
|
||||
kw.SearchApi = deepcolor.CreateApiResultFunc(
|
||||
func(param providers.MediaSearchParam) (*dphttp.Request, error) {
|
||||
return deepcolor.NewGetRequestWithQuery(
|
||||
"http://www.kuwo.cn/api/www/search/searchMusicBykeyWord",
|
||||
map[string]any{
|
||||
"key": param.Keyword,
|
||||
"pn": param.Page,
|
||||
"rn": param.PageSize,
|
||||
}, kw.header)
|
||||
},
|
||||
deepcolor.ParserGJson,
|
||||
func(resp *gjson.Result, result *[]miaosic.MediaInfo) error {
|
||||
resp.Get("data.list").ForEach(func(key, value gjson.Result) bool {
|
||||
*result = append(*result, miaosic.MediaInfo{
|
||||
Title: html.UnescapeString(value.Get("name").String()),
|
||||
Cover: miaosic.Picture{Url: value.Get("pic").String()},
|
||||
Artist: value.Get("artist").String(),
|
||||
Album: value.Get("album").String(),
|
||||
Meta: miaosic.MediaMeta{
|
||||
Provider: kw.GetName(),
|
||||
Identifier: value.Get("rid").String(),
|
||||
},
|
||||
})
|
||||
return true
|
||||
})
|
||||
return nil
|
||||
})
|
||||
//kw.PlaylistFunc = kw.playlistApi
|
||||
return kw
|
||||
}
|
||||
|
||||
@@ -47,42 +115,38 @@ func (k *Kuwo) GetName() string {
|
||||
return "kuwo"
|
||||
}
|
||||
|
||||
func (k *Kuwo) MatchMedia(keyword string) *miaosic.Media {
|
||||
func (k *Kuwo) MatchMedia(keyword string) (miaosic.MediaMeta, bool) {
|
||||
if id := k.IdRegex0.FindString(keyword); id != "" {
|
||||
return &miaosic.Media{
|
||||
Meta: miaosic.MediaMeta{
|
||||
Provider: k.GetName(),
|
||||
Identifier: id,
|
||||
},
|
||||
}
|
||||
return miaosic.MediaMeta{
|
||||
Provider: k.GetName(),
|
||||
Identifier: id,
|
||||
}, true
|
||||
}
|
||||
if id := k.IdRegex1.FindString(keyword); id != "" {
|
||||
return &miaosic.Media{
|
||||
Meta: miaosic.MediaMeta{
|
||||
Provider: k.GetName(),
|
||||
Identifier: id[2:],
|
||||
},
|
||||
}
|
||||
return miaosic.MediaMeta{
|
||||
Provider: k.GetName(),
|
||||
Identifier: id[2:],
|
||||
}, true
|
||||
}
|
||||
return nil
|
||||
return miaosic.MediaMeta{}, false
|
||||
}
|
||||
|
||||
func (k *Kuwo) MatchPlaylist(uri string) *miaosic.Playlist {
|
||||
var id string
|
||||
id = k.PlaylistRegex0.FindString(uri)
|
||||
if id != "" {
|
||||
return &miaosic.Playlist{
|
||||
Meta: miaosic.MediaMeta{k.GetName(), id},
|
||||
}
|
||||
}
|
||||
id = k.PlaylistRegex1.FindString(uri)
|
||||
if id != "" {
|
||||
return &miaosic.Playlist{
|
||||
Meta: miaosic.MediaMeta{k.GetName(), id[9:]},
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
//func (k *Kuwo) MatchPlaylist(uri string) *miaosic.Playlist {
|
||||
// var id string
|
||||
// id = k.PlaylistRegex0.FindString(uri)
|
||||
// if id != "" {
|
||||
// return &miaosic.Playlist{
|
||||
// Meta: miaosic.MediaMeta{k.GetName(), id},
|
||||
// }
|
||||
// }
|
||||
// id = k.PlaylistRegex1.FindString(uri)
|
||||
// if id != "" {
|
||||
// return &miaosic.Playlist{
|
||||
// Meta: miaosic.MediaMeta{k.GetName(), id[9:]},
|
||||
// }
|
||||
// }
|
||||
// return nil
|
||||
//}
|
||||
|
||||
func (k *Kuwo) generateSecret(t, e string) string {
|
||||
if e == "" {
|
||||
@@ -161,128 +225,44 @@ func (k *Kuwo) initToken() {
|
||||
//fmt.Println(searchCookie.Header(), err)
|
||||
}
|
||||
|
||||
func (k *Kuwo) buildInfoApi() dphttp.ApiFunc[*miaosic.Media, *miaosic.Media] {
|
||||
return deepcolor.CreateApiFunc(
|
||||
k.requester,
|
||||
func(media *miaosic.Media) (*dphttp.Request, error) {
|
||||
return deepcolor.NewGetRequestWithQuery(
|
||||
"http://www.kuwo.cn/api/www/music/musicInfo",
|
||||
[]string{"mid"}, k.header)([]string{media.Meta.Identifier})
|
||||
},
|
||||
deepcolor.ParserGJson,
|
||||
func(resp *gjson.Result, media *miaosic.Media) error {
|
||||
if resp.Get("data.musicrid").String() == "" {
|
||||
return miaosic.ErrorExternalApi
|
||||
}
|
||||
media.Title = html.UnescapeString(resp.Get("data.name").String())
|
||||
media.Cover.Url = resp.Get("data.pic").String()
|
||||
media.Artist = resp.Get("data.artist").String()
|
||||
media.Album = resp.Get("data.album").String()
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (k *Kuwo) buildLyricApi() dphttp.ApiFunc[*miaosic.Media, *miaosic.Media] {
|
||||
return deepcolor.CreateApiFunc(
|
||||
k.requester,
|
||||
func(media *miaosic.Media) (*dphttp.Request, error) {
|
||||
return deepcolor.NewGetRequestWithQuery(
|
||||
"http://m.kuwo.cn/newh5/singles/songinfoandlrc",
|
||||
[]string{"musicId"}, k.header)([]string{media.Meta.Identifier})
|
||||
},
|
||||
deepcolor.ParserGJson,
|
||||
func(resp *gjson.Result, media *miaosic.Media) error {
|
||||
lrcs := make([]string, 0)
|
||||
resp.Get("data.lrclist").ForEach(func(key, value gjson.Result) bool {
|
||||
lrcs = append(lrcs, fmt.Sprintf("[00:%s]%s", value.Get("time").String(), value.Get("lineLyric").String()))
|
||||
|
||||
return true
|
||||
})
|
||||
media.Lyric = []miaosic.Lyrics{miaosic.ParseLyrics("default", strings.Join(lrcs, "\n"))}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (k *Kuwo) buildSearchApi() dphttp.ApiFuncResult[string, []*miaosic.Media] {
|
||||
return deepcolor.CreateApiResultFunc(
|
||||
k.requester,
|
||||
func(keyword string) (*dphttp.Request, error) {
|
||||
return deepcolor.NewGetRequestWithQuery(
|
||||
"http://www.kuwo.cn/api/www/search/searchMusicBykeyWord",
|
||||
[]string{"key", "pn", "rn"}, k.header)([]string{keyword, "1", "64"})
|
||||
},
|
||||
deepcolor.ParserGJson,
|
||||
func(resp *gjson.Result, result *[]*miaosic.Media) error {
|
||||
resp.Get("data.list").ForEach(func(key, value gjson.Result) bool {
|
||||
*result = append(*result, &miaosic.Media{
|
||||
Title: html.UnescapeString(value.Get("name").String()),
|
||||
Cover: miaosic.Picture{Url: value.Get("pic").String()},
|
||||
Artist: value.Get("artist").String(),
|
||||
Album: value.Get("album").String(),
|
||||
Meta: miaosic.MediaMeta{
|
||||
Provider: k.GetName(),
|
||||
Identifier: value.Get("rid").String(),
|
||||
},
|
||||
})
|
||||
return true
|
||||
})
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (k *Kuwo) buildFileApi() dphttp.ApiFunc[*miaosic.Media, *miaosic.Media] {
|
||||
return deepcolor.CreateApiFunc(
|
||||
k.requester,
|
||||
func(media *miaosic.Media) (*dphttp.Request, error) {
|
||||
return deepcolor.NewGetRequestWithSingleQuery(
|
||||
"http://antiserver.kuwo.cn/anti.s?type=convert_url&format=mp3&response=url",
|
||||
"rid", k.header)("MUSIC_" + media.Meta.Identifier)
|
||||
},
|
||||
deepcolor.ParserText,
|
||||
func(resp string, media *miaosic.Media) error {
|
||||
media.Url = resp
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (k *Kuwo) playlistApi(src *miaosic.Playlist, dst *miaosic.Playlist) error {
|
||||
dst.Medias = make([]*miaosic.Media, 0)
|
||||
api := deepcolor.CreateChainApiFunc(
|
||||
k.requester,
|
||||
func(page int) (*dphttp.Request, error) {
|
||||
return deepcolor.NewGetRequestWithQuery(
|
||||
"http://www.kuwo.cn/api/www/playlist/playListInfo",
|
||||
[]string{"pid", "pn", "rn"}, k.header)([]string{src.Meta.Identifier, cast.ToString(page), "100"})
|
||||
},
|
||||
deepcolor.ParserGJson,
|
||||
func(resp *gjson.Result, playlist *miaosic.Playlist) error {
|
||||
resp.Get("data.musicList").ForEach(func(key, value gjson.Result) bool {
|
||||
playlist.Medias = append(
|
||||
playlist.Medias,
|
||||
&miaosic.Media{
|
||||
Title: html.UnescapeString(value.Get("name").String()),
|
||||
Artist: value.Get("artist").String(),
|
||||
Cover: miaosic.Picture{Url: value.Get("pic").String()},
|
||||
Album: value.Get("album").String(),
|
||||
Meta: miaosic.MediaMeta{
|
||||
Provider: k.GetName(),
|
||||
Identifier: value.Get("rid").String(),
|
||||
},
|
||||
})
|
||||
return true
|
||||
})
|
||||
return nil
|
||||
},
|
||||
func(page int, resp *gjson.Result, playlist *miaosic.Playlist) (int, bool) {
|
||||
if resp.Get("code").String() != "200" {
|
||||
return page, false
|
||||
}
|
||||
cnt := int(resp.Get("data.total").Int())
|
||||
if cnt <= page*100 {
|
||||
return page, false
|
||||
}
|
||||
return page + 1, true
|
||||
},
|
||||
)
|
||||
return api(1, dst)
|
||||
}
|
||||
//func (k *Kuwo) playlistApi(src *miaosic.Playlist, dst *miaosic.Playlist) error {
|
||||
// dst.Medias = make([]*miaosic.Media, 0)
|
||||
// api := deepcolor.CreateChainApiFunc(
|
||||
// k.requester,
|
||||
// func(page int) (*dphttp.Request, error) {
|
||||
// return deepcolor.NewGetRequestWithQuery(
|
||||
// "http://www.kuwo.cn/api/www/playlist/playListInfo",
|
||||
// []string{"pid", "pn", "rn"}, k.header)([]string{src.Meta.Identifier, cast.ToString(page), "100"})
|
||||
// },
|
||||
// deepcolor.ParserGJson,
|
||||
// func(resp *gjson.Result, playlist *miaosic.Playlist) error {
|
||||
// resp.Get("data.musicList").ForEach(func(key, value gjson.Result) bool {
|
||||
// playlist.Medias = append(
|
||||
// playlist.Medias,
|
||||
// &miaosic.Media{
|
||||
// Title: html.UnescapeString(value.Get("name").String()),
|
||||
// Artist: value.Get("artist").String(),
|
||||
// Cover: miaosic.Picture{Url: value.Get("pic").String()},
|
||||
// Album: value.Get("album").String(),
|
||||
// Meta: miaosic.MediaMeta{
|
||||
// Provider: k.GetName(),
|
||||
// Identifier: value.Get("rid").String(),
|
||||
// },
|
||||
// })
|
||||
// return true
|
||||
// })
|
||||
// return nil
|
||||
// },
|
||||
// func(page int, resp *gjson.Result, playlist *miaosic.Playlist) (int, bool) {
|
||||
// if resp.Get("code").String() != "200" {
|
||||
// return page, false
|
||||
// }
|
||||
// cnt := int(resp.Get("data.total").Int())
|
||||
// if cnt <= page*100 {
|
||||
// return page, false
|
||||
// }
|
||||
// return page + 1, true
|
||||
// },
|
||||
// )
|
||||
// return api(1, dst)
|
||||
//}
|
||||
|
||||
@@ -2,77 +2,69 @@ package kuwo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/aynakeya/deepcolor"
|
||||
"github.com/AynaLivePlayer/miaosic"
|
||||
"github.com/stretchr/testify/require"
|
||||
"miaosic"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var api miaosic.MediaProvider = NewKuwo(deepcolor.NewRestyRequester())
|
||||
var api miaosic.MediaProvider = NewKuwo()
|
||||
|
||||
func TestKuwo_Secret(t *testing.T) {
|
||||
// using 80378195 as d
|
||||
require.Equal(t, "5add7ba59bc95d3d38a8983a82af6efc78d3484c6d253f29a2154dd042b3383604ca7953",
|
||||
api.(*Kuwo).generateSecret("zddnb2yWCXJjk6aWb2tSZBNeaPBChEPY", "Hm_Iuvt_cdb524f42f0cer9b268e4v7y734w5esq24"))
|
||||
|
||||
}
|
||||
//func TestKuwo_Secret(t *testing.T) {
|
||||
// // using 80378195 as d
|
||||
// require.Equal(t, "5add7ba59bc95d3d38a8983a82af6efc78d3484c6d253f29a2154dd042b3383604ca7953",
|
||||
// api.(*Kuwo).generateSecret("zddnb2yWCXJjk6aWb2tSZBNeaPBChEPY", "Hm_Iuvt_cdb524f42f0cer9b268e4v7y734w5esq24"))
|
||||
//
|
||||
//}
|
||||
|
||||
func TestKuwo_Search(t *testing.T) {
|
||||
result, err := api.Search("周杰伦")
|
||||
result, err := api.Search("周杰伦", 1, 20)
|
||||
require.NoError(t, err)
|
||||
fmt.Println(result)
|
||||
media := result[0]
|
||||
err = api.UpdateMediaUrl(media)
|
||||
fmt.Println(err)
|
||||
fmt.Println(media.Url)
|
||||
urls, err := api.GetMediaUrl(media.Meta, miaosic.QualityAny)
|
||||
require.NoError(t, err)
|
||||
fmt.Println(urls)
|
||||
}
|
||||
|
||||
func TestKuwo_GetMusicMeta(t *testing.T) {
|
||||
media := miaosic.Media{
|
||||
Meta: miaosic.MediaMeta{
|
||||
Provider: api.GetName(),
|
||||
Identifier: "22804772",
|
||||
},
|
||||
meta := miaosic.MediaMeta{
|
||||
Provider: api.GetName(),
|
||||
Identifier: "22804772",
|
||||
}
|
||||
err := api.UpdateMedia(&media)
|
||||
info, err := api.GetMediaInfo(meta)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "霜雪千年", media.Title)
|
||||
require.Equal(t, "霜雪千年", info.Title)
|
||||
}
|
||||
|
||||
func TestKuwo_GetMusic(t *testing.T) {
|
||||
media := miaosic.Media{
|
||||
Meta: miaosic.MediaMeta{
|
||||
Provider: api.GetName(),
|
||||
Identifier: "22804772",
|
||||
},
|
||||
meta := miaosic.MediaMeta{
|
||||
Provider: api.GetName(),
|
||||
Identifier: "22804772",
|
||||
}
|
||||
require.NoError(t, api.UpdateMedia(&media))
|
||||
require.NoError(t, api.UpdateMediaUrl(&media))
|
||||
require.Equal(t, "霜雪千年", media.Title)
|
||||
require.True(t, len(media.Url) > 0)
|
||||
urls, err := api.GetMediaUrl(meta, miaosic.QualityAny)
|
||||
require.NoError(t, err)
|
||||
require.True(t, len(urls) > 0)
|
||||
}
|
||||
|
||||
func TestKuwo_UpdateMediaLyric(t *testing.T) {
|
||||
media := miaosic.Media{
|
||||
Meta: miaosic.MediaMeta{
|
||||
Provider: api.GetName(),
|
||||
Identifier: "22804772",
|
||||
},
|
||||
meta := miaosic.MediaMeta{
|
||||
Provider: api.GetName(),
|
||||
Identifier: "22804772",
|
||||
}
|
||||
err := api.UpdateMediaLyric(&media)
|
||||
lyrics, err := api.GetMediaLyric(meta)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, media.Lyric)
|
||||
require.NotEmpty(t, len(lyrics) > 0)
|
||||
}
|
||||
|
||||
func TestKuwo_GetPlaylist(t *testing.T) {
|
||||
playlist := miaosic.Playlist{
|
||||
Meta: miaosic.MediaMeta{
|
||||
Provider: api.GetName(),
|
||||
Identifier: "2959147566",
|
||||
},
|
||||
}
|
||||
err := api.UpdatePlaylist(&playlist)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, playlist.Medias)
|
||||
t.Logf("sucessfully get %d medias", len(playlist.Medias))
|
||||
}
|
||||
//func TestKuwo_GetPlaylist(t *testing.T) {
|
||||
// playlist := miaosic.Playlist{
|
||||
// Meta: miaosic.MediaMeta{
|
||||
// Provider: api.GetName(),
|
||||
// Identifier: "2959147566",
|
||||
// },
|
||||
// }
|
||||
// err := api.UpdatePlaylist(&playlist)
|
||||
// require.NoError(t, err)
|
||||
// require.NotEmpty(t, playlist.Medias)
|
||||
// t.Logf("sucessfully get %d medias", len(playlist.Medias))
|
||||
//}
|
||||
|
||||
@@ -1,135 +1,103 @@
|
||||
package local
|
||||
|
||||
import (
|
||||
"miaosic"
|
||||
"github.com/AynaLivePlayer/miaosic"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type localPlaylist struct {
|
||||
name string
|
||||
medias []localMedia
|
||||
}
|
||||
|
||||
type localMedia struct {
|
||||
info miaosic.MediaInfo
|
||||
quality miaosic.Quality
|
||||
lyrics []miaosic.Lyrics
|
||||
}
|
||||
|
||||
func (l *localPlaylist) GetMediaInfo(meta miaosic.MediaMeta) (miaosic.MediaInfo, error) {
|
||||
for _, m := range l.medias {
|
||||
if m.info.Meta.Identifier == meta.Identifier {
|
||||
return m.info, nil
|
||||
}
|
||||
}
|
||||
return miaosic.MediaInfo{}, miaosic.ErrorInvalidMediaMeta
|
||||
}
|
||||
|
||||
type Local struct {
|
||||
localDir string
|
||||
playlists map[string]*miaosic.Playlist
|
||||
playlists map[string]*localPlaylist
|
||||
}
|
||||
|
||||
func NewLocal(localdir string) *Local {
|
||||
l := &Local{localDir: localdir, playlists: make(map[string]*miaosic.Playlist, 0)}
|
||||
l := &Local{localDir: localdir, playlists: make(map[string]*localPlaylist, 0)}
|
||||
if err := os.MkdirAll(localdir, 0755); err != nil {
|
||||
return l
|
||||
}
|
||||
for _, n := range getPlaylistNames(localdir) {
|
||||
playlist := &miaosic.Playlist{Meta: miaosic.MediaMeta{Provider: n}}
|
||||
playlist := &localPlaylist{name: n, medias: make([]localMedia, 0)}
|
||||
if readLocalPlaylist(localdir, playlist) != nil {
|
||||
l.playlists[playlist.Title] = playlist
|
||||
l.playlists[playlist.name] = playlist
|
||||
}
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *Local) metaToId(meta miaosic.MediaMeta) (playlist string) {
|
||||
return strings.Split(meta.Identifier, "/")[0]
|
||||
}
|
||||
|
||||
func (l *Local) GetName() string {
|
||||
return "local"
|
||||
}
|
||||
|
||||
func (l *Local) MatchMedia(uri string) *miaosic.Media {
|
||||
return nil
|
||||
func (l *Local) MatchMedia(uri string) (miaosic.MediaMeta, bool) {
|
||||
return miaosic.MediaMeta{}, false
|
||||
}
|
||||
|
||||
func (l *Local) MatchPlaylist(uri string) *miaosic.Playlist {
|
||||
return nil
|
||||
func (l *Local) GetMediaInfo(meta miaosic.MediaMeta) (miaosic.MediaInfo, error) {
|
||||
if meta.Provider != l.GetName() {
|
||||
return miaosic.MediaInfo{}, miaosic.ErrorDifferentProvider
|
||||
}
|
||||
playlist, ok := l.playlists[l.metaToId(meta)]
|
||||
if !ok {
|
||||
return miaosic.MediaInfo{}, miaosic.ErrorInvalidMediaMeta
|
||||
}
|
||||
return playlist.GetMediaInfo(meta)
|
||||
}
|
||||
|
||||
func (l *Local) Search(keyword string) ([]*miaosic.Media, error) {
|
||||
allMedias := make([]*miaosic.Media, 0)
|
||||
func (l *Local) GetMediaUrl(meta miaosic.MediaMeta, quality miaosic.Quality) ([]miaosic.MediaUrl, error) {
|
||||
info, err := l.GetMediaInfo(meta)
|
||||
if err != nil {
|
||||
return []miaosic.MediaUrl{}, err
|
||||
}
|
||||
return []miaosic.MediaUrl{{
|
||||
Url: path.Join(l.localDir, info.Meta.Identifier),
|
||||
Quality: miaosic.QualityUnk,
|
||||
}}, nil
|
||||
}
|
||||
|
||||
func (l *Local) GetMediaLyric(meta miaosic.MediaMeta) ([]miaosic.Lyrics, error) {
|
||||
return []miaosic.Lyrics{}, miaosic.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (l *Local) Search(keyword string, page, size int) ([]miaosic.MediaInfo, error) {
|
||||
allMedias := make([]miaosic.MediaInfo, 0)
|
||||
for _, p := range l.playlists {
|
||||
for _, m := range p.Medias {
|
||||
allMedias = append(allMedias, m)
|
||||
for _, m := range p.medias {
|
||||
allMedias = append(allMedias, m.info)
|
||||
}
|
||||
}
|
||||
return RankMedia(keyword, allMedias), nil
|
||||
}
|
||||
|
||||
func (l *Local) UpdatePlaylist(playlist *miaosic.Playlist) error {
|
||||
err := readLocalPlaylist(l.localDir, playlist)
|
||||
if err != nil {
|
||||
return err
|
||||
rankedMedias := rankMedia(keyword, &allMedias)
|
||||
total := len(rankedMedias)
|
||||
if total < page*size {
|
||||
return []miaosic.MediaInfo{}, nil
|
||||
}
|
||||
l.playlists[playlist.Meta.Identifier] = playlist
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Local) UpdateMedia(media *miaosic.Media) error {
|
||||
mediaPath := path.Join(l.localDir, media.Meta.Identifier)
|
||||
_, err := os.Stat(mediaPath)
|
||||
if err != nil {
|
||||
return err
|
||||
if total >= page*size {
|
||||
total = page * size
|
||||
}
|
||||
return readMediaFile(l.localDir, media)
|
||||
return rankedMedias[(page-1)*size : total], nil
|
||||
}
|
||||
|
||||
func (l *Local) UpdateMediaUrl(media *miaosic.Media) error {
|
||||
mediaPath := path.Join(l.localDir, media.Meta.Identifier)
|
||||
_, err := os.Stat(mediaPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
media.Url = mediaPath
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Local) UpdateMediaLyric(media *miaosic.Media) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
//
|
||||
//func (l *Local) Search(keyword string) ([]*model.Media, error) {
|
||||
// allMedias := make([]*model.Media, 0)
|
||||
// for _, p := range l.Playlists {
|
||||
// for _, m := range p.Medias {
|
||||
// allMedias = append(allMedias, m)
|
||||
// }
|
||||
// }
|
||||
// MediaSort(keyword, allMedias)
|
||||
// c := util.Min(len(allMedias), 32)
|
||||
// medias := make([]*model.Media, c)
|
||||
// for i := 0; i < c; i++ {
|
||||
// medias[i] = allMedias[i].Copy()
|
||||
// }
|
||||
// return medias, nil
|
||||
//}
|
||||
//
|
||||
//func (l *Local) SearchV1(keyword string) ([]*model.Media, error) {
|
||||
// result := make([]struct {
|
||||
// M *model.Media
|
||||
// N int
|
||||
// }, 0)
|
||||
// keywords := strings.Split(keyword, " ")
|
||||
// for _, p := range l.Playlists {
|
||||
// for _, m := range p.Medias {
|
||||
// title := strings.ToLower(m.Title)
|
||||
// artist := strings.ToLower(m.Artist)
|
||||
// n := 0
|
||||
// for _, k := range keywords {
|
||||
// kw := strings.ToLower(k)
|
||||
// if strings.Contains(title, kw) || strings.Contains(artist, kw) {
|
||||
// n++
|
||||
// }
|
||||
// if kw == title {
|
||||
// n += 3
|
||||
// }
|
||||
// }
|
||||
// if n > 0 {
|
||||
// result = append(result, struct {
|
||||
// M *model.Media
|
||||
// N int
|
||||
// }{M: m, N: n})
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// sort.Slice(result, func(i, j int) bool {
|
||||
// return result[i].N > result[j].N
|
||||
// })
|
||||
// medias := make([]*model.Media, len(result))
|
||||
// for i, r := range result {
|
||||
// medias[i] = r.M.Copy()
|
||||
// }
|
||||
// return medias, nil
|
||||
//}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package local
|
||||
|
||||
import (
|
||||
"github.com/AynaLivePlayer/miaosic"
|
||||
"github.com/dhowden/tag"
|
||||
"github.com/sahilm/fuzzy"
|
||||
"miaosic"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
@@ -25,10 +25,9 @@ func getPlaylistNames(localdir string) []string {
|
||||
// readLocalPlaylist read files under a directory
|
||||
// and return a _LocalPlaylist object.
|
||||
// This function assume this directory exists
|
||||
func readLocalPlaylist(localdir string, playlist *miaosic.Playlist) error {
|
||||
p1th := playlist.Meta.Identifier
|
||||
playlist.Medias = make([]*miaosic.Media, 0)
|
||||
fullPath := filepath.Join(localdir, p1th)
|
||||
func readLocalPlaylist(localdir string, playlist *localPlaylist) error {
|
||||
playlist.medias = make([]localMedia, 0)
|
||||
fullPath := filepath.Join(localdir, playlist.name)
|
||||
if _, err := os.Stat(fullPath); os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
@@ -37,16 +36,18 @@ func readLocalPlaylist(localdir string, playlist *miaosic.Playlist) error {
|
||||
// if item is a file, read file
|
||||
if !item.IsDir() {
|
||||
fn := item.Name()
|
||||
media := miaosic.Media{
|
||||
Meta: miaosic.MediaMeta{
|
||||
Provider: "local",
|
||||
Identifier: path.Join(playlist.Meta.Identifier, fn),
|
||||
media := localMedia{
|
||||
info: miaosic.MediaInfo{
|
||||
Meta: miaosic.MediaMeta{
|
||||
Provider: "local",
|
||||
Identifier: path.Join(playlist.name, fn),
|
||||
},
|
||||
},
|
||||
}
|
||||
if readMediaFile(localdir, &media) != nil {
|
||||
continue
|
||||
}
|
||||
playlist.Medias = append(playlist.Medias, &media)
|
||||
playlist.medias = append(playlist.medias, media)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -59,8 +60,8 @@ func _getOrDefault(s string, def string) string {
|
||||
return s
|
||||
}
|
||||
|
||||
func readMediaFile(localdir string, media *miaosic.Media) error {
|
||||
p := path.Join(localdir, media.Meta.Identifier)
|
||||
func readMediaFile(localdir string, media *localMedia) error {
|
||||
p := path.Join(localdir, media.info.Meta.Identifier)
|
||||
f, err := os.Open(p)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -70,29 +71,28 @@ func readMediaFile(localdir string, media *miaosic.Media) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
media.Title = _getOrDefault(meta.Title(), filepath.Base(p))
|
||||
media.Artist = _getOrDefault(meta.Artist(), "Unknown")
|
||||
media.Album = _getOrDefault(meta.Album(), "Unknown")
|
||||
media.Lyric = []miaosic.Lyrics{miaosic.ParseLyrics("default", meta.Lyrics())}
|
||||
media.info.Title = _getOrDefault(meta.Title(), filepath.Base(p))
|
||||
media.info.Artist = _getOrDefault(meta.Artist(), "Unknown")
|
||||
media.info.Album = _getOrDefault(meta.Album(), "Unknown")
|
||||
media.lyrics = []miaosic.Lyrics{miaosic.ParseLyrics("default", meta.Lyrics())}
|
||||
if meta.Picture() != nil {
|
||||
media.Cover.Data = meta.Picture().Data
|
||||
media.info.Cover.Data = meta.Picture().Data
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type mediaRanking struct {
|
||||
media *miaosic.Media
|
||||
media *miaosic.MediaInfo
|
||||
score int
|
||||
}
|
||||
|
||||
func RankMedia(keyword string, medias []*miaosic.Media) []*miaosic.Media {
|
||||
func rankMedia(keyword string, medias *[]miaosic.MediaInfo) []miaosic.MediaInfo {
|
||||
patterns := strings.Split(keyword, " ")
|
||||
data := make([]*mediaRanking, 0)
|
||||
|
||||
for _, media := range medias {
|
||||
m := media
|
||||
for i, _ := range *medias {
|
||||
data = append(data, &mediaRanking{
|
||||
media: m,
|
||||
media: &(*medias)[i],
|
||||
score: 0,
|
||||
})
|
||||
}
|
||||
@@ -119,10 +119,10 @@ func RankMedia(keyword string, medias []*miaosic.Media) []*miaosic.Media {
|
||||
return data[i].score > data[j].score
|
||||
})
|
||||
|
||||
result := make([]*miaosic.Media, 0)
|
||||
result := make([]miaosic.MediaInfo, 0)
|
||||
for _, d := range data {
|
||||
if d.score > 0 {
|
||||
result = append(result, d.media)
|
||||
result = append(result, *d.media)
|
||||
}
|
||||
}
|
||||
return result
|
||||
|
||||
@@ -2,14 +2,14 @@ package local
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/AynaLivePlayer/miaosic"
|
||||
"github.com/sahilm/fuzzy"
|
||||
"miaosic"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var testData = []miaosic.Media{
|
||||
var testData = []miaosic.MediaInfo{
|
||||
{Title: "Shape of You", Artist: "Ed Sheeran"},
|
||||
{Title: "Lose Yourself", Artist: "Eminem"},
|
||||
{Title: "Believer", Artist: "Imagine Dragons"},
|
||||
@@ -39,8 +39,8 @@ var testData = []miaosic.Media{
|
||||
}
|
||||
|
||||
func TestLocal_SearchTest1(t *testing.T) {
|
||||
pattern := "王菲"
|
||||
patterns := strings.Split(pattern, " ")
|
||||
testPattern := "王菲"
|
||||
patterns := strings.Split(testPattern, " ")
|
||||
data := make([]*mediaRanking, 0)
|
||||
|
||||
for _, media := range testData {
|
||||
@@ -71,12 +71,7 @@ func TestLocal_SearchTest1(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLocal_SearchTest2(t *testing.T) {
|
||||
data := make([]*miaosic.Media, 0)
|
||||
for _, media := range testData {
|
||||
m := media
|
||||
data = append(data, &m)
|
||||
}
|
||||
for _, media := range RankMedia("怪物 reol", data) {
|
||||
for _, media := range rankMedia("怪物 reol", &testData) {
|
||||
fmt.Println(media)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,54 +1,97 @@
|
||||
package providers
|
||||
|
||||
import (
|
||||
"github.com/AynaLivePlayer/miaosic"
|
||||
"github.com/aynakeya/deepcolor/dphttp"
|
||||
"miaosic"
|
||||
)
|
||||
|
||||
type FileApiParam struct {
|
||||
Meta miaosic.MediaMeta
|
||||
Quality miaosic.Quality
|
||||
}
|
||||
|
||||
type MediaSearchParam struct {
|
||||
Keyword string
|
||||
Page int
|
||||
PageSize int
|
||||
}
|
||||
|
||||
type DeepcolorProvider struct {
|
||||
InfoFunc dphttp.ApiFunc[*miaosic.Media, *miaosic.Media]
|
||||
FileFunc dphttp.ApiFunc[*miaosic.Media, *miaosic.Media]
|
||||
LyricFunc dphttp.ApiFunc[*miaosic.Media, *miaosic.Media]
|
||||
PlaylistFunc dphttp.ApiFunc[*miaosic.Playlist, *miaosic.Playlist]
|
||||
SearchFunc dphttp.ApiFuncResult[string, []*miaosic.Media]
|
||||
InfoApi dphttp.ApiResultFunc[miaosic.MediaMeta, miaosic.MediaInfo]
|
||||
FileApi dphttp.ApiResultFunc[FileApiParam, []miaosic.MediaUrl]
|
||||
LyricApi dphttp.ApiResultFunc[miaosic.MediaMeta, []miaosic.Lyrics]
|
||||
//PlaylistFunc dphttp.ApiFunc[*miaosic.Playlist, *miaosic.Playlist]
|
||||
SearchApi dphttp.ApiResultFunc[MediaSearchParam, []miaosic.MediaInfo]
|
||||
}
|
||||
|
||||
func (d *DeepcolorProvider) UpdatePlaylist(playlist *miaosic.Playlist) error {
|
||||
if d.PlaylistFunc == nil {
|
||||
return miaosic.ErrNotImplemented
|
||||
}
|
||||
return d.PlaylistFunc(playlist, playlist)
|
||||
}
|
||||
|
||||
func (d *DeepcolorProvider) Search(keyword string) ([]*miaosic.Media, error) {
|
||||
if d.SearchFunc == nil {
|
||||
func (p *DeepcolorProvider) Search(keyword string, page, size int) ([]miaosic.MediaInfo, error) {
|
||||
if p.SearchApi == nil {
|
||||
return nil, miaosic.ErrNotImplemented
|
||||
}
|
||||
//result := make([]*miaosic.Media, 0)
|
||||
//err :=
|
||||
//fmt.Println(result)
|
||||
return d.SearchFunc(keyword)
|
||||
return p.SearchApi(MediaSearchParam{Keyword: keyword, Page: page, PageSize: size})
|
||||
}
|
||||
|
||||
func (d *DeepcolorProvider) UpdateMedia(media *miaosic.Media) error {
|
||||
if d.InfoFunc == nil {
|
||||
return miaosic.ErrNotImplemented
|
||||
func (p *DeepcolorProvider) GetMediaInfo(meta miaosic.MediaMeta) (miaosic.MediaInfo, error) {
|
||||
if p.InfoApi == nil {
|
||||
return miaosic.MediaInfo{}, miaosic.ErrNotImplemented
|
||||
}
|
||||
return d.InfoFunc(media, media)
|
||||
val, err := p.InfoApi(meta)
|
||||
if err != nil {
|
||||
val.Meta = meta
|
||||
}
|
||||
return val, err
|
||||
}
|
||||
|
||||
func (d *DeepcolorProvider) UpdateMediaUrl(media *miaosic.Media) error {
|
||||
if d.FileFunc == nil {
|
||||
return miaosic.ErrNotImplemented
|
||||
func (p *DeepcolorProvider) GetMediaUrl(meta miaosic.MediaMeta, quality miaosic.Quality) ([]miaosic.MediaUrl, error) {
|
||||
if p.FileApi == nil {
|
||||
return nil, miaosic.ErrNotImplemented
|
||||
}
|
||||
return d.FileFunc(media, media)
|
||||
return p.FileApi(FileApiParam{Meta: meta, Quality: quality})
|
||||
}
|
||||
|
||||
func (d *DeepcolorProvider) UpdateMediaLyric(media *miaosic.Media) error {
|
||||
media.Lyric = nil
|
||||
if d.LyricFunc == nil {
|
||||
// if no lyric func, return nil
|
||||
return nil
|
||||
func (p *DeepcolorProvider) GetMediaLyric(meta miaosic.MediaMeta) ([]miaosic.Lyrics, error) {
|
||||
if p.LyricApi == nil {
|
||||
return nil, miaosic.ErrNotImplemented
|
||||
}
|
||||
return d.LyricFunc(media, media)
|
||||
return p.LyricApi(meta)
|
||||
}
|
||||
|
||||
//func (d *DeepcolorProvider) UpdatePlaylist(playlist *miaosic.Playlist) error {
|
||||
// if d.PlaylistFunc == nil {
|
||||
// return miaosic.ErrNotImplemented
|
||||
// }
|
||||
// return d.PlaylistFunc(playlist, playlist)
|
||||
//}
|
||||
//
|
||||
//func (d *DeepcolorProvider) Search(keyword string) ([]*miaosic.Media, error) {
|
||||
// if d.SearchFunc == nil {
|
||||
// return nil, miaosic.ErrNotImplemented
|
||||
// }
|
||||
// //result := make([]*miaosic.Media, 0)
|
||||
// //err :=
|
||||
// //fmt.Println(result)
|
||||
// return d.SearchFunc(keyword)
|
||||
//}
|
||||
//
|
||||
//func (d *DeepcolorProvider) UpdateMedia(media *miaosic.Media) error {
|
||||
// if d.InfoFunc == nil {
|
||||
// return miaosic.ErrNotImplemented
|
||||
// }
|
||||
// return d.InfoFunc(media, media)
|
||||
//}
|
||||
//
|
||||
//func (d *DeepcolorProvider) UpdateMediaUrl(media *miaosic.Media) error {
|
||||
// if d.FileFunc == nil {
|
||||
// return miaosic.ErrNotImplemented
|
||||
// }
|
||||
// return d.FileFunc(media, media)
|
||||
//}
|
||||
//
|
||||
//func (d *DeepcolorProvider) UpdateMediaLyric(media *miaosic.Media) error {
|
||||
// media.Lyric = nil
|
||||
// if d.LyricFunc == nil {
|
||||
// // if no lyric func, return nil
|
||||
// return nil
|
||||
// }
|
||||
// return d.LyricFunc(media, media)
|
||||
//}
|
||||
|
||||
8
providers/utils.go
Normal file
8
providers/utils.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package providers
|
||||
|
||||
func CheckPageParam(page, size int) bool {
|
||||
if page < 1 || size < 1 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
Reference in New Issue
Block a user