Paket bauen und veroeffentlichen / paket (push) Failing after 1m21s
- /pult als installierbare Web-App (Manifest, Service Worker, Symbole) - Soundboard: Sounds vom Handy hochladen, bearbeiten, im Stream spielen ueber die neue Browser-Source /sounds - Szenen, Clip und Stummschalter: der Stream-PC waehlt sich mit eigenem Schluessel beim Hub ein (fern:verbinden), Befehle warten auf OBS - Browser-Sources melden, welche Seite sie sind Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
110 lines
3.7 KiB
HTML
110 lines
3.7 KiB
HTML
<!doctype html>
|
|
<html lang="de">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>abdulive - Soundboard</title>
|
|
<link rel="stylesheet" href="/theme.css">
|
|
<style>
|
|
/* Eine reine Tonquelle. Im Stream ist nichts zu sehen - ein Sound, der
|
|
* zusaetzlich seinen Namen ins Bild schreibt, nimmt ihm die Pointe.
|
|
*
|
|
* Mit ?probe=1 steht unten, was gerade klingt. Damit laesst sich im Browser
|
|
* pruefen, ob ein Druck am Handy hier ankommt, auch ohne Lautsprecher. */
|
|
#liste {
|
|
position: fixed;
|
|
left: 12px; right: 12px; bottom: 12px;
|
|
display: none;
|
|
flex-direction: column;
|
|
gap: 6px;
|
|
font: 600 16px/1.2 var(--font-zahl);
|
|
}
|
|
body.probe #liste { display: flex; }
|
|
.laeuft {
|
|
padding: 8px 12px;
|
|
border-radius: 10px;
|
|
background: var(--tinte-klar);
|
|
border-left: 4px solid var(--lila);
|
|
}
|
|
.laeuft.fehler { border-left-color: var(--rot); }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="liste"></div>
|
|
|
|
<script src="/client.js"></script>
|
|
<script>
|
|
(function () {
|
|
'use strict';
|
|
|
|
var liste = document.getElementById('liste');
|
|
var schluessel = Overlay.param('key', '');
|
|
/* Lautstaerke der ganzen Quelle. Besser im OBS-Mixer regeln; das hier ist
|
|
* fuer den Fall, dass alle Sounds gemeinsam zu laut aufgenommen sind. */
|
|
var gesamt = Math.max(0, Math.min(1, Overlay.param('laut', 1)));
|
|
/* Mehr gleichzeitig klingt nicht mehr nach Soundboard, sondern nach Unfall.
|
|
* Der aelteste Sound macht dem neuen Platz. */
|
|
var maxGleichzeitig = Math.max(1, Overlay.param('max', 4));
|
|
var laufend = [];
|
|
|
|
function zeile(name, fehler) {
|
|
var d = document.createElement('div');
|
|
d.className = 'laeuft' + (fehler ? ' fehler' : '');
|
|
d.textContent = name;
|
|
liste.appendChild(d);
|
|
return d;
|
|
}
|
|
|
|
function aufhoeren(eintrag) {
|
|
var i = laufend.indexOf(eintrag);
|
|
if (i !== -1) laufend.splice(i, 1);
|
|
try { eintrag.ton.pause(); } catch (e) { /* egal */ }
|
|
eintrag.ton.removeAttribute('src');
|
|
if (eintrag.zeile.parentNode) eintrag.zeile.parentNode.removeChild(eintrag.zeile);
|
|
}
|
|
|
|
function alleStopp() {
|
|
laufend.slice().forEach(aufhoeren);
|
|
}
|
|
|
|
Overlay.on('sound', function (ev) {
|
|
while (laufend.length >= maxGleichzeitig) aufhoeren(laufend[0]);
|
|
|
|
var ton = new Audio('/soundboard/datei/' + encodeURIComponent(ev.id) +
|
|
(schluessel ? '?key=' + encodeURIComponent(schluessel) : ''));
|
|
var laut = typeof ev.laut === 'number' ? ev.laut : 0.8;
|
|
ton.volume = Math.max(0, Math.min(1, laut * gesamt));
|
|
var eintrag = { ton: ton, zeile: zeile(ev.name || 'Sound') };
|
|
laufend.push(eintrag);
|
|
|
|
ton.onended = function () { aufhoeren(eintrag); };
|
|
ton.onerror = function () {
|
|
console.error('[sounds] nicht abspielbar', ev.name, ton.error && ton.error.code);
|
|
eintrag.zeile.classList.add('fehler');
|
|
setTimeout(function () { aufhoeren(eintrag); }, 3000);
|
|
};
|
|
// Notbremse: ein Sound, der nie "zu Ende" meldet, belegte sonst fuer
|
|
// immer einen Platz.
|
|
setTimeout(function () { aufhoeren(eintrag); }, 5 * 60 * 1000);
|
|
|
|
var p = ton.play();
|
|
// Ein normaler Browser spielt erst nach einem Klick in die Seite. OBS
|
|
// nicht - wer hier im Browser testet, sieht es an der roten Zeile.
|
|
if (p && p.catch) p.catch(function (e) {
|
|
console.error('[sounds] Wiedergabe verweigert', e && e.name);
|
|
eintrag.zeile.textContent = (ev.name || 'Sound') + ' (erst in die Seite klicken)';
|
|
eintrag.zeile.classList.add('fehler');
|
|
setTimeout(function () { aufhoeren(eintrag); }, 3000);
|
|
});
|
|
});
|
|
|
|
Overlay.on('sound-stopp', alleStopp);
|
|
// Der Panikschalter gilt auch hier.
|
|
Overlay.on('still', alleStopp);
|
|
// Nach dem Neuverbinden nichts nachholen: ein Sound zur falschen Zeit ist
|
|
// schlimmer als keiner.
|
|
Overlay.on('state', function () { });
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|