diff --git a/core/external_metadata.go b/core/external_metadata.go index 2ea8d0237..371b564ff 100644 --- a/core/external_metadata.go +++ b/core/external_metadata.go @@ -17,6 +17,7 @@ import ( "github.com/navidrome/navidrome/log" "github.com/navidrome/navidrome/model" "github.com/navidrome/navidrome/utils" + "github.com/navidrome/navidrome/utils/math2" ) const ( @@ -172,7 +173,7 @@ func (e *externalMetadata) SimilarSongs(ctx context.Context, id string, count in return ctx.Err() } - topCount := utils.MaxInt(count, 20) + topCount := math2.Max(count, 20) topSongs, err := e.getMatchingTopSongs(ctx, e.ag, &auxArtist{Name: a.Name, Artist: a}, topCount) if err != nil { log.Warn(ctx, "Error getting artist's top songs", "artist", a.Name, err) diff --git a/model/playlist.go b/model/playlist.go index 8e1f5c16b..1b21700d1 100644 --- a/model/playlist.go +++ b/model/playlist.go @@ -8,7 +8,7 @@ import ( "time" "github.com/navidrome/navidrome/model/criteria" - "github.com/navidrome/navidrome/utils" + "golang.org/x/exp/slices" ) type Playlist struct { @@ -46,7 +46,7 @@ func (pls Playlist) MediaFiles() MediaFiles { func (pls *Playlist) RemoveTracks(idxToRemove []int) { var newTracks PlaylistTracks for i, t := range pls.Tracks { - if utils.IntInSlice(i, idxToRemove) { + if slices.Index(idxToRemove, i) >= 0 { continue } newTracks = append(newTracks, t) diff --git a/server/subsonic/album_lists.go b/server/subsonic/album_lists.go index 3b3ef4553..07bdc25ef 100644 --- a/server/subsonic/album_lists.go +++ b/server/subsonic/album_lists.go @@ -11,6 +11,7 @@ import ( "github.com/navidrome/navidrome/server/subsonic/filter" "github.com/navidrome/navidrome/server/subsonic/responses" "github.com/navidrome/navidrome/utils" + "github.com/navidrome/navidrome/utils/math2" ) func (api *Router) getAlbumList(r *http.Request) (model.Albums, int64, error) { @@ -59,7 +60,7 @@ func (api *Router) getAlbumList(r *http.Request) (model.Albums, int64, error) { } opts.Offset = utils.ParamInt(r, "offset", 0) - opts.Max = utils.MinInt(utils.ParamInt(r, "size", 10), 500) + opts.Max = math2.Min(utils.ParamInt(r, "size", 10), 500) albums, err := api.ds.Album(r.Context()).GetAllWithoutGenres(opts) if err != nil { @@ -167,7 +168,7 @@ func (api *Router) GetNowPlaying(r *http.Request) (*responses.Subsonic, error) { } func (api *Router) GetRandomSongs(r *http.Request) (*responses.Subsonic, error) { - size := utils.MinInt(utils.ParamInt(r, "size", 10), 500) + size := math2.Min(utils.ParamInt(r, "size", 10), 500) genre := utils.ParamString(r, "genre") fromYear := utils.ParamInt(r, "fromYear", 0) toYear := utils.ParamInt(r, "toYear", 0) @@ -185,8 +186,8 @@ func (api *Router) GetRandomSongs(r *http.Request) (*responses.Subsonic, error) } func (api *Router) GetSongsByGenre(r *http.Request) (*responses.Subsonic, error) { - count := utils.MinInt(utils.ParamInt(r, "count", 10), 500) - offset := utils.MinInt(utils.ParamInt(r, "offset", 0), 500) + count := math2.Min(utils.ParamInt(r, "count", 10), 500) + offset := math2.Min(utils.ParamInt(r, "offset", 0), 500) genre := utils.ParamString(r, "genre") songs, err := api.getSongs(r.Context(), offset, count, filter.SongsByGenre(genre)) diff --git a/server/subsonic/api.go b/server/subsonic/api.go index 9e0735881..e2dc22e9b 100644 --- a/server/subsonic/api.go +++ b/server/subsonic/api.go @@ -19,6 +19,7 @@ import ( "github.com/navidrome/navidrome/server/events" "github.com/navidrome/navidrome/server/subsonic/responses" "github.com/navidrome/navidrome/utils" + "github.com/navidrome/navidrome/utils/math2" ) const Version = "1.16.1" @@ -137,7 +138,7 @@ func (api *Router) routes() http.Handler { }) r.Group(func(r chi.Router) { // configure request throttling - maxRequests := utils.MaxInt(2, runtime.NumCPU()) + maxRequests := math2.Max(2, runtime.NumCPU()) r.Use(middleware.ThrottleBacklog(maxRequests, consts.RequestThrottleBacklogLimit, consts.RequestThrottleBacklogTimeout)) hr(r, "getAvatar", api.GetAvatar) hr(r, "getCoverArt", api.GetCoverArt) diff --git a/utils/gravatar/gravatar.go b/utils/gravatar/gravatar.go index efbc57048..b06f79efb 100644 --- a/utils/gravatar/gravatar.go +++ b/utils/gravatar/gravatar.go @@ -5,7 +5,7 @@ import ( "fmt" "strings" - "github.com/navidrome/navidrome/utils" + "github.com/navidrome/navidrome/utils/math2" ) const baseUrl = "https://www.gravatar.com/avatar" @@ -19,7 +19,7 @@ func Url(email string, size int) string { if size < 1 { size = defaultSize } - size = utils.MinInt(maxSize, size) + size = math2.Min(maxSize, size) return fmt.Sprintf("%s/%x?s=%d", baseUrl, hash, size) } diff --git a/utils/ints.go b/utils/ints.go deleted file mode 100644 index 4922e8d30..000000000 --- a/utils/ints.go +++ /dev/null @@ -1,24 +0,0 @@ -package utils - -func MinInt(x, y int) int { - if x < y { - return x - } - return y -} - -func MaxInt(x, y int) int { - if x > y { - return x - } - return y -} - -func IntInSlice(a int, list []int) bool { - for _, b := range list { - if b == a { - return true - } - } - return false -} diff --git a/utils/ints_test.go b/utils/ints_test.go deleted file mode 100644 index 7f1ebe13f..000000000 --- a/utils/ints_test.go +++ /dev/null @@ -1,40 +0,0 @@ -package utils - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -var _ = Describe("Int utils", func() { - Describe("MinInt", func() { - It("returns the first value if it is the smallest", func() { - Expect(MinInt(1, 2)).To(Equal(1)) - }) - It("returns the second value if it is the smallest", func() { - Expect(MinInt(-4, -6)).To(Equal(-6)) - }) - }) - - Describe("MaxInt", func() { - It("returns the first value if it is the biggest", func() { - Expect(MaxInt(1, 2)).To(Equal(2)) - }) - It("returns the second value if it is the smallest", func() { - Expect(MaxInt(-4, -6)).To(Equal(-4)) - }) - }) - - Describe("IntInSlice", func() { - It("returns false if slice is empty", func() { - Expect(IntInSlice(1, nil)).To(BeFalse()) - }) - - It("returns false if number is not in slice", func() { - Expect(IntInSlice(1, []int{3, 4, 5})).To(BeFalse()) - }) - - It("returns true if number is in slice", func() { - Expect(IntInSlice(4, []int{3, 4, 5})).To(BeTrue()) - }) - }) -}) diff --git a/utils/math2/math2.go b/utils/math2/math2.go new file mode 100644 index 000000000..57f212347 --- /dev/null +++ b/utils/math2/math2.go @@ -0,0 +1,31 @@ +package math2 + +import "golang.org/x/exp/constraints" + +func Min[T constraints.Ordered](vs ...T) T { + if len(vs) == 0 { + var zero T + return zero + } + min := vs[0] + for _, v := range vs[1:] { + if v < min { + min = v + } + } + return min +} + +func Max[T constraints.Ordered](vs ...T) T { + if len(vs) == 0 { + var zero T + return zero + } + max := vs[0] + for _, v := range vs[1:] { + if v > max { + max = v + } + } + return max +} diff --git a/utils/math2/math2_test.go b/utils/math2/math2_test.go new file mode 100644 index 000000000..ecf18675d --- /dev/null +++ b/utils/math2/math2_test.go @@ -0,0 +1,38 @@ +package math2_test + +import ( + "testing" + + "github.com/navidrome/navidrome/utils/math2" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestMath2(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Math2 Suite") +} + +var _ = Describe("Min", func() { + It("returns zero value if no arguments are passed", func() { + Expect(math2.Min[int]()).To(BeZero()) + }) + It("returns the smallest int", func() { + Expect(math2.Min(1, 2)).To(Equal(1)) + }) + It("returns the smallest float", func() { + Expect(math2.Min(-4.1, -4.2, -4.0)).To(Equal(-4.2)) + }) +}) + +var _ = Describe("Max", func() { + It("returns zero value if no arguments are passed", func() { + Expect(math2.Max[int]()).To(BeZero()) + }) + It("returns the biggest int", func() { + Expect(math2.Max(1, 2)).To(Equal(2)) + }) + It("returns the biggest float", func() { + Expect(math2.Max(-4.1, -4.2, -4.0)).To(Equal(-4.0)) + }) +})