sync: keep every replayGain element's fields

A second <replayGain> element for the same song cleared whatever the
first one set, because each field was assigned unconditionally and an
absent attribute parses to null. No server is known to split the object
across elements, but the merge costs nothing and the alternative loses
fields silently.

Also covers peaks arriving without gains, which the existing cases did
not.
This commit is contained in:
austinried
2026-10-16 13:06:20 +00:00
parent 069a0f7f19
commit 81e6189ebe
2 changed files with 45 additions and 4 deletions
@@ -210,10 +210,10 @@ internal class SongDraft(
}
fun addReplayGain(attrs: Attributes) {
trackGain = attrs.floatAttr("trackGain")
albumGain = attrs.floatAttr("albumGain")
trackPeak = attrs.floatAttr("trackPeak")
albumPeak = attrs.floatAttr("albumPeak")
attrs.floatAttr("trackGain")?.let { trackGain = it }
attrs.floatAttr("albumGain")?.let { albumGain = it }
attrs.floatAttr("trackPeak")?.let { trackPeak = it }
attrs.floatAttr("albumPeak")?.let { albumPeak = it }
}
fun toSong(): Song =
@@ -231,6 +231,47 @@ class SubsonicXmlTest {
assertEquals(null, songs[1].albumPeak)
}
@Test
fun mapsReplayGainPeaksWithoutGains() {
val songs =
songs(
"""
<subsonic-response status="ok">
<searchResult3>
<song id="s1" title="Peaks only">
<replayGain trackPeak="0.98" albumPeak="0.99"/>
</song>
</searchResult3>
</subsonic-response>
""".trimIndent(),
)
assertEquals(null, songs.single().trackGain)
assertEquals(null, songs.single().albumGain)
assertEquals(0.98f, songs.single().trackPeak)
assertEquals(0.99f, songs.single().albumPeak)
}
@Test
fun keepsTheFieldsOfEveryReplayGainElement() {
val songs =
songs(
"""
<subsonic-response status="ok">
<searchResult3>
<song id="s1" title="Split">
<replayGain trackGain="-3.2"/>
<replayGain trackPeak="0.98"/>
</song>
</searchResult3>
</subsonic-response>
""".trimIndent(),
)
assertEquals(-3.2f, songs.single().trackGain)
assertEquals(0.98f, songs.single().trackPeak)
}
@Test
fun ignoresNonFiniteReplayGainValues() {
val songs =