This commit is contained in:
2026-09-23 15:22:18 +03:00
parent d4f97b80bf
commit 52efc99211
2 changed files with 12 additions and 11 deletions

2
app.py
View File

@@ -30,7 +30,7 @@ from ui_builder import install_ui_builder
from khl_site.khl_data_center import APP as khl_site_app
BASE_DIR = Path(__file__).resolve().parent
BUILD_VERSION = "2026.09.23.4"
BUILD_VERSION = "2026.09.23.5"
# compatibility: BUILD_VERSION = "2026.08.26.1"
# compatibility: BUILD_VERSION = "2026.08.25.1"
# compatibility: BUILD_VERSION = "2026.08.24.15"

View File

@@ -1,3 +1,4 @@
// BUILD158_SETCOUNTDOWN_SUSPENDCOUNTDOWN
// BUILD155: all hockey game/penalty timers use native vMix Countdown; no per-second SetText mirroring.
// BUILD153: settings freeze all data-driven DOM rendering and keep dropdown popovers open.
// BUILD152: all browser-side hockey data polling pauses while operator settings are open.
@@ -4260,23 +4261,23 @@ function startCustomTooltips() {
}
function vmixGameCountdownControlCommands(input, selectedName, millisecondsProvider, action = "start") {
// BUILD157: Runtime is authoritative at every operator Start/Resume transition.
// We seed the CURRENT native vMix countdown position once at that transition and
// then let vMix count locally. There is still absolutely no per-second vMix write.
// This deliberately removes BUILD108/156's fragile browser-only "seeded" assumption:
// vMix may have been restarted/reloaded while the browser still remembered the target.
// BUILD158: restore the proven BUILD93/105 native-countdown transport.
// Runtime supplies the countdown duration/value once on each Start/Resume via
// SetCountdown, then vMix counts locally. A pause uses SuspendCountdown so the
// native countdown is stopped without StopCountdown's reset-to-start behaviour.
// There is never any per-second vMix timer write in this path.
const target = { Input: String(input || "").trim(), SelectedName: String(selectedName || "").trim() };
if (!target.Input || !target.SelectedName) return [];
if (action === "pause" || action === "stop") {
return [{ Function: "PauseCountdown", ...target }];
return [{ Function: "SuspendCountdown", ...target }];
}
const milliseconds = typeof millisecondsProvider === "function" ? millisecondsProvider() : millisecondsProvider;
const value = vmixCountdownValue(milliseconds);
if (action === "set") {
return [{ Function: "ChangeCountdown", ...target, Value: value }];
return [{ Function: "SetCountdown", ...target, Value: value }];
}
return [
{ Function: "ChangeCountdown", ...target, Value: value },
{ Function: "SetCountdown", ...target, Value: value },
{ Function: "StartCountdown", ...target },
];
}
@@ -5533,7 +5534,7 @@ function startCustomTooltips() {
step.game_vmix_input, step.game_vmix_selected_name, () => gameTimerState.currentMs, "pause"
));
} else {
// BUILD157: every Start/Resume re-seeds from the current Runtime value once,
// BUILD158: every Start/Resume sends SetCountdown from the current Runtime value,
// then starts the native countdown. vMix performs the second-by-second count
// locally; Runtime never mirrors timer_tick values to vMix.
commands.push(...vmixGameCountdownControlCommands(
@@ -5572,7 +5573,7 @@ function startCustomTooltips() {
eventKey, input: target.input, selectedName: target.selected_name, overlay: target.overlay, sourceSide, targetSide: side, mode: "countdown", running: eventRunning,
});
// BUILD157: penalty countdowns use the same robust transition model as
// BUILD158: penalty countdowns use the restored SetCountdown transition model as
// the game clock. Every Start/Resume sends current remaining time once and
// StartCountdown, then vMix counts locally. Pause remains a native pause.
if (pausing || !eventRunning) {