update api

This commit is contained in:
aynakeya
2023-10-30 20:36:27 -07:00
parent 4ec679f01c
commit 7dde9cf6ae
19 changed files with 646 additions and 620 deletions

View File

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

View File

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

View File

@@ -1,9 +1,9 @@
package bilibili
import (
"miaosic"
"github.com/AynaLivePlayer/miaosic"
)
func init() {
miaosic.RegisterProvider(NewBilibili(miaosic.Requester))
miaosic.RegisterProvider(NewBilibili())
}

View File

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

View File

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

View File

@@ -0,0 +1,7 @@
package bilivideo
import "github.com/AynaLivePlayer/miaosic"
func init() {
miaosic.RegisterProvider(NewBilibiliViedo())
}

View File

@@ -1,7 +1,7 @@
package kuwo
import "miaosic"
import "github.com/AynaLivePlayer/miaosic"
func init() {
miaosic.RegisterProvider(NewKuwo(miaosic.Requester))
miaosic.RegisterProvider(NewKuwo())
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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
View File

@@ -0,0 +1,8 @@
package providers
func CheckPageParam(page, size int) bool {
if page < 1 || size < 1 {
return false
}
return true
}