docs(player): explain stereo-pair AirPlay limit

This commit is contained in:
Lukáš Lipinský
2026-09-05 11:56:18 +02:00
committed by Tobias Gesellchen
parent cb441da981
commit cdd06e367a
5 changed files with 61 additions and 0 deletions
@@ -0,0 +1,12 @@
import assert from 'node:assert/strict';
import { readFile } from 'node:fs/promises';
import test from 'node:test';
const app = await readFile(new URL('../static/js/app.js', import.meta.url), 'utf8');
test('explains the documented AirPlay limitation only for ST10 stereo pairs', () => {
assert.match(app, /isSoundTouch10StereoPair\(device\)/);
assert.match(app, /role="note" aria-label="Stereo pair limitation"/);
assert.match(app, /AirPlay unavailable while paired\./);
assert.match(app, /Unpair them to use AirPlay\./);
});
@@ -0,0 +1,20 @@
import assert from 'node:assert/strict';
import test from 'node:test';
import { isSoundTouch10StereoPair } from '../static/js/stereoPresentation.mjs';
test('identifies only projected SoundTouch 10 stereo pairs', () => {
assert.equal(isSoundTouch10StereoPair({
info: { type: 'SoundTouch 10' },
stereoPair: { masterDeviceId: 'left' },
}), true);
assert.equal(isSoundTouch10StereoPair({
info: { type: 'ST10' },
stereoPair: { masterDeviceId: 'left' },
}), true);
assert.equal(isSoundTouch10StereoPair({ info: { type: 'SoundTouch 10' } }), false);
assert.equal(isSoundTouch10StereoPair({
info: { type: 'SoundTouch 20' },
stereoPair: { masterDeviceId: 'left' },
}), false);
});
@@ -693,6 +693,22 @@ img { display: block; max-width: 100%; }
.source-icon { font-size: .9rem; line-height: 1; }
.source-name { font-weight: 500; }
.stereo-pair-note {
display: flex;
flex-direction: column;
gap: .2rem;
margin-top: 1rem;
padding: .65rem .75rem;
border: 1px solid var(--border);
border-left: 3px solid var(--accent);
border-radius: var(--radius);
background: var(--surface);
color: var(--text-dim);
font-size: .8rem;
line-height: 1.4;
}
.stereo-pair-note strong { color: var(--text); }
/* ── Zone ────────────────────────────────────────────────────────────────── */
.zone-section { margin-top: 1.25rem; }
@@ -16,6 +16,7 @@ import { PlayURL } from './components/PlayURL.js';
import { TTS } from './components/TTS.js';
import { Announcements } from './components/Announcements.js';
import { api } from './api.js';
import { isSoundTouch10StereoPair } from './stereoPresentation.mjs';
const html = htm.bind(h);
@@ -53,6 +54,12 @@ function DeviceDetail({ deviceId, devices, onBack, onDevicesChanged, notify }) {
onChanged=${onDevicesChanged}
notify=${notify}
/>
${isSoundTouch10StereoPair(device) ? html`
<aside class="stereo-pair-note" role="note" aria-label="Stereo pair limitation">
<strong>AirPlay unavailable while paired.</strong>
<span>SoundTouch 10 speakers cannot use AirPlay while paired. Unpair them to use AirPlay.</span>
</aside>
` : null}
<${Zone} deviceId=${deviceId} devices=${devices} />
<${Recents} deviceId=${deviceId} />
</div>
@@ -0,0 +1,6 @@
export function isSoundTouch10StereoPair(device) {
if (!device?.stereoPair) return false;
const model = String(device?.info?.type || '').toLowerCase().replace(/[^a-z0-9]/g, '');
return model === 'st10' || model === 'soundtouch10';
}