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 _stingerUntilEnded = false;
|
||||||
let _lastStingerAt = -Infinity;
|
let _lastStingerAt = -Infinity;
|
||||||
let _prevStreak = 0;
|
let _prevStreak = 0;
|
||||||
|
let _lastAccuracyPct = null; // from perf events; stats:recorded carries none
|
||||||
let _bound = false;
|
let _bound = false;
|
||||||
|
|
||||||
function now() { return Date.now(); }
|
function now() { return Date.now(); }
|
||||||
@@ -259,23 +260,29 @@
|
|||||||
_pendingLoop = _loadingLoop;
|
_pendingLoop = _loadingLoop;
|
||||||
_loadingLoop = null;
|
_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 = () => {
|
const back = () => {
|
||||||
if (!_stingerUntilEnded) return;
|
if (!_stingerUntilEnded) return;
|
||||||
_stingerUntilEnded = false;
|
_stingerUntilEnded = false;
|
||||||
video.removeEventListener('ended', back);
|
video.removeEventListener('ended', back);
|
||||||
// Fade back to the loop layer (which kept playing underneath).
|
// Fade back to the loop layer (which kept playing underneath).
|
||||||
fadeMixTo(_activeLayer === 1 ? 1 : 0, STINGER_FADE_MS);
|
fadeMixTo(_activeLayer === 1 ? 1 : 0, STINGER_FADE_MS);
|
||||||
// A crowd-state switch that committed mid-stinger was deferred;
|
flushPending();
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
loadAndPlay(video, _manifest.stingers[name], false, (ok) => {
|
loadAndPlay(video, _manifest.stingers[name], false, (ok) => {
|
||||||
if (!ok || !_venueActive) { _stingerUntilEnded = false; return; }
|
if (!ok || !_venueActive) {
|
||||||
|
_stingerUntilEnded = false;
|
||||||
|
flushPending();
|
||||||
|
return;
|
||||||
|
}
|
||||||
video.addEventListener('ended', back);
|
video.addEventListener('ended', back);
|
||||||
fadeMixTo(layer === 1 ? 1 : 0, STINGER_FADE_MS);
|
fadeMixTo(layer === 1 ? 1 : 0, STINGER_FADE_MS);
|
||||||
// Safety: an `ended` that never fires (decode stall) must not
|
// Safety: an `ended` that never fires (decode stall) must not
|
||||||
@@ -288,6 +295,7 @@
|
|||||||
if (!_venueActive || !_manifest) return;
|
if (!_venueActive || !_manifest) return;
|
||||||
bindVideosToRenderer();
|
bindVideosToRenderer();
|
||||||
const d = (e && e.detail) || {};
|
const d = (e && e.detail) || {};
|
||||||
|
if (Number.isFinite(Number(d.accuracyPct))) _lastAccuracyPct = Number(d.accuracyPct);
|
||||||
const streak = Number(d.streak) || 0;
|
const streak = Number(d.streak) || 0;
|
||||||
const sting = stingerForStreak(_prevStreak, streak);
|
const sting = stingerForStreak(_prevStreak, streak);
|
||||||
_prevStreak = streak;
|
_prevStreak = streak;
|
||||||
@@ -302,10 +310,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onStatsRecorded(e) {
|
function onStatsRecorded() {
|
||||||
if (!_venueActive || !_manifest) return;
|
if (!_venueActive || !_manifest) return;
|
||||||
const d = (e && e.detail) || {};
|
// stats:recorded carries only {filename, arrangement} — the accuracy
|
||||||
const sting = stingerForAccuracy(d.accuracy != null ? d.accuracy : d.accuracyPct);
|
// comes from the last v3:live-performance-state of the finished song.
|
||||||
|
const sting = stingerForAccuracy(_lastAccuracyPct);
|
||||||
|
_lastAccuracyPct = null; // one reaction per song
|
||||||
if (sting) {
|
if (sting) {
|
||||||
_lastStingerAt = -Infinity; // end-of-song reaction always allowed
|
_lastStingerAt = -Infinity; // end-of-song reaction always allowed
|
||||||
playStinger(sting);
|
playStinger(sting);
|
||||||
|
|||||||
Reference in New Issue
Block a user