fixed TODOs, first checkpoint saving queue on server
This commit is contained in:
+45
-13
@@ -28,11 +28,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
configFile = "config.toml"
|
configFile = "config.toml"
|
||||||
portableDir = "supersonic_portable"
|
portableDir = "supersonic_portable"
|
||||||
savedQueueFile = "saved_queue.json"
|
savedQueueFile = "saved_queue.json"
|
||||||
themesDir = "themes"
|
savedUnshuffledQueueFile = "saved_unshuffled_queue.json"
|
||||||
audioCacheSubdir = "audio"
|
themesDir = "themes"
|
||||||
|
audioCacheSubdir = "audio"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -549,30 +550,61 @@ func (a *App) SavePlayQueueIfEnabled() {
|
|||||||
queueServer = qs
|
queueServer = qs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SavePlayQueue(a.ServerManager.ServerID.String(), a.PlaybackManager, path.Join(a.configDir, savedQueueFile), queueServer)
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) LoadSavedPlayQueue() error {
|
func (a *App) LoadSavedPlayQueue() error {
|
||||||
queueFilePath := path.Join(a.configDir, savedQueueFile)
|
queueFilePath := path.Join(a.configDir, savedQueueFile)
|
||||||
queue, err := LoadPlayQueue(queueFilePath, a.ServerManager, a.Config.Application.SaveQueueToServer)
|
playQueue, err := LoadPlayQueue(queueFilePath, a.ServerManager, a.Config.Application.SaveQueueToServer)
|
||||||
|
var unshuffledPlayQueue *SavedPlayQueue
|
||||||
|
|
||||||
|
if a.Config.Playback.Shuffle {
|
||||||
|
unshuffledQueueFilePath := path.Join(a.configDir, savedUnshuffledQueueFile)
|
||||||
|
unshuffledPlayQueue, err = LoadPlayQueue(unshuffledQueueFilePath, a.ServerManager, a.Config.Application.SaveQueueToServer) //unshuffledPlayQueue is only stored locally
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(queue.Tracks) == 0 {
|
if len(playQueue.Tracks) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if len(a.PlaybackManager.GetPlayQueue()) > 0 {
|
if len(a.PlaybackManager.GetActivePlayQueue()) > 0 {
|
||||||
// don't restore play queue if the user has already queued new tracks
|
// don't restore play queue if the user has already queued new tracks
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
a.PlaybackManager.LoadTracks(queue.Tracks, Replace, false)
|
a.PlaybackManager.LoadTracks(playQueue.Tracks, Replace, false)
|
||||||
if queue.TrackIndex >= 0 && queue.TrackIndex < len(queue.Tracks) {
|
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
|
// TODO: This isn't ideal but doesn't seem to cause an audible play-for-a-split-second artifact
|
||||||
a.PlaybackManager.PlayTrackAt(queue.TrackIndex)
|
a.PlaybackManager.PlayTrackAt(playQueue.TrackIndex)
|
||||||
a.PlaybackManager.Pause()
|
a.PlaybackManager.Pause()
|
||||||
time.Sleep(100 * time.Millisecond) // MPV seek fails if run quickly after
|
time.Sleep(100 * time.Millisecond) // MPV seek fails if run quickly after
|
||||||
a.PlaybackManager.SeekSeconds(queue.TimePos)
|
a.PlaybackManager.SeekSeconds(playQueue.TimePos)
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.Config.Playback.Shuffle {
|
||||||
|
// 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
|
||||||
|
|
||||||
|
//shuffled := sharedutil.CopyTrackSliceToMediaItemSlice(playQueue.Tracks)
|
||||||
|
//unshuffled := sharedutil.CopyTrackSliceToMediaItemSlice(unshuffledPlayQueue.Tracks)
|
||||||
|
|
||||||
|
//a.PlaybackManager.engine.setPlayQueue(unshuffled)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-21
@@ -250,6 +250,14 @@ func (p *playbackEngine) setShuffledPlayQueue(items []mediaprovider.MediaItem) {
|
|||||||
p.shuffledPlayQueue = items
|
p.shuffledPlayQueue = items
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *playbackEngine) setActivePlayQueue(items []mediaprovider.MediaItem) {
|
||||||
|
if p.shuffle {
|
||||||
|
p.setShuffledPlayQueue(items)
|
||||||
|
} else {
|
||||||
|
p.setPlayQueue(items)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (p *playbackEngine) getPlayQueueItemAt(idx int) mediaprovider.MediaItem {
|
func (p *playbackEngine) getPlayQueueItemAt(idx int) mediaprovider.MediaItem {
|
||||||
return p.getPlayQueue()[idx]
|
return p.getPlayQueue()[idx]
|
||||||
}
|
}
|
||||||
@@ -263,6 +271,10 @@ func (p *playbackEngine) GetPlayQueueDeepCopy() []mediaprovider.MediaItem {
|
|||||||
return deepCopyMediaItemSlice(p.getPlayQueue())
|
return deepCopyMediaItemSlice(p.getPlayQueue())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *playbackEngine) GetShuffledPlayQueueDeepCopy() []mediaprovider.MediaItem {
|
||||||
|
return deepCopyMediaItemSlice(p.getPlayQueue())
|
||||||
|
}
|
||||||
|
|
||||||
func (p *playbackEngine) GetActivePlayQueueDeepCopy() []mediaprovider.MediaItem {
|
func (p *playbackEngine) GetActivePlayQueueDeepCopy() []mediaprovider.MediaItem {
|
||||||
return deepCopyMediaItemSlice(p.getActivePlayQueue())
|
return deepCopyMediaItemSlice(p.getActivePlayQueue())
|
||||||
}
|
}
|
||||||
@@ -314,8 +326,7 @@ func (p *playbackEngine) GetLoopMode() LoopMode {
|
|||||||
return p.loopMode
|
return p.loopMode
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO_SHUFFLE: rename?
|
func (p *playbackEngine) GetNowPlayingIdxFrom(items []mediaprovider.MediaItem) int {
|
||||||
func (p *playbackEngine) GetNewNowPlayingIdx(items []mediaprovider.MediaItem) int {
|
|
||||||
newNowPlayingIdx := -1
|
newNowPlayingIdx := -1
|
||||||
if p.nowPlayingIdx >= 0 {
|
if p.nowPlayingIdx >= 0 {
|
||||||
nowPlayingID := p.getPlayQueueItemAt(p.nowPlayingIdx).Metadata().ID
|
nowPlayingID := p.getPlayQueueItemAt(p.nowPlayingIdx).Metadata().ID
|
||||||
@@ -340,10 +351,10 @@ func (p *playbackEngine) SetShuffle(shuffle bool) {
|
|||||||
rand.Shuffle(len(shuffledQueue), func(i, j int) {
|
rand.Shuffle(len(shuffledQueue), func(i, j int) {
|
||||||
shuffledQueue[i], shuffledQueue[j] = shuffledQueue[j], shuffledQueue[i]
|
shuffledQueue[i], shuffledQueue[j] = shuffledQueue[j], shuffledQueue[i]
|
||||||
})
|
})
|
||||||
p.shuffledPlayQueue = sharedutil.ReorderItems(shuffledQueue, []int{p.GetNewNowPlayingIdx(shuffledQueue)}, 0)
|
p.shuffledPlayQueue = sharedutil.ReorderItems(shuffledQueue, []int{p.GetNowPlayingIdxFrom(shuffledQueue)}, 0)
|
||||||
newNowPlayingIdx = 0
|
newNowPlayingIdx = 0
|
||||||
} else {
|
} else {
|
||||||
newNowPlayingIdx = p.GetNewNowPlayingIdx(p.playQueue)
|
newNowPlayingIdx = p.GetNowPlayingIdxFrom(p.playQueue)
|
||||||
}
|
}
|
||||||
|
|
||||||
p.shuffle = shuffle
|
p.shuffle = shuffle
|
||||||
@@ -460,7 +471,7 @@ func (p *playbackEngine) LoadItems(items []mediaprovider.MediaItem, insertQueueM
|
|||||||
// Load tracks into the play queue.
|
// Load tracks into the play queue.
|
||||||
// If replacing the current queue (!appendToQueue), playback will be stopped.
|
// 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, shuffle bool) error {
|
||||||
newTracks := copyTrackSliceToMediaItemSlice(tracks)
|
newTracks := sharedutil.CopyTrackSliceToMediaItemSlice(tracks)
|
||||||
return p.doLoaditems(newTracks, insertQueueMode, shuffle)
|
return p.doLoaditems(newTracks, insertQueueMode, shuffle)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -501,13 +512,7 @@ func (p *playbackEngine) LoadRadioStation(radio *mediaprovider.RadioStation, ins
|
|||||||
if insertMode == InsertNext {
|
if insertMode == InsertNext {
|
||||||
insertIdx = p.nowPlayingIdx + 1
|
insertIdx = p.nowPlayingIdx + 1
|
||||||
}
|
}
|
||||||
new := make([]mediaprovider.MediaItem, p.getPlayQueueLength()+1)
|
p.insertItemsIntoPlayQueueAt([]mediaprovider.MediaItem{radio}, insertIdx)
|
||||||
firstHalf := p.playQueue[:insertIdx]
|
|
||||||
copy(new, firstHalf)
|
|
||||||
new[len(firstHalf)] = radio
|
|
||||||
copy(new[len(firstHalf)+1:], p.playQueue[insertIdx:]) //TODO_SHUFFLE: Test shuffle with radio stations
|
|
||||||
p.setPlayQueue(new)
|
|
||||||
|
|
||||||
p.invokeNoArgCallbacks(p.onQueueChange)
|
p.invokeNoArgCallbacks(p.onQueueChange)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -584,7 +589,7 @@ func (p *playbackEngine) RemoveTracksFromQueue(idxs []int) {
|
|||||||
// remove tracks by ID from playQueue
|
// remove tracks by ID from playQueue
|
||||||
ids := p.GetTrackIdsFromIdx(idxs)
|
ids := p.GetTrackIdsFromIdx(idxs)
|
||||||
newPlayQueue := make([]mediaprovider.MediaItem, 0, p.getPlayQueueLength()-len(idxs))
|
newPlayQueue := make([]mediaprovider.MediaItem, 0, p.getPlayQueueLength()-len(idxs))
|
||||||
for _, tr := range p.playQueue { //TODO_SHUFFLE: Rework this to use a func for getPlayQueue
|
for _, tr := range p.getPlayQueue() {
|
||||||
if slices.Contains(ids, tr.Metadata().ID) {
|
if slices.Contains(ids, tr.Metadata().ID) {
|
||||||
//remove id from id list, handles having the same track present multiple times in playQueue
|
//remove id from id list, handles having the same track present multiple times in playQueue
|
||||||
idx := slices.Index(ids, tr.Metadata().ID)
|
idx := slices.Index(ids, tr.Metadata().ID)
|
||||||
@@ -935,14 +940,6 @@ func deepCopyMediaItemSlice(tracks []mediaprovider.MediaItem) []mediaprovider.Me
|
|||||||
return newTracks
|
return newTracks
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyTrackSliceToMediaItemSlice(tracks []*mediaprovider.Track) []mediaprovider.MediaItem {
|
|
||||||
newTracks := make([]mediaprovider.MediaItem, len(tracks))
|
|
||||||
for i, tr := range tracks {
|
|
||||||
newTracks[i] = tr.Copy()
|
|
||||||
}
|
|
||||||
return newTracks
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *playbackEngine) invokeOnSongChangeCallbacks() {
|
func (p *playbackEngine) invokeOnSongChangeCallbacks() {
|
||||||
if p.callbacksDisabled {
|
if p.callbacksDisabled {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -385,7 +385,7 @@ func (p *PlaybackManager) LoadPlaylist(playlistID string, insertQueueMode Insert
|
|||||||
// Load tracks into the play queue.
|
// Load tracks into the play queue.
|
||||||
// If replacing the current queue (!appendToQueue), playback will be stopped.
|
// 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, shuffle bool) {
|
||||||
items := copyTrackSliceToMediaItemSlice(tracks)
|
items := sharedutil.CopyTrackSliceToMediaItemSlice(tracks)
|
||||||
p.cmdQueue.LoadItems(items, insertQueueMode, shuffle)
|
p.cmdQueue.LoadItems(items, insertQueueMode, shuffle)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -565,10 +565,18 @@ func (p *PlaybackManager) fetchAndPlayTracks(fetchFn func() ([]*mediaprovider.Tr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *PlaybackManager) GetActivePlayQueue() []mediaprovider.MediaItem {
|
||||||
|
return p.engine.GetActivePlayQueueDeepCopy()
|
||||||
|
}
|
||||||
|
|
||||||
func (p *PlaybackManager) GetPlayQueue() []mediaprovider.MediaItem {
|
func (p *PlaybackManager) GetPlayQueue() []mediaprovider.MediaItem {
|
||||||
return p.engine.GetPlayQueueDeepCopy()
|
return p.engine.GetPlayQueueDeepCopy()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *PlaybackManager) GetShuffledPlayQueue() []mediaprovider.MediaItem {
|
||||||
|
return p.engine.GetShuffledPlayQueueDeepCopy()
|
||||||
|
}
|
||||||
|
|
||||||
// Any time the user changes the favorite status of a track elsewhere in the app,
|
// Any time the user changes the favorite status of a track elsewhere in the app,
|
||||||
// this should be called to ensure the in-memory track model is updated.
|
// this should be called to ensure the in-memory track model is updated.
|
||||||
func (p *PlaybackManager) OnTrackFavoriteStatusChanged(id string, fav bool) {
|
func (p *PlaybackManager) OnTrackFavoriteStatusChanged(id string, fav bool) {
|
||||||
@@ -640,7 +648,6 @@ func (p *PlaybackManager) SetAutoplay(autoplay bool) {
|
|||||||
|
|
||||||
func (p *PlaybackManager) SetShuffle(shuffle bool) {
|
func (p *PlaybackManager) SetShuffle(shuffle bool) {
|
||||||
p.cfg.Shuffle = shuffle
|
p.cfg.Shuffle = shuffle
|
||||||
fmt.Println("Setting shuffle in config")
|
|
||||||
p.engine.SetShuffle(shuffle)
|
p.engine.SetShuffle(shuffle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,8 +24,7 @@ type serializedSavedPlayQueue struct {
|
|||||||
|
|
||||||
// SavePlayQueue saves the current play queue and playback position to a JSON file.
|
// SavePlayQueue saves the current play queue and playback position to a JSON file.
|
||||||
// If the provided CanSavePlayQueue server is non-nil, it will also save to the server.
|
// If the provided CanSavePlayQueue server is non-nil, it will also save to the server.
|
||||||
func SavePlayQueue(serverID string, pm *PlaybackManager, filepath string, server mediaprovider.CanSavePlayQueue) error {
|
func SavePlayQueue(serverID string, queue []mediaprovider.MediaItem, pm *PlaybackManager, filepath string, server mediaprovider.CanSavePlayQueue) error {
|
||||||
queue := pm.GetPlayQueue()
|
|
||||||
stats := pm.PlaybackStatus()
|
stats := pm.PlaybackStatus()
|
||||||
trackIdx := pm.NowPlayingIndex()
|
trackIdx := pm.NowPlayingIndex()
|
||||||
|
|
||||||
|
|||||||
@@ -186,3 +186,11 @@ func DownloadFileWithContext(ctx context.Context, url string, destPath string) (
|
|||||||
|
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CopyTrackSliceToMediaItemSlice(tracks []*mediaprovider.Track) []mediaprovider.MediaItem {
|
||||||
|
newTracks := make([]mediaprovider.MediaItem, len(tracks))
|
||||||
|
for i, tr := range tracks {
|
||||||
|
newTracks[i] = tr.Copy()
|
||||||
|
}
|
||||||
|
return newTracks
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user