release / web (push) Successful in 1m44s
release / go (push) Successful in 2m12s
release / govulncheck (push) Successful in 40s
release / android (push) Successful in 5m28s
release / Build signed APK (releases and dev) (push) Successful in 4m42s
release / integration (push) Successful in 15m33s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 1m21s
release / Verify release artifacts (tag releases only) (push) Skipped
ReplayGain 2.0 values (gain to -18 LUFS, linear peak) derived from the stored track and album loudness: - Web: GET /api/tracks/replay-gain?ids=... (up to 200), a lookup the player calls for its queue, rather than a field on every TrackRef surface. - Android: track_gain/track_peak and album_gain/album_peak on the sync views, so cached tracks level offline. Storing a measurement logs a track change, and an album's values moving logs an album change, both before the write (#2704), so caches pick the gains up. - OpenSubsonic: replayGain on every song (album, getSong, search3, starred), as a JSON object and an XML element. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
59 lines
1.8 KiB
Go
59 lines
1.8 KiB
Go
package subsonic
|
|
|
|
import (
|
|
"encoding/json"
|
|
"encoding/xml"
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.fabledsword.com/bvandeusen/minstrel/internal/db/dbq"
|
|
"git.fabledsword.com/bvandeusen/minstrel/internal/library"
|
|
)
|
|
|
|
// OpenSubsonic's replayGain is an object in JSON and an element with
|
|
// attributes in XML. Clients parse both, so both are pinned (#4997).
|
|
func TestSongRef_ReplayGainEncodesForBothFormats(t *testing.T) {
|
|
gain, peak := float32(-4.5), float32(0.8913)
|
|
tr := dbq.Track{Title: "Song", FilePath: "/m/a.flac", FileFormat: "flac"}
|
|
s := songRef(tr, "Album", "Artist", library.ReplayGain{TrackGain: &gain, TrackPeak: &peak})
|
|
|
|
b, err := json.Marshal(s)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var m map[string]any
|
|
if err := json.Unmarshal(b, &m); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
rg, ok := m["replayGain"].(map[string]any)
|
|
if !ok {
|
|
t.Fatalf("JSON has no replayGain object: %s", b)
|
|
}
|
|
if rg["trackGain"] != -4.5 || rg["trackPeak"] == nil {
|
|
t.Errorf("JSON replayGain = %v, want trackGain -4.5 and a trackPeak", rg)
|
|
}
|
|
if _, ok := rg["albumGain"]; ok {
|
|
t.Errorf("JSON replayGain carries albumGain with no album value: %v", rg)
|
|
}
|
|
|
|
x, err := xml.Marshal(s)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !strings.Contains(string(x), `<replayGain trackGain="-4.5" trackPeak="0.8913"></replayGain>`) {
|
|
t.Errorf("XML lacks the replayGain element: %s", x)
|
|
}
|
|
}
|
|
|
|
func TestSongRef_NoReplayGainWhenUnmeasured(t *testing.T) {
|
|
s := songRef(dbq.Track{Title: "Song", FilePath: "/m/a.mp3"}, "Album", "Artist", library.ReplayGain{})
|
|
if s.ReplayGain != nil {
|
|
t.Fatalf("unmeasured song carries replayGain %+v", s.ReplayGain)
|
|
}
|
|
b, _ := json.Marshal(s)
|
|
x, _ := xml.Marshal(s)
|
|
if strings.Contains(string(b), "replayGain") || strings.Contains(string(x), "replayGain") {
|
|
t.Errorf("unmeasured song encodes replayGain: %s / %s", b, x)
|
|
}
|
|
}
|