diff --git a/app/routes/api.py b/app/routes/api.py index 6ba9bfd..8fff21b 100644 --- a/app/routes/api.py +++ b/app/routes/api.py @@ -131,6 +131,7 @@ def _auto_random_tick(): delay = rand_between(imin, imax) * 60 with auto_random_lock: if state.auto_random_active: + auto_random_params['next_ts'] = time.time() + delay auto_random_timer = threading.Timer(delay, _auto_random_tick) auto_random_timer.daemon = True auto_random_timer.start() @@ -436,6 +437,7 @@ def api_soundboard_auto_start(): auto_random_params['imax'] = imax auto_random_params['dmin'] = dmin auto_random_params['dmax'] = dmax + auto_random_params['next_ts'] = time.time() + delay global auto_random_timer auto_random_timer = threading.Timer(delay, _auto_random_tick) auto_random_timer.daemon = True @@ -455,7 +457,20 @@ def api_soundboard_auto_stop(): def api_soundboard_status(): with auto_random_lock: active = state.auto_random_active - return jsonify({"active": active}) + next_ts = auto_random_params.get('next_ts') + imin = auto_random_params.get('imin') + imax = auto_random_params.get('imax') + dmin = auto_random_params.get('dmin') + dmax = auto_random_params.get('dmax') + next_seconds = max(0, next_ts - time.time()) if next_ts else None + return jsonify({ + "active": active, + "next_seconds": next_seconds, + "interval_min": imin, + "interval_max": imax, + "delay_min": dmin, + "delay_max": dmax + }) def _stop_auto_random_internal(): @@ -467,6 +482,7 @@ def _stop_auto_random_internal(): auto_random_timer = None stopped = True state.auto_random_active = False + auto_random_params.clear() return stopped diff --git a/templates/soundboard.html b/templates/soundboard.html index 88b3d43..ea642f7 100644 --- a/templates/soundboard.html +++ b/templates/soundboard.html @@ -50,7 +50,6 @@ const content = document.getElementById('sb-content'); let currentSB = null; - let autoTimer = null; const statusBox = (msg, type='info') => { console.log(msg); }; @@ -80,6 +79,7 @@ renderBackgrounds(sb.backgrounds || []); renderSounds(sb.sounds || []); renderRandom(sb.random_pool || []); + updateAutoStatus(); } function renderBackgrounds(list) { @@ -169,7 +169,11 @@ }); const data = await res.json(); if (data.success) { - status.textContent = `Aktiv (nächster in ${(data.next_seconds/60).toFixed(1)} min)`; + if (data.next_seconds !== undefined && data.next_seconds !== null) { + status.textContent = `Aktiv (nächster in ${(data.next_seconds/60).toFixed(1)} min)`; + } else { + status.textContent = 'Aktiv'; + } start.disabled = true; stop.disabled = false; } else { @@ -188,6 +192,33 @@ }; } + async function updateAutoStatus() { + const res = await fetch('/api/soundboard/status'); + const data = await res.json(); + const status = document.getElementById('auto-status'); + const start = document.getElementById('auto-start'); + const stop = document.getElementById('auto-stop'); + if (!status || !start || !stop) return; + if (data.active) { + if (data.next_seconds !== null && data.next_seconds !== undefined) { + status.textContent = `Aktiv (nächster in ${(data.next_seconds/60).toFixed(1)} min)`; + } else { + status.textContent = 'Aktiv'; + } + start.disabled = true; + stop.disabled = false; + // optional: Formularwerte mit Serverparametern füllen + if (data.interval_min) document.getElementById('auto-interval-min').value = data.interval_min; + if (data.interval_max) document.getElementById('auto-interval-max').value = data.interval_max; + if (data.delay_min !== undefined && data.delay_min !== null) document.getElementById('auto-delay-min').value = data.delay_min; + if (data.delay_max !== undefined && data.delay_max !== null) document.getElementById('auto-delay-max').value = data.delay_max; + } else { + status.textContent = 'Aus'; + start.disabled = false; + stop.disabled = true; + } + } + async function playSound(sound) { const payload = { sound_id: sound.id || sound.file, @@ -240,6 +271,8 @@ // Autoload erstes Thema (falls vorhanden) if (selectEl && selectEl.value) { loadSoundboard(selectEl.value); + } else { + updateAutoStatus(); } {% endblock %}