implement remove track for shuffle

This commit is contained in:
Siiiiinth
2026-02-15 09:29:17 -08:00
committed by Drew Weymouth
parent 9874ca8c06
commit 17e20e1596
+86 -64
View File
@@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"log" "log"
"math/rand" "math/rand"
"slices"
"strings" "strings"
"time" "time"
@@ -238,11 +239,11 @@ func (p *playbackEngine) clearPlayQueue() {
} }
func (p *playbackEngine) setPlayQueue(items []mediaprovider.MediaItem) { func (p *playbackEngine) setPlayQueue(items []mediaprovider.MediaItem) {
if p.shuffle {
p.shuffledPlayQueue = items
} else {
p.playQueue = items p.playQueue = items
} }
func (p *playbackEngine) setShuffledPlayQueue(items []mediaprovider.MediaItem) {
p.shuffledPlayQueue = items
} }
func (p *playbackEngine) getPlayQueueItemAt(idx int) mediaprovider.MediaItem { func (p *playbackEngine) getPlayQueueItemAt(idx int) mediaprovider.MediaItem {
@@ -305,64 +306,46 @@ func (p *playbackEngine) GetLoopMode() LoopMode {
return p.loopMode return p.loopMode
} }
// TODO_SHUFFLE: rename?
func (p *playbackEngine) GetNewNowPlayingIdx(items []mediaprovider.MediaItem) int {
newNowPlayingIdx := -1
if p.nowPlayingIdx >= 0 {
nowPlayingID := p.getPlayQueueItemAt(p.nowPlayingIdx).Metadata().ID
for i, tr := range items {
if tr.Metadata().ID == nowPlayingID {
newNowPlayingIdx = i
break
}
}
}
return newNowPlayingIdx
}
func (p *playbackEngine) SetShuffle(shuffle bool) { func (p *playbackEngine) SetShuffle(shuffle bool) {
//TODO_SHUFFLE: fix very bad code
if p.shuffle == shuffle { if p.shuffle == shuffle {
return return
} }
newNowPlayingIdx := -1
if shuffle { if shuffle {
fmt.Println("shuffling")
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]
}) })
newNowPlayingIdx := -1 newNowPlayingIdx = p.GetNewNowPlayingIdx(shuffledQueue)
if p.nowPlayingIdx >= 0 {
nowPlayingID := p.getPlayQueueItemAt(p.nowPlayingIdx).Metadata().ID
for i, tr := range shuffledQueue {
if tr.Metadata().ID == nowPlayingID {
newNowPlayingIdx = i
break
}
}
}
p.shuffle = shuffle
p.shuffledPlayQueue = shuffledQueue p.shuffledPlayQueue = shuffledQueue
if p.nowPlayingIdx >= 0 && newNowPlayingIdx == -1 {
return
}
if p.nowPlayingIdx >= 0 {
p.handleNextTrackUpdated()
}
p.nowPlayingIdx = newNowPlayingIdx
p.invokeNoArgCallbacks(p.onQueueChange)
} else { } else {
fmt.Println("deshuffling") newNowPlayingIdx = p.GetNewNowPlayingIdx(p.playQueue)
newQueue := deepCopyMediaItemSlice(p.playQueue)
newNowPlayingIdx := -1
if p.nowPlayingIdx >= 0 {
nowPlayingID := p.getPlayQueueItemAt(p.nowPlayingIdx).Metadata().ID
for i, tr := range newQueue {
if tr.Metadata().ID == nowPlayingID {
newNowPlayingIdx = i
break
}
}
} }
p.shuffle = shuffle p.shuffle = shuffle
p.playQueue = newQueue
if p.nowPlayingIdx >= 0 && newNowPlayingIdx == -1 { if p.nowPlayingIdx >= 0 && newNowPlayingIdx == -1 {
return return
} }
if p.nowPlayingIdx >= 0 {
p.handleNextTrackUpdated() p.handleNextTrackUpdated()
}
p.nowPlayingIdx = newNowPlayingIdx p.nowPlayingIdx = newNowPlayingIdx
p.invokeNoArgCallbacks(p.onQueueChange) p.invokeNoArgCallbacks(p.onQueueChange)
} }
}
func (p *playbackEngine) GetShuffle() bool { func (p *playbackEngine) GetShuffle() bool {
return p.shuffle return p.shuffle
@@ -585,36 +568,29 @@ func (p *playbackEngine) UpdatePlayQueue(items []mediaprovider.MediaItem) error
} }
func (p *playbackEngine) RemoveTracksFromQueue(idxs []int) { func (p *playbackEngine) RemoveTracksFromQueue(idxs []int) {
newQueue := make([]mediaprovider.MediaItem, 0, p.getPlayQueueLength()-len(idxs))
idxSet := sharedutil.ToSet(idxs)
isPlayingTrackRemoved := false isPlayingTrackRemoved := false
isNextPlayingTrackremoved := false isNextPlayingTrackremoved := false
nowPlaying := p.NowPlayingIndex() nowPlaying := p.NowPlayingIndex()
newNowPlaying := nowPlaying newNowPlaying := nowPlaying
for i, tr := range p.getPlayQueue() {
if _, ok := idxSet[i]; ok { if p.shuffle {
if i < nowPlaying { ids := p.GetTrackIdsFromIdx(idxs)
// if removing a track earlier than the currently playing one (if any), newPlayQueue := make([]mediaprovider.MediaItem, 0, p.getPlayQueueLength()-len(idxs))
// decrement new now playing index by one to account for new position in queue p.RemoveTracksFromQueueById(ids, &newPlayQueue)
newNowPlaying-- p.setPlayQueue(newPlayQueue)
} else if i == nowPlaying {
isPlayingTrackRemoved = true newShuffledQueue := make([]mediaprovider.MediaItem, 0, p.getPlayQueueLength()-len(idxs))
// If we are removing the currently playing track, we need to scrobble it p.RemoveTracksFromQueueByIdx(idxs, &newShuffledQueue, &newNowPlaying, &isPlayingTrackRemoved, &isNextPlayingTrackremoved)
p.checkScrobble() p.setShuffledPlayQueue(newShuffledQueue)
p.alreadyScrobbled = true
} else if nowPlaying >= 0 && i == nowPlaying+1 {
isNextPlayingTrackremoved = true
}
} else { } else {
// not removing this track newPlayQueue := make([]mediaprovider.MediaItem, 0, p.getPlayQueueLength()-len(idxs))
newQueue = append(newQueue, tr) p.RemoveTracksFromQueueByIdx(idxs, &newPlayQueue, &newNowPlaying, &isPlayingTrackRemoved, &isNextPlayingTrackremoved)
p.setPlayQueue(newPlayQueue)
} }
}
//TODO_SHUFFLE: Removing a track should remove from both shuffled and unshuffled queue
p.setPlayQueue(newQueue)
p.nowPlayingIdx = newNowPlaying p.nowPlayingIdx = newNowPlaying
if isPlayingTrackRemoved { if isPlayingTrackRemoved {
if newNowPlaying == len(newQueue) { if newNowPlaying == p.getPlayQueueLength() {
// we had been playing the last track, and removed it // we had been playing the last track, and removed it
p.Stop() p.Stop()
} else { } else {
@@ -624,7 +600,7 @@ func (p *playbackEngine) RemoveTracksFromQueue(idxs []int) {
// setNextTrack and onSongChange callbacks will be handled // setNextTrack and onSongChange callbacks will be handled
// when we receive new track event from player // when we receive new track event from player
} else if isNextPlayingTrackremoved { } else if isNextPlayingTrackremoved {
if newNowPlaying < len(newQueue)-1 { if newNowPlaying < p.getPlayQueueLength()-1 {
p.handleNextTrackUpdated() p.handleNextTrackUpdated()
} else { } else {
// no next track to play // no next track to play
@@ -635,6 +611,52 @@ func (p *playbackEngine) RemoveTracksFromQueue(idxs []int) {
p.invokeNoArgCallbacks(p.onQueueChange) p.invokeNoArgCallbacks(p.onQueueChange)
} }
func (p *playbackEngine) RemoveTracksFromQueueByIdx(idxs []int, newQueue *[]mediaprovider.MediaItem, newNowPlaying *int, isPlayingTrackRemoved *bool, isNextPlayingTrackRemoved *bool) {
idxSet := sharedutil.ToSet(idxs)
nowPlaying := p.NowPlayingIndex()
for i, tr := range p.getPlayQueue() {
if _, ok := idxSet[i]; ok {
if i < nowPlaying {
// if removing a track earlier than the currently playing one (if any),
// decrement new now playing index by one to account for new position in queue
*newNowPlaying--
} else if i == nowPlaying {
*isPlayingTrackRemoved = true
// If we are removing the currently playing track, we need to scrobble it
p.checkScrobble()
p.alreadyScrobbled = true
} else if nowPlaying >= 0 && i == nowPlaying+1 {
*isNextPlayingTrackRemoved = true
}
} else {
// not removing this track
*newQueue = append(*newQueue, tr)
}
}
}
func (p *playbackEngine) RemoveTracksFromQueueById(ids []string, newQueue *[]mediaprovider.MediaItem) {
for _, tr := range p.playQueue { //TODO_SHUFFLE: Rework this to use a func for getPlayQueue
if slices.Contains(ids, tr.Metadata().ID) {
//remove id from id list, handles having the same track present multiple times in playQueue
idx := slices.Index(ids, tr.Metadata().ID)
ids = slices.Delete(ids, idx, idx+1)
} else {
// not removing this track
*newQueue = append(*newQueue, tr)
}
}
}
func (p *playbackEngine) GetTrackIdsFromIdx(idx []int) []string {
ids := make([]string, 0, len(idx))
for _, v := range idx {
ids = append(ids, p.getPlayQueueItemAt(v).Metadata().ID)
}
return ids
}
func (p *playbackEngine) SetReplayGainOptions(config ReplayGainConfig) { func (p *playbackEngine) SetReplayGainOptions(config ReplayGainConfig) {
rGainPlayer, ok := p.player.(player.ReplayGainPlayer) rGainPlayer, ok := p.player.(player.ReplayGainPlayer)
if !ok { if !ok {