fix(scrobble): Navidrome Now Playing with local playback and mixed-server queue (#1055)

* fix(scrobble): report Now Playing on playback server with local bytes

Navidrome presence and play-count scrobbles no longer skip when audio plays
from hot cache, offline pins, or favorites-auto, and reachability follows the
queue/playback server instead of the browsed active server.

* docs: changelog and credits for PR #1055
This commit is contained in:
cucadmuh
2026-06-10 04:25:22 +03:00
committed by GitHub
parent ae9be74719
commit 707a41f615
8 changed files with 131 additions and 20 deletions
+9 -4
View File
@@ -1,6 +1,6 @@
import { savePlayQueue } from '../api/subsonicPlayQueue';
import type { QueueItemRef, Track } from './playerStoreTypes';
import { isActiveServerReachable } from '../utils/network/activeServerReachability';
import { isSubsonicServerReachable } from '../utils/network/subsonicNetworkGuard';
import { getPlaybackServerId } from '../utils/playback/playbackServer';
import { getPlaybackProgressSnapshot } from './playbackProgress';
import { usePlayerStore } from './playerStore';
@@ -27,12 +27,17 @@ const QUEUE_ID_LIMIT = 1000;
let syncTimeout: ReturnType<typeof setTimeout> | null = null;
let lastQueueHeartbeatAt = 0;
function isPlaybackServerReachable(): boolean {
const serverId = getPlaybackServerId();
return serverId ? isSubsonicServerReachable(serverId) : false;
}
export function syncQueueToServer(queue: QueueItemRef[], currentTrack: Track | null, currentTime: number): void {
if (!isActiveServerReachable()) return;
if (!isPlaybackServerReachable()) return;
if (syncTimeout) clearTimeout(syncTimeout);
syncTimeout = setTimeout(() => {
syncTimeout = null;
if (!isActiveServerReachable()) return;
if (!isPlaybackServerReachable()) return;
const ids = queue.slice(0, QUEUE_ID_LIMIT).map(r => r.trackId);
const pos = Math.floor(currentTime * 1000);
const serverId = getPlaybackServerId();
@@ -47,7 +52,7 @@ export function flushQueueSyncToServer(queue: QueueItemRef[], currentTrack: Trac
clearTimeout(syncTimeout);
syncTimeout = null;
}
if (!isActiveServerReachable()) return Promise.resolve();
if (!isPlaybackServerReachable()) return Promise.resolve();
if (!currentTrack || queue.length === 0) return Promise.resolve();
lastQueueHeartbeatAt = Date.now();
const ids = queue.slice(0, QUEUE_ID_LIMIT).map(r => r.trackId);