wip restore queues on start
This commit is contained in:
+32
-13
@@ -21,6 +21,7 @@ import (
|
||||
"github.com/dweymouth/supersonic/backend/player/mpv"
|
||||
"github.com/dweymouth/supersonic/backend/util"
|
||||
"github.com/dweymouth/supersonic/backend/windows"
|
||||
"github.com/dweymouth/supersonic/sharedutil"
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/20after4/configdir"
|
||||
@@ -32,6 +33,7 @@ const (
|
||||
portableDir = "supersonic_portable"
|
||||
savedQueueFile = "saved_queue.json"
|
||||
savedUnshuffledQueueFile = "saved_unshuffled_queue.json"
|
||||
savedShuffledQueueFile = "saved_shuffled_queue.json"
|
||||
themesDir = "themes"
|
||||
audioCacheSubdir = "audio"
|
||||
)
|
||||
@@ -552,8 +554,13 @@ func (a *App) SavePlayQueueIfEnabled() {
|
||||
}
|
||||
SavePlayQueue(a.ServerManager.ServerID.String(), a.PlaybackManager.GetActivePlayQueue(), a.PlaybackManager, path.Join(a.configDir, savedQueueFile), queueServer)
|
||||
if a.Config.Playback.Shuffle {
|
||||
// if shuffle, also save the unshuffeled queue to enable unshuffling on restarting supersonic
|
||||
SavePlayQueue(a.ServerManager.ServerID.String(), a.PlaybackManager.GetPlayQueue(), a.PlaybackManager, path.Join(a.configDir, savedUnshuffledQueueFile), queueServer)
|
||||
// if shuffle
|
||||
// save the unshuffeled queue to enable unshuffling on restarting supersonic
|
||||
// save the shuffled queue again to enable checking if the playQueue was changed server side on start up
|
||||
|
||||
// both files are just saved locally
|
||||
SavePlayQueue(a.ServerManager.ServerID.String(), a.PlaybackManager.GetPlayQueue(), a.PlaybackManager, path.Join(a.configDir, savedUnshuffledQueueFile), nil)
|
||||
SavePlayQueue(a.ServerManager.ServerID.String(), a.PlaybackManager.GetShuffledPlayQueue(), a.PlaybackManager, path.Join(a.configDir, savedShuffledQueueFile), nil)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -561,10 +568,20 @@ func (a *App) LoadSavedPlayQueue() error {
|
||||
queueFilePath := path.Join(a.configDir, savedQueueFile)
|
||||
playQueue, err := LoadPlayQueue(queueFilePath, a.ServerManager, a.Config.Application.SaveQueueToServer)
|
||||
var unshuffledPlayQueue *SavedPlayQueue
|
||||
var shuffledPlayQueue *SavedPlayQueue
|
||||
|
||||
if a.Config.Playback.Shuffle {
|
||||
isShuffe := a.Config.Playback.Shuffle
|
||||
|
||||
if isShuffe {
|
||||
unshuffledQueueFilePath := path.Join(a.configDir, savedUnshuffledQueueFile)
|
||||
unshuffledPlayQueue, err = LoadPlayQueue(unshuffledQueueFilePath, a.ServerManager, a.Config.Application.SaveQueueToServer) //unshuffledPlayQueue is only stored locally
|
||||
unshuffledPlayQueue, err = LoadPlayQueue(unshuffledQueueFilePath, a.ServerManager, false)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
shuffledQueueFilePath := path.Join(a.configDir, savedUnshuffledQueueFile)
|
||||
shuffledPlayQueue, err = LoadPlayQueue(shuffledQueueFilePath, a.ServerManager, false)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -581,7 +598,7 @@ func (a *App) LoadSavedPlayQueue() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
a.PlaybackManager.LoadTracks(playQueue.Tracks, Replace, false)
|
||||
a.PlaybackManager.LoadTracks(playQueue.Tracks, Replace, Both, false)
|
||||
if playQueue.TrackIndex >= 0 && playQueue.TrackIndex < len(playQueue.Tracks) {
|
||||
// TODO: This isn't ideal but doesn't seem to cause an audible play-for-a-split-second artifact
|
||||
a.PlaybackManager.PlayTrackAt(playQueue.TrackIndex)
|
||||
@@ -590,20 +607,22 @@ func (a *App) LoadSavedPlayQueue() error {
|
||||
a.PlaybackManager.SeekSeconds(playQueue.TimePos)
|
||||
}
|
||||
|
||||
if a.Config.Playback.Shuffle {
|
||||
if isShuffe {
|
||||
// check if queue was changed server side
|
||||
// if playQueue.items same as unshuffledPlayQueue.items
|
||||
// set shuffle to false, only load normal playqueue
|
||||
if len(playQueue.Tracks) != len(unshuffledPlayQueue.Tracks) {
|
||||
// queue was changed server side, no need to compare elements
|
||||
a.PlaybackManager.SetShuffle(false)
|
||||
} else {
|
||||
//TODO_SHUFFLE: implement
|
||||
serverStatePlayQueue := sharedutil.CopyTrackSliceToMediaItemSlice(playQueue.Tracks)
|
||||
clientStatePlayQueue := sharedutil.CopyTrackSliceToMediaItemSlice(shuffledPlayQueue.Tracks)
|
||||
|
||||
//shuffled := sharedutil.CopyTrackSliceToMediaItemSlice(playQueue.Tracks)
|
||||
//unshuffled := sharedutil.CopyTrackSliceToMediaItemSlice(unshuffledPlayQueue.Tracks)
|
||||
|
||||
//a.PlaybackManager.engine.setPlayQueue(unshuffled)
|
||||
if slices.Equal(serverStatePlayQueue, clientStatePlayQueue) {
|
||||
fmt.Println("Loading unshuffled items into playQueue")
|
||||
a.PlaybackManager.SetShuffle(true)
|
||||
a.PlaybackManager.LoadTracks(unshuffledPlayQueue.Tracks, Replace, PlayQueue, false)
|
||||
} else {
|
||||
a.PlaybackManager.SetShuffle(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -35,6 +35,7 @@ type playbackCommand struct {
|
||||
Arg any
|
||||
Arg2 any
|
||||
Arg3 any
|
||||
Arg4 any
|
||||
OnDone func()
|
||||
}
|
||||
|
||||
@@ -148,13 +149,14 @@ func (c *playbackCommandQueue) LoadRadioStation(radio *mediaprovider.RadioStatio
|
||||
c.cmdAvailable.Signal()
|
||||
}
|
||||
|
||||
func (c *playbackCommandQueue) LoadItems(items []mediaprovider.MediaItem, insertQueueMode InsertQueueMode, shuffle bool) {
|
||||
func (c *playbackCommandQueue) LoadItems(items []mediaprovider.MediaItem, insertQueueMode InsertQueueMode, queueType QueueType, shuffle bool) {
|
||||
c.mutex.Lock()
|
||||
c.queue = append(c.queue, playbackCommand{
|
||||
Type: cmdLoadItems,
|
||||
Arg: items,
|
||||
Arg2: insertQueueMode,
|
||||
Arg3: shuffle,
|
||||
Arg3: queueType,
|
||||
Arg4: shuffle,
|
||||
})
|
||||
c.mutex.Unlock()
|
||||
c.cmdAvailable.Signal()
|
||||
|
||||
+30
-13
@@ -7,6 +7,7 @@ import (
|
||||
"log"
|
||||
"math/rand"
|
||||
"slices"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/dweymouth/supersonic/backend/mediaprovider"
|
||||
@@ -33,6 +34,14 @@ const (
|
||||
Append
|
||||
)
|
||||
|
||||
type QueueType int
|
||||
|
||||
const (
|
||||
PlayQueue QueueType = iota
|
||||
ShuffledPlayQueue
|
||||
Both
|
||||
)
|
||||
|
||||
// The playback loop mode (LoopNone, LoopAll, LoopOne).
|
||||
type LoopMode int
|
||||
|
||||
@@ -239,7 +248,7 @@ func (p *playbackEngine) getPlayQueueLength() int {
|
||||
|
||||
func (p *playbackEngine) clearPlayQueue() {
|
||||
p.playQueue = nil
|
||||
p.SetShuffle(false)
|
||||
p.shuffledPlayQueue = nil
|
||||
}
|
||||
|
||||
func (p *playbackEngine) setPlayQueue(items []mediaprovider.MediaItem) {
|
||||
@@ -254,9 +263,17 @@ func (p *playbackEngine) getPlayQueueItemAt(idx int) mediaprovider.MediaItem {
|
||||
return p.getPlayQueue()[idx]
|
||||
}
|
||||
|
||||
func (p *playbackEngine) insertItemsIntoPlayQueueAt(items []mediaprovider.MediaItem, idx int) {
|
||||
p.playQueue = append(p.playQueue[:idx], append(items, p.playQueue[idx:]...)...)
|
||||
p.shuffledPlayQueue = append(p.shuffledPlayQueue[:idx], append(items, p.shuffledPlayQueue[idx:]...)...)
|
||||
func (p *playbackEngine) insertItemsIntoPlayQueueAt(items []mediaprovider.MediaItem, idx int, queueType QueueType) {
|
||||
switch queueType {
|
||||
case Both:
|
||||
p.playQueue = append(p.playQueue[:idx], append(items, p.playQueue[idx:]...)...)
|
||||
p.shuffledPlayQueue = append(p.shuffledPlayQueue[:idx], append(items, p.shuffledPlayQueue[idx:]...)...)
|
||||
case PlayQueue:
|
||||
fmt.Println("Inserting into playQueue at: " + strconv.Itoa(idx))
|
||||
p.playQueue = append(p.playQueue[:idx], append(items, p.playQueue[idx:]...)...)
|
||||
case ShuffledPlayQueue:
|
||||
p.shuffledPlayQueue = append(p.shuffledPlayQueue[:idx], append(items, p.shuffledPlayQueue[idx:]...)...)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *playbackEngine) GetPlayQueueDeepCopy() []mediaprovider.MediaItem {
|
||||
@@ -320,7 +337,7 @@ func (p *playbackEngine) GetLoopMode() LoopMode {
|
||||
|
||||
func (p *playbackEngine) GetNowPlayingIdxFrom(items []mediaprovider.MediaItem) int {
|
||||
newNowPlayingIdx := -1
|
||||
if p.nowPlayingIdx >= 0 {
|
||||
if p.nowPlayingIdx >= 0 && len(items) > p.nowPlayingIdx {
|
||||
nowPlayingID := p.getPlayQueueItemAt(p.nowPlayingIdx).Metadata().ID
|
||||
for i, tr := range items {
|
||||
if tr.Metadata().ID == nowPlayingID {
|
||||
@@ -455,19 +472,19 @@ func (p *playbackEngine) Continue() error {
|
||||
|
||||
// Load items into the play queue.
|
||||
// If replacing the current queue (!appendToQueue), playback will be stopped.
|
||||
func (p *playbackEngine) LoadItems(items []mediaprovider.MediaItem, insertQueueMode InsertQueueMode, shuffle bool) error {
|
||||
func (p *playbackEngine) LoadItems(items []mediaprovider.MediaItem, insertQueueMode InsertQueueMode, queueType QueueType, shuffle bool) error {
|
||||
newItems := deepCopyMediaItemSlice(items)
|
||||
return p.doLoaditems(newItems, insertQueueMode, shuffle)
|
||||
return p.doLoaditems(newItems, insertQueueMode, queueType, shuffle)
|
||||
}
|
||||
|
||||
// Load tracks into the play queue.
|
||||
// If replacing the current queue (!appendToQueue), playback will be stopped.
|
||||
func (p *playbackEngine) LoadTracks(tracks []*mediaprovider.Track, insertQueueMode InsertQueueMode, shuffle bool) error {
|
||||
func (p *playbackEngine) LoadTracks(tracks []*mediaprovider.Track, insertQueueMode InsertQueueMode, queueType QueueType, shuffle bool) error {
|
||||
newTracks := sharedutil.CopyTrackSliceToMediaItemSlice(tracks)
|
||||
return p.doLoaditems(newTracks, insertQueueMode, shuffle)
|
||||
return p.doLoaditems(newTracks, insertQueueMode, queueType, shuffle)
|
||||
}
|
||||
|
||||
func (p *playbackEngine) doLoaditems(items []mediaprovider.MediaItem, insertQueueMode InsertQueueMode, shuffle bool) error {
|
||||
func (p *playbackEngine) doLoaditems(items []mediaprovider.MediaItem, insertQueueMode InsertQueueMode, queueType QueueType, shuffle bool) error {
|
||||
if insertQueueMode == Replace {
|
||||
p.player.Stop(false)
|
||||
p.nowPlayingIdx = -1
|
||||
@@ -477,7 +494,7 @@ func (p *playbackEngine) doLoaditems(items []mediaprovider.MediaItem, insertQueu
|
||||
defer p.handleNextTrackUpdated()
|
||||
}
|
||||
|
||||
if shuffle {
|
||||
if shuffle || p.shuffle {
|
||||
rand.Shuffle(len(items), func(i, j int) { items[i], items[j] = items[j], items[i] })
|
||||
}
|
||||
|
||||
@@ -486,7 +503,7 @@ func (p *playbackEngine) doLoaditems(items []mediaprovider.MediaItem, insertQueu
|
||||
insertIdx = p.nowPlayingIdx + 1
|
||||
}
|
||||
|
||||
p.insertItemsIntoPlayQueueAt(items, insertIdx)
|
||||
p.insertItemsIntoPlayQueueAt(items, insertIdx, queueType)
|
||||
p.invokeNoArgCallbacks(p.onQueueChange)
|
||||
return nil
|
||||
}
|
||||
@@ -504,7 +521,7 @@ func (p *playbackEngine) LoadRadioStation(radio *mediaprovider.RadioStation, ins
|
||||
if insertMode == InsertNext {
|
||||
insertIdx = p.nowPlayingIdx + 1
|
||||
}
|
||||
p.insertItemsIntoPlayQueueAt([]mediaprovider.MediaItem{radio}, insertIdx)
|
||||
p.insertItemsIntoPlayQueueAt([]mediaprovider.MediaItem{radio}, insertIdx, Both)
|
||||
p.invokeNoArgCallbacks(p.onQueueChange)
|
||||
}
|
||||
|
||||
|
||||
+14
-13
@@ -364,7 +364,7 @@ func (p *PlaybackManager) LoadAlbum(albumID string, insertQueueMode InsertQueueM
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.LoadTracks(album.Tracks, insertQueueMode, shuffle)
|
||||
p.LoadTracks(album.Tracks, insertQueueMode, Both, shuffle)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -378,21 +378,21 @@ func (p *PlaybackManager) LoadPlaylist(playlistID string, insertQueueMode Insert
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.LoadTracks(playlist.Tracks, insertQueueMode, shuffle)
|
||||
p.LoadTracks(playlist.Tracks, insertQueueMode, Both, shuffle)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Load tracks into the play queue.
|
||||
// If replacing the current queue (!appendToQueue), playback will be stopped.
|
||||
func (p *PlaybackManager) LoadTracks(tracks []*mediaprovider.Track, insertQueueMode InsertQueueMode, shuffle bool) {
|
||||
func (p *PlaybackManager) LoadTracks(tracks []*mediaprovider.Track, insertQueueMode InsertQueueMode, queueType QueueType, shuffle bool) {
|
||||
items := sharedutil.CopyTrackSliceToMediaItemSlice(tracks)
|
||||
p.cmdQueue.LoadItems(items, insertQueueMode, shuffle)
|
||||
p.cmdQueue.LoadItems(items, insertQueueMode, queueType, shuffle)
|
||||
}
|
||||
|
||||
// Load items into the play queue.
|
||||
// Load items into the currently active queue. (shuffledPlayQueue/playQueue)
|
||||
// If replacing the current queue (!appendToQueue), playback will be stopped.
|
||||
func (p *PlaybackManager) LoadItems(items []mediaprovider.MediaItem, insertQueueMode InsertQueueMode, shuffle bool) {
|
||||
p.cmdQueue.LoadItems(items, insertQueueMode, shuffle)
|
||||
func (p *PlaybackManager) LoadItems(items []mediaprovider.MediaItem, insertQueueMode InsertQueueMode, queueType QueueType, shuffle bool) {
|
||||
p.cmdQueue.LoadItems(items, insertQueueMode, queueType, shuffle)
|
||||
}
|
||||
|
||||
// Replaces the play queue with the given set of tracks.
|
||||
@@ -429,7 +429,7 @@ func (p *PlaybackManager) PlayTrack(trackID string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.LoadTracks([]*mediaprovider.Track{tr}, Replace, false)
|
||||
p.LoadTracks([]*mediaprovider.Track{tr}, Replace, Both, false)
|
||||
if p.engine.replayGainCfg.Mode == ReplayGainAuto {
|
||||
p.SetReplayGainMode(player.ReplayGainTrack)
|
||||
}
|
||||
@@ -467,7 +467,7 @@ func (p *PlaybackManager) PlayArtistDiscography(artistID string, shuffleTracks b
|
||||
log.Printf("failed to get artist tracks: %v\n", err)
|
||||
return
|
||||
}
|
||||
p.LoadTracks(tr, Replace, shuffleTracks)
|
||||
p.LoadTracks(tr, Replace, Both, shuffleTracks)
|
||||
if p.engine.replayGainCfg.Mode == ReplayGainAuto {
|
||||
if shuffleTracks {
|
||||
p.SetReplayGainMode(player.ReplayGainTrack)
|
||||
@@ -532,7 +532,7 @@ func (p *PlaybackManager) PlayRandomAlbums(genreName string) error {
|
||||
break
|
||||
}
|
||||
if al, err := mp.GetAlbum(al.ID); err == nil {
|
||||
p.LoadTracks(al.Tracks, insertMode, false)
|
||||
p.LoadTracks(al.Tracks, insertMode, Both, false)
|
||||
if i == 0 {
|
||||
p.PlayFromBeginning()
|
||||
insertMode = Append
|
||||
@@ -556,7 +556,7 @@ func (p *PlaybackManager) fetchAndPlayTracks(fetchFn func() ([]*mediaprovider.Tr
|
||||
if songs, err := fetchFn(); err != nil {
|
||||
return err
|
||||
} else {
|
||||
p.LoadTracks(songs, Replace, false)
|
||||
p.LoadTracks(songs, Replace, Both, false)
|
||||
if p.engine.replayGainCfg.Mode == ReplayGainAuto {
|
||||
p.SetReplayGainMode(player.ReplayGainTrack)
|
||||
}
|
||||
@@ -806,7 +806,7 @@ func (p *PlaybackManager) enqueueAutoplayTracks() {
|
||||
}
|
||||
|
||||
if len(tracks) > 0 {
|
||||
p.LoadTracks(tracks, Append, false /*no need to shuffle, already random*/)
|
||||
p.LoadTracks(tracks, Append, Both, false /*no need to shuffle, already random*/)
|
||||
}
|
||||
}()
|
||||
}
|
||||
@@ -850,7 +850,8 @@ func (p *PlaybackManager) runCmdQueue(ctx context.Context) {
|
||||
err := p.engine.LoadItems(
|
||||
c.Arg.([]mediaprovider.MediaItem),
|
||||
c.Arg2.(InsertQueueMode),
|
||||
c.Arg3.(bool),
|
||||
c.Arg3.(QueueType),
|
||||
c.Arg4.(bool),
|
||||
)
|
||||
logIfErr("LoadItems", err)
|
||||
case cmdLoadRadioStation:
|
||||
|
||||
Reference in New Issue
Block a user