Add config, prompting for server connect on first run
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
package backend
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/pelletier/go-toml"
|
||||
)
|
||||
|
||||
type ServerConfig struct {
|
||||
ID uuid.UUID
|
||||
Nickname string
|
||||
Hostname string
|
||||
Username string
|
||||
Default bool
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Servers []*ServerConfig
|
||||
}
|
||||
|
||||
func DefaultConfig() *Config {
|
||||
return &Config{}
|
||||
}
|
||||
|
||||
func ReadConfigFile(filepath string) (*Config, error) {
|
||||
f, err := os.Open(filepath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
c := &Config{}
|
||||
if err := toml.NewDecoder(f).Decode(c); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (c *Config) GetDefaultServer() *ServerConfig {
|
||||
for _, s := range c.Servers {
|
||||
if s.Default {
|
||||
return s
|
||||
}
|
||||
}
|
||||
if len(c.Servers) > 0 {
|
||||
return c.Servers[0]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Config) SetDefaultServer(serverID uuid.UUID) {
|
||||
var found bool
|
||||
for _, s := range c.Servers {
|
||||
f := s.ID == serverID
|
||||
if f {
|
||||
found = true
|
||||
}
|
||||
s.Default = f
|
||||
}
|
||||
if !found && len(c.Servers) > 0 {
|
||||
c.Servers[0].Default = true
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Config) AddServer(nickname, hostname, username string) *ServerConfig {
|
||||
s := &ServerConfig{
|
||||
ID: uuid.New(),
|
||||
Nickname: nickname,
|
||||
Hostname: hostname,
|
||||
Username: username,
|
||||
}
|
||||
c.Servers = append(c.Servers, s)
|
||||
return s
|
||||
}
|
||||
|
||||
func (c *Config) WriteConfigFile(filepath string) error {
|
||||
b, err := toml.Marshal(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
os.WriteFile(filepath, b, 0644)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -7,12 +7,16 @@ require (
|
||||
github.com/20after4/configdir v0.1.1
|
||||
github.com/bluele/gcache v0.0.2
|
||||
github.com/dweymouth/go-subsonic v0.0.0-20221214005741-bd8048fa1863
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/pelletier/go-toml v1.9.3
|
||||
github.com/wildeyedskies/go-mpv v0.0.0-20221204042335-e8961dc66756
|
||||
github.com/zalando/go-keyring v0.2.1
|
||||
)
|
||||
|
||||
require (
|
||||
fyne.io/systray v1.10.1-0.20220621085403-9a2652634e93 // indirect
|
||||
github.com/alessio/shellescape v1.4.1 // indirect
|
||||
github.com/danieljoos/wincred v1.1.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
||||
|
||||
@@ -45,6 +45,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
|
||||
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/akavel/rsrc v0.10.2/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
|
||||
github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0=
|
||||
github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
@@ -65,6 +67,8 @@ github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
|
||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/danieljoos/wincred v1.1.0 h1:3RNcEpBg4IhIChZdFRSdlQt1QjCp1sMAPIrOnm7Yf8g=
|
||||
github.com/danieljoos/wincred v1.1.0/go.mod h1:XYlo+eRTsVA9aHGp7NGjFkPla4m+DCL7hqDjlFjiygg=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -101,6 +105,7 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211213063430-748e38ca8aec h1:3FLiRYO6Pl
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211213063430-748e38ca8aec/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
@@ -166,6 +171,8 @@ github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLe
|
||||
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
@@ -267,6 +274,7 @@ github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564 h1:HunZiaEKNGVdhTRQO
|
||||
github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564/go.mod h1:afMbS0qvv1m5tfENCwnOdZGOF8RGR/FsZ7bvBxQGZG4=
|
||||
github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 h1:m59mIOBO4kfcNCEzJNy71UkeF4XIx2EVmL9KLwDQdmM=
|
||||
github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9/go.mod h1:mvWM0+15UqyrFKqdRjY6LuAVJR0HOVhJlEgZ5JWtSWU=
|
||||
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
@@ -290,6 +298,8 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.0 h1:OtISOGfH6sOWa1/qXqqAiOIAO6Z5J3AEAE18WAq6BiQ=
|
||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/zalando/go-keyring v0.2.1 h1:MBRN/Z8H4U5wEKXiD67YbDAr5cj/DOStmSga70/2qKc=
|
||||
github.com/zalando/go-keyring v0.2.1/go.mod h1:g63M2PPn0w5vjmEbwAX3ib5I+41zdm4esSETOn9Y6Dw=
|
||||
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
||||
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
|
||||
|
||||
@@ -5,16 +5,17 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"path"
|
||||
"supersonic/backend"
|
||||
"supersonic/player"
|
||||
"supersonic/ui"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/app"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/layout"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
"github.com/20after4/configdir"
|
||||
"github.com/dweymouth/go-subsonic"
|
||||
"github.com/zalando/go-keyring"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -22,7 +23,13 @@ const (
|
||||
configFile = "config.toml"
|
||||
)
|
||||
|
||||
func configPath() string {
|
||||
return path.Join(configdir.LocalConfig(appname), configFile)
|
||||
}
|
||||
|
||||
func main() {
|
||||
// TODO: organize this whole file better. Move some stuff to mainwindow?
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
p := player.NewWithClientName(appname)
|
||||
@@ -30,33 +37,67 @@ func main() {
|
||||
log.Fatalf("failed to initialize mpv player: %s", err.Error())
|
||||
}
|
||||
|
||||
configdir.MakePath(configdir.LocalConfig(appname))
|
||||
|
||||
cfg, err := backend.ReadConfigFile(configPath())
|
||||
if err != nil {
|
||||
log.Printf("Error reading app config file: %v", err)
|
||||
cfg = backend.DefaultConfig()
|
||||
}
|
||||
server := cfg.GetDefaultServer()
|
||||
|
||||
myApp := app.New()
|
||||
myWindow := myApp.NewWindow(appname)
|
||||
mainWindow := ui.NewMainWindow(myApp, appname, p)
|
||||
|
||||
b := ui.NewBottomPanel(p)
|
||||
c := container.NewBorder(nil, b, nil, nil, &layout.Spacer{})
|
||||
if server == nil {
|
||||
d := ui.NewAddServerDialog("Connect to Server")
|
||||
pop := widget.NewModalPopUp(d, mainWindow.Canvas())
|
||||
d.OnSubmit = func() {
|
||||
pop.Hide()
|
||||
server = cfg.AddServer(d.Nickname, d.Host, d.Username)
|
||||
err := keyring.Set(appname, server.ID.String(), d.Password)
|
||||
if err != nil {
|
||||
log.Printf("error setting keyring credentials: %v", err)
|
||||
}
|
||||
setupServer(ctx, mainWindow, p, server)
|
||||
}
|
||||
pop.Show()
|
||||
} else {
|
||||
setupServer(ctx, mainWindow, p, server)
|
||||
}
|
||||
|
||||
myWindow.SetContent(c)
|
||||
myWindow.Resize(fyne.NewSize(1000, 800))
|
||||
myWindow.Show()
|
||||
mainWindow.Show()
|
||||
myApp.Run()
|
||||
cfg.WriteConfigFile(configPath())
|
||||
|
||||
cancel()
|
||||
p.Destroy()
|
||||
}
|
||||
|
||||
func setupServer(ctx context.Context, myWindow ui.MainWindow, p *player.Player, server *backend.ServerConfig) {
|
||||
pass, err := keyring.Get(appname, server.ID.String())
|
||||
if err != nil {
|
||||
log.Printf("error reading keyring credentials: %v", err)
|
||||
}
|
||||
|
||||
s := &subsonic.Client{
|
||||
Client: &http.Client{},
|
||||
BaseUrl: "***REMOVED***",
|
||||
User: "drew",
|
||||
BaseUrl: server.Hostname,
|
||||
User: server.Username,
|
||||
ClientName: appname,
|
||||
}
|
||||
|
||||
if err := s.Authenticate("***REMOVED***"); err != nil {
|
||||
if err := s.Authenticate(pass); err != nil {
|
||||
// TODO: error dialog
|
||||
fmt.Printf("error authenticating: %v\n", err)
|
||||
}
|
||||
|
||||
lm := backend.NewLibraryManager(s)
|
||||
pm := backend.NewPlaybackManager(ctx, s, p)
|
||||
im := backend.NewImageManager(s, configdir.LocalCache(appname, "covers"))
|
||||
b.ImageManager = im
|
||||
myWindow.BottomPanel.ImageManager = im
|
||||
|
||||
b.SetPlaybackManager(pm)
|
||||
myWindow.BottomPanel.SetPlaybackManager(pm)
|
||||
pm.OnSongChange(func(song *subsonic.Child) {
|
||||
if song == nil {
|
||||
myWindow.SetTitle("gomuse")
|
||||
@@ -66,8 +107,6 @@ func main() {
|
||||
})
|
||||
|
||||
ag := ui.NewAlbumGrid(lm.RecentlyAddedIter(), pm, im)
|
||||
myWindow.SetContent(container.NewBorder(nil, b, nil, nil, ag))
|
||||
myApp.Run()
|
||||
cancel()
|
||||
p.Destroy()
|
||||
myWindow.SetContent(container.NewBorder(nil, myWindow.BottomPanel, nil, nil, ag))
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"supersonic/player"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/layout"
|
||||
)
|
||||
|
||||
type MainWindow struct {
|
||||
Window fyne.Window
|
||||
|
||||
BottomPanel *BottomPanel
|
||||
}
|
||||
|
||||
func NewMainWindow(app fyne.App, appName string, p *player.Player) MainWindow {
|
||||
m := MainWindow{
|
||||
Window: app.NewWindow(appName),
|
||||
BottomPanel: NewBottomPanel(p),
|
||||
}
|
||||
c := container.NewBorder(nil, m.BottomPanel, nil, nil, &layout.Spacer{})
|
||||
m.Window.SetContent(c)
|
||||
m.Window.Resize(fyne.NewSize(1000, 800))
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *MainWindow) Show() {
|
||||
m.Window.Show()
|
||||
}
|
||||
|
||||
func (m *MainWindow) Canvas() fyne.Canvas {
|
||||
return m.Window.Canvas()
|
||||
}
|
||||
|
||||
func (m *MainWindow) SetTitle(title string) {
|
||||
m.Window.SetTitle(title)
|
||||
}
|
||||
|
||||
func (m *MainWindow) SetContent(c fyne.CanvasObject) {
|
||||
m.Window.SetContent(c)
|
||||
}
|
||||
Reference in New Issue
Block a user