From 2c06a4234ecccfd4cecc5c99aaada9941e9da13f Mon Sep 17 00:00:00 2001 From: Deluan Date: Wed, 1 May 2024 13:57:11 -0400 Subject: [PATCH] Fix int types in OpenSubsonic responses. Refer to https://support.symfonium.app/t/symfonium-sync-crashes-when-tpos-is-not-an-int/4204 --- server/subsonic/helpers.go | 10 +++++----- server/subsonic/responses/responses.go | 8 ++++---- utils/number/number.go | 8 ++++++++ utils/number/number_test.go | 27 +++++++++++++++++++++----- 4 files changed, 39 insertions(+), 14 deletions(-) diff --git a/server/subsonic/helpers.go b/server/subsonic/helpers.go index 189c07d4..54baecb9 100644 --- a/server/subsonic/helpers.go +++ b/server/subsonic/helpers.go @@ -7,7 +7,6 @@ import ( "mime" "net/http" "sort" - "strconv" "strings" "github.com/navidrome/navidrome/consts" @@ -15,6 +14,7 @@ import ( "github.com/navidrome/navidrome/model/request" "github.com/navidrome/navidrome/server/public" "github.com/navidrome/navidrome/server/subsonic/responses" + "github.com/navidrome/navidrome/utils/number" ) func newResponse() *responses.Subsonic { @@ -254,12 +254,12 @@ func toItemDate(date string) responses.ItemDate { } parts := strings.Split(date, "-") if len(parts) > 2 { - itemDate.Day, _ = strconv.Atoi(parts[2]) + itemDate.Day = number.ParseInt[int32](parts[2]) } if len(parts) > 1 { - itemDate.Month, _ = strconv.Atoi(parts[1]) + itemDate.Month = number.ParseInt[int32](parts[1]) } - itemDate.Year, _ = strconv.Atoi(parts[0]) + itemDate.Year = number.ParseInt[int32](parts[0]) return itemDate } @@ -278,7 +278,7 @@ func buildDiscSubtitles(_ context.Context, a model.Album) responses.DiscTitles { } discTitles := responses.DiscTitles{} for num, title := range a.Discs { - discTitles = append(discTitles, responses.DiscTitle{Disc: num, Title: title}) + discTitles = append(discTitles, responses.DiscTitle{Disc: int32(num), Title: title}) } sort.Slice(discTitles, func(i, j int) bool { return discTitles[i].Disc < discTitles[j].Disc diff --git a/server/subsonic/responses/responses.go b/server/subsonic/responses/responses.go index 9e5587fb..a5ebc5a3 100644 --- a/server/subsonic/responses/responses.go +++ b/server/subsonic/responses/responses.go @@ -502,7 +502,7 @@ type ReplayGain struct { } type DiscTitle struct { - Disc int `xml:"disc,attr" json:"disc"` + Disc int32 `xml:"disc,attr" json:"disc"` Title string `xml:"title,attr" json:"title"` } @@ -523,7 +523,7 @@ func marshalJSONArray[T any](v []T) ([]byte, error) { } type ItemDate struct { - Year int `xml:"year,attr,omitempty" json:"year,omitempty"` - Month int `xml:"month,attr,omitempty" json:"month,omitempty"` - Day int `xml:"day,attr,omitempty" json:"day,omitempty"` + Year int32 `xml:"year,attr,omitempty" json:"year,omitempty"` + Month int32 `xml:"month,attr,omitempty" json:"month,omitempty"` + Day int32 `xml:"day,attr,omitempty" json:"day,omitempty"` } diff --git a/utils/number/number.go b/utils/number/number.go index 0d10dfb0..dc0bc19c 100644 --- a/utils/number/number.go +++ b/utils/number/number.go @@ -3,9 +3,17 @@ package number import ( "crypto/rand" "math/big" + "strconv" + + "golang.org/x/exp/constraints" ) func RandomInt64(max int64) int64 { rnd, _ := rand.Int(rand.Reader, big.NewInt(max)) return rnd.Int64() } + +func ParseInt[T constraints.Integer](s string) T { + r, _ := strconv.ParseInt(s, 10, 64) + return T(r) +} diff --git a/utils/number/number_test.go b/utils/number/number_test.go index ad597b7a..5f94b4e9 100644 --- a/utils/number/number_test.go +++ b/utils/number/number_test.go @@ -13,10 +13,27 @@ func TestNumber(t *testing.T) { RunSpecs(t, "Number Suite") } -var _ = Describe("RandomInt64", func() { - It("should return a random int64", func() { - for i := 0; i < 10000; i++ { - Expect(number.RandomInt64(100)).To(BeNumerically("<", 100)) - } +var _ = Describe("number package", func() { + Describe("RandomInt64", func() { + It("should return a random int64", func() { + for i := 0; i < 10000; i++ { + Expect(number.RandomInt64(100)).To(BeNumerically("<", 100)) + } + }) + }) + + Describe("ParseInt", func() { + It("should parse a string into an int", func() { + Expect(number.ParseInt[int64]("123")).To(Equal(int64(123))) + }) + It("should parse a string into an int32", func() { + Expect(number.ParseInt[int32]("123")).To(Equal(int32(123))) + }) + It("should parse a string into an int64", func() { + Expect(number.ParseInt[int]("123")).To(Equal(123)) + }) + It("should parse a string into an uint", func() { + Expect(number.ParseInt[uint]("123")).To(Equal(uint(123))) + }) }) })