mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-10 23:21:59 +01:00
scrobble: only dedupe when the track was already announced
The now-playing suppression keyed off the item id alone, so a track loaded while paused (which sets the tracked id without announcing) never sent its first now-playing when playback then started from the beginning. Gate the suppression on nowPlayingSent as well, and cover that case plus the transition at the combine boundary.
This commit is contained in:
@@ -59,7 +59,7 @@ class ScrobblePolicy(
|
||||
item?.id != songId ||
|
||||
(item != null && item.id == lastItemId && positionMs < previousPosition && positionMs <= RESTART_POSITION_MS)
|
||||
if (restarted) {
|
||||
val sameSong = item != null && item.id == songId
|
||||
val alreadyAnnounced = nowPlayingSent && item?.id == songId
|
||||
songId = item?.id
|
||||
lastItemId = null
|
||||
playedMs = 0
|
||||
@@ -69,7 +69,7 @@ class ScrobblePolicy(
|
||||
if (item == null || !isPlaying) return null
|
||||
nowPlayingSent = true
|
||||
startedAt = now()
|
||||
return if (sameSong) null else Scrobble.NowPlaying(item.id)
|
||||
return if (alreadyAnnounced) null else Scrobble.NowPlaying(item.id)
|
||||
}
|
||||
lastPositionMs = positionMs
|
||||
lastItemId = item?.id
|
||||
|
||||
@@ -170,6 +170,14 @@ class ScrobblePolicyTest {
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun announcesWhenATrackLoadedWhilePausedStartsFromTheBeginning() {
|
||||
val item = track(id = "s1")
|
||||
assertNull(policy.advance(item, 200_000, isPlaying = false, positionMs = 0))
|
||||
assertNull(policy.advance(item, 200_000, isPlaying = false, positionMs = 2_500))
|
||||
assertEquals(Scrobble.NowPlaying("s1"), policy.advance(item, 200_000, isPlaying = true, positionMs = 0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aTransitionDoesNotReannounceTheNewTrackOnAStaleLowPosition() {
|
||||
val first = track(id = "s1")
|
||||
|
||||
@@ -190,4 +190,34 @@ class ScrobblerTest {
|
||||
enabled.value = true
|
||||
assertEquals(listOf(Call.NowPlaying("s1")), sink.calls)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aTransitionSendsNowPlayingOnceForTheNewTrack() =
|
||||
runTest {
|
||||
val sink = RecordingSink()
|
||||
val scrobbler = Scrobbler(sink = sink, enabled = flowOf(true), scope = testScope(), policy = ScrobblePolicy(now = { 1_000L }))
|
||||
val state = MutableStateFlow(PlaybackState())
|
||||
val position = MutableStateFlow(0L)
|
||||
scrobbler.attach(state, position)
|
||||
val first = QueueItem("s1", "One", "Artist", "Album", null, durationMs = 30_000)
|
||||
val second = QueueItem("s2", "Two", "Artist", "Album", null, durationMs = 30_000)
|
||||
|
||||
state.value = PlaybackState(item = first, isPlaying = true)
|
||||
var tick = 500L
|
||||
while (tick <= 15_000L) {
|
||||
position.value = tick
|
||||
tick += 500
|
||||
}
|
||||
position.value = 0L
|
||||
state.value = PlaybackState(item = second, isPlaying = true)
|
||||
|
||||
assertEquals(
|
||||
listOf(
|
||||
Call.NowPlaying("s1"),
|
||||
Call.Scrobble("s1", 1_000L),
|
||||
Call.NowPlaying("s2"),
|
||||
),
|
||||
sink.calls,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user