173 lines
5.8 KiB
HTML
173 lines
5.8 KiB
HTML
{% extends "base.html" %}
|
||
|
||
{% block title %}Soundboard – Themen{% endblock %}
|
||
|
||
{% block content %}
|
||
<div class="container my-5">
|
||
<h1>Soundboard</h1>
|
||
<p class="lead mb-4">Themenbezogene Soundsets, unabhängig vom Hub.</p>
|
||
|
||
<div class="row mb-4">
|
||
<div class="col-md-6">
|
||
<label class="form-label fw-bold">Thema wählen</label>
|
||
<select id="soundboard-select" class="form-select">
|
||
{% for sb in soundboard_configs %}
|
||
<option value="{{ sb.filename }}">{{ sb.name }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
</div>
|
||
<div class="col-md-6 d-flex align-items-end">
|
||
<div class="btn-group">
|
||
<button id="btn-load-sb" class="btn btn-primary">Laden</button>
|
||
<button id="btn-play-random" class="btn btn-outline-secondary" disabled>Zufällig (max 2/h pro Datei)</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="sb-content" style="display:none">
|
||
<div class="mb-4">
|
||
<label class="form-label fw-bold">Lautstärke</label>
|
||
<input type="range" class="form-range" id="sb-volume" min="0" max="100" value="80" step="5">
|
||
<small class="text-muted">Wirkt global auf alle Soundboard-Kanäle.</small>
|
||
</div>
|
||
<div id="sb-backgrounds" class="mb-4"></div>
|
||
<div id="sb-sounds" class="mb-4"></div>
|
||
<div id="sb-random" class="mb-4"></div>
|
||
</div>
|
||
|
||
<div class="mt-4">
|
||
<a href="{{ url_for('main.index') }}" class="btn btn-secondary">Zurück</a>
|
||
</div>
|
||
</div>
|
||
{% endblock %}
|
||
|
||
{% block scripts %}
|
||
<script>
|
||
const selectEl = document.getElementById('soundboard-select');
|
||
const loadBtn = document.getElementById('btn-load-sb');
|
||
const randBtn = document.getElementById('btn-play-random');
|
||
const content = document.getElementById('sb-content');
|
||
|
||
let currentSB = null;
|
||
const statusBox = (msg, type='info') => {
|
||
console.log(msg);
|
||
};
|
||
|
||
async function loadSoundboard(filename) {
|
||
loadBtn.disabled = true;
|
||
try {
|
||
const res = await fetch('/api/soundboard/load', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ filename })
|
||
});
|
||
const data = await res.json();
|
||
if (!data.success) throw new Error(data.message || 'Load failed');
|
||
currentSB = data.soundboard;
|
||
renderSoundboard(currentSB);
|
||
content.style.display = 'block';
|
||
randBtn.disabled = false;
|
||
} catch (e) {
|
||
alert('Konnte Soundboard nicht laden: ' + e.message);
|
||
} finally {
|
||
loadBtn.disabled = false;
|
||
}
|
||
}
|
||
|
||
function renderSoundboard(sb) {
|
||
renderBackgrounds(sb.backgrounds || []);
|
||
renderSounds(sb.sounds || []);
|
||
renderRandom(sb.random_pool || []);
|
||
}
|
||
|
||
function renderBackgrounds(list) {
|
||
const container = document.getElementById('sb-backgrounds');
|
||
if (!list.length) { container.innerHTML=''; return; }
|
||
container.innerHTML = '<h4>Hintergrund (Loop)</h4><div class="d-flex flex-wrap gap-2"></div>';
|
||
const wrap = container.querySelector('div');
|
||
list.forEach(s => {
|
||
const btn = document.createElement('button');
|
||
btn.className = 'btn btn-outline-secondary';
|
||
btn.textContent = s.name || s.id || s.file;
|
||
btn.onclick = () => playSound(s);
|
||
const stop = document.createElement('button');
|
||
stop.className = 'btn btn-outline-danger';
|
||
stop.textContent = 'Stop';
|
||
stop.onclick = () => stopSound(s.channel);
|
||
wrap.append(btn, stop);
|
||
});
|
||
}
|
||
|
||
function renderSounds(list) {
|
||
const container = document.getElementById('sb-sounds');
|
||
if (!list.length) { container.innerHTML=''; return; }
|
||
container.innerHTML = '<h4>Einzelsounds</h4><div class="d-flex flex-wrap gap-2"></div>';
|
||
const wrap = container.querySelector('div');
|
||
list.forEach(s => {
|
||
const btn = document.createElement('button');
|
||
btn.className = 'btn btn-primary';
|
||
btn.textContent = s.name || s.id || s.file;
|
||
btn.onclick = () => playSound(s);
|
||
wrap.append(btn);
|
||
});
|
||
}
|
||
|
||
function renderRandom(list) {
|
||
const container = document.getElementById('sb-random');
|
||
if (!list.length) { container.innerHTML=''; randBtn.disabled=true; return; }
|
||
const items = list.map(s => `<li>${s.name || s.id || s.file}</li>`).join('');
|
||
container.innerHTML = '<h4>Zufallspool</h4><p class="text-muted">max 2x pro Stunde je Datei.</p><ul>' + items + '</ul>';
|
||
}
|
||
|
||
async function playSound(sound) {
|
||
const payload = {
|
||
sound_id: sound.id || sound.file,
|
||
channel: sound.channel ?? null,
|
||
loop: !!sound.loop
|
||
};
|
||
const res = await fetch('/api/play_sound', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify(payload)
|
||
});
|
||
const data = await res.json();
|
||
if (!data.success) statusBox(data.message || 'Fehler beim Abspielen', 'warn');
|
||
}
|
||
|
||
async function stopSound(channel) {
|
||
const res = await fetch('/api/stop_sound', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ channel })
|
||
});
|
||
const data = await res.json();
|
||
if (!data.success) statusBox(data.message || 'Fehler beim Stoppen', 'warn');
|
||
}
|
||
|
||
loadBtn.onclick = () => loadSoundboard(selectEl.value);
|
||
randBtn.onclick = async () => {
|
||
const res = await fetch('/api/soundboard/play_random', { method: 'POST' });
|
||
const data = await res.json();
|
||
if (!data.success) statusBox(data.message || 'Random fehlgeschlagen', 'warn');
|
||
};
|
||
|
||
// Lautstärke
|
||
const vol = document.getElementById('sb-volume');
|
||
if (vol) {
|
||
vol.addEventListener('input', async () => {
|
||
const v = parseInt(vol.value, 10) / 100;
|
||
await fetch('/api/set_volume', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ volume: v })
|
||
});
|
||
});
|
||
}
|
||
|
||
// Autoload erstes Thema (falls vorhanden)
|
||
if (selectEl && selectEl.value) {
|
||
loadSoundboard(selectEl.value);
|
||
}
|
||
</script>
|
||
{% endblock %}
|