mirror of
https://github.com/AynaLivePlayer/AynaLivePlayer.git
synced 2026-05-12 02:25:00 +08:00
update
This commit is contained in:
3
Makefile
3
Makefile
@@ -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
|
||||
|
||||
19
app/main.go
19
app/main.go
@@ -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()
|
||||
|
||||
BIN
assets/empty.png
BIN
assets/empty.png
Binary file not shown.
|
Before Width: | Height: | Size: 3.8 KiB |
BIN
assets/icon.ico
Normal file
BIN
assets/icon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 264 KiB |
@@ -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": "有新版本可用"
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
package adapter
|
||||
|
||||
import "AynaLivePlayer/core/model"
|
||||
|
||||
type IApplication interface {
|
||||
Version() model.VersionInfo
|
||||
LatestVersion() model.VersionInfo
|
||||
CheckUpdate() error
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package adapter
|
||||
|
||||
type Plugin interface {
|
||||
Name() string
|
||||
Enable() error
|
||||
Disable() error
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
54
core/events/playlists.go
Normal 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
7
core/events/provider.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package events
|
||||
|
||||
const MediaProviderUpdate = "update.media.provider.update"
|
||||
|
||||
type MediaProviderUpdateEvent struct {
|
||||
Providers []string
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
7
go.mod
@@ -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
3
go.sum
@@ -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=
|
||||
|
||||
17
gui/gui.go
17
gui/gui.go
@@ -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
85
gui/history_list.go
Normal 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()
|
||||
})
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
202
gui/playlists.go
Normal 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)
|
||||
}
|
||||
@@ -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
22
gui/tray.go
Normal 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()
|
||||
})
|
||||
}
|
||||
@@ -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,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -31,8 +31,4 @@ func handleSearch() {
|
||||
Medias: medias,
|
||||
})
|
||||
})
|
||||
global.EventManager.CallA(
|
||||
events.SearchProviderUpdate, events.SearchProviderUpdateEvent{
|
||||
Providers: miaosic.ListAvailableProviders(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
41
internal/source/source.go
Normal 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(),
|
||||
})
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package i18n
|
||||
|
||||
import (
|
||||
"AynaLivePlayer/common/util"
|
||||
config2 "AynaLivePlayer/pkg/config"
|
||||
"AynaLivePlayer/pkg/util"
|
||||
"encoding/json"
|
||||
"os"
|
||||
)
|
||||
|
||||
Submodule pkg/miaosic updated: 9067996562...8f83aed586
@@ -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
31
playground/jpgbug/main.go
Normal 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()
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package webinfo
|
||||
|
||||
import (
|
||||
"AynaLivePlayer/common/util"
|
||||
"AynaLivePlayer/pkg/util"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user