[READ-ONLY] Mirror of https://github.com/FoxxMD/multi-scrobbler. Scrobble plays from multiple sources to multiple clients docs.multi-scrobbler.app
deezer docker jellyfin koito lastfm listenbrainz maloja mopidy mpris music music-assistant plex scrobble self-hosted spotify subsonic tautulli youtube-music
0

Configure Feed

Select the types of activity you want to include in your feed.

fix(player): Check for 0 duration before finalizing listen session with duration-based calculation

FoxxMD (Mar 17, 2025, 8:40 PM UTC) 0dca49ab 6a71d4a4

+24 -1
+1 -1
src/backend/sources/PlayerState/PositionalPlayerState.ts
··· 90 90 duration, 91 91 } = {} 92 92 } = this.currentPlay; 93 - if(duration !== undefined && (duration - this.currentListenRange.end.position) < this.gracefulEndBuffer) { 93 + if(duration !== undefined && duration !== 0 && (duration - this.currentListenRange.end.position) < this.gracefulEndBuffer) { 94 94 // likely the track was listened to until it ended 95 95 // but polling interval or network delays caused MS to not get data on the very end 96 96 // also...within 3 seconds of ending is close enough to call this complete IMO
+23
src/backend/tests/player/player.test.ts
··· 257 257 assert.equal(player.getListenDuration(), 7); 258 258 }); 259 259 260 + it('Listened for is track duration invariant', function () { 261 + const player = new TestPositionalPlayerState(logger, [NO_DEVICE, NO_USER]); 262 + 263 + const positioned = clone(newPlay); 264 + positioned.data.duration = 0; 265 + 266 + player.update(testState({play: positioned, position: 3, status: REPORTED_PLAYER_STATUSES.playing})); 267 + 268 + player.currentListenRange.rtPlayer.setPosition(10000); 269 + player.update(testState({play: positioned, position: 10, status: REPORTED_PLAYER_STATUSES.playing}), dayjs().add(10, 'seconds')); 270 + 271 + player.currentListenRange.rtPlayer.setPosition(20000); 272 + player.update(testState({play: positioned, position: 20, status: REPORTED_PLAYER_STATUSES.playing}), dayjs().add(20, 'seconds')); 273 + 274 + const otherPlay = clone(positioned); 275 + otherPlay.data.track = "A New Track"; 276 + player.currentListenRange.rtPlayer.setPosition(30000); 277 + const [currPlay, prevPlay] = player.update(testState({play: otherPlay, position: 2, status: REPORTED_PLAYER_STATUSES.playing}), dayjs().add(30, 'seconds')); 278 + 279 + assert.isDefined(prevPlay); 280 + assert.equal(prevPlay.data.listenedFor, 17); 281 + }); 282 + 260 283 it('Range ends if position over drifts', function () { 261 284 const player = new TestPositionalPlayerState(logger, [NO_DEVICE, NO_USER]); 262 285