fix(player): follow Library's selected device to its pair master

If the device selected in the Library tab disappeared from the
devices map (e.g. it just became a hidden stereo-pair member per
device_projection.go), the sync effect fell back to entries[0][0] --
whichever key happens to sort first in the map -- silently redirecting
the user's Library browsing session to an unrelated speaker.

Now checks first whether the vanished device reappears as a member of
some other device's stereoPair (the pair's master, which now
represents the same physical speaker for control purposes) and
follows it there. Only falls back to an arbitrary device when the
selection is gone for a genuinely unrelated reason (removed, discovery
gap), matching the prior behavior for that case.

No JS unit-test framework exists in this repo for component-level
logic (consistent with the rest of the client-side code), so this is
verified by manual trace rather than an automated regression test.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Tobias Gesellchen
2026-08-30 22:27:56 +02:00
co-authored by Claude Sonnet 5
parent 78c6c1bfca
commit 862ddbb87d
@@ -23,11 +23,26 @@ export function Library({ devices }) {
// invalidate the current selection.
useEffect(() => {
const entries = Object.entries(devices);
if ((!deviceId || !devices[deviceId]) && entries.length > 0) {
setDeviceId(entries[0][0]);
} else if (deviceId && entries.length === 0) {
setDeviceId(null);
if (deviceId && devices[deviceId]) return;
if (entries.length === 0) {
if (deviceId) setDeviceId(null);
return;
}
if (deviceId) {
// The selected device vanished from the list -- if that's because
// it just became a hidden stereo-pair member (see
// device_projection.go), follow it to its pair's master instead
// of silently jumping to an unrelated device.
const master = entries.find(([, d]) => d.stereoPair?.members?.some(m => m.ipAddress === deviceId));
if (master) {
setDeviceId(master[0]);
return;
}
}
setDeviceId(entries[0][0]);
}, [devices, deviceId]);
// Reload registered servers whenever deviceId changes.