mirror of
https://github.com/navidrome/navidrome.git
synced 2026-08-31 07:30:32 +00:00
refactor(model): keep the blurhash off native JSON and fold its specs
Nothing on the native API consumes blurHash: the web UI reads thumbHash, and Jellyfin's mappers take the Go field directly rather than through this serialization. It was shipping ~40 unused bytes on every row of every list response, on a surface that accretes clients once published. The JSON specs were five marshal-and-check-keys blocks over the same struct; they collapse to one populated case, one bare case, and a guard that the blurhash stays off the wire.
This commit is contained in:
parent
df301ae1a8
commit
8f82a8deaa
@ -20,9 +20,10 @@ const ImageTypePrimary = "primary"
|
||||
type ItemImage struct {
|
||||
ImageHash string `structs:"-" json:"imageHash,omitempty"`
|
||||
ImageAbsent bool `structs:"-" json:"imageAbsent,omitempty"`
|
||||
BlurHash string `structs:"-" json:"blurHash,omitempty"`
|
||||
ThumbHash string `structs:"-" json:"thumbHash,omitempty"`
|
||||
// A blurhash carries no aspect ratio, so clients need these to shape the placeholder.
|
||||
// BlurHash is Jellyfin's; its mappers read this field directly, so it stays off native JSON.
|
||||
BlurHash string `structs:"-" json:"-"`
|
||||
ThumbHash string `structs:"-" json:"thumbHash,omitempty"`
|
||||
// A thumbhash's own aspect is quantised, so clients need these to shape the placeholder exactly.
|
||||
ImageWidth int `structs:"-" json:"imageWidth,omitempty"`
|
||||
ImageHeight int `structs:"-" json:"imageHeight,omitempty"`
|
||||
}
|
||||
|
||||
@ -8,64 +8,49 @@ import (
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func jsonOf(v any) map[string]any {
|
||||
GinkgoHelper()
|
||||
data, err := json.Marshal(v)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
var out map[string]any
|
||||
Expect(json.Unmarshal(data, &out)).To(Succeed())
|
||||
return out
|
||||
}
|
||||
|
||||
var _ = Describe("ItemImage JSON", func() {
|
||||
It("exposes artwork state on an album", func() {
|
||||
It("exposes the artwork state a client needs to render a placeholder", func() {
|
||||
al := model.Album{ID: "al-1", Name: "Album"}
|
||||
al.ImageHash = "0123456789abcdef"
|
||||
al.BlurHash = "LEHV6nWB2yk8"
|
||||
|
||||
var out map[string]any
|
||||
data, err := json.Marshal(al)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(json.Unmarshal(data, &out)).To(Succeed())
|
||||
|
||||
Expect(out).To(HaveKeyWithValue("imageHash", "0123456789abcdef"))
|
||||
Expect(out).To(HaveKeyWithValue("blurHash", "LEHV6nWB2yk8"))
|
||||
})
|
||||
|
||||
It("exposes the thumbhash, and omits it when the entity has none", func() {
|
||||
al := model.Album{ID: "al-4", Name: "Album"}
|
||||
al.ThumbHash = "1QcSHQRn"
|
||||
|
||||
var out map[string]any
|
||||
data, err := json.Marshal(al)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(json.Unmarshal(data, &out)).To(Succeed())
|
||||
Expect(out).To(HaveKeyWithValue("thumbHash", "1QcSHQRn"))
|
||||
|
||||
var bare map[string]any
|
||||
data, err = json.Marshal(model.Album{ID: "al-5", Name: "Album"})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(json.Unmarshal(data, &bare)).To(Succeed())
|
||||
Expect(bare).ToNot(HaveKey("thumbHash"))
|
||||
})
|
||||
|
||||
// Without the dimensions, clients cannot know the placeholder's shape and default to a square.
|
||||
It("exposes the image dimensions alongside the blurhash", func() {
|
||||
al := model.Album{ID: "al-3", Name: "Album"}
|
||||
al.BlurHash = "LEHV6nWB2yk8"
|
||||
al.ImageWidth, al.ImageHeight = 1200, 800
|
||||
|
||||
var out map[string]any
|
||||
data, err := json.Marshal(al)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(json.Unmarshal(data, &out)).To(Succeed())
|
||||
|
||||
Expect(out).To(HaveKeyWithValue("imageWidth", BeNumerically("==", 1200)))
|
||||
Expect(out).To(HaveKeyWithValue("imageHeight", BeNumerically("==", 800)))
|
||||
Expect(jsonOf(al)).To(SatisfyAll(
|
||||
HaveKeyWithValue("imageHash", "0123456789abcdef"),
|
||||
HaveKeyWithValue("thumbHash", "1QcSHQRn"),
|
||||
HaveKeyWithValue("imageWidth", BeNumerically("==", 1200)),
|
||||
HaveKeyWithValue("imageHeight", BeNumerically("==", 800)),
|
||||
))
|
||||
})
|
||||
|
||||
It("omits artwork state when the entity has none", func() {
|
||||
var out map[string]any
|
||||
data, err := json.Marshal(model.Album{ID: "al-2", Name: "Album"})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(json.Unmarshal(data, &out)).To(Succeed())
|
||||
It("keeps the blurhash off the native API, where nothing consumes it", func() {
|
||||
al := model.Album{ID: "al-1", Name: "Album"}
|
||||
al.BlurHash = "LEHV6nWB2yk8"
|
||||
Expect(jsonOf(al)).ToNot(HaveKey("blurHash"))
|
||||
})
|
||||
|
||||
Expect(out).ToNot(HaveKey("imageHash"))
|
||||
Expect(out).ToNot(HaveKey("blurHash"))
|
||||
Expect(out).ToNot(HaveKey("imageAbsent"))
|
||||
Expect(out).ToNot(HaveKey("imageWidth"))
|
||||
Expect(out).ToNot(HaveKey("imageHeight"))
|
||||
It("omits every artwork field when the entity has none", func() {
|
||||
out := jsonOf(model.Album{ID: "al-2", Name: "Album"})
|
||||
for _, key := range []string{
|
||||
"imageHash", "blurHash", "thumbHash", "imageAbsent", "imageWidth", "imageHeight",
|
||||
} {
|
||||
Expect(out).ToNot(HaveKey(key))
|
||||
}
|
||||
})
|
||||
|
||||
It("exposes known-absent artwork so clients can skip the request", func() {
|
||||
ar := model.Artist{ID: "ar-1", Name: "Artist"}
|
||||
ar.ImageAbsent = true
|
||||
Expect(jsonOf(ar)).To(HaveKeyWithValue("imageAbsent", true))
|
||||
})
|
||||
|
||||
Describe("AspectRatio", func() {
|
||||
@ -85,16 +70,4 @@ var _ = Describe("ItemImage JSON", func() {
|
||||
Expect(img.AspectRatio()).To(BeNil())
|
||||
})
|
||||
})
|
||||
|
||||
It("exposes known-absent artwork so clients can skip the request", func() {
|
||||
ar := model.Artist{ID: "ar-1", Name: "Artist"}
|
||||
ar.ImageAbsent = true
|
||||
|
||||
var out map[string]any
|
||||
data, err := json.Marshal(ar)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(json.Unmarshal(data, &out)).To(Succeed())
|
||||
|
||||
Expect(out).To(HaveKeyWithValue("imageAbsent", true))
|
||||
})
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user