added new functions for random sounds
This commit is contained in:
parent
4a4f55fbe9
commit
63e62670d5
@ -24,8 +24,8 @@ AUTO_STATE_PATH = os.path.join(Config.LOG_DIR, 'auto_random_state.json')
|
|||||||
# Sound-Cache: path -> pygame.mixer.Sound
|
# Sound-Cache: path -> pygame.mixer.Sound
|
||||||
loaded_sounds = {}
|
loaded_sounds = {}
|
||||||
random_history = defaultdict(deque) # sound_id -> deque[timestamps]
|
random_history = defaultdict(deque) # sound_id -> deque[timestamps]
|
||||||
MAX_PER_HOUR = 2
|
DEFAULT_MAX_PER_HOUR = 2
|
||||||
WINDOW_SECONDS = 3600
|
DEFAULT_WINDOW_SECONDS = 3600
|
||||||
|
|
||||||
def _ensure_mixer():
|
def _ensure_mixer():
|
||||||
from config import Config
|
from config import Config
|
||||||
@ -103,8 +103,9 @@ def _pick_random_sound():
|
|||||||
candidates = []
|
candidates = []
|
||||||
for sound in rnd_list:
|
for sound in rnd_list:
|
||||||
sid = sound.get('id') or sound.get('file')
|
sid = sound.get('id') or sound.get('file')
|
||||||
dq = _prune_history(sid, now)
|
max_per_hour, window_seconds = _get_limits(sound)
|
||||||
if len(dq) < MAX_PER_HOUR:
|
dq = _prune_history(sid, now, window_seconds)
|
||||||
|
if len(dq) < max_per_hour:
|
||||||
candidates.append(sound)
|
candidates.append(sound)
|
||||||
|
|
||||||
if not candidates:
|
if not candidates:
|
||||||
@ -117,6 +118,30 @@ def _pick_random_sound():
|
|||||||
return sound_entry, None
|
return sound_entry, None
|
||||||
|
|
||||||
|
|
||||||
|
def _get_limits(sound_entry=None):
|
||||||
|
"""
|
||||||
|
Ermittelt Grenzen für Random-Wiedergabe.
|
||||||
|
Priorität: pro Sound (max_per_hour, window_minutes) -> aktuelles Soundboard -> Defaults.
|
||||||
|
"""
|
||||||
|
max_per_hour = DEFAULT_MAX_PER_HOUR
|
||||||
|
window_seconds = DEFAULT_WINDOW_SECONDS
|
||||||
|
|
||||||
|
if state.current_soundboard:
|
||||||
|
sb = state.current_soundboard
|
||||||
|
max_per_hour = int(sb.get('random_limit_per_hour', max_per_hour))
|
||||||
|
window_minutes = sb.get('random_window_minutes')
|
||||||
|
if window_minutes:
|
||||||
|
window_seconds = int(window_minutes * 60)
|
||||||
|
|
||||||
|
if sound_entry:
|
||||||
|
if 'max_per_hour' in sound_entry:
|
||||||
|
max_per_hour = int(sound_entry['max_per_hour'])
|
||||||
|
if 'window_minutes' in sound_entry:
|
||||||
|
window_seconds = int(sound_entry['window_minutes'] * 60)
|
||||||
|
|
||||||
|
return max_per_hour, window_seconds
|
||||||
|
|
||||||
|
|
||||||
def _auto_random_tick():
|
def _auto_random_tick():
|
||||||
global auto_random_timer
|
global auto_random_timer
|
||||||
with auto_random_lock:
|
with auto_random_lock:
|
||||||
@ -165,9 +190,9 @@ def _persist_auto_state(clear=False):
|
|||||||
logger.error(f"Persist auto-random state fehlgeschlagen: {e}")
|
logger.error(f"Persist auto-random state fehlgeschlagen: {e}")
|
||||||
|
|
||||||
|
|
||||||
def _prune_history(sound_id, now):
|
def _prune_history(sound_id, now, window_seconds=DEFAULT_WINDOW_SECONDS):
|
||||||
dq = random_history[sound_id]
|
dq = random_history[sound_id]
|
||||||
while dq and now - dq[0] > WINDOW_SECONDS:
|
while dq and now - dq[0] > window_seconds:
|
||||||
dq.popleft()
|
dq.popleft()
|
||||||
return dq
|
return dq
|
||||||
|
|
||||||
@ -451,6 +476,8 @@ def api_soundboard_auto_start():
|
|||||||
imax = float(data.get('interval_max', 10))
|
imax = float(data.get('interval_max', 10))
|
||||||
dmin = float(data.get('delay_min', 3))
|
dmin = float(data.get('delay_min', 3))
|
||||||
dmax = float(data.get('delay_max', 12))
|
dmax = float(data.get('delay_max', 12))
|
||||||
|
limit_ph = int(data.get('limit_per_hour', DEFAULT_MAX_PER_HOUR))
|
||||||
|
window_min = float(data.get('window_minutes', DEFAULT_WINDOW_SECONDS/60))
|
||||||
if imax < imin: imax = imin
|
if imax < imin: imax = imin
|
||||||
if dmax < dmin: dmax = dmin
|
if dmax < dmin: dmax = dmin
|
||||||
|
|
||||||
@ -465,6 +492,8 @@ def api_soundboard_auto_start():
|
|||||||
auto_random_params['dmax'] = dmax
|
auto_random_params['dmax'] = dmax
|
||||||
auto_random_params['next_ts'] = time.time() + delay
|
auto_random_params['next_ts'] = time.time() + delay
|
||||||
auto_random_params['theme'] = state.current_soundboard.get('filename')
|
auto_random_params['theme'] = state.current_soundboard.get('filename')
|
||||||
|
auto_random_params['limit_per_hour'] = limit_ph
|
||||||
|
auto_random_params['window_seconds'] = window_min * 60
|
||||||
global auto_random_timer
|
global auto_random_timer
|
||||||
auto_random_timer = threading.Timer(delay, _auto_random_tick)
|
auto_random_timer = threading.Timer(delay, _auto_random_tick)
|
||||||
auto_random_timer.daemon = True
|
auto_random_timer.daemon = True
|
||||||
@ -500,6 +529,8 @@ def api_soundboard_status():
|
|||||||
dmin = auto_random_params.get('dmin')
|
dmin = auto_random_params.get('dmin')
|
||||||
dmax = auto_random_params.get('dmax')
|
dmax = auto_random_params.get('dmax')
|
||||||
current_theme = state.current_soundboard.get('filename') if state.current_soundboard else None
|
current_theme = state.current_soundboard.get('filename') if state.current_soundboard else None
|
||||||
|
limit_ph = auto_random_params.get('limit_per_hour', DEFAULT_MAX_PER_HOUR)
|
||||||
|
window_sec = auto_random_params.get('window_seconds', DEFAULT_WINDOW_SECONDS)
|
||||||
next_seconds = max(0, next_ts - time.time()) if next_ts else None
|
next_seconds = max(0, next_ts - time.time()) if next_ts else None
|
||||||
return jsonify({
|
return jsonify({
|
||||||
"active": active,
|
"active": active,
|
||||||
@ -508,7 +539,9 @@ def api_soundboard_status():
|
|||||||
"interval_max": imax,
|
"interval_max": imax,
|
||||||
"delay_min": dmin,
|
"delay_min": dmin,
|
||||||
"delay_max": dmax,
|
"delay_max": dmax,
|
||||||
"current_theme": current_theme
|
"current_theme": current_theme,
|
||||||
|
"limit_per_hour": limit_ph,
|
||||||
|
"window_minutes": window_sec/60 if window_sec else None
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@ -557,7 +590,9 @@ def _restore_auto_state():
|
|||||||
'dmin': data.get('dmin', 3),
|
'dmin': data.get('dmin', 3),
|
||||||
'dmax': data.get('dmax', 12),
|
'dmax': data.get('dmax', 12),
|
||||||
'next_ts': next_ts,
|
'next_ts': next_ts,
|
||||||
'theme': theme
|
'theme': theme,
|
||||||
|
'limit_per_hour': data.get('limit_per_hour', DEFAULT_MAX_PER_HOUR),
|
||||||
|
'window_seconds': data.get('window_seconds', DEFAULT_WINDOW_SECONDS)
|
||||||
})
|
})
|
||||||
delay = max(1, next_ts - time.time())
|
delay = max(1, next_ts - time.time())
|
||||||
global auto_random_timer
|
global auto_random_timer
|
||||||
|
|||||||
@ -144,6 +144,14 @@
|
|||||||
<label class="form-label">Startverzögerung max (Minuten)</label>
|
<label class="form-label">Startverzögerung max (Minuten)</label>
|
||||||
<input id="auto-delay-max" type="number" class="form-control" value="12" min="0" max="120">
|
<input id="auto-delay-max" type="number" class="form-control" value="12" min="0" max="120">
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<label class="form-label">Max Wiederholungen pro Stunde</label>
|
||||||
|
<input id="auto-limit-ph" type="number" class="form-control" value="2" min="1" max="50">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<label class="form-label">Limit-Fenster (Minuten)</label>
|
||||||
|
<input id="auto-window-min" type="number" class="form-control" value="60" min="1" max="240">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-3 d-flex gap-2 align-items-center">
|
<div class="mt-3 d-flex gap-2 align-items-center">
|
||||||
<button id="auto-start" class="btn btn-success" ${!randBtn.disabled ? '' : 'disabled'}>Auto-Start</button>
|
<button id="auto-start" class="btn btn-success" ${!randBtn.disabled ? '' : 'disabled'}>Auto-Start</button>
|
||||||
@ -161,11 +169,17 @@
|
|||||||
const imax = Math.max(imin, parseInt(document.getElementById('auto-interval-max').value, 10) || 10);
|
const imax = Math.max(imin, parseInt(document.getElementById('auto-interval-max').value, 10) || 10);
|
||||||
const dmin = Math.max(0, parseInt(document.getElementById('auto-delay-min').value, 10) || 3);
|
const dmin = Math.max(0, parseInt(document.getElementById('auto-delay-min').value, 10) || 3);
|
||||||
const dmax = Math.max(dmin, parseInt(document.getElementById('auto-delay-max').value, 10) || 12);
|
const dmax = Math.max(dmin, parseInt(document.getElementById('auto-delay-max').value, 10) || 12);
|
||||||
|
const limitPh = Math.max(1, parseInt(document.getElementById('auto-limit-ph').value, 10) || 2);
|
||||||
|
const windowMin = Math.max(1, parseInt(document.getElementById('auto-window-min').value, 10) || 60);
|
||||||
|
|
||||||
const res = await fetch('/api/soundboard/auto_start', {
|
const res = await fetch('/api/soundboard/auto_start', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ interval_min: imin, interval_max: imax, delay_min: dmin, delay_max: dmax })
|
body: JSON.stringify({
|
||||||
|
interval_min: imin, interval_max: imax,
|
||||||
|
delay_min: dmin, delay_max: dmax,
|
||||||
|
limit_per_hour: limitPh, window_minutes: windowMin
|
||||||
|
})
|
||||||
});
|
});
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
@ -212,6 +226,8 @@
|
|||||||
if (data.interval_max) document.getElementById('auto-interval-max').value = data.interval_max;
|
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_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;
|
if (data.delay_max !== undefined && data.delay_max !== null) document.getElementById('auto-delay-max').value = data.delay_max;
|
||||||
|
if (data.limit_per_hour !== undefined && data.limit_per_hour !== null) document.getElementById('auto-limit-ph').value = data.limit_per_hour;
|
||||||
|
if (data.window_minutes !== undefined && data.window_minutes !== null) document.getElementById('auto-window-min').value = data.window_minutes;
|
||||||
} else {
|
} else {
|
||||||
status.textContent = 'Aus';
|
status.textContent = 'Aus';
|
||||||
start.disabled = false;
|
start.disabled = false;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user