wip restore queues on start

This commit is contained in:
Siiiiinth
2026-02-09 08:09:01 +01:00
parent 2d29b7f271
commit 48226d5461
10 changed files with 101 additions and 61 deletions
+32 -13
View File
@@ -21,6 +21,7 @@ import (
"github.com/dweymouth/supersonic/backend/player/mpv" "github.com/dweymouth/supersonic/backend/player/mpv"
"github.com/dweymouth/supersonic/backend/util" "github.com/dweymouth/supersonic/backend/util"
"github.com/dweymouth/supersonic/backend/windows" "github.com/dweymouth/supersonic/backend/windows"
"github.com/dweymouth/supersonic/sharedutil"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/20after4/configdir" "github.com/20after4/configdir"
@@ -32,6 +33,7 @@ const (
portableDir = "supersonic_portable" portableDir = "supersonic_portable"
savedQueueFile = "saved_queue.json" savedQueueFile = "saved_queue.json"
savedUnshuffledQueueFile = "saved_unshuffled_queue.json" savedUnshuffledQueueFile = "saved_unshuffled_queue.json"
savedShuffledQueueFile = "saved_shuffled_queue.json"
themesDir = "themes" themesDir = "themes"
audioCacheSubdir = "audio" 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) SavePlayQueue(a.ServerManager.ServerID.String(), a.PlaybackManager.GetActivePlayQueue(), a.PlaybackManager, path.Join(a.configDir, savedQueueFile), queueServer)
if a.Config.Playback.Shuffle { if a.Config.Playback.Shuffle {
// if shuffle, also save the unshuffeled queue to enable unshuffling on restarting supersonic // if shuffle
SavePlayQueue(a.ServerManager.ServerID.String(), a.PlaybackManager.GetPlayQueue(), a.PlaybackManager, path.Join(a.configDir, savedUnshuffledQueueFile), queueServer) // 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) queueFilePath := path.Join(a.configDir, savedQueueFile)
playQueue, err := LoadPlayQueue(queueFilePath, a.ServerManager, a.Config.Application.SaveQueueToServer) playQueue, err := LoadPlayQueue(queueFilePath, a.ServerManager, a.Config.Application.SaveQueueToServer)
var unshuffledPlayQueue *SavedPlayQueue var unshuffledPlayQueue *SavedPlayQueue
var shuffledPlayQueue *SavedPlayQueue
if a.Config.Playback.Shuffle { isShuffe := a.Config.Playback.Shuffle
if isShuffe {
unshuffledQueueFilePath := path.Join(a.configDir, savedUnshuffledQueueFile) 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 { if err != nil {
return err return err
@@ -581,7 +598,7 @@ func (a *App) LoadSavedPlayQueue() error {
return nil 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) { 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(playQueue.TrackIndex) a.PlaybackManager.PlayTrackAt(playQueue.TrackIndex)
@@ -590,20 +607,22 @@ func (a *App) LoadSavedPlayQueue() error {
a.PlaybackManager.SeekSeconds(playQueue.TimePos) a.PlaybackManager.SeekSeconds(playQueue.TimePos)
} }
if a.Config.Playback.Shuffle { if isShuffe {
// check if queue was changed server side // 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) { if len(playQueue.Tracks) != len(unshuffledPlayQueue.Tracks) {
// queue was changed server side, no need to compare elements // queue was changed server side, no need to compare elements
a.PlaybackManager.SetShuffle(false) a.PlaybackManager.SetShuffle(false)
} else { } else {
//TODO_SHUFFLE: implement serverStatePlayQueue := sharedutil.CopyTrackSliceToMediaItemSlice(playQueue.Tracks)
clientStatePlayQueue := sharedutil.CopyTrackSliceToMediaItemSlice(shuffledPlayQueue.Tracks)
//shuffled := sharedutil.CopyTrackSliceToMediaItemSlice(playQueue.Tracks) if slices.Equal(serverStatePlayQueue, clientStatePlayQueue) {
//unshuffled := sharedutil.CopyTrackSliceToMediaItemSlice(unshuffledPlayQueue.Tracks) fmt.Println("Loading unshuffled items into playQueue")
a.PlaybackManager.SetShuffle(true)
//a.PlaybackManager.engine.setPlayQueue(unshuffled) a.PlaybackManager.LoadTracks(unshuffledPlayQueue.Tracks, Replace, PlayQueue, false)
} else {
a.PlaybackManager.SetShuffle(false)
}
} }
} }
return nil return nil
+4 -2
View File
@@ -35,6 +35,7 @@ type playbackCommand struct {
Arg any Arg any
Arg2 any Arg2 any
Arg3 any Arg3 any
Arg4 any
OnDone func() OnDone func()
} }
@@ -148,13 +149,14 @@ func (c *playbackCommandQueue) LoadRadioStation(radio *mediaprovider.RadioStatio
c.cmdAvailable.Signal() 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.mutex.Lock()
c.queue = append(c.queue, playbackCommand{ c.queue = append(c.queue, playbackCommand{
Type: cmdLoadItems, Type: cmdLoadItems,
Arg: items, Arg: items,
Arg2: insertQueueMode, Arg2: insertQueueMode,
Arg3: shuffle, Arg3: queueType,
Arg4: shuffle,
}) })
c.mutex.Unlock() c.mutex.Unlock()
c.cmdAvailable.Signal() c.cmdAvailable.Signal()
+28 -11
View File
@@ -7,6 +7,7 @@ import (
"log" "log"
"math/rand" "math/rand"
"slices" "slices"
"strconv"
"time" "time"
"github.com/dweymouth/supersonic/backend/mediaprovider" "github.com/dweymouth/supersonic/backend/mediaprovider"
@@ -33,6 +34,14 @@ const (
Append Append
) )
type QueueType int
const (
PlayQueue QueueType = iota
ShuffledPlayQueue
Both
)
// The playback loop mode (LoopNone, LoopAll, LoopOne). // The playback loop mode (LoopNone, LoopAll, LoopOne).
type LoopMode int type LoopMode int
@@ -239,7 +248,7 @@ func (p *playbackEngine) getPlayQueueLength() int {
func (p *playbackEngine) clearPlayQueue() { func (p *playbackEngine) clearPlayQueue() {
p.playQueue = nil p.playQueue = nil
p.SetShuffle(false) p.shuffledPlayQueue = nil
} }
func (p *playbackEngine) setPlayQueue(items []mediaprovider.MediaItem) { func (p *playbackEngine) setPlayQueue(items []mediaprovider.MediaItem) {
@@ -254,9 +263,17 @@ func (p *playbackEngine) getPlayQueueItemAt(idx int) mediaprovider.MediaItem {
return p.getPlayQueue()[idx] return p.getPlayQueue()[idx]
} }
func (p *playbackEngine) insertItemsIntoPlayQueueAt(items []mediaprovider.MediaItem, idx int) { 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.playQueue = append(p.playQueue[:idx], append(items, p.playQueue[idx:]...)...)
p.shuffledPlayQueue = append(p.shuffledPlayQueue[:idx], append(items, p.shuffledPlayQueue[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 { func (p *playbackEngine) GetPlayQueueDeepCopy() []mediaprovider.MediaItem {
@@ -320,7 +337,7 @@ func (p *playbackEngine) GetLoopMode() LoopMode {
func (p *playbackEngine) GetNowPlayingIdxFrom(items []mediaprovider.MediaItem) int { func (p *playbackEngine) GetNowPlayingIdxFrom(items []mediaprovider.MediaItem) int {
newNowPlayingIdx := -1 newNowPlayingIdx := -1
if p.nowPlayingIdx >= 0 { if p.nowPlayingIdx >= 0 && len(items) > p.nowPlayingIdx {
nowPlayingID := p.getPlayQueueItemAt(p.nowPlayingIdx).Metadata().ID nowPlayingID := p.getPlayQueueItemAt(p.nowPlayingIdx).Metadata().ID
for i, tr := range items { for i, tr := range items {
if tr.Metadata().ID == nowPlayingID { if tr.Metadata().ID == nowPlayingID {
@@ -455,19 +472,19 @@ func (p *playbackEngine) Continue() error {
// Load items into the play queue. // Load items 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) 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) newItems := deepCopyMediaItemSlice(items)
return p.doLoaditems(newItems, insertQueueMode, shuffle) return p.doLoaditems(newItems, insertQueueMode, queueType, shuffle)
} }
// 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, queueType QueueType, shuffle bool) error {
newTracks := sharedutil.CopyTrackSliceToMediaItemSlice(tracks) 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 { if insertQueueMode == Replace {
p.player.Stop(false) p.player.Stop(false)
p.nowPlayingIdx = -1 p.nowPlayingIdx = -1
@@ -477,7 +494,7 @@ func (p *playbackEngine) doLoaditems(items []mediaprovider.MediaItem, insertQueu
defer p.handleNextTrackUpdated() 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] }) 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 insertIdx = p.nowPlayingIdx + 1
} }
p.insertItemsIntoPlayQueueAt(items, insertIdx) p.insertItemsIntoPlayQueueAt(items, insertIdx, queueType)
p.invokeNoArgCallbacks(p.onQueueChange) p.invokeNoArgCallbacks(p.onQueueChange)
return nil return nil
} }
@@ -504,7 +521,7 @@ func (p *playbackEngine) LoadRadioStation(radio *mediaprovider.RadioStation, ins
if insertMode == InsertNext { if insertMode == InsertNext {
insertIdx = p.nowPlayingIdx + 1 insertIdx = p.nowPlayingIdx + 1
} }
p.insertItemsIntoPlayQueueAt([]mediaprovider.MediaItem{radio}, insertIdx) p.insertItemsIntoPlayQueueAt([]mediaprovider.MediaItem{radio}, insertIdx, Both)
p.invokeNoArgCallbacks(p.onQueueChange) p.invokeNoArgCallbacks(p.onQueueChange)
} }
+14 -13
View File
@@ -364,7 +364,7 @@ func (p *PlaybackManager) LoadAlbum(albumID string, insertQueueMode InsertQueueM
if err != nil { if err != nil {
return err return err
} }
p.LoadTracks(album.Tracks, insertQueueMode, shuffle) p.LoadTracks(album.Tracks, insertQueueMode, Both, shuffle)
return nil return nil
} }
@@ -378,21 +378,21 @@ func (p *PlaybackManager) LoadPlaylist(playlistID string, insertQueueMode Insert
if err != nil { if err != nil {
return err return err
} }
p.LoadTracks(playlist.Tracks, insertQueueMode, shuffle) p.LoadTracks(playlist.Tracks, insertQueueMode, Both, shuffle)
return nil return nil
} }
// 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, queueType QueueType, shuffle bool) {
items := sharedutil.CopyTrackSliceToMediaItemSlice(tracks) 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. // If replacing the current queue (!appendToQueue), playback will be stopped.
func (p *PlaybackManager) LoadItems(items []mediaprovider.MediaItem, insertQueueMode InsertQueueMode, shuffle bool) { func (p *PlaybackManager) LoadItems(items []mediaprovider.MediaItem, insertQueueMode InsertQueueMode, queueType QueueType, shuffle bool) {
p.cmdQueue.LoadItems(items, insertQueueMode, shuffle) p.cmdQueue.LoadItems(items, insertQueueMode, queueType, shuffle)
} }
// Replaces the play queue with the given set of tracks. // Replaces the play queue with the given set of tracks.
@@ -429,7 +429,7 @@ func (p *PlaybackManager) PlayTrack(trackID string) error {
if err != nil { if err != nil {
return err return err
} }
p.LoadTracks([]*mediaprovider.Track{tr}, Replace, false) p.LoadTracks([]*mediaprovider.Track{tr}, Replace, Both, false)
if p.engine.replayGainCfg.Mode == ReplayGainAuto { if p.engine.replayGainCfg.Mode == ReplayGainAuto {
p.SetReplayGainMode(player.ReplayGainTrack) 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) log.Printf("failed to get artist tracks: %v\n", err)
return return
} }
p.LoadTracks(tr, Replace, shuffleTracks) p.LoadTracks(tr, Replace, Both, shuffleTracks)
if p.engine.replayGainCfg.Mode == ReplayGainAuto { if p.engine.replayGainCfg.Mode == ReplayGainAuto {
if shuffleTracks { if shuffleTracks {
p.SetReplayGainMode(player.ReplayGainTrack) p.SetReplayGainMode(player.ReplayGainTrack)
@@ -532,7 +532,7 @@ func (p *PlaybackManager) PlayRandomAlbums(genreName string) error {
break break
} }
if al, err := mp.GetAlbum(al.ID); err == nil { 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 { if i == 0 {
p.PlayFromBeginning() p.PlayFromBeginning()
insertMode = Append insertMode = Append
@@ -556,7 +556,7 @@ func (p *PlaybackManager) fetchAndPlayTracks(fetchFn func() ([]*mediaprovider.Tr
if songs, err := fetchFn(); err != nil { if songs, err := fetchFn(); err != nil {
return err return err
} else { } else {
p.LoadTracks(songs, Replace, false) p.LoadTracks(songs, Replace, Both, false)
if p.engine.replayGainCfg.Mode == ReplayGainAuto { if p.engine.replayGainCfg.Mode == ReplayGainAuto {
p.SetReplayGainMode(player.ReplayGainTrack) p.SetReplayGainMode(player.ReplayGainTrack)
} }
@@ -806,7 +806,7 @@ func (p *PlaybackManager) enqueueAutoplayTracks() {
} }
if len(tracks) > 0 { 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( err := p.engine.LoadItems(
c.Arg.([]mediaprovider.MediaItem), c.Arg.([]mediaprovider.MediaItem),
c.Arg2.(InsertQueueMode), c.Arg2.(InsertQueueMode),
c.Arg3.(bool), c.Arg3.(QueueType),
c.Arg4.(bool),
) )
logIfErr("LoadItems", err) logIfErr("LoadItems", err)
case cmdLoadRadioStation: case cmdLoadRadioStation:
+1 -1
View File
@@ -260,7 +260,7 @@ func NewAlbumPageHeader(page *AlbumPage) *AlbumPageHeader {
go a.page.pm.PlayAlbum(a.page.albumID, 0, false) go a.page.pm.PlayAlbum(a.page.albumID, 0, false)
}) })
shuffleBtn := widget.NewButtonWithIcon(lang.L("Shuffle"), myTheme.ShuffleIcon, func() { shuffleBtn := widget.NewButtonWithIcon(lang.L("Shuffle"), myTheme.ShuffleIcon, func() {
a.page.pm.LoadTracks(a.page.tracklist.GetTracks(), backend.Replace, true) a.page.pm.LoadTracks(a.page.tracklist.GetTracks(), backend.Replace, backend.Both, true)
a.page.pm.PlayFromBeginning() a.page.pm.PlayFromBeginning()
}) })
var pop *widget.PopUpMenu var pop *widget.PopUpMenu
+1 -1
View File
@@ -98,7 +98,7 @@ func (a *FavoritesPage) createHeader(activeBtnIdx int) {
widget.NewButtonWithIcon("", myTheme.TracksIcon, a.onShowFavoriteSongs)) widget.NewButtonWithIcon("", myTheme.TracksIcon, a.onShowFavoriteSongs))
a.shuffleBtn = widget.NewButtonWithIcon(lang.L("Shuffle"), myTheme.ShuffleIcon, func() { a.shuffleBtn = widget.NewButtonWithIcon(lang.L("Shuffle"), myTheme.ShuffleIcon, func() {
if tr := a.tracklistOrNil(); tr != nil { if tr := a.tracklistOrNil(); tr != nil {
a.pm.LoadTracks(tr.GetTracks(), backend.Replace, true /*shuffle*/) a.pm.LoadTracks(tr.GetTracks(), backend.Replace, backend.Both, true /*shuffle*/)
a.pm.PlayFromBeginning() a.pm.PlayFromBeginning()
} }
}) })
+4 -4
View File
@@ -159,18 +159,18 @@ func NewNowPlayingPage(
a.relatedList.OnSetRating = a.queueList.OnSetRating a.relatedList.OnSetRating = a.queueList.OnSetRating
a.relatedList.OnSetFavorite = a.queueList.OnSetFavorite a.relatedList.OnSetFavorite = a.queueList.OnSetFavorite
a.relatedList.OnPlayItemAt = func(idx int) { a.relatedList.OnPlayItemAt = func(idx int) {
a.pm.LoadTracks(a.related, backend.Replace, false) a.pm.LoadTracks(a.related, backend.Replace, backend.Both, false)
a.pm.PlayTrackAt(idx) a.pm.PlayTrackAt(idx)
} }
a.relatedList.OnAddToQueue = func(items []mediaprovider.MediaItem) { a.relatedList.OnAddToQueue = func(items []mediaprovider.MediaItem) {
a.pm.LoadItems(items, backend.Append, false) a.pm.LoadItems(items, backend.Append, backend.Both, false)
} }
a.relatedList.OnPlaySelection = func(items []mediaprovider.MediaItem, shuffle bool) { a.relatedList.OnPlaySelection = func(items []mediaprovider.MediaItem, shuffle bool) {
a.pm.LoadItems(items, backend.Replace, shuffle) a.pm.LoadItems(items, backend.Replace, backend.Both, shuffle)
a.pm.PlayFromBeginning() a.pm.PlayFromBeginning()
} }
a.relatedList.OnPlaySelectionNext = func(items []mediaprovider.MediaItem) { a.relatedList.OnPlaySelectionNext = func(items []mediaprovider.MediaItem) {
a.pm.LoadItems(items, backend.InsertNext, false) a.pm.LoadItems(items, backend.InsertNext, backend.Both, false)
} }
a.relatedList.OnPlaySongRadio = func(track *mediaprovider.Track) { a.relatedList.OnPlaySongRadio = func(track *mediaprovider.Track) {
go func() { go func() {
+2 -2
View File
@@ -348,11 +348,11 @@ func NewPlaylistPageHeader(page *PlaylistPage) *PlaylistPageHeader {
}) })
a.editButton.Hidden = true a.editButton.Hidden = true
playButton := widget.NewButtonWithIcon(lang.L("Play"), theme.MediaPlayIcon(), func() { playButton := widget.NewButtonWithIcon(lang.L("Play"), theme.MediaPlayIcon(), func() {
a.page.pm.LoadTracks(a.page.tracks, backend.Replace, false) a.page.pm.LoadTracks(a.page.tracks, backend.Replace, backend.Both, false)
a.page.pm.PlayFromBeginning() a.page.pm.PlayFromBeginning()
}) })
shuffleBtn := widget.NewButtonWithIcon(lang.L("Shuffle"), myTheme.ShuffleIcon, func() { shuffleBtn := widget.NewButtonWithIcon(lang.L("Shuffle"), myTheme.ShuffleIcon, func() {
a.page.pm.LoadTracks(a.page.tracks, backend.Replace, true) a.page.pm.LoadTracks(a.page.tracks, backend.Replace, backend.Both, true)
a.page.pm.PlayFromBeginning() a.page.pm.PlayFromBeginning()
}) })
+7 -7
View File
@@ -25,20 +25,20 @@ func (m *Controller) ConnectTracklistActions(tracklist *widgets.Tracklist) {
func (m *Controller) connectTracklistActionsWithReplayGainMode(tracklist *widgets.Tracklist, mode player.ReplayGainMode) { func (m *Controller) connectTracklistActionsWithReplayGainMode(tracklist *widgets.Tracklist, mode player.ReplayGainMode) {
tracklist.OnAddToPlaylist = m.DoAddTracksToPlaylistWorkflow tracklist.OnAddToPlaylist = m.DoAddTracksToPlaylistWorkflow
tracklist.OnPlaySelectionNext = func(tracks []*mediaprovider.Track) { tracklist.OnPlaySelectionNext = func(tracks []*mediaprovider.Track) {
m.App.PlaybackManager.LoadTracks(tracks, backend.InsertNext, false) m.App.PlaybackManager.LoadTracks(tracks, backend.InsertNext, backend.Both, false)
} }
tracklist.OnAddToQueue = func(tracks []*mediaprovider.Track) { tracklist.OnAddToQueue = func(tracks []*mediaprovider.Track) {
m.App.PlaybackManager.LoadTracks(tracks, backend.Append, false) m.App.PlaybackManager.LoadTracks(tracks, backend.Append, backend.Both, false)
} }
tracklist.OnPlayTrackAt = func(idx int) { tracklist.OnPlayTrackAt = func(idx int) {
m.App.PlaybackManager.LoadTracks(tracklist.GetTracks(), backend.Replace, false) m.App.PlaybackManager.LoadTracks(tracklist.GetTracks(), backend.Replace, backend.Both, false)
if m.App.Config.ReplayGain.Mode == backend.ReplayGainAuto { if m.App.Config.ReplayGain.Mode == backend.ReplayGainAuto {
m.App.PlaybackManager.SetReplayGainMode(mode) m.App.PlaybackManager.SetReplayGainMode(mode)
} }
m.App.PlaybackManager.PlayTrackAt(idx) m.App.PlaybackManager.PlayTrackAt(idx)
} }
tracklist.OnPlaySelection = func(tracks []*mediaprovider.Track, shuffle bool) { tracklist.OnPlaySelection = func(tracks []*mediaprovider.Track, shuffle bool) {
m.App.PlaybackManager.LoadTracks(tracks, backend.Replace, shuffle) m.App.PlaybackManager.LoadTracks(tracks, backend.Replace, backend.Both, shuffle)
if m.App.Config.ReplayGain.Mode == backend.ReplayGainAuto { if m.App.Config.ReplayGain.Mode == backend.ReplayGainAuto {
m.App.PlaybackManager.SetReplayGainMode(mode) m.App.PlaybackManager.SetReplayGainMode(mode)
} }
@@ -70,7 +70,7 @@ func (m *Controller) connectTracklistActionsWithReplayGainMode(tracklist *widget
log.Println("Error getting song radio: ", err) log.Println("Error getting song radio: ", err)
return return
} }
m.App.PlaybackManager.LoadTracks(tracks, backend.Replace, false) m.App.PlaybackManager.LoadTracks(tracks, backend.Replace, backend.Both, false)
if m.App.Config.ReplayGain.Mode == backend.ReplayGainAuto { if m.App.Config.ReplayGain.Mode == backend.ReplayGainAuto {
m.App.PlaybackManager.SetReplayGainMode(mode) m.App.PlaybackManager.SetReplayGainMode(mode)
} }
@@ -164,11 +164,11 @@ func (m *Controller) onDownloadAlbum(albumID string) {
func (m *Controller) ConnectArtistGridActions(grid *widgets.GridView) { func (m *Controller) ConnectArtistGridActions(grid *widgets.GridView) {
grid.OnShowItemPage = func(id string) { m.NavigateTo(ArtistRoute(id)) } grid.OnShowItemPage = func(id string) { m.NavigateTo(ArtistRoute(id)) }
grid.OnPlayNext = func(artistID string) { grid.OnPlayNext = func(artistID string) {
go m.App.PlaybackManager.LoadTracks(m.GetArtistTracks(artistID), backend.InsertNext, false) go m.App.PlaybackManager.LoadTracks(m.GetArtistTracks(artistID), backend.InsertNext, backend.Both, false)
} }
grid.OnPlay = func(artistID string, shuffle bool) { go m.App.PlaybackManager.PlayArtistDiscography(artistID, shuffle) } grid.OnPlay = func(artistID string, shuffle bool) { go m.App.PlaybackManager.PlayArtistDiscography(artistID, shuffle) }
grid.OnAddToQueue = func(artistID string) { grid.OnAddToQueue = func(artistID string) {
go m.App.PlaybackManager.LoadTracks(m.GetArtistTracks(artistID), backend.Append, false) go m.App.PlaybackManager.LoadTracks(m.GetArtistTracks(artistID), backend.Append, backend.Both, false)
} }
grid.OnAddToPlaylist = func(artistID string) { grid.OnAddToPlaylist = func(artistID string) {
m.DoAddTracksToPlaylistWorkflow( m.DoAddTracksToPlaylistWorkflow(
+6 -5
View File
@@ -46,7 +46,7 @@ func (c *Controller) ShowQuickSearch() {
case mediaprovider.ContentTypeTrack: case mediaprovider.ContentTypeTrack:
c.App.PlaybackManager.LoadTracks( c.App.PlaybackManager.LoadTracks(
[]*mediaprovider.Track{item.(*mediaprovider.Track)}, []*mediaprovider.Track{item.(*mediaprovider.Track)},
backend.Replace, false /*shuffle*/) backend.Replace, backend.Both, false /*shuffle*/)
c.App.PlaybackManager.PlayFromBeginning() c.App.PlaybackManager.PlayFromBeginning()
case mediaprovider.ContentTypeAlbum: case mediaprovider.ContentTypeAlbum:
go c.App.PlaybackManager.PlayAlbum(id, 0, shuffle) go c.App.PlaybackManager.PlayAlbum(id, 0, shuffle)
@@ -69,7 +69,7 @@ func (c *Controller) ShowQuickSearch() {
go func() { go func() {
tracks, err := c.GetSongRadioTracks(track) tracks, err := c.GetSongRadioTracks(track)
if err != nil { if err != nil {
c.App.PlaybackManager.LoadTracks(tracks, backend.Replace, false) c.App.PlaybackManager.LoadTracks(tracks, backend.Replace, backend.Both, false)
c.App.PlaybackManager.PlayFromBeginning() c.App.PlaybackManager.PlayFromBeginning()
} }
}() }()
@@ -99,6 +99,7 @@ func (c *Controller) ShowQuickSearch() {
func (c *Controller) handleSearchDialogOnAddToQueue(t mediaprovider.ContentType, id string, item any, next bool) { func (c *Controller) handleSearchDialogOnAddToQueue(t mediaprovider.ContentType, id string, item any, next bool) {
insertMode := backend.Append insertMode := backend.Append
queueType := backend.Both
if next { if next {
insertMode = backend.InsertNext insertMode = backend.InsertNext
} }
@@ -106,13 +107,13 @@ func (c *Controller) handleSearchDialogOnAddToQueue(t mediaprovider.ContentType,
case mediaprovider.ContentTypeTrack: case mediaprovider.ContentTypeTrack:
c.App.PlaybackManager.LoadTracks( c.App.PlaybackManager.LoadTracks(
[]*mediaprovider.Track{item.(*mediaprovider.Track)}, []*mediaprovider.Track{item.(*mediaprovider.Track)},
insertMode, false /*shuffle*/) insertMode, queueType, false /*shuffle*/)
case mediaprovider.ContentTypeAlbum: case mediaprovider.ContentTypeAlbum:
go c.App.PlaybackManager.LoadAlbum(id, insertMode, false) go c.App.PlaybackManager.LoadAlbum(id, insertMode, false)
case mediaprovider.ContentTypeArtist: case mediaprovider.ContentTypeArtist:
go func() { go func() {
tracks := c.GetArtistTracks(id) tracks := c.GetArtistTracks(id)
c.App.PlaybackManager.LoadTracks(tracks, insertMode, false) c.App.PlaybackManager.LoadTracks(tracks, insertMode, queueType, false)
}() }()
case mediaprovider.ContentTypePlaylist: case mediaprovider.ContentTypePlaylist:
go c.App.PlaybackManager.LoadPlaylist(id, insertMode, false) go c.App.PlaybackManager.LoadPlaylist(id, insertMode, false)
@@ -120,7 +121,7 @@ func (c *Controller) handleSearchDialogOnAddToQueue(t mediaprovider.ContentType,
go func() { go func() {
tr, err := c.App.ServerManager.Server.GetRandomTracks(id /*genre name*/, c.App.Config.Application.EnqueueBatchSize) tr, err := c.App.ServerManager.Server.GetRandomTracks(id /*genre name*/, c.App.Config.Application.EnqueueBatchSize)
if err != nil { if err != nil {
c.App.PlaybackManager.LoadTracks(tr, insertMode, false /*shuffle*/) c.App.PlaybackManager.LoadTracks(tr, insertMode, queueType, false /*shuffle*/)
} }
}() }()
case mediaprovider.ContentTypeRadioStation: case mediaprovider.ContentTypeRadioStation: