zebra-report: persist music-mode + mic/camera device selection — mirror source

This commit is contained in:
russell@unturf.com 2026-06-01 21:38:24 -04:00
parent 97b7ce8883
commit 5a83718328
No known key found for this signature in database

View file

@ -429,7 +429,10 @@ function logLine(kind, msg){
* Go side does with ed25519.PublicKey. * Go side does with ed25519.PublicKey.
* ================================================================== */ * ================================================================== */
const ID_KEY = 'zebra-spaces-id-v1'; const ID_KEY = 'zebra-spaces-id-v1';
const HANDLE_KEY = 'zebra-spaces-handle-v1'; const HANDLE_KEY = 'zebra-spaces-handle-v1';
const MUSIC_MODE_KEY = 'zebra-spaces-music-mode-v1';
const MIC_DEV_KEY = 'zebra-spaces-mic-device-v1';
const CAM_DEV_KEY = 'zebra-spaces-cam-device-v1';
const VAULT_PREFIX = 'zspc-id-v1|'; const VAULT_PREFIX = 'zspc-id-v1|';
const PBKDF2_ITER = 600000; const PBKDF2_ITER = 600000;
@ -578,6 +581,14 @@ $('handle').addEventListener('input', (e) => {
await loadOrCreateIdentity(); await loadOrCreateIdentity();
myHandle = localStorage.getItem(HANDLE_KEY) || ''; myHandle = localStorage.getItem(HANDLE_KEY) || '';
$('handle').value = myHandle; $('handle').value = myHandle;
/* preferences that should outlive a reload — music-mode toggle and the
* last-picked mic + camera deviceIds. They're applied here before any
* device enumeration / mic acquisition so the very first getUserMedia
* call uses the right device + constraints. */
try { musicMode = localStorage.getItem(MUSIC_MODE_KEY) === '1'; } catch(_){}
try { micDeviceId = localStorage.getItem(MIC_DEV_KEY) || ''; } catch(_){}
try { cameraDeviceId = localStorage.getItem(CAM_DEV_KEY) || ''; } catch(_){}
if ($('music-mode')) $('music-mode').checked = musicMode;
renderIdentity(); renderIdentity();
logLine('', 'pubkey '+myKeys.pubHex); logLine('', 'pubkey '+myKeys.pubHex);
@ -1735,6 +1746,7 @@ $('btn-camera-share').addEventListener('click', () => { sfuPublishCamera().catch
$('btn-camera-stop').addEventListener('click', () => { sfuUnpublishCamera(); }); $('btn-camera-stop').addEventListener('click', () => { sfuUnpublishCamera(); });
$('camera-select').addEventListener('change', async (e) => { $('camera-select').addEventListener('change', async (e) => {
cameraDeviceId = e.target.value; cameraDeviceId = e.target.value;
try { localStorage.setItem(CAM_DEV_KEY, cameraDeviceId); } catch(_){}
if (sfuCameraPC){ if (sfuCameraPC){
/* restart with the new device — getUserMedia must be re-called with /* restart with the new device — getUserMedia must be re-called with
* the new deviceId; replaceTrack on a sender from a different device * the new deviceId; replaceTrack on a sender from a different device
@ -1976,10 +1988,12 @@ $('btn-mute').addEventListener('click', () => {
}); });
$('mic-select').addEventListener('change', async (e) => { $('mic-select').addEventListener('change', async (e) => {
micDeviceId = e.target.value; micDeviceId = e.target.value;
try { localStorage.setItem(MIC_DEV_KEY, micDeviceId); } catch(_){}
if (micStream){ try { await applyMicMode(); } catch(err){ logLine('err','input switch failed: '+err.message); await refreshMicList(); } } if (micStream){ try { await applyMicMode(); } catch(err){ logLine('err','input switch failed: '+err.message); await refreshMicList(); } }
}); });
$('music-mode').addEventListener('change', async (e) => { $('music-mode').addEventListener('change', async (e) => {
musicMode = e.target.checked; musicMode = e.target.checked;
try { localStorage.setItem(MUSIC_MODE_KEY, musicMode ? '1' : '0'); } catch(_){}
logLine('', 'mic mode: '+(musicMode?'MUSIC':'VOICE')); logLine('', 'mic mode: '+(musicMode?'MUSIC':'VOICE'));
if (micStream){ try { await applyMicMode(); } catch(err){ logLine('err','mic mode switch failed: '+err.message); } } if (micStream){ try { await applyMicMode(); } catch(err){ logLine('err','mic mode switch failed: '+err.message); } }
}); });
@ -2057,8 +2071,8 @@ logLine('', 'ready — pick a handle, type a rendezvous code, enter the space');
<footer style="margin:2.2rem auto 0;font-size:0.65rem;color:#999;line-height:1.7;word-break:break-all;font-family:monospace"> <footer style="margin:2.2rem auto 0;font-size:0.65rem;color:#999;line-height:1.7;word-break:break-all;font-family:monospace">
<span id="pi-seal" style="color:#777;cursor:default;user-select:none" title="">page integrity</span> &nbsp;·&nbsp; built <span class="stamp-date">2026-06-02</span><br> <span id="pi-seal" style="color:#777;cursor:default;user-select:none" title="">page integrity</span> &nbsp;·&nbsp; built <span class="stamp-date">2026-06-02</span><br>
md5 <span class="stamp-md5">6a2292078a9f6fa8c5fb156b60d670bb</span><br> md5 <span class="stamp-md5">b3dc62bb089cc56ac842287fa3ce2c7b</span><br>
sha256 <span class="stamp-sha">f857a87db69a0f93a63350630b7856f851dc55ccf84b7ebed763a2a0502ca3ef</span><br> sha256 <span class="stamp-sha">e164446240db3632db870b3f35efaf8dd5b8cbdb10b56177746bec9ba4c9fd36</span><br>
<span style="color:#bbb">hashes are of this page with these two fields zeroed — to verify, blank them and re-hash</span><br> <span style="color:#bbb">hashes are of this page with these two fields zeroed — to verify, blank them and re-hash</span><br>
<span style="color:#bbb">one self-contained file — <strong>save a copy</strong> and verify against these hashes; point at your own servers with ?signal= and ?turncred=, or <a href="host-your-own.html" style="color:#999">host your own community</a></span> <span style="color:#bbb">one self-contained file — <strong>save a copy</strong> and verify against these hashes; point at your own servers with ?signal= and ?turncred=, or <a href="host-your-own.html" style="color:#999">host your own community</a></span>
</footer> </footer>