save and load play queue on exit/startup (partial impl)

This commit is contained in:
Drew Weymouth
2024-01-07 16:25:15 -08:00
parent d2743815bf
commit c4c4a71d5e
4 changed files with 134 additions and 25 deletions
+12
View File
@@ -25,6 +25,7 @@ const (
sessionDir = "session"
sessionLockFile = ".lock"
sessionActivateFile = ".activate"
savedQueueFile = "saved_queue.json"
)
var (
@@ -300,6 +301,9 @@ func (a *App) DeleteServerCacheDir(serverID uuid.UUID) error {
func (a *App) Shutdown() {
a.MPRISHandler.Shutdown()
a.PlaybackManager.DisableCallbacks()
if a.Config.Application.SavePlayQueue {
SavePlayQueue(a.ServerManager.ServerID.String(), a.PlaybackManager, configdir.LocalConfig(a.appName, savedQueueFile))
}
a.PlaybackManager.Stop() // will trigger scrobble check
a.Config.LocalPlayback.Volume = a.LocalPlayer.GetVolume()
a.cancel()
@@ -308,6 +312,14 @@ func (a *App) Shutdown() {
os.RemoveAll(configdir.LocalConfig(a.appName, sessionDir))
}
func (a *App) LoadSavedPlayQueue() error {
queue, err := LoadPlayQueue(configdir.LocalConfig(a.appName, savedQueueFile), a.ServerManager)
if err != nil {
return err
}
return a.PlaybackManager.LoadTracks(queue.Tracks, false, false)
}
func (a *App) SaveConfigFile() {
a.Config.WriteConfigFile(a.configPath())
a.lastWrittenCfg = *a.Config
+2
View File
@@ -41,6 +41,7 @@ type AppConfig struct {
SettingsTab string
AllowMultiInstance bool
MaxImageCacheSizeMB int
SavePlayQueue bool
// Experimental - may be removed in future
FontNormalTTF string
@@ -147,6 +148,7 @@ func DefaultConfig(appVersionTag string) *Config {
AllowMultiInstance: false,
MaxImageCacheSizeMB: 50,
UIScaleSize: "Normal",
SavePlayQueue: false,
},
AlbumPage: AlbumPageConfig{
TracklistColumns: []string{"Artist", "Time", "Plays", "Favorite", "Rating"},
+83
View File
@@ -0,0 +1,83 @@
package backend
import (
"encoding/json"
"errors"
"os"
"github.com/dweymouth/supersonic/backend/mediaprovider"
)
type SavedPlayQueue struct {
Tracks []*mediaprovider.Track
TrackIndex int
TimePos float64
}
type serializedSavedPlayQueue struct {
ServerID string `json:"serverID"`
TrackIDs []string `json:"trackIDs"`
TrackIndex int `json:"trackIndex"`
TimePos float64 `json:"timePos"`
}
// SavePlayQueue saves the current play queue and playback position to a JSON file.
func SavePlayQueue(serverID string, pm *PlaybackManager, filepath string) error {
queue := pm.GetPlayQueue()
stats := pm.PlayerStatus()
trackIdx := pm.NowPlayingIndex()
trackIDs := make([]string, len(queue))
for i, tr := range queue {
trackIDs[i] = tr.ID
}
saved := serializedSavedPlayQueue{
ServerID: serverID,
TrackIDs: trackIDs,
TrackIndex: trackIdx,
TimePos: stats.TimePos,
}
b, err := json.Marshal(saved)
if err != nil {
return err
}
return os.WriteFile(filepath, b, 0644)
}
// Loads the saved play queue from the given filepath using the current server.
// Returns an error if the queue could not be loaded for any reason, including the
// currently logged in server being different than the server from which the queue was saved.
func LoadPlayQueue(filepath string, sm *ServerManager) (*SavedPlayQueue, error) {
b, err := os.ReadFile(filepath)
if err != nil {
return nil, err
}
var savedData serializedSavedPlayQueue
if err := json.Unmarshal(b, &savedData); err != nil {
return nil, err
}
if sm.ServerID.String() != savedData.ServerID {
return nil, errors.New("saved play queue was from a different server")
}
tracks := make([]*mediaprovider.Track, len(savedData.TrackIDs))
mp := sm.Server
for i, id := range savedData.TrackIDs {
if tr, err := mp.GetTrack(id); err != nil {
return nil, err
} else {
tracks[i] = tr
}
}
savedQueue := &SavedPlayQueue{
Tracks: tracks,
TrackIndex: savedData.TrackIndex,
TimePos: savedData.TimePos,
}
return savedQueue, nil
}