load full queue state on start
This commit is contained in:
+21
-20
@@ -622,11 +622,11 @@ func (a *App) SavePlayQueueIfEnabled() {
|
|||||||
func (a *App) LoadSavedPlayQueue() error {
|
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
|
var shuffledPlayQueue *SavedPlayQueue
|
||||||
|
|
||||||
isShuffe := a.Config.Playback.Shuffle
|
isShuffe := a.Config.Playback.Shuffle
|
||||||
|
|
||||||
if isShuffe {
|
if isShuffe {
|
||||||
unshuffledQueueFilePath := path.Join(a.configDir, savedUnshuffledQueueFile)
|
unshuffledQueueFilePath := path.Join(a.configDir, savedUnshuffledQueueFile)
|
||||||
unshuffledPlayQueue, err = LoadPlayQueue(unshuffledQueueFilePath, a.ServerManager, false)
|
unshuffledPlayQueue, err = LoadPlayQueue(unshuffledQueueFilePath, a.ServerManager, false)
|
||||||
@@ -635,7 +635,7 @@ func (a *App) LoadSavedPlayQueue() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
shuffledQueueFilePath := path.Join(a.configDir, savedUnshuffledQueueFile)
|
shuffledQueueFilePath := path.Join(a.configDir, savedShuffledQueueFile)
|
||||||
shuffledPlayQueue, err = LoadPlayQueue(shuffledQueueFilePath, a.ServerManager, false)
|
shuffledPlayQueue, err = LoadPlayQueue(shuffledQueueFilePath, a.ServerManager, false)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -653,7 +653,25 @@ func (a *App) LoadSavedPlayQueue() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
a.PlaybackManager.LoadTracks(playQueue.Tracks, Replace, false)
|
if isShuffe {
|
||||||
|
serverStatePlayQueue := sharedutil.CopyTrackSliceToMediaItemSlice(playQueue.Tracks)
|
||||||
|
clientStatePlayQueue := sharedutil.CopyTrackSliceToMediaItemSlice(shuffledPlayQueue.Tracks)
|
||||||
|
|
||||||
|
// Compare items by ID. This fails if any 2 elements don't match up. Two queues with the same items but different order will thus not count as same
|
||||||
|
if slices.EqualFunc(serverStatePlayQueue, clientStatePlayQueue, func(a, b mediaprovider.MediaItem) bool {
|
||||||
|
return (a.Metadata().ID == b.Metadata().ID)
|
||||||
|
}) {
|
||||||
|
a.PlaybackManager.SetQueueState(playQueue.Tracks, ShuffledPlayQueue)
|
||||||
|
a.PlaybackManager.SetQueueState(unshuffledPlayQueue.Tracks, PlayQueue)
|
||||||
|
} else {
|
||||||
|
a.PlaybackManager.SetShuffle(false)
|
||||||
|
a.PlaybackManager.SetQueueState(playQueue.Tracks, PlayQueue)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
a.PlaybackManager.SetQueueState(playQueue.Tracks, PlayQueue)
|
||||||
|
}
|
||||||
|
|
||||||
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)
|
||||||
@@ -662,23 +680,6 @@ func (a *App) LoadSavedPlayQueue() error {
|
|||||||
a.PlaybackManager.SeekSeconds(playQueue.TimePos)
|
a.PlaybackManager.SeekSeconds(playQueue.TimePos)
|
||||||
}
|
}
|
||||||
|
|
||||||
if isShuffe {
|
|
||||||
// check if queue was changed server side
|
|
||||||
if len(playQueue.Tracks) != len(unshuffledPlayQueue.Tracks) {
|
|
||||||
// queue was changed server side, no need to compare elements
|
|
||||||
a.PlaybackManager.SetShuffle(false)
|
|
||||||
} else {
|
|
||||||
serverStatePlayQueue := sharedutil.CopyTrackSliceToMediaItemSlice(playQueue.Tracks)
|
|
||||||
clientStatePlayQueue := sharedutil.CopyTrackSliceToMediaItemSlice(shuffledPlayQueue.Tracks)
|
|
||||||
|
|
||||||
if slices.Equal(serverStatePlayQueue, clientStatePlayQueue) {
|
|
||||||
fmt.Println("Loading unshuffled items into playQueue")
|
|
||||||
a.PlaybackManager.LoadTracks(unshuffledPlayQueue.Tracks, Replace, false)
|
|
||||||
} else {
|
|
||||||
a.PlaybackManager.SetShuffle(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ const (
|
|||||||
// arg2: InsertMode
|
// arg2: InsertMode
|
||||||
// arg3: bool (shuffle)
|
// arg3: bool (shuffle)
|
||||||
cmdLoadItems
|
cmdLoadItems
|
||||||
|
cmdSetQueueState
|
||||||
cmdLoadRadioStation // arg: *mediaprovider.RadioStation, arg2: InsertQueueMode
|
cmdLoadRadioStation // arg: *mediaprovider.RadioStation, arg2: InsertQueueMode
|
||||||
|
|
||||||
cmdForceRestartPlayback
|
cmdForceRestartPlayback
|
||||||
@@ -160,6 +161,17 @@ func (c *playbackCommandQueue) LoadItems(items []mediaprovider.MediaItem, insert
|
|||||||
c.cmdAvailable.Signal()
|
c.cmdAvailable.Signal()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *playbackCommandQueue) SetQueueState(tracks []*mediaprovider.Track, queueType QueueType) {
|
||||||
|
c.mutex.Lock()
|
||||||
|
c.queue = append(c.queue, playbackCommand{
|
||||||
|
Type: cmdSetQueueState,
|
||||||
|
Arg: tracks,
|
||||||
|
Arg2: queueType,
|
||||||
|
})
|
||||||
|
c.mutex.Unlock()
|
||||||
|
c.cmdAvailable.Signal()
|
||||||
|
}
|
||||||
|
|
||||||
func (c *playbackCommandQueue) addCommand(command playbackCommand) {
|
func (c *playbackCommandQueue) addCommand(command playbackCommand) {
|
||||||
c.mutex.Lock()
|
c.mutex.Lock()
|
||||||
c.queue = append(c.queue, command)
|
c.queue = append(c.queue, command)
|
||||||
@@ -194,7 +206,7 @@ func (c *playbackCommandQueue) seekBackOrFwd(direction int) {
|
|||||||
switch cmd.Type {
|
switch cmd.Type {
|
||||||
case cmdSeekFwdBackN:
|
case cmdSeekFwdBackN:
|
||||||
lastIdx = i
|
lastIdx = i
|
||||||
case cmdRemoveTracksFromQueue, cmdLoadItems, cmdPlayTrackAt,
|
case cmdRemoveTracksFromQueue, cmdLoadItems, cmdSetQueueState, cmdPlayTrackAt,
|
||||||
cmdLoadRadioStation, cmdUpdatePlayQueue, cmdStopAndClearPlayQueue:
|
cmdLoadRadioStation, cmdUpdatePlayQueue, cmdStopAndClearPlayQueue:
|
||||||
// any queue-modifying command means we can't coalesce any
|
// any queue-modifying command means we can't coalesce any
|
||||||
// more seekFwdBackN commands before here
|
// more seekFwdBackN commands before here
|
||||||
|
|||||||
+40
-20
@@ -110,6 +110,7 @@ type playbackEngine struct {
|
|||||||
onSongChange []func(nowPlaying mediaprovider.MediaItem, justScrobbledIfAny *mediaprovider.Track)
|
onSongChange []func(nowPlaying mediaprovider.MediaItem, justScrobbledIfAny *mediaprovider.Track)
|
||||||
onPlayTimeUpdate []func(float64, float64, bool)
|
onPlayTimeUpdate []func(float64, float64, bool)
|
||||||
onLoopModeChange []func(LoopMode)
|
onLoopModeChange []func(LoopMode)
|
||||||
|
onShuffleChange []func(bool)
|
||||||
onVolumeChange []func(int)
|
onVolumeChange []func(int)
|
||||||
onSeek []func()
|
onSeek []func()
|
||||||
onPaused []func()
|
onPaused []func()
|
||||||
@@ -149,6 +150,8 @@ func NewPlaybackEngine(
|
|||||||
pm.loopMode = LoopOne
|
pm.loopMode = LoopOne
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pm.shuffle = playbackCfg.Shuffle
|
||||||
|
|
||||||
pm.registerPlayerCallbacks(p)
|
pm.registerPlayerCallbacks(p)
|
||||||
s.OnLogout(func() {
|
s.OnLogout(func() {
|
||||||
pm.StopAndClearPlayQueue()
|
pm.StopAndClearPlayQueue()
|
||||||
@@ -231,12 +234,13 @@ func (p *playbackEngine) SetPlayer(pl player.BasePlayer) error {
|
|||||||
// ======================= START PLAY QUEUE FUNCS ===========================
|
// ======================= START PLAY QUEUE FUNCS ===========================
|
||||||
|
|
||||||
func (p *playbackEngine) getPlayQueue() []mediaprovider.MediaItem {
|
func (p *playbackEngine) getPlayQueue() []mediaprovider.MediaItem {
|
||||||
if p.shuffle {
|
|
||||||
return p.shuffledPlayQueue
|
|
||||||
}
|
|
||||||
return p.playQueue
|
return p.playQueue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *playbackEngine) getShuffledPlayQueue() []mediaprovider.MediaItem {
|
||||||
|
return p.shuffledPlayQueue
|
||||||
|
}
|
||||||
|
|
||||||
func (p *playbackEngine) getActivePlayQueue() []mediaprovider.MediaItem {
|
func (p *playbackEngine) getActivePlayQueue() []mediaprovider.MediaItem {
|
||||||
if p.shuffle {
|
if p.shuffle {
|
||||||
return p.shuffledPlayQueue
|
return p.shuffledPlayQueue
|
||||||
@@ -245,10 +249,12 @@ func (p *playbackEngine) getActivePlayQueue() []mediaprovider.MediaItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *playbackEngine) getPlayQueueLength() int {
|
func (p *playbackEngine) getPlayQueueLength() int {
|
||||||
return len(p.getPlayQueue())
|
return len(p.getActivePlayQueue())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *playbackEngine) clearPlayQueue() {
|
func (p *playbackEngine) clearPlayQueue() {
|
||||||
|
p.player.Stop(false)
|
||||||
|
p.nowPlayingIdx = -1
|
||||||
p.playQueue = nil
|
p.playQueue = nil
|
||||||
p.shuffledPlayQueue = nil
|
p.shuffledPlayQueue = nil
|
||||||
}
|
}
|
||||||
@@ -262,7 +268,7 @@ func (p *playbackEngine) setShuffledPlayQueue(items []mediaprovider.MediaItem) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *playbackEngine) getPlayQueueItemAt(idx int) mediaprovider.MediaItem {
|
func (p *playbackEngine) getPlayQueueItemAt(idx int) mediaprovider.MediaItem {
|
||||||
return p.getPlayQueue()[idx]
|
return p.getActivePlayQueue()[idx]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *playbackEngine) insertItemsIntoPlayQueueAt(items []mediaprovider.MediaItem, idx int, queueType QueueType) {
|
func (p *playbackEngine) insertItemsIntoPlayQueueAt(items []mediaprovider.MediaItem, idx int, queueType QueueType) {
|
||||||
@@ -282,7 +288,7 @@ func (p *playbackEngine) GetPlayQueueDeepCopy() []mediaprovider.MediaItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *playbackEngine) GetShuffledPlayQueueDeepCopy() []mediaprovider.MediaItem {
|
func (p *playbackEngine) GetShuffledPlayQueueDeepCopy() []mediaprovider.MediaItem {
|
||||||
return deepCopyMediaItemSlice(p.getPlayQueue())
|
return deepCopyMediaItemSlice(p.getShuffledPlayQueue())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *playbackEngine) GetActivePlayQueueDeepCopy() []mediaprovider.MediaItem {
|
func (p *playbackEngine) GetActivePlayQueueDeepCopy() []mediaprovider.MediaItem {
|
||||||
@@ -351,23 +357,26 @@ func (p *playbackEngine) GetNowPlayingIdxFrom(items []mediaprovider.MediaItem) i
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *playbackEngine) SetShuffle(shuffle bool) {
|
func (p *playbackEngine) SetShuffle(shuffle bool) {
|
||||||
|
for _, cb := range p.onShuffleChange {
|
||||||
|
cb(shuffle)
|
||||||
|
}
|
||||||
|
|
||||||
if p.shuffle == shuffle {
|
if p.shuffle == shuffle {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
newNowPlayingIdx := 0
|
||||||
var newNowPlayingIdx int
|
|
||||||
if shuffle {
|
if shuffle {
|
||||||
shuffledQueue := deepCopyMediaItemSlice(p.playQueue)
|
shuffledQueue := deepCopyMediaItemSlice(p.playQueue)
|
||||||
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.GetNowPlayingIdxFrom(shuffledQueue)}, 0)
|
p.setShuffledPlayQueue(sharedutil.ReorderItems(shuffledQueue, []int{p.GetNowPlayingIdxFrom(shuffledQueue)}, 0))
|
||||||
newNowPlayingIdx = 0
|
|
||||||
} else {
|
} else {
|
||||||
newNowPlayingIdx = p.GetNowPlayingIdxFrom(p.playQueue)
|
newNowPlayingIdx = p.GetNowPlayingIdxFrom(p.playQueue)
|
||||||
}
|
}
|
||||||
|
|
||||||
p.shuffle = shuffle
|
p.shuffle = shuffle
|
||||||
|
|
||||||
if p.nowPlayingIdx >= 0 && newNowPlayingIdx == -1 {
|
if p.nowPlayingIdx >= 0 && newNowPlayingIdx == -1 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -471,6 +480,23 @@ func (p *playbackEngine) Continue() error {
|
|||||||
return p.player.Continue()
|
return p.player.Continue()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load items into the specified queue(s). This overrides the queue. For standard inserts or replaces use p.LoadItems
|
||||||
|
// This is used on program startup to populate both the playQueue and shuffledPlayQueue with the previously saved client state.
|
||||||
|
func (p *playbackEngine) SetQueueState(tracks []*mediaprovider.Track, queueType QueueType) error {
|
||||||
|
newTracks := sharedutil.CopyTrackSliceToMediaItemSlice(tracks)
|
||||||
|
switch queueType {
|
||||||
|
case PlayQueue:
|
||||||
|
p.setPlayQueue(newTracks)
|
||||||
|
case ShuffledPlayQueue:
|
||||||
|
p.setShuffledPlayQueue(newTracks)
|
||||||
|
case Both:
|
||||||
|
p.setPlayQueue(newTracks)
|
||||||
|
p.setShuffledPlayQueue(newTracks)
|
||||||
|
}
|
||||||
|
p.invokeNoArgCallbacks(p.onQueueChange)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// 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, shuffle bool) error {
|
||||||
@@ -489,8 +515,6 @@ func (p *playbackEngine) doLoaditems(items []mediaprovider.MediaItem, insertQueu
|
|||||||
queueType := PlayQueue
|
queueType := PlayQueue
|
||||||
|
|
||||||
if insertQueueMode == Replace {
|
if insertQueueMode == Replace {
|
||||||
p.player.Stop(false)
|
|
||||||
p.nowPlayingIdx = -1
|
|
||||||
p.clearPlayQueue()
|
p.clearPlayQueue()
|
||||||
}
|
}
|
||||||
if nextChanged := len(items) > 0 && (insertQueueMode != Append || (p.nowPlayingIdx == p.getPlayQueueLength()-1)); nextChanged {
|
if nextChanged := len(items) > 0 && (insertQueueMode != Append || (p.nowPlayingIdx == p.getPlayQueueLength()-1)); nextChanged {
|
||||||
@@ -528,8 +552,6 @@ func (p *playbackEngine) doLoaditems(items []mediaprovider.MediaItem, insertQueu
|
|||||||
|
|
||||||
func (p *playbackEngine) LoadRadioStation(radio *mediaprovider.RadioStation, insertMode InsertQueueMode) {
|
func (p *playbackEngine) LoadRadioStation(radio *mediaprovider.RadioStation, insertMode InsertQueueMode) {
|
||||||
if insertMode == Replace {
|
if insertMode == Replace {
|
||||||
p.player.Stop(false)
|
|
||||||
p.nowPlayingIdx = -1
|
|
||||||
p.clearPlayQueue()
|
p.clearPlayQueue()
|
||||||
}
|
}
|
||||||
if nextChanged := insertMode == InsertNext || (insertMode == Append && p.nowPlayingIdx == p.getPlayQueueLength()-1); nextChanged {
|
if nextChanged := insertMode == InsertNext || (insertMode == Append && p.nowPlayingIdx == p.getPlayQueueLength()-1); nextChanged {
|
||||||
@@ -546,9 +568,7 @@ func (p *playbackEngine) LoadRadioStation(radio *mediaprovider.RadioStation, ins
|
|||||||
// Stop playback and clear the play queue.
|
// Stop playback and clear the play queue.
|
||||||
func (p *playbackEngine) StopAndClearPlayQueue() {
|
func (p *playbackEngine) StopAndClearPlayQueue() {
|
||||||
changed := p.getPlayQueueLength() > 0
|
changed := p.getPlayQueueLength() > 0
|
||||||
p.player.Stop(false)
|
|
||||||
p.clearPlayQueue()
|
p.clearPlayQueue()
|
||||||
p.nowPlayingIdx = -1
|
|
||||||
if changed {
|
if changed {
|
||||||
p.invokeNoArgCallbacks(p.onQueueChange)
|
p.invokeNoArgCallbacks(p.onQueueChange)
|
||||||
}
|
}
|
||||||
@@ -557,7 +577,7 @@ func (p *playbackEngine) StopAndClearPlayQueue() {
|
|||||||
// 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 *playbackEngine) OnTrackFavoriteStatusChanged(id string, fav bool) {
|
func (p *playbackEngine) OnTrackFavoriteStatusChanged(id string, fav bool) {
|
||||||
if item := sharedutil.FindMediaItemByID(id, p.getPlayQueue()); item != nil {
|
if item := sharedutil.FindMediaItemByID(id, p.getActivePlayQueue()); item != nil {
|
||||||
if tr, ok := item.(*mediaprovider.Track); ok {
|
if tr, ok := item.(*mediaprovider.Track); ok {
|
||||||
tr.Favorite = fav
|
tr.Favorite = fav
|
||||||
}
|
}
|
||||||
@@ -567,7 +587,7 @@ func (p *playbackEngine) OnTrackFavoriteStatusChanged(id string, fav bool) {
|
|||||||
// Any time the user changes the rating of a track elsewhere in the app,
|
// Any time the user changes the rating 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 *playbackEngine) OnTrackRatingChanged(id string, rating int) {
|
func (p *playbackEngine) OnTrackRatingChanged(id string, rating int) {
|
||||||
if item := sharedutil.FindMediaItemByID(id, p.getPlayQueue()); item != nil {
|
if item := sharedutil.FindMediaItemByID(id, p.getActivePlayQueue()); item != nil {
|
||||||
if tr, ok := item.(*mediaprovider.Track); ok {
|
if tr, ok := item.(*mediaprovider.Track); ok {
|
||||||
tr.Rating = rating
|
tr.Rating = rating
|
||||||
}
|
}
|
||||||
@@ -616,7 +636,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.getPlayQueue() {
|
for _, tr := range p.getActivePlayQueue() {
|
||||||
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)
|
||||||
@@ -664,7 +684,7 @@ func (p *playbackEngine) RemoveTracksFromQueueByIdx(idxs []int, newQueue *[]medi
|
|||||||
idxSet := sharedutil.ToSet(idxs)
|
idxSet := sharedutil.ToSet(idxs)
|
||||||
nowPlaying := p.NowPlayingIndex()
|
nowPlaying := p.NowPlayingIndex()
|
||||||
|
|
||||||
for i, tr := range p.getPlayQueue() {
|
for i, tr := range p.getActivePlayQueue() {
|
||||||
if _, ok := idxSet[i]; ok {
|
if _, ok := idxSet[i]; ok {
|
||||||
if i < nowPlaying {
|
if i < nowPlaying {
|
||||||
// if removing a track earlier than the currently playing one (if any),
|
// if removing a track earlier than the currently playing one (if any),
|
||||||
|
|||||||
@@ -333,6 +333,11 @@ func (p *PlaybackManager) OnLoopModeChange(cb func(LoopMode)) {
|
|||||||
p.engine.onLoopModeChange = append(p.engine.onLoopModeChange, cb)
|
p.engine.onLoopModeChange = append(p.engine.onLoopModeChange, cb)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Registers a callback that is notified whenever the shuffle state changes.
|
||||||
|
func (p *PlaybackManager) OnShuffleChange(cb func(bool)) {
|
||||||
|
p.engine.onShuffleChange = append(p.engine.onShuffleChange, cb)
|
||||||
|
}
|
||||||
|
|
||||||
// Registers a callback that is notified whenever the volume changes.
|
// Registers a callback that is notified whenever the volume changes.
|
||||||
func (p *PlaybackManager) OnVolumeChange(cb func(int)) {
|
func (p *PlaybackManager) OnVolumeChange(cb func(int)) {
|
||||||
p.engine.onVolumeChange = append(p.engine.onVolumeChange, cb)
|
p.engine.onVolumeChange = append(p.engine.onVolumeChange, cb)
|
||||||
@@ -400,6 +405,12 @@ func (p *PlaybackManager) LoadItems(items []mediaprovider.MediaItem, insertQueue
|
|||||||
p.cmdQueue.LoadItems(items, insertQueueMode, shuffle)
|
p.cmdQueue.LoadItems(items, insertQueueMode, shuffle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load items into the currently active queue. (shuffledPlayQueue/playQueue)
|
||||||
|
// If replacing the current queue (!appendToQueue), playback will be stopped.
|
||||||
|
func (p *PlaybackManager) SetQueueState(tracks []*mediaprovider.Track, queueType QueueType) {
|
||||||
|
p.cmdQueue.SetQueueState(tracks, queueType)
|
||||||
|
}
|
||||||
|
|
||||||
// Replaces the play queue with the given set of tracks.
|
// Replaces the play queue with the given set of tracks.
|
||||||
// Does not stop playback if the currently playing track is in the new queue,
|
// Does not stop playback if the currently playing track is in the new queue,
|
||||||
// but updates the now playing index to point to the first instance of the track in the new queue.
|
// but updates the now playing index to point to the first instance of the track in the new queue.
|
||||||
@@ -743,7 +754,7 @@ func (p *PlaybackManager) enqueueAutoplayTracks() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// last 500 played items
|
// last 500 played items
|
||||||
queue := p.GetPlayQueue()
|
queue := p.GetActivePlayQueue()
|
||||||
if l := len(queue); l > 500 {
|
if l := len(queue); l > 500 {
|
||||||
queue = queue[l-500:]
|
queue = queue[l-500:]
|
||||||
}
|
}
|
||||||
@@ -858,6 +869,12 @@ func (p *PlaybackManager) runCmdQueue(ctx context.Context) {
|
|||||||
c.Arg3.(bool),
|
c.Arg3.(bool),
|
||||||
)
|
)
|
||||||
logIfErr("LoadItems", err)
|
logIfErr("LoadItems", err)
|
||||||
|
case cmdSetQueueState:
|
||||||
|
err := p.engine.SetQueueState(
|
||||||
|
c.Arg.([]*mediaprovider.Track),
|
||||||
|
c.Arg2.(QueueType),
|
||||||
|
)
|
||||||
|
logIfErr("SetQueueState", err)
|
||||||
case cmdLoadRadioStation:
|
case cmdLoadRadioStation:
|
||||||
p.engine.LoadRadioStation(
|
p.engine.LoadRadioStation(
|
||||||
c.Arg.(*mediaprovider.RadioStation),
|
c.Arg.(*mediaprovider.RadioStation),
|
||||||
|
|||||||
@@ -106,6 +106,9 @@ func NewBottomPanel(pm *backend.PlaybackManager, im *backend.ImageManager, contr
|
|||||||
pm.OnLoopModeChange(func(lm backend.LoopMode) {
|
pm.OnLoopModeChange(func(lm backend.LoopMode) {
|
||||||
fyne.Do(func() { bp.AuxControls.SetLoopMode(lm) })
|
fyne.Do(func() { bp.AuxControls.SetLoopMode(lm) })
|
||||||
})
|
})
|
||||||
|
pm.OnShuffleChange(func(lm bool) {
|
||||||
|
fyne.Do(func() { bp.AuxControls.SetShuffle(lm) })
|
||||||
|
})
|
||||||
pm.OnVolumeChange(func(vol int) {
|
pm.OnVolumeChange(func(vol int) {
|
||||||
fyne.Do(func() { bp.AuxControls.VolumeControl.SetVolume(vol) })
|
fyne.Do(func() { bp.AuxControls.VolumeControl.SetVolume(vol) })
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -461,7 +461,7 @@ func (a *NowPlayingPage) Reload() {
|
|||||||
a.relatedList.DisableRating = !a.canRate
|
a.relatedList.DisableRating = !a.canRate
|
||||||
a.relatedList.DisableSharing = !a.canShare
|
a.relatedList.DisableSharing = !a.canShare
|
||||||
|
|
||||||
a.queue = a.pm.GetPlayQueue()
|
a.queue = a.pm.GetActivePlayQueue()
|
||||||
a.queueList.SetItems(a.queue)
|
a.queueList.SetItems(a.queue)
|
||||||
a.totalTime = 0.0
|
a.totalTime = 0.0
|
||||||
for _, tr := range a.queue {
|
for _, tr := range a.queue {
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ func New(app *backend.App, appVersion string, mainWindow fyne.Window) *Controlle
|
|||||||
c.initVisualizations()
|
c.initVisualizations()
|
||||||
c.App.PlaybackManager.OnQueueChange(util.FyneDoFunc(func() {
|
c.App.PlaybackManager.OnQueueChange(util.FyneDoFunc(func() {
|
||||||
if c.popUpQueue != nil {
|
if c.popUpQueue != nil {
|
||||||
c.popUpQueueList.SetItems(c.App.PlaybackManager.GetPlayQueue())
|
c.popUpQueueList.SetItems(c.App.PlaybackManager.GetActivePlayQueue())
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
c.App.PlaybackManager.OnSongChange(func(track mediaprovider.MediaItem, _ *mediaprovider.Track) {
|
c.App.PlaybackManager.OnSongChange(func(track mediaprovider.MediaItem, _ *mediaprovider.Track) {
|
||||||
@@ -192,7 +192,7 @@ func (m *Controller) ShowPopUpPlayQueue() {
|
|||||||
if m.popUpQueue == nil {
|
if m.popUpQueue == nil {
|
||||||
m.popUpQueueList = widgets.NewPlayQueueList(m.App.ImageManager, false)
|
m.popUpQueueList = widgets.NewPlayQueueList(m.App.ImageManager, false)
|
||||||
m.popUpQueueList.Reorderable = true
|
m.popUpQueueList.Reorderable = true
|
||||||
m.popUpQueueList.SetItems(m.App.PlaybackManager.GetPlayQueue())
|
m.popUpQueueList.SetItems(m.App.PlaybackManager.GetActivePlayQueue())
|
||||||
m.ConnectPlayQueuelistActions(m.popUpQueueList)
|
m.ConnectPlayQueuelistActions(m.popUpQueueList)
|
||||||
|
|
||||||
title := widget.NewRichTextWithText(lang.L("Play Queue"))
|
title := widget.NewRichTextWithText(lang.L("Play Queue"))
|
||||||
|
|||||||
+1
-1
@@ -119,7 +119,7 @@ func NewMainWindow(fyneApp fyne.App, appName, displayAppName, appVersion string,
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
app.PlaybackManager.OnQueueChange(func() {
|
app.PlaybackManager.OnQueueChange(func() {
|
||||||
fyne.Do(func() { m.Sidebar.SetQueueTracks(app.PlaybackManager.GetPlayQueue()) })
|
fyne.Do(func() { m.Sidebar.SetQueueTracks(app.PlaybackManager.GetActivePlayQueue()) })
|
||||||
})
|
})
|
||||||
app.ServerManager.OnServerConnected(func(conf *backend.ServerConfig) {
|
app.ServerManager.OnServerConnected(func(conf *backend.ServerConfig) {
|
||||||
go m.RunOnServerConnectedTasks(conf, app, displayAppName)
|
go m.RunOnServerConnectedTasks(conf, app, displayAppName)
|
||||||
|
|||||||
Reference in New Issue
Block a user