This commit is contained in:
aynakeya
2024-04-13 00:59:44 -07:00
parent 119862a023
commit fd872c1f5b
58 changed files with 806 additions and 350 deletions

View File

@@ -26,8 +26,7 @@ clear:
$(RM) config.ini log.txt playlists.txt liverooms.json
bundle:
fyne bundle --name resImageEmpty --package resource ./assets/empty.png > ./resource/bundle.go
fyne bundle --append --name resImageIcon --package resource ./assets/icon.jpg >> ./resource/bundle.go
fyne bundle --name resImageIcon --package resource ./assets/icon.png > ./resource/bundle.go
# fyne bundle --append --name resFontMSYaHei --package resource ./assets/msyh.ttc >> ./resource/bundle.go
# fyne bundle --append --name resFontMSYaHeiBold --package resource ./assets/msyhbd.ttc >> ./resource/bundle.go
fyne bundle --append --name resFontMSYaHei --package resource ./assets/msyh0.ttf >> ./resource/bundle.go

View File

@@ -34,24 +34,6 @@ var Log = &_LogConfig{
MaxSize: 5,
}
//func createController(log adapter.ILogger) adapter.IControlBridge {
// logbridge := log.WithModule("ControlBridge")
// em := event.MainManager.NewChildManager()
// liveroom := internal.NewLiveRoomController(
// logbridge)
// lyric := internal.NewLyricLoader()
// provider := internal.NewProviderController(logbridge)
// playlist := internal.NewPlaylistController(em, logbridge, provider)
// plugin := internal.NewPluginController(logbridge)
// mpvPlayer := player.NewMpvPlayer(em, logbridge)
// playControl := internal.NewPlayerController(mpvPlayer, playlist, lyric, provider, logbridge)
// ctr := internal.NewController(
// liveroom, playControl, playlist, provider, plugin,
// logbridge,
// )
// return ctr
//}
func setupGlobal() {
global.EventManager = event.NewManger(128, 16)
global.Logger = loggerRepo.NewZapColoredLogger()
@@ -66,7 +48,6 @@ func main() {
setupGlobal()
global.Logger.Info("================Program Start================")
global.Logger.Infof("================Current Version: %s================", model.Version(config.Version))
//mainController := createController(log)
internal.Initialize()
gui.Initialize()
global.EventManager.Start()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

BIN
assets/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 KiB

View File

@@ -280,6 +280,10 @@
"en": "Search",
"zh-CN": "搜索"
},
"gui.tray.btn.show": {
"en": "Show",
"zh-CN": "打开"
},
"gui.update.new_version": {
"en": "New Version Available",
"zh-CN": "有新版本可用"

View File

@@ -1,9 +0,0 @@
package adapter
import "AynaLivePlayer/core/model"
type IApplication interface {
Version() model.VersionInfo
LatestVersion() model.VersionInfo
CheckUpdate() error
}

View File

@@ -1,31 +0,0 @@
package adapter
import (
"AynaLivePlayer/core/model"
"AynaLivePlayer/pkg/event"
)
type LiveClientCtor func(id string, ev *event.Manager, log ILogger) (LiveClient, error)
type LiveClient interface {
ClientName() string
RoomName() string
Connect() bool
Disconnect() bool
Status() bool
EventManager() *event.Manager
}
type ILiveRoom interface {
Client() LiveClient
Model() *model.LiveRoom // should return mutable model (not a copy)
Identifier() string
DisplayName() string
Status() bool
EventManager() *event.Manager
}
type LiveRoomExecutor interface {
Match(command string) bool
Execute(command string, args []string, danmu *model.DanmuMessage)
}

View File

@@ -1,23 +0,0 @@
package adapter
type LogLevel uint32
const (
LogLevelError LogLevel = iota
LogLevelWarn
LogLevelInfo
LogLevelDebug
)
type ILogger interface {
Debug(args ...interface{})
Debugf(format string, args ...interface{})
Info(args ...interface{})
Infof(format string, args ...interface{})
Warn(args ...interface{})
Warnf(format string, args ...interface{})
Error(args ...interface{})
Errorf(format string, args ...interface{})
WithModule(prefix string) ILogger
SetLogLevel(level LogLevel)
}

View File

@@ -1,40 +0,0 @@
package adapter
import (
"AynaLivePlayer/core/model"
"AynaLivePlayer/pkg/event"
)
type PlayerCtor func(ev *event.Manager, log ILogger) IPlayer
type IPlayer interface {
// Start the player
Start()
// Stop the player
Stop()
// Play play a media
Play(media *model.Media) error
// GetPlaying get playing media
// if player is idle, return nil
GetPlaying() *model.Media
// IsPaused return true if player is paused
IsPaused() bool
// Pause pause player
Pause() error
// Unpause unpause player
Unpause() error
// SetVolume set volume
SetVolume(volume float64) error
// IsIdle return true if player is playing anything
IsIdle() bool
// Seek to position, if absolute is true, position is absolute time, otherwise position is relative time
Seek(position float64, absolute bool) error
// SetWindowHandle set window handle for video output
SetWindowHandle(handle uintptr) error
// ObserveProperty observe player property change
ObserveProperty(property model.PlayerProperty, name string, handler event.HandlerFunc) error
// GetAudioDeviceList get audio device list
GetAudioDeviceList() ([]model.AudioDevice, error)
// SetAudioDevice set audio device
SetAudioDevice(device string) error
}

View File

@@ -1,22 +0,0 @@
package adapter
import (
"AynaLivePlayer/core/model"
"AynaLivePlayer/pkg/event"
)
type IPlaylist interface {
Identifier() string // must unique for each playlist
Model() *model.Playlist // mutable model (not a copy)
EventManager() *event.Manager
DisplayName() string
Size() int
Get(index int) *model.Media
Pop() *model.Media
Replace(medias []*model.Media)
Push(media *model.Media)
Insert(index int, media *model.Media)
Delete(index int) *model.Media
Move(src int, dst int)
Next() *model.Media
}

View File

@@ -1,7 +0,0 @@
package adapter
type Plugin interface {
Name() string
Enable() error
Disable() error
}

View File

@@ -1,17 +0,0 @@
package adapter
import "AynaLivePlayer/core/model"
type MediaProviderConfig map[string]string
type MediaProviderCtor func(config MediaProviderConfig) MediaProvider
type MediaProvider interface {
GetName() string
MatchMedia(keyword string) *model.Media
GetPlaylist(playlist *model.Meta) ([]*model.Media, error)
FormatPlaylistUrl(uri string) string
Search(keyword string) ([]*model.Media, error)
UpdateMedia(media *model.Media) error
UpdateMediaUrl(media *model.Media) error
UpdateMediaLyric(media *model.Media) error
}

View File

@@ -1,91 +0,0 @@
package adapter
import (
"AynaLivePlayer/core/model"
"AynaLivePlayer/pkg/event"
)
// IControlBridge is the interface for all controller and
// all system use cases.
type IControlBridge interface {
App() IApplication
LiveRooms() ILiveRoomController
PlayControl() IPlayController
Playlists() IPlaylistController
Provider() IProviderController
Plugin() IPluginController
LoadPlugins(plugins ...Plugin)
Logger() ILogger
CloseAndSave()
}
type ILiveRoomController interface {
Size() int
Get(index int) ILiveRoom
GetRoomStatus(index int) bool
Connect(index int) error
Disconnect(index int) error
AddRoom(clientName, roomId string) (*model.LiveRoom, error)
DeleteRoom(index int) error
AddDanmuCommand(executor LiveRoomExecutor)
GetAllClientNames() []string
}
type IProviderController interface {
GetPriority() []string
PrepareMedia(media *model.Media) error
MediaMatch(keyword string) *model.Media
Search(keyword string) ([]*model.Media, error)
SearchWithProvider(keyword string, provider string) ([]*model.Media, error)
PreparePlaylist(playlist IPlaylist) error
}
type IPluginController interface {
LoadPlugin(plugin Plugin)
LoadPlugins(plugins ...Plugin)
ClosePlugins()
}
type IPlaylistController interface {
Size() int
GetHistory() IPlaylist
AddToHistory(media *model.Media)
GetDefault() IPlaylist
GetCurrent() IPlaylist
Get(index int) IPlaylist
Add(pname string, uri string) (IPlaylist, error)
Remove(index int) (IPlaylist, error)
SetDefault(index int) error
PreparePlaylistByIndex(index int) error
}
type IPlayControlConfig struct {
SkipPlaylist bool
AutoNextWhenFail bool
}
type IPlayController interface {
EventManager() *event.Manager
GetPlaying() *model.Media
GetPlayer() IPlayer
PlayNext()
Play(media *model.Media) error
Add(keyword string, user interface{})
AddWithProvider(keyword string, provider string, user interface{})
Seek(position float64, absolute bool)
Toggle() bool
SetVolume(volume float64)
Destroy()
GetCurrentAudioDevice() string
GetAudioDevices() []model.AudioDevice
SetAudioDevice(device string)
GetLyric() ILyricLoader
Config() *IPlayControlConfig
}
type ILyricLoader interface {
EventManager() *event.Manager
Get() *model.Lyric
Reload(lyric string)
Update(time float64)
}

54
core/events/playlists.go Normal file
View File

@@ -0,0 +1,54 @@
package events
import (
"AynaLivePlayer/core/model"
)
const PlaylistManagerSetSystemCmd = "cmd.playlist.manager.set.system"
type PlaylistManagerSetSystemCmdEvent struct {
PlaylistID string
}
const PlaylistManagerSystemUpdate = "update.playlist.manager.system"
type PlaylistManagerSystemUpdateEvent struct {
Info model.PlaylistInfo
}
const PlaylistManagerRefreshCurrentCmd = "cmd.playlist.manager.refresh.current"
type PlaylistManagerRefreshCurrentCmdEvent struct {
PlaylistID string
}
const PlaylistManagerGetCurrentCmd = "cmd.playlist.manager.get.current"
type PlaylistManagerGetCurrentCmdEvent struct {
PlaylistID string
}
const PlaylistManagerCurrentUpdate = "update.playlist.manager.current"
type PlaylistManagerCurrentUpdateEvent struct {
Medias []model.Media
}
const PlaylistManagerInfoUpdate = "update.playlist.manager.info"
type PlaylistManagerInfoUpdateEvent struct {
Playlists []model.PlaylistInfo
}
const PlaylistManagerAddPlaylistCmd = "cmd.playlist.manager.add"
type PlaylistManagerAddPlaylistCmdEvent struct {
Provider string
URL string
}
const PlaylistManagerRemovePlaylistCmd = "cmd.playlist.manager.remove"
type PlaylistManagerRemovePlaylistCmdEvent struct {
PlaylistID string
}

7
core/events/provider.go Normal file
View File

@@ -0,0 +1,7 @@
package events
const MediaProviderUpdate = "update.media.provider.update"
type MediaProviderUpdateEvent struct {
Providers []string
}

View File

@@ -16,9 +16,3 @@ const SearchResultUpdate = "update.search_result"
type SearchResultUpdateEvent struct {
Medias []model.Media
}
const SearchProviderUpdate = "update.search.provider.update"
type SearchProviderUpdateEvent struct {
Providers []string
}

View File

@@ -11,7 +11,6 @@ type User struct {
var PlaylistUser = User{Name: "Playlists"}
var SystemUser = User{Name: "System"}
var HistoryUser = User{Name: "History"}
type Media struct {
Info miaosic.MediaInfo

View File

@@ -1,5 +1,7 @@
package model
import "github.com/AynaLivePlayer/miaosic"
type PlaylistMode int
const (
@@ -11,8 +13,19 @@ const (
type PlaylistID string
const (
PlaylistIDPlayer PlaylistID = "player"
PlaylistIDSystem PlaylistID = "system"
PlaylistIDHistory PlaylistID = "history"
PlaylistIDPlaylists PlaylistID = "playlists"
PlaylistIDPlayer PlaylistID = "player"
PlaylistIDSystem PlaylistID = "system"
PlaylistIDHistory PlaylistID = "history"
)
type PlaylistInfo struct {
Meta miaosic.MetaData
Title string
}
func (p PlaylistInfo) DisplayName() string {
if p.Title != "" {
return p.Title
}
return p.Meta.ID()
}

7
go.mod
View File

@@ -12,14 +12,11 @@ require (
fyne.io/x/fyne v0.0.0-20240326131024-3ba9170cc3be
github.com/AynaLivePlayer/liveroom-sdk v0.1.0
github.com/AynaLivePlayer/miaosic v0.1.5
github.com/XiaoMengXinX/Music163Api-Go v0.1.30
github.com/antonfisher/nested-logrus-formatter v1.3.1
github.com/aynakeya/go-mpv v0.0.6
github.com/dhowden/tag v0.0.0-20230630033851-978a0926ee25
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20221017161538-93cebf72946b
github.com/go-resty/resty/v2 v2.7.0
github.com/gorilla/websocket v1.5.0
github.com/jinzhu/copier v0.4.0
github.com/mattn/go-colorable v0.1.12
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
github.com/sirupsen/logrus v1.9.3
@@ -36,10 +33,12 @@ require (
require (
fyne.io/systray v1.10.1-0.20231115130155-104f5ef7839e // indirect
github.com/PuerkitoBio/goquery v1.7.1 // indirect
github.com/XiaoMengXinX/Music163Api-Go v0.1.30 // indirect
github.com/andybalholm/cascadia v1.2.0 // indirect
github.com/aynakeya/deepcolor v1.0.2 // indirect
github.com/aynakeya/open-bilibili-live v0.0.5 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dhowden/tag v0.0.0-20230630033851-978a0926ee25 // indirect
github.com/fredbi/uri v1.0.0 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/fyne-io/gl-js v0.0.0-20220119005834-d2da28d9ccfe // indirect
@@ -51,9 +50,11 @@ require (
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/google/uuid v1.5.0 // indirect
github.com/gopherjs/gopherjs v1.17.2 // indirect
github.com/jinzhu/copier v0.4.0 // indirect
github.com/jsummers/gobmp v0.0.0-20151104160322-e2ba15ffa76e // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/sahilm/fuzzy v0.1.0 // indirect
github.com/spf13/cast v1.5.1 // indirect
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c // indirect
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef // indirect

3
go.sum
View File

@@ -234,6 +234,7 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
@@ -271,6 +272,8 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI=
github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=

View File

@@ -34,7 +34,7 @@ func Initialize() {
black_magic()
logger.Info("Initializing GUI")
//os.Setenv("FYNE_FONT", config.GetAssetPath("msyh.ttc"))
App = app.New()
App = app.NewWithID(config.ProgramName)
App.Settings().SetTheme(&myTheme{})
MainWindow = App.NewWindow(fmt.Sprintf("%s Ver %s", config.ProgramName, model.Version(config.Version)))
@@ -48,12 +48,12 @@ func Initialize() {
container.NewTabItem(i18n.T("gui.tab.room"),
container.NewBorder(nil, nil, createRoomSelector(), nil, createRoomController()),
),
//container.NewTabItem(i18n.T("gui.tab.playlist"),
// container.NewBorder(nil, nil, createPlaylists(), nil, createPlaylistMedias()),
//),
//container.NewTabItem(i18n.T("gui.tab.history"),
// container.NewBorder(nil, nil, nil, nil, createHistoryList()),
//),
container.NewTabItem(i18n.T("gui.tab.playlist"),
container.NewBorder(nil, nil, createPlaylists(), nil, createPlaylistMedias()),
),
container.NewTabItem(i18n.T("gui.tab.history"),
container.NewBorder(nil, nil, nil, nil, createHistoryList()),
),
//container.NewTabItem(i18n.T("gui.tab.config"),
// createConfigLayout(),
//),
@@ -79,6 +79,9 @@ func Initialize() {
})
MainWindow.SetFixedSize(true)
if config.General.ShowSystemTray {
setupSysTray()
}
//if config2.General.AutoCheckUpdate {
// go checkUpdate()
//}

85
gui/history_list.go Normal file
View File

@@ -0,0 +1,85 @@
package gui
import (
"AynaLivePlayer/core/events"
"AynaLivePlayer/core/model"
"AynaLivePlayer/global"
"AynaLivePlayer/pkg/event"
"AynaLivePlayer/pkg/i18n"
"fmt"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
"sync"
)
var History = &struct {
Medias []model.Media
List *widget.List
mux sync.RWMutex
}{}
func createHistoryList() fyne.CanvasObject {
History.List = widget.NewList(
func() int {
return len(History.Medias)
},
func() fyne.CanvasObject {
return container.NewBorder(nil, nil,
widget.NewLabel("index"),
container.NewHBox(
widget.NewButtonWithIcon("", theme.MediaPlayIcon(), nil),
widget.NewButtonWithIcon("", theme.ContentAddIcon(), nil),
),
container.NewGridWithColumns(3,
newLabelWithWrapping("title", fyne.TextTruncate),
newLabelWithWrapping("artist", fyne.TextTruncate),
newLabelWithWrapping("user", fyne.TextTruncate)))
},
func(id widget.ListItemID, object fyne.CanvasObject) {
m := History.Medias[len(History.Medias)-id-1]
object.(*fyne.Container).Objects[0].(*fyne.Container).Objects[0].(*widget.Label).SetText(
m.Info.Title)
object.(*fyne.Container).Objects[0].(*fyne.Container).Objects[1].(*widget.Label).SetText(
m.Info.Artist)
object.(*fyne.Container).Objects[0].(*fyne.Container).Objects[2].(*widget.Label).SetText(
m.ToUser().Name)
object.(*fyne.Container).Objects[1].(*widget.Label).SetText(fmt.Sprintf("%d", id))
btns := object.(*fyne.Container).Objects[2].(*fyne.Container).Objects
m.User = model.SystemUser
btns[0].(*widget.Button).OnTapped = func() {
global.EventManager.CallA(events.PlayerPlayCmd, events.PlayerPlayCmdEvent{
Media: m,
})
}
btns[1].(*widget.Button).OnTapped = func() {
global.EventManager.CallA(events.PlaylistInsertCmd(model.PlaylistIDPlayer), events.PlaylistInsertCmdEvent{
Media: m,
Position: -1,
})
}
})
registerHistoryHandler()
return container.NewBorder(
container.NewBorder(nil, nil,
widget.NewLabel("#"), widget.NewLabel(i18n.T("gui.history.operation")),
container.NewGridWithColumns(3,
widget.NewLabel(i18n.T("gui.history.title")),
widget.NewLabel(i18n.T("gui.history.artist")),
widget.NewLabel(i18n.T("gui.history.user")))),
nil, nil, nil,
History.List,
)
}
func registerHistoryHandler() {
global.EventManager.RegisterA(
events.PlaylistDetailUpdate(model.PlaylistIDHistory),
"gui.history.update", func(event *event.Event) {
History.mux.Lock()
History.Medias = event.Data.(events.PlaylistDetailUpdateEvent).Medias
History.List.Refresh()
History.mux.Unlock()
})
}

View File

@@ -106,6 +106,7 @@ func createRoomSelector() fyne.CanvasObject {
if id >= len(RoomTab.rooms) {
return
}
logger.Infof("Select room %s", RoomTab.rooms[id].LiveRoom.Identifier())
RoomTab.Index = id
room := RoomTab.rooms[RoomTab.Index]
RoomTab.RoomTitle.SetText(room.DisplayName())
@@ -141,6 +142,7 @@ func registerRoomHandlers() {
events.LiveRoomRoomsUpdate,
"gui.liveroom.rooms_update",
func(event *event.Event) {
logger.Infof("Update rooms")
data := event.Data.(events.LiveRoomRoomsUpdateEvent)
RoomTab.lock.Lock()
RoomTab.rooms = data.Rooms

View File

@@ -1,13 +1,13 @@
package gui
import (
"AynaLivePlayer/common/util"
"AynaLivePlayer/core/events"
"AynaLivePlayer/global"
"AynaLivePlayer/gui/component"
"AynaLivePlayer/gui/gutil"
"AynaLivePlayer/pkg/event"
"AynaLivePlayer/pkg/i18n"
"AynaLivePlayer/pkg/util"
"AynaLivePlayer/resource"
"context"
"fyne.io/fyne/v2"

View File

@@ -26,7 +26,6 @@ func createLyricObj(lyric *miaosic.Lyrics) []fyne.CanvasObject {
}
func createLyricWindow() fyne.Window {
// create widgets
w := App.NewWindow(i18n.T("gui.lyric.title"))
currentLrc := newLabelWithWrapping("", fyne.TextWrapBreak)
@@ -45,7 +44,7 @@ func createLyricWindow() fyne.Window {
global.EventManager.RegisterA(
events.PlayerLyricPosUpdate, "player.lyric.current_lyric", func(event *event.Event) {
e := event.Data.(events.PlayerLyricPosUpdateEvent)
logger.Debugf("lyric update", e)
logger.Debug("lyric update", e)
if prevIndex >= len(fullLrc.Objects) || e.CurrentIndex >= len(fullLrc.Objects) {
// fix race condition
return

202
gui/playlists.go Normal file
View File

@@ -0,0 +1,202 @@
package gui
import (
"AynaLivePlayer/core/events"
"AynaLivePlayer/core/model"
"AynaLivePlayer/global"
"AynaLivePlayer/pkg/event"
"AynaLivePlayer/pkg/i18n"
"fmt"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/dialog"
"fyne.io/fyne/v2/layout"
"fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
)
type PlaylistsTab struct {
Playlists *widget.List
PlaylistMedia *widget.List
Index int
AddBtn *widget.Button
RemoveBtn *widget.Button
SetAsSystemBtn *widget.Button
RefreshBtn *widget.Button
CurrentSystemPlaylist *widget.Label
currentMedias []model.Media
currentPlaylists []model.PlaylistInfo
providers []string
}
var PlaylistManager = &PlaylistsTab{}
func createPlaylists() fyne.CanvasObject {
PlaylistManager.Playlists = widget.NewList(
func() int {
return len(PlaylistManager.currentPlaylists)
},
func() fyne.CanvasObject {
return widget.NewLabel("AAAAAAAAAAAAAAAA")
},
func(id widget.ListItemID, object fyne.CanvasObject) {
object.(*widget.Label).SetText(PlaylistManager.currentPlaylists[id].DisplayName())
})
PlaylistManager.AddBtn = widget.NewButton(i18n.T("gui.playlist.button.add"), func() {
providerEntry := widget.NewSelect(PlaylistManager.providers, nil)
idEntry := widget.NewEntry()
dia := dialog.NewCustomConfirm(
i18n.T("gui.playlist.add.title"),
i18n.T("gui.playlist.add.confirm"),
i18n.T("gui.playlist.add.cancel"),
container.NewVBox(
container.New(
layout.NewFormLayout(),
widget.NewLabel(i18n.T("gui.playlist.add.source")),
providerEntry,
widget.NewLabel(i18n.T("gui.playlist.add.id_url")),
idEntry,
),
widget.NewLabel(i18n.T("gui.playlist.add.prompt")),
),
func(b bool) {
if b && len(providerEntry.Selected) > 0 && len(idEntry.Text) > 0 {
logger.Infof("add playlists %s %s", providerEntry.Selected, idEntry.Text)
global.EventManager.CallA(
events.PlaylistManagerAddPlaylistCmd,
events.PlaylistManagerAddPlaylistCmdEvent{
Provider: providerEntry.Selected,
URL: idEntry.Text,
})
}
},
MainWindow,
)
dia.Resize(fyne.NewSize(512, 256))
dia.Show()
})
PlaylistManager.RemoveBtn = widget.NewButton(i18n.T("gui.playlist.button.remove"), func() {
if PlaylistManager.Index >= len(PlaylistManager.currentPlaylists) {
return
}
logger.Infof("remove playlists %s", PlaylistManager.currentPlaylists[PlaylistManager.Index].Meta.ID())
global.EventManager.CallA(
events.PlaylistManagerRemovePlaylistCmd,
events.PlaylistManagerRemovePlaylistCmdEvent{
PlaylistID: PlaylistManager.currentPlaylists[PlaylistManager.Index].Meta.ID(),
})
})
PlaylistManager.Playlists.OnSelected = func(id widget.ListItemID) {
if id >= len(PlaylistManager.currentPlaylists) {
return
}
PlaylistManager.Index = id
global.EventManager.CallA(events.PlaylistManagerGetCurrentCmd, events.PlaylistManagerGetCurrentCmdEvent{
PlaylistID: PlaylistManager.currentPlaylists[id].Meta.ID(),
})
}
global.EventManager.RegisterA(events.MediaProviderUpdate,
"gui.playlists.provider.update", func(event *event.Event) {
providers := event.Data.(events.MediaProviderUpdateEvent)
s := make([]string, len(providers.Providers))
copy(s, providers.Providers)
PlaylistManager.providers = s
})
global.EventManager.RegisterA(events.PlaylistManagerInfoUpdate,
"gui.playlists.info.update", func(event *event.Event) {
data := event.Data.(events.PlaylistManagerInfoUpdateEvent)
prevLen := len(PlaylistManager.currentPlaylists)
PlaylistManager.currentPlaylists = data.Playlists
logger.Infof("receive playlist info update, try to refresh playlists. prevLen=%d, newLen=%d", prevLen, len(PlaylistManager.currentPlaylists))
PlaylistManager.Playlists.Refresh()
if prevLen != len(PlaylistManager.currentPlaylists) {
PlaylistManager.Playlists.Select(0)
}
})
global.EventManager.RegisterA(events.PlaylistManagerSystemUpdate,
"gui.playlists.system.update", func(event *event.Event) {
data := event.Data.(events.PlaylistManagerSystemUpdateEvent)
PlaylistManager.CurrentSystemPlaylist.SetText(i18n.T("gui.playlist.current") + data.Info.DisplayName())
})
return container.NewHBox(
container.NewBorder(
nil, container.NewCenter(container.NewHBox(PlaylistManager.AddBtn, PlaylistManager.RemoveBtn)),
nil, nil,
PlaylistManager.Playlists,
),
widget.NewSeparator(),
)
}
func createPlaylistMedias() fyne.CanvasObject {
PlaylistManager.RefreshBtn = widget.NewButtonWithIcon(
i18n.T("gui.playlist.button.refresh"), theme.ViewRefreshIcon(),
func() {
if PlaylistManager.Index >= len(PlaylistManager.currentPlaylists) {
return
}
global.EventManager.CallA(events.PlaylistManagerRefreshCurrentCmd, events.PlaylistManagerRefreshCurrentCmdEvent{
PlaylistID: PlaylistManager.currentPlaylists[PlaylistManager.Index].Meta.ID(),
})
})
PlaylistManager.SetAsSystemBtn = widget.NewButton(
i18n.T("gui.playlist.button.set_as_system"),
func() {
if PlaylistManager.Index >= len(PlaylistManager.currentPlaylists) {
return
}
logger.Infof("set playlist %s as system", PlaylistManager.currentPlaylists[PlaylistManager.Index].Meta.ID())
global.EventManager.CallA(events.PlaylistManagerSetSystemCmd, events.PlaylistManagerSetSystemCmdEvent{
PlaylistID: PlaylistManager.currentPlaylists[PlaylistManager.Index].Meta.ID(),
})
})
PlaylistManager.CurrentSystemPlaylist = widget.NewLabel("Current: ")
PlaylistManager.PlaylistMedia = widget.NewList(
func() int {
return len(PlaylistManager.currentMedias)
},
func() fyne.CanvasObject {
return container.NewBorder(nil, nil,
widget.NewLabel("index"),
container.NewHBox(
widget.NewButtonWithIcon("", theme.MediaPlayIcon(), nil),
widget.NewButtonWithIcon("", theme.ContentAddIcon(), nil),
),
container.NewGridWithColumns(2,
newLabelWithWrapping("title", fyne.TextTruncate),
newLabelWithWrapping("artist", fyne.TextTruncate)))
},
func(id widget.ListItemID, object fyne.CanvasObject) {
m := PlaylistManager.currentMedias[id]
object.(*fyne.Container).Objects[0].(*fyne.Container).Objects[0].(*widget.Label).SetText(
m.Info.Title)
object.(*fyne.Container).Objects[0].(*fyne.Container).Objects[1].(*widget.Label).SetText(
m.Info.Artist)
object.(*fyne.Container).Objects[1].(*widget.Label).SetText(fmt.Sprintf("%d", id))
btns := object.(*fyne.Container).Objects[2].(*fyne.Container).Objects
m.User = model.SystemUser
btns[0].(*widget.Button).OnTapped = func() {
global.EventManager.CallA(events.PlayerPlayCmd, events.PlayerPlayCmdEvent{
Media: m,
})
}
btns[1].(*widget.Button).OnTapped = func() {
global.EventManager.CallA(events.PlaylistInsertCmd(model.PlaylistIDPlayer), events.PlaylistInsertCmdEvent{
Media: m,
Position: -1,
})
}
})
global.EventManager.RegisterA(events.PlaylistManagerCurrentUpdate,
"gui.playlists.current.update", func(event *event.Event) {
logger.Infof("receive current playlist update, try to refresh playlist medias")
data := event.Data.(events.PlaylistManagerCurrentUpdateEvent)
PlaylistManager.currentMedias = data.Medias
PlaylistManager.PlaylistMedia.Refresh()
})
return container.NewBorder(
container.NewHBox(PlaylistManager.RefreshBtn, PlaylistManager.SetAsSystemBtn, PlaylistManager.CurrentSystemPlaylist), nil,
nil, nil,
PlaylistManager.PlaylistMedia)
}

View File

@@ -40,9 +40,9 @@ func createSearchBar() fyne.CanvasObject {
})
})
global.EventManager.RegisterA(events.SearchProviderUpdate,
global.EventManager.RegisterA(events.MediaProviderUpdate,
"gui.search.provider.update", func(event *event.Event) {
providers := event.Data.(events.SearchProviderUpdateEvent)
providers := event.Data.(events.MediaProviderUpdateEvent)
s := make([]string, len(providers.Providers))
copy(s, providers.Providers)
SearchBar.UseSource.Options = s

22
gui/tray.go Normal file
View File

@@ -0,0 +1,22 @@
package gui
import (
"AynaLivePlayer/pkg/i18n"
"AynaLivePlayer/resource"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/driver/desktop"
)
func setupSysTray() {
if desk, ok := App.(desktop.App); ok {
m := fyne.NewMenu("MyApp",
fyne.NewMenuItem(i18n.T("gui.tray.btn.show"), func() {
MainWindow.Show()
}))
desk.SetSystemTrayMenu(m)
desk.SetSystemTrayIcon(resource.ImageIcon)
}
MainWindow.SetCloseIntercept(func() {
MainWindow.Hide()
})
}

View File

@@ -4,6 +4,7 @@ import (
"AynaLivePlayer/core/events"
"AynaLivePlayer/core/model"
"AynaLivePlayer/global"
"AynaLivePlayer/internal/playlist"
"AynaLivePlayer/pkg/event"
)
@@ -47,10 +48,18 @@ func handlePlayNext() {
events.PlayerPlayNextCmd,
"internal.controller.playcontrol.playnext",
func(event *event.Event) {
global.EventManager.CallA(events.PlaylistNextCmd(model.PlaylistIDPlayer),
events.PlaylistNextCmdEvent{
Remove: true,
})
if playlist.PlayerPlaylist.Size() > 0 {
global.EventManager.CallA(events.PlaylistNextCmd(model.PlaylistIDPlayer),
events.PlaylistNextCmdEvent{
Remove: true,
})
} else {
global.EventManager.CallA(events.PlaylistNextCmd(model.PlaylistIDSystem),
events.PlaylistNextCmdEvent{
Remove: true,
})
}
})
global.EventManager.RegisterA(events.PlaylistNextUpdate(model.PlaylistIDPlayer),
@@ -62,4 +71,14 @@ func handlePlayNext() {
Media: data.Media,
})
})
global.EventManager.RegisterA(events.PlaylistNextUpdate(model.PlaylistIDSystem),
"internal.controller.playcontrol.play_when_next.system_playlist", func(event *event.Event) {
data := event.Data.(events.PlaylistNextUpdateEvent)
global.EventManager.CallA(
events.PlayerPlayCmd,
events.PlayerPlayCmdEvent{
Media: data.Media,
})
})
}

View File

@@ -29,6 +29,7 @@ func createLyricLoader() {
if err == nil && len(lyric) > 0 {
lyricManager.Lyric = lyric[0]
} else {
lyricManager.Lyric = miaosic.ParseLyrics("", "")
log.Errorf("failed to get lyric for %s (%s): %s", data.Media.Info.Title, data.Media.Info.Meta.ID(), err)
}
global.EventManager.CallA(events.PlayerLyricReload, events.PlayerLyricReloadEvent{

View File

@@ -31,8 +31,4 @@ func handleSearch() {
Medias: medias,
})
})
global.EventManager.CallA(
events.SearchProviderUpdate, events.SearchProviderUpdateEvent{
Providers: miaosic.ListAvailableProviders(),
})
}

View File

@@ -1,8 +0,0 @@
package internal
import (
_ "github.com/AynaLivePlayer/miaosic/providers/bilibili"
_ "github.com/AynaLivePlayer/miaosic/providers/bilivideo"
_ "github.com/AynaLivePlayer/miaosic/providers/kuwo"
_ "github.com/AynaLivePlayer/miaosic/providers/netease"
)

View File

@@ -5,10 +5,12 @@ import (
"AynaLivePlayer/internal/liveroom"
"AynaLivePlayer/internal/player"
"AynaLivePlayer/internal/playlist"
"AynaLivePlayer/internal/source"
)
func Initialize() {
player.SetupMpvPlayer()
source.Initialize()
playlist.Initialize()
controller.Initialize()
liveroom.Initialize()
@@ -16,5 +18,6 @@ func Initialize() {
func Stop() {
liveroom.StopAndSave()
playlist.Close()
player.StopMpvPlayer()
}

View File

@@ -1,13 +1,13 @@
package mpv
import (
"AynaLivePlayer/common/util"
"AynaLivePlayer/core/events"
"AynaLivePlayer/core/model"
"AynaLivePlayer/global"
"AynaLivePlayer/pkg/config"
"AynaLivePlayer/pkg/event"
"AynaLivePlayer/pkg/logger"
"AynaLivePlayer/pkg/util"
"fmt"
"github.com/AynaLivePlayer/miaosic"
"github.com/aynakeya/go-mpv"

View File

@@ -6,6 +6,8 @@ import (
"AynaLivePlayer/global"
"AynaLivePlayer/pkg/config"
"AynaLivePlayer/pkg/event"
"AynaLivePlayer/pkg/logger"
"github.com/AynaLivePlayer/miaosic"
)
var PlayerPlaylist *playlist = nil
@@ -15,27 +17,41 @@ var PlaylistsPlaylist *playlist = nil
type playlistConfig struct {
SystemPlaylistMode model.PlaylistMode
SystemPlaylistID string
PlaylistsPath string
playlists []miaosic.Playlist
}
func (p *playlistConfig) Name() string {
return "playlist"
return "Playlist"
}
func (p *playlistConfig) OnLoad() {
return
err := config.LoadJson(p.PlaylistsPath, &p.playlists)
if err != nil {
log.Errorf("Failed to load playlists: %s", err.Error())
}
log.Infof("Loaded %d playlists", len(p.playlists))
}
func (p *playlistConfig) OnSave() {
_ = config.SaveJson(p.PlaylistsPath, p.playlists)
return
}
var cfg = &playlistConfig{}
var cfg = &playlistConfig{
SystemPlaylistMode: model.PlaylistModeNormal,
PlaylistsPath: "playlists.json",
playlists: make([]miaosic.Playlist, 0),
}
var log logger.ILogger = nil
func Initialize() {
log = global.Logger.WithPrefix("Playlists")
PlayerPlaylist = newPlaylist(model.PlaylistIDPlayer)
SystemPlaylist = newPlaylist(model.PlaylistIDSystem)
HistoryPlaylist = newPlaylist(model.PlaylistIDHistory)
PlaylistsPlaylist = newPlaylist(model.PlaylistIDPlaylists)
config.LoadConfig(cfg)
global.EventManager.RegisterA(events.PlaylistModeChangeCmd(model.PlaylistIDSystem), "internal.playlist.system_init", func(event *event.Event) {
@@ -45,4 +61,26 @@ func Initialize() {
global.EventManager.CallA(events.PlaylistModeChangeUpdate(model.PlaylistIDSystem), events.PlaylistModeChangeUpdateEvent{
Mode: cfg.SystemPlaylistMode,
})
global.EventManager.RegisterA(
events.PlayerPlayingUpdate,
"internal.playlist.player_playing_update",
func(event *event.Event) {
if event.Data.(events.PlayerPlayingUpdateEvent).Removed {
return
}
global.EventManager.CallA(events.PlaylistInsertCmd(model.PlaylistIDHistory), events.PlaylistInsertCmdEvent{
Media: event.Data.(events.PlayerPlayingUpdateEvent).Media,
Position: -1,
})
})
createPlaylistManager()
}
func Close() {
cfg.playlists = make([]miaosic.Playlist, 0)
for _, v := range allPlaylists {
cfg.playlists = append(cfg.playlists, *v)
}
}

View File

@@ -1,3 +1,233 @@
package playlist
import (
"AynaLivePlayer/core/events"
"AynaLivePlayer/core/model"
"AynaLivePlayer/global"
"AynaLivePlayer/pkg/event"
"errors"
"github.com/AynaLivePlayer/miaosic"
)
// todo: implement the playlist controller
var allPlaylists = make(map[string]*miaosic.Playlist)
var currentSelected string = ""
func createPlaylistManager() {
allPlaylists = make(map[string]*miaosic.Playlist)
for _, pl := range cfg.playlists {
value := pl.Copy()
allPlaylists[pl.Meta.ID()] = &value
}
currentSelected = ""
if len(cfg.playlists) > 0 {
currentSelected = cfg.playlists[0].Meta.ID()
}
global.EventManager.CallA(
events.PlaylistManagerCurrentUpdate,
events.PlaylistManagerCurrentUpdateEvent{
Medias: make([]model.Media, 0),
})
global.EventManager.CallA(
events.PlaylistManagerSetSystemCmd,
events.PlaylistManagerSetSystemCmdEvent{
PlaylistID: cfg.SystemPlaylistID,
})
global.EventManager.RegisterA(events.PlaylistManagerSetSystemCmd,
"internal.playlist.system_playlist.set",
func(event *event.Event) {
data := event.Data.(events.PlaylistManagerSetSystemCmdEvent)
// default case
if data.PlaylistID == "" {
return
}
log.Infof("try to set system playlist %s", data.PlaylistID)
pl, ok := allPlaylists[data.PlaylistID]
if !ok {
global.EventManager.CallA(
events.ErrorUpdate,
events.ErrorUpdateEvent{
Error: errors.New("playlist not found"),
})
return
}
cfg.SystemPlaylistID = pl.Meta.ID()
global.EventManager.CallA(
events.PlaylistManagerSystemUpdate,
events.PlaylistManagerSystemUpdateEvent{
Info: model.PlaylistInfo{
Meta: pl.Meta,
Title: pl.DisplayName(),
},
})
log.Infof("replace system playlist with %d medias", len(pl.Medias))
medias := make([]model.Media, len(pl.Medias))
for i, v := range pl.Medias {
medias[i] = model.Media{
Info: v,
User: model.SystemUser,
}
}
SystemPlaylist.Replace(medias)
})
global.EventManager.RegisterA(
events.PlaylistManagerRefreshCurrentCmd,
"internal.playlist.current_playlist.refresh",
func(event *event.Event) {
data := event.Data.(events.PlaylistManagerRefreshCurrentCmdEvent)
log.Infof("try to refresh playlist %s", data.PlaylistID)
currentSelected = data.PlaylistID
// default case
if currentSelected == "" {
return
}
pl, ok := allPlaylists[data.PlaylistID]
if !ok {
global.EventManager.CallA(
events.ErrorUpdate,
events.ErrorUpdateEvent{
Error: errors.New("playlist not found"),
})
return
}
getPlaylist, err := miaosic.GetPlaylist(pl.Meta)
if err != nil {
global.EventManager.CallA(
events.ErrorUpdate,
events.ErrorUpdateEvent{
Error: err,
})
return
}
allPlaylists[pl.Meta.ID()] = getPlaylist
updateCurrenMedias(getPlaylist)
updatePlaylistManagerInfos()
})
global.EventManager.RegisterA(
events.PlaylistManagerGetCurrentCmd,
"internal.playlist.current_playlist.get",
func(event *event.Event) {
data := event.Data.(events.PlaylistManagerGetCurrentCmdEvent)
log.Infof("try to get playlist %s", data.PlaylistID)
currentSelected = data.PlaylistID
// default case
if currentSelected == "" {
return
}
pl, ok := allPlaylists[data.PlaylistID]
if !ok {
global.EventManager.CallA(
events.ErrorUpdate,
events.ErrorUpdateEvent{
Error: errors.New("playlist not found"),
})
return
}
updateCurrenMedias(pl)
})
global.EventManager.RegisterA(
events.PlaylistManagerAddPlaylistCmd,
"internal.playlist.add_playlist",
func(event *event.Event) {
data := event.Data.(events.PlaylistManagerAddPlaylistCmdEvent)
log.Info("try to add playlist", data)
meta, ok := miaosic.MatchPlaylistByProvider(data.Provider, data.URL)
if !ok {
global.EventManager.CallA(
events.ErrorUpdate,
events.ErrorUpdateEvent{
Error: errors.New("not proper url"),
})
return
}
_, ok = allPlaylists[meta.ID()]
if ok {
global.EventManager.CallA(
events.ErrorUpdate,
events.ErrorUpdateEvent{
Error: errors.New("playlist already exists"),
})
return
}
pl, err := miaosic.GetPlaylist(meta)
if err != nil {
global.EventManager.CallA(
events.ErrorUpdate,
events.ErrorUpdateEvent{
Error: err,
})
return
}
allPlaylists[meta.ID()] = pl
updatePlaylistManagerInfos()
})
global.EventManager.RegisterA(
events.PlaylistManagerRemovePlaylistCmd,
"internal.playlist.remove_playlist",
func(event *event.Event) {
data := event.Data.(events.PlaylistManagerRemovePlaylistCmdEvent)
if data.PlaylistID == cfg.SystemPlaylistID {
global.EventManager.CallA(
events.ErrorUpdate,
events.ErrorUpdateEvent{
Error: errors.New("cannot remove system playlist"),
})
return
}
_, ok := allPlaylists[data.PlaylistID]
if !ok {
global.EventManager.CallA(
events.ErrorUpdate,
events.ErrorUpdateEvent{
Error: errors.New("playlist not found"),
})
return
}
delete(allPlaylists, data.PlaylistID)
updatePlaylistManagerInfos()
})
updatePlaylistManagerInfos()
}
func updateCurrenMedias(pl *miaosic.Playlist) {
medias := make([]model.Media, len(pl.Medias))
for i, v := range pl.Medias {
medias[i] = model.Media{
Info: v,
User: model.SystemUser,
}
}
global.EventManager.CallA(
events.PlaylistManagerCurrentUpdate,
events.PlaylistManagerCurrentUpdateEvent{
Medias: medias,
})
}
func updatePlaylistManagerInfos() {
playlists := make([]model.PlaylistInfo, 0)
keys := make([]string, 0)
for k := range allPlaylists {
keys = append(keys, k)
}
for _, k := range keys {
playlists = append(playlists, model.PlaylistInfo{
Meta: allPlaylists[k].Meta,
Title: allPlaylists[k].DisplayName(),
})
}
log.InfoW("update playlist manager infos")
global.EventManager.CallA(
events.PlaylistManagerInfoUpdate,
events.PlaylistManagerInfoUpdateEvent{
Playlists: playlists,
})
}

41
internal/source/source.go Normal file
View File

@@ -0,0 +1,41 @@
package source
import (
"AynaLivePlayer/core/events"
"AynaLivePlayer/global"
"AynaLivePlayer/pkg/config"
"github.com/AynaLivePlayer/miaosic"
_ "github.com/AynaLivePlayer/miaosic/providers/bilibili"
_ "github.com/AynaLivePlayer/miaosic/providers/bilivideo"
_ "github.com/AynaLivePlayer/miaosic/providers/kuwo"
"github.com/AynaLivePlayer/miaosic/providers/local"
_ "github.com/AynaLivePlayer/miaosic/providers/netease"
)
type _sourceConfig struct {
LocalSourcePath string
}
func (_ _sourceConfig) Name() string {
return "Source"
}
func (_ _sourceConfig) OnLoad() {
}
func (_ _sourceConfig) OnSave() {
}
var sourceCfg = &_sourceConfig{
LocalSourcePath: "./music",
}
func Initialize() {
config.LoadConfig(sourceCfg)
miaosic.RegisterProvider(local.NewLocal(sourceCfg.LocalSourcePath))
global.EventManager.CallA(
events.MediaProviderUpdate, events.MediaProviderUpdateEvent{
Providers: miaosic.ListAvailableProviders(),
})
}

View File

@@ -6,6 +6,7 @@ type _GeneralConfig struct {
Height float32
Language string
AutoCheckUpdate bool
ShowSystemTray bool
}
func (c *_GeneralConfig) Name() string {
@@ -14,6 +15,7 @@ func (c *_GeneralConfig) Name() string {
var General = &_GeneralConfig{
Language: "zh-CN",
ShowSystemTray: false,
AutoCheckUpdate: true,
Width: 960,
Height: 480,

View File

@@ -1,8 +1,8 @@
package i18n
import (
"AynaLivePlayer/common/util"
config2 "AynaLivePlayer/pkg/config"
"AynaLivePlayer/pkg/util"
"encoding/json"
"os"
)

View File

@@ -23,7 +23,7 @@ func main() {
func Regen(w fyne.Window) {
tabs := container.NewDocTabs()
for _, datum := range generateData(100) {
for _, datum := range generateData(600) {
tabs.Append(newItemTab(&datum))
}
w.SetContent(tabs)
@@ -38,7 +38,7 @@ func generateData(n int) (result []int) {
func newItemTab(i *int) *container.TabItem {
c := container.NewVBox(
BindIntWithEntry(i),
BindIntWithLabel(i),
widget.NewButton("Regen", func() {
Regen(w)
}),

31
playground/jpgbug/main.go Normal file
View File

@@ -0,0 +1,31 @@
package main
import (
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/driver/desktop"
"fyne.io/fyne/v2/widget"
)
func main() {
a := app.New()
w := a.NewWindow("SysTray")
//icon, _ := fyne.LoadResourceFromPath("./assets/icon.jpg")
icon, _ := fyne.LoadResourceFromPath("./assets/icon.png")
if desk, ok := a.(desktop.App); ok {
m := fyne.NewMenu("MyApp",
fyne.NewMenuItem("Show", func() {
w.Show()
}))
desk.SetSystemTrayMenu(m)
desk.SetSystemTrayIcon(icon)
}
w.SetContent(widget.NewLabel("Fyne System Tray"))
w.SetCloseIntercept(func() {
w.Hide()
})
w.ShowAndRun()
}

View File

@@ -1,21 +0,0 @@
package main
import (
"AynaLivePlayer/gui/xfyne"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
"time"
)
var w fyne.Window
func main() {
a := app.NewWithID("io.fyne.demo")
w = a.NewWindow("Fyne Demo")
go func() {
time.Sleep(5 * time.Second)
println("Window handle:", xfyne.GetWindowHandle(w))
}()
w.Resize(fyne.NewSize(1080, 720))
w.ShowAndRun()
}

View File

@@ -1,7 +1,7 @@
package webinfo
import (
"AynaLivePlayer/common/util"
"AynaLivePlayer/pkg/util"
"encoding/json"
"io/ioutil"
)

View File

@@ -2,7 +2,6 @@ package webinfo
import (
"AynaLivePlayer/adapters/logger"
"AynaLivePlayer/common/util"
"AynaLivePlayer/core/adapter"
"AynaLivePlayer/core/events"
"AynaLivePlayer/core/model"
@@ -11,6 +10,7 @@ import (
"AynaLivePlayer/pkg/config"
"AynaLivePlayer/pkg/event"
"AynaLivePlayer/pkg/i18n"
"AynaLivePlayer/pkg/util"
"fmt"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/container"

View File

@@ -1,20 +1,11 @@
package resource
//var ProgramIcon = []byte{}
//var EmptyImage = []byte{}
//
//func init() {
// loadResource(config.GetAssetPath("icon.jpg"), &ProgramIcon)
// loadResource(config.GetAssetPath("empty.png"), &EmptyImage)
//}
//
//func loadResource(path string, res *[]byte) {
// if file, err := ioutil.ReadFile(path); err == nil {
// *res = file
// }
//}
import "fyne.io/fyne/v2"
var ImageEmpty = resImageEmpty
var ImageEmpty = &fyne.StaticResource{
StaticName: "flat-color-icons--audio-file.svg",
StaticContent: []byte("<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 48 48\"><path fill=\"none\" d=\"M204 0h48v48h-48z\"/><path fill=\"#90caf9\" d=\"M244 45h-32V3h22l10 10z\"/><path fill=\"#e1f5fe\" d=\"M242.5 14H233V4.5z\"/><g fill=\"#1976d2\"><circle cx=\"227\" cy=\"30\" r=\"4\"/><path d=\"m234 21l-5-2v11h2v-7.1l3 1.1z\"/></g><path fill=\"#90caf9\" d=\"M40 45H8V3h22l10 10z\"/><path fill=\"#e1f5fe\" d=\"M38.5 14H29V4.5z\"/><g fill=\"#1976d2\"><circle cx=\"23\" cy=\"30\" r=\"4\"/><path d=\"m30 21l-5-2v11h2v-7.1l3 1.1z\"/></g></svg>"),
}
var ImageIcon = resImageIcon
var FontMSYaHei = resFontMSYaHei
var FontMSYaHeiBold = resFontMSYaHeiBold

View File

@@ -5,9 +5,14 @@
- @5 delete optimization
- race condition in RichText. i dont care fu
- info-server 歌词服务器,用于媒体源没有歌词的情况
- 媒体源 - 歌单信息获取
- web弹幕协议的断线handler
- 架构重构
- 黑名单
beta
- web 重连
- 黑名单
- bilibili 歌词来源
----