mirror of
https://github.com/got-feedBack/feedBack.git
synced 2026-09-13 16:30:09 +00:00
fix(venue-crowd): flush deferred loop on stinger failure, source accuracy from perf events
Codex preflight round 3: (1) a failed/timed-out stinger left a deferred
loop switch queued forever; the failure path now flushes it. (2)
stats:recorded only carries {filename, arrangement}, so the end-of-song
reaction now uses the accuracyPct from the song's last
v3:live-performance-state event (a real percentage) instead of a field
that never existed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
5e5d892a63
commit
1172bc30cb
+22
-12
@@ -111,6 +111,7 @@
|
||||
let _stingerUntilEnded = false;
|
||||
let _lastStingerAt = -Infinity;
|
||||
let _prevStreak = 0;
|
||||
let _lastAccuracyPct = null; // from perf events; stats:recorded carries none
|
||||
let _bound = false;
|
||||
|
||||
function now() { return Date.now(); }
|
||||
@@ -259,23 +260,29 @@
|
||||
_pendingLoop = _loadingLoop;
|
||||
_loadingLoop = null;
|
||||
}
|
||||
// A loop switch deferred (or preempted) by this stinger must play
|
||||
// once the stinger is done OR failed — the machine already advanced,
|
||||
// so nothing re-triggers it later.
|
||||
const flushPending = () => {
|
||||
if (!_pendingLoop || !_venueActive) return;
|
||||
const pending = _pendingLoop;
|
||||
_pendingLoop = null;
|
||||
showLoop(pending, FADE_MS);
|
||||
};
|
||||
const back = () => {
|
||||
if (!_stingerUntilEnded) return;
|
||||
_stingerUntilEnded = false;
|
||||
video.removeEventListener('ended', back);
|
||||
// Fade back to the loop layer (which kept playing underneath).
|
||||
fadeMixTo(_activeLayer === 1 ? 1 : 0, STINGER_FADE_MS);
|
||||
// A crowd-state switch that committed mid-stinger was deferred;
|
||||
// play it now or the old loop would linger indefinitely (the
|
||||
// machine already advanced, so no later event re-triggers it).
|
||||
if (_pendingLoop) {
|
||||
const pending = _pendingLoop;
|
||||
_pendingLoop = null;
|
||||
showLoop(pending, FADE_MS);
|
||||
}
|
||||
flushPending();
|
||||
};
|
||||
loadAndPlay(video, _manifest.stingers[name], false, (ok) => {
|
||||
if (!ok || !_venueActive) { _stingerUntilEnded = false; return; }
|
||||
if (!ok || !_venueActive) {
|
||||
_stingerUntilEnded = false;
|
||||
flushPending();
|
||||
return;
|
||||
}
|
||||
video.addEventListener('ended', back);
|
||||
fadeMixTo(layer === 1 ? 1 : 0, STINGER_FADE_MS);
|
||||
// Safety: an `ended` that never fires (decode stall) must not
|
||||
@@ -288,6 +295,7 @@
|
||||
if (!_venueActive || !_manifest) return;
|
||||
bindVideosToRenderer();
|
||||
const d = (e && e.detail) || {};
|
||||
if (Number.isFinite(Number(d.accuracyPct))) _lastAccuracyPct = Number(d.accuracyPct);
|
||||
const streak = Number(d.streak) || 0;
|
||||
const sting = stingerForStreak(_prevStreak, streak);
|
||||
_prevStreak = streak;
|
||||
@@ -302,10 +310,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
function onStatsRecorded(e) {
|
||||
function onStatsRecorded() {
|
||||
if (!_venueActive || !_manifest) return;
|
||||
const d = (e && e.detail) || {};
|
||||
const sting = stingerForAccuracy(d.accuracy != null ? d.accuracy : d.accuracyPct);
|
||||
// stats:recorded carries only {filename, arrangement} — the accuracy
|
||||
// comes from the last v3:live-performance-state of the finished song.
|
||||
const sting = stingerForAccuracy(_lastAccuracyPct);
|
||||
_lastAccuracyPct = null; // one reaction per song
|
||||
if (sting) {
|
||||
_lastStingerAt = -Infinity; // end-of-song reaction always allowed
|
||||
playStinger(sting);
|
||||
|
||||
Reference in New Issue
Block a user