mirror of
https://github.com/navidrome/navidrome.git
synced 2026-08-31 07:30:32 +00:00
* build: upgrade to Go 1.27 Bumps the toolchain in go.mod, both golang base images in the Dockerfile, and the devcontainer VARIANT. CI needs no change, as the workflows resolve the version through go-version-file: go.mod. Tests, race tests, build and vet all pass on go1.27.0. * build: upgrade golangci-lint to v2.13.0 v2.13.0 is the first release built with Go 1.27, so it can lint a module whose go directive is 1.27. It also enables gosec's G404 on math/rand/v2, which flags the three rand.Shuffle call sites. Shuffle order is not a security decision, and the crypto-backed alternative in utils/random costs 25x and allocates per swap, so the call sites are annotated rather than the rule excluded, keeping G404 active for the cases where it would matter. * chore(deps): update Go dependencies to latest versions Signed-off-by: Deluan <deluan@navidrome.org> * build: bump golangci-lint to v2.13.2 --------- Signed-off-by: Deluan <deluan@navidrome.org>
139 lines
3.0 KiB
Go
139 lines
3.0 KiB
Go
package playback
|
|
|
|
import (
|
|
"fmt"
|
|
"math/rand"
|
|
"strings"
|
|
|
|
"github.com/navidrome/navidrome/log"
|
|
"github.com/navidrome/navidrome/model"
|
|
)
|
|
|
|
type Queue struct {
|
|
Index int
|
|
Items model.MediaFiles
|
|
}
|
|
|
|
func NewQueue() *Queue {
|
|
return &Queue{
|
|
Index: -1,
|
|
Items: model.MediaFiles{},
|
|
}
|
|
}
|
|
|
|
func (pd *Queue) String() string {
|
|
var filenames strings.Builder
|
|
for idx, item := range pd.Items {
|
|
filenames.WriteString(fmt.Sprint(idx) + ":" + item.Path + " ")
|
|
}
|
|
return fmt.Sprintf("#Items: %d, idx: %d, files: %s", len(pd.Items), pd.Index, filenames.String())
|
|
}
|
|
|
|
// returns the current mediafile or nil
|
|
func (pd *Queue) Current() *model.MediaFile {
|
|
if pd.Index == -1 {
|
|
return nil
|
|
}
|
|
if pd.Index >= len(pd.Items) {
|
|
log.Error("internal error: current song index out of bounds", "idx", pd.Index, "length", len(pd.Items))
|
|
return nil
|
|
}
|
|
|
|
return &pd.Items[pd.Index]
|
|
}
|
|
|
|
// returns the whole queue
|
|
func (pd *Queue) Get() model.MediaFiles {
|
|
return pd.Items
|
|
}
|
|
|
|
func (pd *Queue) Size() int {
|
|
return len(pd.Items)
|
|
}
|
|
|
|
func (pd *Queue) IsEmpty() bool {
|
|
return len(pd.Items) < 1
|
|
}
|
|
|
|
// set is similar to a clear followed by a add, but will not change the currently playing track.
|
|
func (pd *Queue) Set(items model.MediaFiles) {
|
|
pd.Clear()
|
|
pd.Items = append(pd.Items, items...)
|
|
}
|
|
|
|
// adding mediafiles to the queue
|
|
func (pd *Queue) Add(items model.MediaFiles) {
|
|
pd.Items = append(pd.Items, items...)
|
|
if pd.Index == -1 && len(pd.Items) > 0 {
|
|
pd.Index = 0
|
|
}
|
|
}
|
|
|
|
// empties whole queue
|
|
func (pd *Queue) Clear() {
|
|
pd.Index = -1
|
|
pd.Items = nil
|
|
}
|
|
|
|
// idx Zero-based index of the song to skip to or remove.
|
|
func (pd *Queue) Remove(idx int) {
|
|
current := pd.Current()
|
|
backupID := ""
|
|
if current != nil {
|
|
backupID = current.ID
|
|
}
|
|
|
|
pd.Items = append(pd.Items[:idx], pd.Items[idx+1:]...)
|
|
|
|
var err error
|
|
pd.Index, err = pd.getMediaFileIndexByID(backupID)
|
|
if err != nil {
|
|
// we seem to have deleted the current id, setting to default:
|
|
pd.Index = -1
|
|
}
|
|
}
|
|
|
|
func (pd *Queue) Shuffle() {
|
|
current := pd.Current()
|
|
backupID := ""
|
|
if current != nil {
|
|
backupID = current.ID
|
|
}
|
|
|
|
//nolint:gosec // shuffle order is not a security decision
|
|
rand.Shuffle(len(pd.Items), func(i, j int) { pd.Items[i], pd.Items[j] = pd.Items[j], pd.Items[i] })
|
|
|
|
var err error
|
|
pd.Index, err = pd.getMediaFileIndexByID(backupID)
|
|
if err != nil {
|
|
log.Error("Could not find ID while shuffling: %s", backupID)
|
|
}
|
|
}
|
|
|
|
func (pd *Queue) getMediaFileIndexByID(id string) (int, error) {
|
|
for idx, item := range pd.Items {
|
|
if item.ID == id {
|
|
return idx, nil
|
|
}
|
|
}
|
|
return -1, fmt.Errorf("ID not found in playlist: %s", id)
|
|
}
|
|
|
|
// Sets the index to a new, valid value inside the Items. Values lower than zero are going to be zero,
|
|
// values above will be limited by number of items.
|
|
func (pd *Queue) SetIndex(idx int) {
|
|
pd.Index = max(0, min(idx, len(pd.Items)-1))
|
|
}
|
|
|
|
// Are we at the last track?
|
|
func (pd *Queue) IsAtLastElement() bool {
|
|
return (pd.Index + 1) >= len(pd.Items)
|
|
}
|
|
|
|
// Goto next index
|
|
func (pd *Queue) IncreaseIndex() {
|
|
if !pd.IsAtLastElement() {
|
|
pd.SetIndex(pd.Index + 1)
|
|
}
|
|
}
|