More scrobble fixes

This commit is contained in:
Wolfgang Kulhanek
2025-10-16 17:05:40 +02:00
parent e722aa4b7c
commit 4b2fb29cc1

View File

@@ -43,6 +43,25 @@ import { SmapiTokenStore, InMemorySmapiTokenStore } from "./smapi_token_store";
export const BONOB_ACCESS_TOKEN_HEADER = "bat";
// Session storage for tracking active streams (for scrobbling)
type StreamSession = {
serviceToken: string;
trackId: string;
timestamp: number;
};
const streamSessions = new Map<string, StreamSession>();
// Clean up old sessions (older than 1 hour)
setInterval(() => {
const oneHourAgo = Date.now() - (60 * 60 * 1000);
for (const [sid, session] of streamSessions.entries()) {
if (session.timestamp < oneHourAgo) {
streamSessions.delete(sid);
}
}
}, 5 * 60 * 1000); // Run every 5 minutes
interface RangeFilter extends Transform {
range: (length: number) => string;
}
@@ -401,6 +420,14 @@ function server(
if (!serviceToken) {
return res.status(401).send();
} else {
// Store session for scrobbling later (when Sonos reports playback)
streamSessions.set(id, {
serviceToken,
trackId: id,
timestamp: Date.now(),
});
logger.debug(`Stored stream session for track ${id}`);
return musicService
.login(serviceToken)
.then((it) =>
@@ -655,11 +682,13 @@ function server(
// For "final" reports, determine if we should scrobble
if (type === "final" && durationPlayedSeconds > 0) {
// Extract authentication from request headers or body
// Sonos may send credentials in Authorization header or in the request
const authHeader = req.headers["authorization"];
let serviceToken: string | undefined;
// Retrieve authentication from stream session storage
const session = streamSessions.get(trackId!);
let serviceToken: string | undefined = session?.serviceToken;
if (!serviceToken) {
// Fallback: try to extract from Authorization header (if present)
const authHeader = req.headers["authorization"];
if (authHeader && authHeader.startsWith("Bearer ")) {
const token = authHeader.substring(7);
const smapiToken = serverOpts.smapiTokenStore.get(token);
@@ -670,6 +699,7 @@ function server(
);
}
}
}
if (serviceToken) {
await musicService.login(serviceToken).then((musicLibrary) => {