another big refactor to make code more manageable
This commit is contained in:
@@ -14,11 +14,11 @@ type AlbumIterator interface {
|
||||
}
|
||||
|
||||
type LibraryManager struct {
|
||||
s *subsonic.Client
|
||||
s *ServerManager
|
||||
albumCache gcache.Cache
|
||||
}
|
||||
|
||||
func NewLibraryManager(s *subsonic.Client) *LibraryManager {
|
||||
func NewLibraryManager(s *ServerManager) *LibraryManager {
|
||||
cache := gcache.New(250).LRU().Build()
|
||||
return &LibraryManager{
|
||||
s: s,
|
||||
@@ -52,7 +52,7 @@ func (l *LibraryManager) GetAlbum(id string) (*subsonic.AlbumID3, error) {
|
||||
return a.(*subsonic.AlbumID3), nil
|
||||
}
|
||||
}
|
||||
a, err := l.s.GetAlbum(id)
|
||||
a, err := l.s.Server.GetAlbum(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -74,7 +74,7 @@ func (l *LibraryManager) newBaseIter(listType string) *baseIter {
|
||||
return &baseIter{
|
||||
listType: listType,
|
||||
l: l,
|
||||
s: l.s,
|
||||
s: l.s.Server,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
package backend
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"path"
|
||||
"supersonic/player"
|
||||
|
||||
"github.com/20after4/configdir"
|
||||
"github.com/zalando/go-keyring"
|
||||
)
|
||||
|
||||
const (
|
||||
AppName = "supersonic"
|
||||
configFile = "config.toml"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNoServers = errors.New("no servers set up")
|
||||
)
|
||||
|
||||
type App struct {
|
||||
Config *Config
|
||||
ServerManager *ServerManager
|
||||
ImageManager *ImageManager
|
||||
LibraryManager *LibraryManager
|
||||
PlaybackManager *PlaybackManager
|
||||
Player *player.Player
|
||||
|
||||
bgrndCtx context.Context
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
func StartupApp() (*App, error) {
|
||||
a := &App{}
|
||||
a.bgrndCtx, a.cancel = context.WithCancel(context.Background())
|
||||
|
||||
a.readConfig()
|
||||
|
||||
if err := a.initMPV(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
a.ServerManager = NewServerManager()
|
||||
a.PlaybackManager = NewPlaybackManager(a.bgrndCtx, a.ServerManager, a.Player)
|
||||
a.LibraryManager = NewLibraryManager(a.ServerManager)
|
||||
a.ImageManager = NewImageManager(a.ServerManager, configdir.LocalCache(AppName))
|
||||
|
||||
return a, nil
|
||||
}
|
||||
|
||||
func (a *App) readConfig() {
|
||||
configdir.MakePath(configdir.LocalConfig(AppName))
|
||||
cfg, err := ReadConfigFile(configPath())
|
||||
if err != nil {
|
||||
log.Printf("Error reading app config file: %v", err)
|
||||
cfg = DefaultConfig()
|
||||
}
|
||||
a.Config = cfg
|
||||
}
|
||||
|
||||
func (a *App) initMPV() error {
|
||||
p := player.NewWithClientName(AppName)
|
||||
if err := p.Init(); err != nil {
|
||||
return fmt.Errorf("failed to initialize mpv player: %s", err.Error())
|
||||
}
|
||||
a.Player = p
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) LoginToDefaultServer() error {
|
||||
serverCfg := a.Config.GetDefaultServer()
|
||||
if serverCfg == nil {
|
||||
return ErrNoServers
|
||||
}
|
||||
pass, err := keyring.Get(AppName, serverCfg.ID.String())
|
||||
if err != nil {
|
||||
return fmt.Errorf("error reading keyring credentials: %v", err)
|
||||
}
|
||||
return a.ServerManager.ConnectToServer(serverCfg, pass)
|
||||
}
|
||||
|
||||
func (a *App) Shutdown() {
|
||||
a.cancel()
|
||||
a.Player.Destroy()
|
||||
}
|
||||
|
||||
func configPath() string {
|
||||
return path.Join(configdir.LocalConfig(AppName), configFile)
|
||||
}
|
||||
+14
-11
@@ -10,24 +10,23 @@ import (
|
||||
|
||||
"github.com/20after4/configdir"
|
||||
"github.com/bluele/gcache"
|
||||
subsonic "github.com/dweymouth/go-subsonic"
|
||||
)
|
||||
|
||||
type ImageManager struct {
|
||||
s *subsonic.Client
|
||||
cacheDir string
|
||||
s *ServerManager
|
||||
baseCacheDir string
|
||||
thumbnailCache gcache.Cache
|
||||
}
|
||||
|
||||
func NewImageManager(s *subsonic.Client, cacheDir string) *ImageManager {
|
||||
func NewImageManager(s *ServerManager, baseCacheDir string) *ImageManager {
|
||||
cache := gcache.New(100).LRU().Build()
|
||||
if err := configdir.MakePath(cacheDir); err != nil {
|
||||
if err := configdir.MakePath(baseCacheDir); err != nil {
|
||||
log.Println("failed to create album cover cache dir")
|
||||
cacheDir = ""
|
||||
baseCacheDir = ""
|
||||
}
|
||||
return &ImageManager{
|
||||
s: s,
|
||||
cacheDir: cacheDir,
|
||||
baseCacheDir: baseCacheDir,
|
||||
thumbnailCache: cache,
|
||||
}
|
||||
}
|
||||
@@ -41,8 +40,8 @@ func (i *ImageManager) GetAlbumThumbnail(albumID string) (image.Image, error) {
|
||||
}
|
||||
|
||||
// on disc cache
|
||||
path := filepath.Join(i.cacheDir, fmt.Sprintf("%s.jpg", albumID))
|
||||
if i.cacheDir != "" {
|
||||
path := filepath.Join(i.coverCacheDir(), fmt.Sprintf("%s.jpg", albumID))
|
||||
if i.coverCacheDir() != "" {
|
||||
if _, err := os.Stat(path); err == nil {
|
||||
// serve image from on-disc cache
|
||||
// TODO: image may have changed on server.
|
||||
@@ -58,11 +57,11 @@ func (i *ImageManager) GetAlbumThumbnail(albumID string) (image.Image, error) {
|
||||
}
|
||||
|
||||
// fetch from server
|
||||
img, err := i.s.GetCoverArt(albumID, map[string]string{"size": "300"})
|
||||
img, err := i.s.Server.GetCoverArt(albumID, map[string]string{"size": "300"})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if i.cacheDir != "" {
|
||||
if i.coverCacheDir() != "" {
|
||||
if f, err := os.Create(path); err == nil {
|
||||
defer f.Close()
|
||||
if err := jpeg.Encode(f, img, nil /*options*/); err != nil {
|
||||
@@ -73,3 +72,7 @@ func (i *ImageManager) GetAlbumThumbnail(albumID string) (image.Image, error) {
|
||||
i.thumbnailCache.Set(albumID, img)
|
||||
return img, nil
|
||||
}
|
||||
|
||||
func (i *ImageManager) coverCacheDir() string {
|
||||
return configdir.LocalCache(i.baseCacheDir, i.s.ServerID.String(), "covers")
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ type PlaybackManager struct {
|
||||
ctx context.Context
|
||||
cancelPollPos context.CancelFunc
|
||||
pollingTick *time.Ticker
|
||||
client *subsonic.Client
|
||||
sm *ServerManager
|
||||
player *player.Player
|
||||
|
||||
playQueue []*subsonic.Child
|
||||
@@ -21,10 +21,10 @@ type PlaybackManager struct {
|
||||
onPlayTimeUpdate []func(float64, float64)
|
||||
}
|
||||
|
||||
func NewPlaybackManager(ctx context.Context, cli *subsonic.Client, p *player.Player) *PlaybackManager {
|
||||
func NewPlaybackManager(ctx context.Context, s *ServerManager, p *player.Player) *PlaybackManager {
|
||||
pm := &PlaybackManager{
|
||||
ctx: ctx,
|
||||
client: cli,
|
||||
sm: s,
|
||||
player: p,
|
||||
}
|
||||
p.OnTrackChange(func(tracknum int64) {
|
||||
@@ -77,7 +77,7 @@ func (p *PlaybackManager) OnPlayTimeUpdate(cb func(float64, float64)) {
|
||||
|
||||
// Loads the specified album into the play queue.
|
||||
func (p *PlaybackManager) LoadAlbum(albumID string, appendToQueue bool) error {
|
||||
album, err := p.client.GetAlbum(albumID)
|
||||
album, err := p.sm.Server.GetAlbum(albumID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -87,7 +87,7 @@ func (p *PlaybackManager) LoadAlbum(albumID string, appendToQueue bool) error {
|
||||
p.playQueue = nil
|
||||
}
|
||||
for _, song := range album.Song {
|
||||
url, err := p.client.GetStreamURL(song.ID, map[string]string{})
|
||||
url, err := p.sm.Server.GetStreamURL(song.ID, map[string]string{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package backend
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
subsonic "github.com/dweymouth/go-subsonic"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type ServerManager struct {
|
||||
ServerID uuid.UUID
|
||||
Server *subsonic.Client
|
||||
|
||||
onServerConnected []func()
|
||||
}
|
||||
|
||||
func NewServerManager() *ServerManager {
|
||||
return &ServerManager{}
|
||||
}
|
||||
|
||||
func (s *ServerManager) ConnectToServer(conf *ServerConfig, password string) error {
|
||||
cli := &subsonic.Client{
|
||||
Client: &http.Client{},
|
||||
BaseUrl: conf.Hostname,
|
||||
User: conf.Username,
|
||||
ClientName: "supersonic",
|
||||
}
|
||||
if err := cli.Authenticate(password); err != nil {
|
||||
return err
|
||||
}
|
||||
s.Server = cli
|
||||
s.ServerID = conf.ID
|
||||
for _, cb := range s.onServerConnected {
|
||||
cb()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ServerManager) OnServerConnected(cb func()) {
|
||||
s.onServerConnected = append(s.onServerConnected, cb)
|
||||
}
|
||||
Reference in New Issue
Block a user