Add config, prompting for server connect on first run

This commit is contained in:
Drew Weymouth
2022-12-24 11:58:24 -08:00
parent 3b3927bfda
commit 99522a773f
5 changed files with 197 additions and 17 deletions
+85
View File
@@ -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
}
+4
View File
@@ -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
+10
View File
@@ -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=
+56 -17
View File
@@ -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))
}
+42
View File
@@ -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)
}