diff --git a/app/xxx/main.go b/app/xxx/main.go index 6722fef..48e31b8 100644 --- a/app/xxx/main.go +++ b/app/xxx/main.go @@ -1,11 +1,43 @@ package main import ( - "AynaLivePlayer/plugin/textinfo" + "fyne.io/fyne/v2/app" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/data/binding" + "fyne.io/fyne/v2/widget" + "strconv" + "time" ) func main() { - x := &textinfo.TextInfo{} - x.Enable() - x.RenderTemplates() + var app = app.New() + + var ( + labelText = "" + bindedLabelText = binding.BindString(&labelText) + + label = widget.NewLabelWithData(bindedLabelText) + ) + + var window = app.NewWindow("Canvas") + + var verticalBox = container.NewVBox(label) + window.SetContent(verticalBox) + + go func() { + for i := 0; ; i++ { + var newLabelText = strconv.Itoa(i) + if err := bindedLabelText.Set(newLabelText); err != nil { + panic(err) + } + + time.Sleep(time.Microsecond) + + // NOTE: the only thing, that helps prevent UI updates from freezes, except for the direct manipulation with window size, e.g. update window size from 499x499 -> 500x500 and vice-versa for each iteration + canvas.Refresh(label) + } + }() + + window.ShowAndRun() } diff --git a/config/config_player.go b/config/config_player.go index 1e0db9a..3042379 100644 --- a/config/config_player.go +++ b/config/config_player.go @@ -15,8 +15,8 @@ func (c *_PlayerConfig) Name() string { } var Player = &_PlayerConfig{ - Playlists: []string{"2382819181", "4987059624", "646548465"}, - PlaylistsProvider: []string{"netease", "netease", "netease"}, + Playlists: []string{"2382819181", "4987059624", "list1"}, + PlaylistsProvider: []string{"netease", "netease", "local"}, PlaylistIndex: 0, PlaylistRandom: true, AudioDevice: "auto", diff --git a/config/config_provider.go b/config/config_provider.go index 4ac0089..c412ea6 100644 --- a/config/config_provider.go +++ b/config/config_provider.go @@ -10,6 +10,6 @@ func (c *_ProviderConfig) Name() string { } var Provider = &_ProviderConfig{ - Priority: []string{"netease", "kuwo", "bilibili", "bilibili-video"}, + Priority: []string{"netease", "kuwo", "bilibili", "local", "bilibili-video"}, LocalDir: "./music", } diff --git a/controller/playlist.go b/controller/playlist.go index ebc5fcf..0d6d80f 100644 --- a/controller/playlist.go +++ b/controller/playlist.go @@ -5,6 +5,9 @@ import "AynaLivePlayer/player" func AddToHistory(media *player.Media) { l().Tracef("add media %s (%s) to history", media.Title, media.Artist) media = media.Copy() + if History.Size() >= 1024 { + History.Replace([]*player.Media{}) + } History.Push(media) return } diff --git a/controller/provider.go b/controller/provider.go index 12f1368..dfd8584 100644 --- a/controller/provider.go +++ b/controller/provider.go @@ -8,7 +8,7 @@ import ( func PrepareMedia(media *player.Media) error { var err error - if media.Title == "" || media.Cover == "" { + if media.Title == "" || !media.Cover.Exists() { l().Trace("fetching media info") if err = provider.UpdateMedia(media); err != nil { l().Warn("fail to prepare media when fetch info", err) diff --git a/go.mod b/go.mod index b3ab0b5..c4b1bbb 100644 --- a/go.mod +++ b/go.mod @@ -4,28 +4,17 @@ go 1.16 require ( fyne.io/fyne/v2 v2.1.4 - github.com/BurntSushi/toml v0.4.1 - github.com/Kodeworks/golang-image-ico v0.0.0-20141118225523-73f0f4cfade9 github.com/XiaoMengXinX/Music163Api-Go v0.1.26 github.com/antonfisher/nested-logrus-formatter v1.3.1 github.com/aynakeya/blivedm v0.1.3 github.com/aynakeya/go-mpv v0.0.4 - github.com/go-ole/go-ole v1.2.6 + github.com/dhowden/tag v0.0.0-20220618230019-adf36e896086 github.com/go-resty/resty/v2 v2.7.0 - github.com/jackmordaunt/icns v0.0.0-20181231085925-4f16af745526 github.com/jinzhu/copier v0.3.5 - github.com/josephspurrier/goversioninfo v0.0.0-20200309025242-14b0ab84c6ca - github.com/lucor/goinfo v0.0.0-20210802170112-c078a2b0f08b github.com/mitchellh/panicwrap v1.0.0 - github.com/pkg/errors v0.9.1 github.com/sirupsen/logrus v1.8.1 github.com/spf13/cast v1.3.1 - github.com/stretchr/testify v1.5.1 github.com/tidwall/gjson v1.14.1 - github.com/urfave/cli/v2 v2.3.0 - golang.org/x/mod v0.4.2 - golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c - golang.org/x/tools v0.1.5 gopkg.in/ini.v1 v1.66.4 ) diff --git a/go.sum b/go.sum index ab1dc96..c5495f9 100644 --- a/go.sum +++ b/go.sum @@ -1,21 +1,21 @@ fyne.io/fyne/v2 v2.1.4 h1:bt1+28++kAzRzPB0GM2EuSV4cnl8rXNX4cjfd8G06Rc= fyne.io/fyne/v2 v2.1.4/go.mod h1:p+E/Dh+wPW8JwR2DVcsZ9iXgR9ZKde80+Y+40Is54AQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw= github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/Kodeworks/golang-image-ico v0.0.0-20141118225523-73f0f4cfade9 h1:1ltqoej5GtaWF8jaiA49HwsZD459jqm9YFz9ZtMFpQA= github.com/Kodeworks/golang-image-ico v0.0.0-20141118225523-73f0f4cfade9/go.mod h1:7uhhqiBaR4CpN0k9rMjOtjpcfGd6DG2m04zQxKnWQ0I= github.com/XiaoMengXinX/Music163Api-Go v0.1.26 h1:Nybor5okI8C0jzAiRvGfpLHdDrPqUbjx5kXWIZDX6pw= github.com/XiaoMengXinX/Music163Api-Go v0.1.26/go.mod h1:kLU/CkLxKnEJFCge0URvQ0lHt6ImoG1/2aVeNbgV2RQ= -github.com/akavel/rsrc v0.8.0 h1:zjWn7ukO9Kc5Q62DOJCcxGpXC18RawVtYAGdz2aLlfw= github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= github.com/antonfisher/nested-logrus-formatter v1.3.1 h1:NFJIr+pzwv5QLHTPyKz9UMEoHck02Q9L0FP13b/xSbQ= github.com/antonfisher/nested-logrus-formatter v1.3.1/go.mod h1:6WTfyWFkBc9+zyBaKIqRrg/KwMqBbodBjgbHjDz7zjA= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dhowden/itl v0.0.0-20170329215456-9fbe21093131/go.mod h1:eVWQJVQ67aMvYhpkDwaH2Goy2vo6v8JCMfGXfQ9sPtw= +github.com/dhowden/plist v0.0.0-20141002110153-5db6e0d9931a/go.mod h1:sLjdR6uwx3L6/Py8F+QgAfeiuY87xuYGwCDqRFrvCzw= +github.com/dhowden/tag v0.0.0-20220618230019-adf36e896086 h1:ORubSQoKnncsBnR4zD9CuYFJCPOCuSNEpWEZrDdBXkc= +github.com/dhowden/tag v0.0.0-20220618230019-adf36e896086/go.mod h1:Z3Lomva4pyMWYezjMAU5QWRh0p1VvO4199OHlFnyKkM= github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3 h1:FDqhDm7pcsLhhWl1QtD8vlzI4mm59llRvNzrFg6/LAA= github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3/go.mod h1:CzM2G82Q9BDUvMTGHnXf/6OExw/Dz2ivDj48nVg7Lg8= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= @@ -24,7 +24,6 @@ github.com/go-gl/gl v0.0.0-20210813123233-e4099ee2221f h1:s0O46d8fPwk9kU4k1jj76w github.com/go-gl/gl v0.0.0-20210813123233-e4099ee2221f/go.mod h1:wjpnOv6ONl2SuJSxqCPVaPZibGFdSci9HFocT9qtVYM= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211024062804-40e447a793be h1:Z28GdQBfKOL8tNHjvaDn3wHDO7AzTRkmAXvHvnopp98= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211024062804-40e447a793be/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-resty/resty/v2 v2.6.0/go.mod h1:PwvJS6hvaPkjtjNg9ph+VrSD92bi5Zq73w/BIH7cC3Q= github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY= @@ -37,31 +36,24 @@ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/jackmordaunt/icns v0.0.0-20181231085925-4f16af745526 h1:NfuKjkj/Xc2z1xZIj+EmNCm5p1nKJPyw3F4E20usXvg= github.com/jackmordaunt/icns v0.0.0-20181231085925-4f16af745526/go.mod h1:UQkeMHVoNcyXYq9otUupF7/h/2tmHlhrS2zw7ZVvUqc= github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg= github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= -github.com/josephspurrier/goversioninfo v0.0.0-20200309025242-14b0ab84c6ca h1:ozPUX9TKQZVek4lZWYRsQo7uS8vJ+q4OOHvRhHiCLfU= github.com/josephspurrier/goversioninfo v0.0.0-20200309025242-14b0ab84c6ca/go.mod h1:eJTEwMjXb7kZ633hO3Ln9mBUCOjX2+FlTljvpl9SYdE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lucor/goinfo v0.0.0-20210802170112-c078a2b0f08b h1:tLSDWcFhT0WRlnsFszh4iaFTexWF8mmccGTk88Siq7Q= github.com/lucor/goinfo v0.0.0-20210802170112-c078a2b0f08b/go.mod h1:PRq09yoB+Q2OJReAmwzKivcYyremnibWGbK7WfftHzc= github.com/mitchellh/panicwrap v1.0.0 h1:67zIyVakCIvcs69A0FGfZjBdPleaonSgGlXRSRlb6fE= github.com/mitchellh/panicwrap v1.0.0/go.mod h1:pKvZHwWrZowLUzftuFq7coarnxbBXU4aQh3N0BJOeeA= -github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= @@ -86,7 +78,6 @@ github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JT github.com/tidwall/pretty v1.1.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= -github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.3.8 h1:Nw158Q8QN+CPgTmVRByhVwapp8Mm1e2blinhmx4wx5E= @@ -95,7 +86,6 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/image v0.0.0-20200430140353-33d19683fad8 h1:6WW6V3x1P/jokJBpRQYUJnMHRP6isStQwCozxnU7XQw= golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -122,11 +112,9 @@ golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= diff --git a/gui/config_layout.go b/gui/config_layout.go index 3f92d5a..9fa499e 100644 --- a/gui/config_layout.go +++ b/gui/config_layout.go @@ -22,6 +22,10 @@ func (t *TestConfig) CreatePanel() fyne.CanvasObject { } func createConfigLayout() fyne.CanvasObject { + // initialize config panels + for _, c := range ConfigList { + c.CreatePanel() + } content := container.NewMax() entryList := widget.NewList( func() int { diff --git a/gui/gui.go b/gui/gui.go index 2a230cc..9f05d51 100644 --- a/gui/gui.go +++ b/gui/gui.go @@ -29,6 +29,7 @@ func l() *logrus.Entry { } func Initialize() { + l().Info("Initializing GUI") os.Setenv("FYNE_FONT", config.GetAssetPath("msyh.ttc")) App = app.New() MainWindow = App.NewWindow(fmt.Sprintf("AynaLivePlayer Ver.%s", config.VERSION)) diff --git a/gui/helper.go b/gui/helper.go index 8763ba5..b92ab19 100644 --- a/gui/helper.go +++ b/gui/helper.go @@ -1,8 +1,12 @@ package gui import ( + "AynaLivePlayer/player" + "bytes" "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/storage" "fyne.io/fyne/v2/widget" ) @@ -74,3 +78,19 @@ func newFixedSplitContainer(horizontal bool, leading, trailing fyne.CanvasObject fs.Split.BaseWidget.ExtendBaseWidget(s) return fs } + +func newImageFromPlayerPicture(picture player.Picture) (*canvas.Image, error) { + if picture.Data != nil { + return canvas.NewImageFromReader(bytes.NewReader(picture.Data), "cover"), nil + } else { + uri, err := storage.ParseURI(picture.Url) + if err != nil || uri == nil { + return nil, err + } + img := canvas.NewImageFromURI(uri) + if img == nil { + return nil, err + } + return img, err + } +} diff --git a/gui/player_controller.go b/gui/player_controller.go index a730a87..e3b6493 100644 --- a/gui/player_controller.go +++ b/gui/player_controller.go @@ -10,7 +10,6 @@ import ( "fyne.io/fyne/v2" "fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/container" - "fyne.io/fyne/v2/storage" "fyne.io/fyne/v2/theme" "fyne.io/fyne/v2/widget" "github.com/aynakeya/go-mpv" @@ -195,24 +194,34 @@ func registerPlayControllerHandler() { PlayController.Artist.SetText( media.Artist) PlayController.Username.SetText(media.ToUser().Name) - if media.Cover == "" { + if !media.Cover.Exists() { PlayController.SetDefaultCover() } else { - uri, err := storage.ParseURI(media.Cover) - if err != nil || uri == nil { - l().Warn("fail to load parse cover url", media.Cover) - } - // async update go func() { - img := canvas.NewImageFromURI(uri) - if img == nil { + picture, err := newImageFromPlayerPicture(media.Cover) + if err != nil { l().Warn("fail to load parse cover url", media.Cover) PlayController.SetDefaultCover() return } - PlayController.Cover.Resource = img.Resource + PlayController.Cover.Resource = picture.Resource PlayController.Cover.Refresh() }() + //uri, err := storage.ParseURI(media.Cover) + //if err != nil || uri == nil { + // l().Warn("fail to load parse cover url", media.Cover) + //} + //// async update + //go func() { + // img := canvas.NewImageFromURI(uri) + // if img == nil { + // l().Warn("fail to load parse cover url", media.Cover) + // PlayController.SetDefaultCover() + // return + // } + // PlayController.Cover.Resource = img.Resource + // PlayController.Cover.Refresh() + //}() } }) return diff --git a/music/list1/Lopu$,眠,Aevv - Love Letter <3.mp3 b/music/list1/Lopu$,眠,Aevv - Love Letter <3.mp3 new file mode 100644 index 0000000..1388c32 Binary files /dev/null and b/music/list1/Lopu$,眠,Aevv - Love Letter <3.mp3 differ diff --git a/music/list1/著小生zoki,洛天依 - 【洛天依】影子小姐.mp3 b/music/list1/著小生zoki,洛天依 - 【洛天依】影子小姐.mp3 new file mode 100644 index 0000000..c484087 Binary files /dev/null and b/music/list1/著小生zoki,洛天依 - 【洛天依】影子小姐.mp3 differ diff --git a/player/media.go b/player/media.go index b3c4e9b..2dc8863 100644 --- a/player/media.go +++ b/player/media.go @@ -5,10 +5,19 @@ import ( "github.com/jinzhu/copier" ) +type Picture struct { + Url string + Data []byte +} + +func (p Picture) Exists() bool { + return p.Url != "" || p.Data != nil +} + type Media struct { Title string Artist string - Cover string + Cover Picture Album string Lyric string Url string diff --git a/plugin/textinfo/textinfo.go b/plugin/textinfo/textinfo.go index bdedd0c..36a481f 100644 --- a/plugin/textinfo/textinfo.go +++ b/plugin/textinfo/textinfo.go @@ -13,6 +13,7 @@ import ( "fyne.io/fyne/v2/data/binding" "fyne.io/fyne/v2/widget" "github.com/aynakeya/go-mpv" + "github.com/go-resty/resty/v2" "github.com/sirupsen/logrus" "io/ioutil" "os" @@ -41,6 +42,7 @@ type MediaInfo struct { Artist string Album string Username string + Cover player.Picture } type OutInfo struct { @@ -159,6 +161,34 @@ func (t *TextInfo) RenderTemplates() { } } +func (t *TextInfo) OutputCover() { + if !t.Rendering { + return + } + if !t.info.Current.Cover.Exists() { + return + } + if t.info.Current.Cover.Data != nil { + err := ioutil.WriteFile(filepath.Join(Out_Path, "cover.jpg"), t.info.Current.Cover.Data, 0666) + if err != nil { + l().Warnf("write cover file failed: %s", err) + } + return + } + go func() { + resp, err := resty.New().R(). + Get(t.info.Current.Cover.Url) + if err != nil { + l().Warnf("get cover %s content failed: %s", t.info.Current.Cover.Url, err) + return + } + err = ioutil.WriteFile(filepath.Join(Out_Path, "cover.jpg"), resp.Body(), 0666) + if err != nil { + l().Warnf("write cover file failed: %s", err) + } + }() +} + func (t *TextInfo) registerHandlers() { controller.MainPlayer.EventHandler.RegisterA(player.EventPlay, "plugin.textinfo.current", func(event *event.Event) { t.info.Current = MediaInfo{ @@ -166,9 +196,11 @@ func (t *TextInfo) registerHandlers() { Title: event.Data.(player.PlayEvent).Media.Title, Artist: event.Data.(player.PlayEvent).Media.Artist, Album: event.Data.(player.PlayEvent).Media.Album, + Cover: event.Data.(player.PlayEvent).Media.Cover, Username: event.Data.(player.PlayEvent).Media.ToUser().Name, } t.RenderTemplates() + t.OutputCover() }) if controller.MainPlayer.ObserveProperty("time-pos", func(property *mpv.EventProperty) { if property.Data == nil { diff --git a/provider/bilibili.go b/provider/bilibili.go index cfdb804..11cd289 100644 --- a/provider/bilibili.go +++ b/provider/bilibili.go @@ -76,7 +76,7 @@ func (b *Bilibili) Search(keyword string) ([]*player.Media, error) { gjson.Get(resp, "data.result").ForEach(func(key, value gjson.Result) bool { result = append(result, &player.Media{ Title: value.Get("title").String(), - Cover: value.Get("cover").String(), + Cover: player.Picture{Url: value.Get("cover").String()}, Artist: value.Get("author").String(), Meta: Meta{ Name: b.GetName(), @@ -99,7 +99,7 @@ func (b *Bilibili) UpdateMedia(media *player.Media) error { return ErrorExternalApi } media.Title = gjson.Get(resp, "data.title").String() - media.Cover = gjson.Get(resp, "data.cover").String() + media.Cover.Url = gjson.Get(resp, "data.cover").String() media.Artist = gjson.Get(resp, "data.author").String() media.Album = media.Title return nil diff --git a/provider/bilivideo.go b/provider/bilivideo.go index d563354..b1bfd0c 100644 --- a/provider/bilivideo.go +++ b/provider/bilivideo.go @@ -92,7 +92,7 @@ func (b *BilibiliVideo) Search(keyword string) ([]*player.Media, error) { jresp.Get("data.result").ForEach(func(key, value gjson.Result) bool { result = append(result, &player.Media{ Title: r.ReplaceAllString(value.Get("title").String(), ""), - Cover: "https:" + value.Get("pic").String(), + Cover: player.Picture{Url: "https:" + value.Get("pic").String()}, Artist: value.Get("author").String(), Meta: Meta{ Name: b.GetName(), @@ -115,7 +115,7 @@ func (b *BilibiliVideo) UpdateMedia(media *player.Media) error { } media.Title = jresp.Get("data.View.title").String() media.Artist = jresp.Get("data.View.owner.name").String() - media.Cover = jresp.Get("data.View.pic").String() + media.Cover.Url = jresp.Get("data.View.pic").String() media.Album = media.Title return nil } @@ -139,11 +139,11 @@ func (b *BilibiliVideo) UpdateMediaUrl(media *player.Media) error { return ErrorExternalApi } jresp = gjson.Parse(resp) - url := jresp.Get("data.durl.0.url").String() - if url == "" { + uri := jresp.Get("data.durl.0.url").String() + if uri == "" { return ErrorExternalApi } - media.Url = url + media.Url = uri header := make(map[string]string) _ = copier.Copy(&header, &b.header) header["Referer"] = fmt.Sprintf("https://www.bilibili.com/video/%s", b.getBv(media.Meta.(Meta).Id)) diff --git a/provider/kuwo.go b/provider/kuwo.go index 3eb76c4..867a967 100644 --- a/provider/kuwo.go +++ b/provider/kuwo.go @@ -116,7 +116,7 @@ func (k *Kuwo) Search(keyword string) ([]*player.Media, error) { gjson.Parse(resp).Get("data.list").ForEach(func(key, value gjson.Result) bool { result = append(result, &player.Media{ Title: html.UnescapeString(value.Get("name").String()), - Cover: value.Get("pic").String(), + Cover: player.Picture{Url: value.Get("pic").String()}, Artist: value.Get("artist").String(), Album: value.Get("album").String(), Meta: Meta{ @@ -139,7 +139,7 @@ func (k *Kuwo) UpdateMedia(media *player.Media) error { return ErrorExternalApi } media.Title = html.UnescapeString(jresp.Get("data.name").String()) - media.Cover = jresp.Get("data.pic").String() + media.Cover.Url = jresp.Get("data.pic").String() media.Artist = jresp.Get("data.artist").String() media.Album = jresp.Get("data.album").String() return nil @@ -193,7 +193,7 @@ func (k *Kuwo) GetPlaylist(meta Meta) ([]*player.Media, error) { &player.Media{ Title: html.UnescapeString(value.Get("name").String()), Artist: value.Get("artist").String(), - Cover: value.Get("pic").String(), + Cover: player.Picture{Url: value.Get("pic").String()}, Album: value.Get("album").String(), Meta: Meta{ Name: k.GetName(), diff --git a/provider/local.go b/provider/local.go index 292f852..064f5f6 100644 --- a/provider/local.go +++ b/provider/local.go @@ -4,6 +4,8 @@ import ( "AynaLivePlayer/config" "AynaLivePlayer/player" "os" + "sort" + "strings" ) type _LocalPlaylist struct { @@ -19,7 +21,7 @@ var LocalAPI *Local func init() { LocalAPI = _newLocal() - //Providers[LocalAPI.GetName()] = LocalAPI + Providers[LocalAPI.GetName()] = LocalAPI } func _newLocal() *Local { @@ -27,43 +29,99 @@ func _newLocal() *Local { if err := os.MkdirAll(config.Provider.LocalDir, 0755); err != nil { return l } - + for _, n := range getPlaylistNames() { + l.Playlists = append(l.Playlists, _LocalPlaylist{Name: n}) + } + for i, _ := range l.Playlists { + _ = readLocalPlaylist(&l.Playlists[i]) + } return l } func (l *Local) GetName() string { return "local" } + func (l *Local) MatchMedia(keyword string) *player.Media { - //TODO implement me - panic("implement me") + return nil } func (l *Local) UpdateMediaLyric(media *player.Media) error { - //TODO implement me - panic("implement me") + // already update in UpdateMedia, do nothing + return nil } func (l *Local) FormatPlaylistUrl(uri string) string { - return "" + return uri } -func (l *Local) GetPlaylist(playlist string) ([]*player.Media, error) { - //TODO implement me - panic("implement me") +func (l *Local) GetPlaylist(playlist Meta) ([]*player.Media, error) { + var pl *_LocalPlaylist = nil + for _, p := range l.Playlists { + if p.Name == playlist.Id { + pl = &p + } + } + if pl == nil { + l.Playlists = append(l.Playlists, _LocalPlaylist{Name: playlist.Id}) + pl = &l.Playlists[len(l.Playlists)-1] + } + if readLocalPlaylist(pl) != nil { + return nil, ErrorExternalApi + } + return pl.Medias, nil } func (l *Local) Search(keyword string) ([]*player.Media, error) { - //TODO implement me - panic("implement me") + result := make([]struct { + M *player.Media + N int + }, 0) + keywords := strings.Split(keyword, " ") + for _, p := range l.Playlists { + for _, m := range p.Medias { + n := 0 + for _, k := range keywords { + if strings.Contains(m.Title, k) || strings.Contains(m.Artist, k) { + n++ + } + if k == m.Title { + n += 2 + } + } + if n > 0 { + result = append(result, struct { + M *player.Media + N int + }{M: m, N: n}) + } + } + } + sort.Slice(result, func(i, j int) bool { + return result[i].N > result[j].N + }) + medias := make([]*player.Media, len(result)) + for i, r := range result { + medias[i] = r.M.Copy() + } + return medias, nil } func (l *Local) UpdateMedia(media *player.Media) error { - //TODO implement me - panic("implement me") + mediaPath := media.Meta.(Meta).Id + _, err := os.Stat(mediaPath) + if err != nil { + return err + } + return readMediaFile(media) } func (l *Local) UpdateMediaUrl(media *player.Media) error { - //TODO implement me - panic("implement me") + mediaPath := media.Meta.(Meta).Id + _, err := os.Stat(mediaPath) + if err != nil { + return err + } + media.Url = mediaPath + return nil } diff --git a/provider/local_helper.go b/provider/local_helper.go new file mode 100644 index 0000000..bafb9ac --- /dev/null +++ b/provider/local_helper.go @@ -0,0 +1,73 @@ +package provider + +import ( + "AynaLivePlayer/config" + "AynaLivePlayer/player" + "AynaLivePlayer/util" + "github.com/dhowden/tag" + "io/ioutil" + "os" + "path/filepath" +) + +func getPlaylistNames() []string { + names := make([]string, 0) + items, _ := ioutil.ReadDir(config.Provider.LocalDir) + for _, item := range items { + if item.IsDir() { + names = append(names, item.Name()) + } + } + return names +} + +// readLocalPlaylist read files under a directory +// and return a _LocalPlaylist object. +// This function assume this directory exists +func readLocalPlaylist(playlist *_LocalPlaylist) error { + p1th := playlist.Name + playlist.Medias = make([]*player.Media, 0) + fullPath := filepath.Join(config.Provider.LocalDir, p1th) + if _, err := os.Stat(fullPath); os.IsNotExist(err) { + return err + } + items, _ := ioutil.ReadDir(fullPath) + for _, item := range items { + // if item is a file, read file + if !item.IsDir() { + fn := item.Name() + media := player.Media{ + Meta: Meta{ + Name: LocalAPI.GetName(), + Id: filepath.Join(fullPath, fn), + }, + } + if readMediaFile(&media) != nil { + continue + } + playlist.Medias = append(playlist.Medias, &media) + } + } + return nil +} + +func readMediaFile(media *player.Media) error { + p := media.Meta.(Meta).Id + f, err := os.Open(p) + if err != nil { + return err + } + defer f.Close() + meta, err := tag.ReadFrom(f) + if err != nil { + return err + } + media.Title = util.GetOrDefault(meta.Title(), filepath.Base(p)) + media.Artist = util.GetOrDefault(meta.Artist(), "Unknown") + media.Album = util.GetOrDefault(meta.Album(), "Unknown") + media.Lyric = meta.Lyrics() + if meta.Picture() != nil { + media.Cover.Data = meta.Picture().Data + } + return nil +} diff --git a/provider/netease.go b/provider/netease.go index 31b4a86..7d37cbd 100644 --- a/provider/netease.go +++ b/provider/netease.go @@ -120,7 +120,7 @@ func (n *Netease) GetPlaylist(meta Meta) ([]*player.Media, error) { medias = append(medias, &player.Media{ Title: result2.Songs[i].Name, Artist: _neteaseGetArtistNames(result2.Songs[i]), - Cover: result2.Songs[i].Al.PicUrl, + Cover: player.Picture{Url: result2.Songs[i].Al.PicUrl}, Album: result2.Songs[i].Al.Name, Url: "", Header: nil, @@ -158,7 +158,7 @@ func (n *Netease) Search(keyword string) ([]*player.Media, error) { medias = append(medias, &player.Media{ Title: song.Name, Artist: strings.Join(artists, ","), - Cover: "", + Cover: player.Picture{}, Album: song.Album.Name, Url: "", Header: nil, @@ -182,7 +182,7 @@ func (n *Netease) UpdateMedia(media *player.Media) error { return ErrorExternalApi } media.Title = result.Songs[0].Name - media.Cover = result.Songs[0].Al.PicUrl + media.Cover.Url = result.Songs[0].Al.PicUrl media.Album = result.Songs[0].Al.Name media.Artist = _neteaseGetArtistNames(result.Songs[0]) return nil diff --git a/util/string.go b/util/string.go index 8e7c4fe..a54b5a6 100644 --- a/util/string.go +++ b/util/string.go @@ -44,3 +44,10 @@ func StringSliceCopy(src []string) []string { copy(x, src) return x } + +func GetOrDefault(s string, def string) string { + if s == "" { + return def + } + return s +}