From: Ian Campbell Date: Tue, 11 Mar 2025 23:38:35 +0000 (+0000) Subject: listenbrainz: Cross-port fixes from last.fm scrobbler (#2027) X-Git-Url: https://git.kitaultman.com/?a=commitdiff_plain;h=d937a47ff8ad2056d66223723ff1f79e6bc4b342;p=music-assistant-server.git listenbrainz: Cross-port fixes from last.fm scrobbler (#2027) Parts of #2018 apply here too. I have not personally witnessed these duplications in my scrobbles, but I see no reason why the two should differ in this regard. --- diff --git a/music_assistant/providers/listenbrainz_scrobble/__init__.py b/music_assistant/providers/listenbrainz_scrobble/__init__.py index d1c8e9ba..153b3047 100644 --- a/music_assistant/providers/listenbrainz_scrobble/__init__.py +++ b/music_assistant/providers/listenbrainz_scrobble/__init__.py @@ -51,6 +51,7 @@ class ListenBrainzScrobbleProvider(PluginProvider): _client: ListenBrainz = None _currently_playing: str | None = None _on_unload: list[Callable[[], None]] = [] + _last_scrobbled: str | None = None def __init__( self, @@ -87,7 +88,16 @@ class ListenBrainzScrobbleProvider(PluginProvider): self.logger.error("no client available during _on_mass_media_item_played") return - report = event.data + report: MediaItemPlaybackProgressReport = event.data + + # poor mans attempt to detect a song on loop + if not report.fully_played and report.uri == self._last_scrobbled: + self.logger.debug( + "reset _last_scrobbled and _currently_playing because the song was restarted" + ) + self._last_scrobbled = None + # reset currently playing to avoid it expiring when looping single songs + self._currently_playing = None def make_listen(report: Any) -> Listen: # album artist and track number are not available without an extra API call @@ -116,6 +126,7 @@ class ListenBrainzScrobbleProvider(PluginProvider): listen = make_listen(report) listen.listened_at = int(time.time()) self._client.submit_single_listen(listen) + self._last_scrobbled = report.uri except Exception as err: self.logger.exception(err) @@ -126,12 +137,12 @@ class ListenBrainzScrobbleProvider(PluginProvider): if self.should_scrobble(report): await asyncio.to_thread(scrobble) - if report.fully_played: - # reset currently playing to avoid it expiring when looping songs - self._currently_playing = None - def should_scrobble(self, report: MediaItemPlaybackProgressReport) -> bool: """Determine if a track should be scrobbled, to be extended later.""" + if self._last_scrobbled == report.uri: + self.logger.debug("skipped scrobbling due to duplicate event") + return False + # ideally we want more precise control # but because the event is triggered every 30s # and we don't have full queue details to determine