feat(scrobble): send Subsonic scrobble on playback start (now-playing)

This commit is contained in:
joelilas
2026-01-26 18:45:48 +01:00
parent 2bd20b397d
commit c1952b0002
3 changed files with 66 additions and 1 deletions

View File

@@ -571,3 +571,38 @@ async def stream(stream_id: str):
logger.error("Failed to stream song: %s", await response.text())
return None
return str(response.url)
async def scrobble(song_id: str, *, submission: bool=True, timestamp: int=None) -> bool:
''' Submit a scrobble event for a song to the Subsonic/Navidrome API.
Parameters:
- song_id: The Subsonic song id to scrobble
- submission: Whether this is a final submission (True) or a now-playing ping (False)
- timestamp: Optional Unix epoch seconds for when the song was played
'''
scrobble_params: dict[str, any] = {
"id": song_id,
"submission": "true" if submission else "false",
}
if timestamp is not None:
scrobble_params["time"] = str(timestamp)
params = SUBSONIC_REQUEST_PARAMS | scrobble_params
try:
session = await get_session()
async with await session.get(f"{env.SUBSONIC_SERVER}/rest/scrobble.view", params=params) as response:
response.raise_for_status()
data = await response.json()
if await check_subsonic_error(data):
logger.warning("Scrobble returned a Subsonic error for song %s", song_id)
return False
logger.debug("Scrobble response: %s", data)
return True
except aiohttp.ClientError as e:
logger.error("HTTP error during scrobble for song %s: %s", song_id, e)
return False
except Exception as e:
logger.error("Unexpected error during scrobble for song %s: %s", song_id, e)
return False