build121 - можно создавать шорткаты без обязательно снятия оверлея

This commit is contained in:
2026-08-26 14:12:05 +03:00
parent 6256f54fdf
commit 41ca064b3b
2 changed files with 27 additions and 28 deletions

2
app.py
View File

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

View File

@@ -2538,14 +2538,13 @@ function startCustomTooltips() {
prevent_default: sequence.prevent_default !== false, prevent_default: sequence.prevent_default !== false,
allow_in_inputs: Boolean(sequence.allow_in_inputs), allow_in_inputs: Boolean(sequence.allow_in_inputs),
toggle_all_overlays_on_repeat: Boolean(sequence.toggle_all_overlays_on_repeat), toggle_all_overlays_on_repeat: Boolean(sequence.toggle_all_overlays_on_repeat),
// BUILD117: keep the legacy toggle flag for config compatibility, but let the // BUILD121: overlay repeat-out targets are optional. Generic shortcuts do not
// operator choose exactly which vMix overlay channels are taken OUT on repeat. // necessarily control graphics, so an empty selection is valid and is the default.
// Existing scoreboard configs had no list, so the safe default remains 1/2/3. // Existing saved selections are preserved exactly. The dedicated scoreboard preset
// BUILD118 exposes vMix 29 Overlay channels 1..8 while leaving 4..8 untouched by default. // still explicitly creates O1/O2/O3 because that preset is a graphics shortcut.
repeat_overlay_outs: (() => { repeat_overlay_outs: (() => {
const raw = Array.isArray(sequence.repeat_overlay_outs) ? sequence.repeat_overlay_outs : [1, 2, 3]; const raw = Array.isArray(sequence.repeat_overlay_outs) ? sequence.repeat_overlay_outs : [];
const normalized = [...new Set(raw.map((value) => Number(value)).filter((value) => Number.isInteger(value) && value >= 1 && value <= 8))]; return [...new Set(raw.map((value) => Number(value)).filter((value) => Number.isInteger(value) && value >= 1 && value <= 8))];
return normalized.length ? normalized : [1, 2, 3];
})(), })(),
sync_hockey_team_states: sequence.sync_hockey_team_states === undefined sync_hockey_team_states: sequence.sync_hockey_team_states === undefined
? Boolean(sequence.toggle_all_overlays_on_repeat) ? Boolean(sequence.toggle_all_overlays_on_repeat)
@@ -5564,22 +5563,25 @@ function startCustomTooltips() {
// BUILD118: repeat OUT is configurable across vMix Overlay channels 1..8. Do not use // BUILD118: repeat OUT is configurable across vMix Overlay channels 1..8. Do not use
// OverlayInputAllOff: explicit OverlayInputNOut preserves each configured // OverlayInputAllOff: explicit OverlayInputNOut preserves each configured
// transition-out and avoids touching unrelated channels that are not selected. // transition-out and avoids touching unrelated channels that are not selected.
const repeatOverlayOuts = (Array.isArray(sequence.repeat_overlay_outs) ? sequence.repeat_overlay_outs : [1, 2, 3]) const selectedOverlayOuts = (Array.isArray(sequence.repeat_overlay_outs) ? sequence.repeat_overlay_outs : [])
.map((value) => Number(value)) .map((value) => Number(value))
.filter((value, index, values) => Number.isInteger(value) && value >= 1 && value <= 8 && values.indexOf(value) === index); .filter((value, index, values) => Number.isInteger(value) && value >= 1 && value <= 8 && values.indexOf(value) === index);
const selectedOverlayOuts = repeatOverlayOuts.length ? repeatOverlayOuts : [1, 2, 3]; // Empty is intentionally valid: a shortcut may have no graphics/Overlay action.
await sendRuntimeVmixSequence( // In that case do not swallow the repeat press; execute its normal steps below.
selectedOverlayOuts.map((number) => ({ Function: `OverlayInput${number}Out` })), if (selectedOverlayOuts.length) {
execution, await sendRuntimeVmixSequence(
); selectedOverlayOuts.map((number) => ({ Function: `OverlayInput${number}Out` })),
if (sequence.sync_hockey_team_states) hockeyClearTeamStateOverlayTracking(); execution,
state.shortcutSequenceOverlayState.set(sequence.id, false); );
state.quickPanelOnAirSequences.delete(String(sequence.id || "")); if (sequence.sync_hockey_team_states) hockeyClearTeamStateOverlayTracking();
refreshQuickPanelOnAirClasses(); state.shortcutSequenceOverlayState.set(sequence.id, false);
window.dispatchEvent(new CustomEvent("ui-builder:shortcut-sequence-finish", { detail: { sequence: clone(sequence), meta: { ...meta, overlay_group_action: "off" } } })); state.quickPanelOnAirSequences.delete(String(sequence.id || ""));
if (meta.source === "quick-panel-button") toast(`Выполнено: ${sequence.name} · кнопка «${meta.button_label || sequence.name}»`); refreshQuickPanelOnAirClasses();
else if (String(meta.source || "").startsWith("keyboard")) toast(`Шорткат выполнен: ${sequence.name}`); window.dispatchEvent(new CustomEvent("ui-builder:shortcut-sequence-finish", { detail: { sequence: clone(sequence), meta: { ...meta, overlay_group_action: "off" } } }));
return true; if (meta.source === "quick-panel-button") toast(`Выполнено: ${sequence.name} · кнопка «${meta.button_label || sequence.name}»`);
else if (String(meta.source || "").startsWith("keyboard")) toast(`Шорткат выполнен: ${sequence.name}`);
return true;
}
} }
if (sequence.is_scoreboard_sequence) { if (sequence.is_scoreboard_sequence) {
await syncConfiguredScoreboardCountdownsToRuntime(); await syncConfiguredScoreboardCountdownsToRuntime();
@@ -14391,7 +14393,7 @@ function renderHockeyPenaltyDashboard(node, component, runtime) {
<label class="check-inline"><input type="checkbox" data-sequence-overlay-group ${sequence.toggle_all_overlays_on_repeat ? "checked" : ""}> повторное нажатие снимает выбранные Overlay</label> <label class="check-inline"><input type="checkbox" data-sequence-overlay-group ${sequence.toggle_all_overlays_on_repeat ? "checked" : ""}> повторное нажатие снимает выбранные Overlay</label>
<span class="check-inline" data-sequence-overlay-outs-wrap> <span class="check-inline" data-sequence-overlay-outs-wrap>
снять: снять:
${[1, 2, 3, 4, 5, 6, 7, 8].map((number) => `<label class="check-inline"><input type="checkbox" data-sequence-overlay-out="${number}" ${(sequence.repeat_overlay_outs || [1, 2, 3]).includes(number) ? "checked" : ""}> O${number}</label>`).join("")} ${[1, 2, 3, 4, 5, 6, 7, 8].map((number) => `<label class="check-inline"><input type="checkbox" data-sequence-overlay-out="${number}" ${(sequence.repeat_overlay_outs || []).includes(number) ? "checked" : ""}> O${number}</label>`).join("")}
</span> </span>
<label class="check-inline"><input type="checkbox" data-sequence-scoreboard ${sequence.is_scoreboard_sequence ? "checked" : ""}> этот сценарий — верхний счёт</label> <label class="check-inline"><input type="checkbox" data-sequence-scoreboard ${sequence.is_scoreboard_sequence ? "checked" : ""}> этот сценарий — верхний счёт</label>
<label class="check-inline"><input type="checkbox" data-sequence-team-states ${sequence.sync_hockey_team_states ? "checked" : ""}> добавлять состояния команд к верхнему счёту</label> <label class="check-inline"><input type="checkbox" data-sequence-team-states ${sequence.sync_hockey_team_states ? "checked" : ""}> добавлять состояния команд к верхнему счёту</label>
@@ -14430,11 +14432,8 @@ function renderHockeyPenaltyDashboard(node, component, runtime) {
const selected = [...card.querySelectorAll("[data-sequence-overlay-out]:checked")] const selected = [...card.querySelectorAll("[data-sequence-overlay-out]:checked")]
.map((item) => Number(item.dataset.sequenceOverlayOut)) .map((item) => Number(item.dataset.sequenceOverlayOut))
.filter((value) => Number.isInteger(value) && value >= 1 && value <= 8); .filter((value) => Number.isInteger(value) && value >= 1 && value <= 8);
if (!selected.length) { // BUILD121: zero selected overlays is valid. Some shortcuts do not put any
event.target.checked = true; // graphics on air, so there is nothing that must be taken OUT on repeat.
toast("Для повторного снятия выберите хотя бы один Overlay");
return;
}
sequence.repeat_overlay_outs = selected; sequence.repeat_overlay_outs = selected;
})); }));
card.querySelector("[data-sequence-scoreboard]").addEventListener("change", (event) => { card.querySelector("[data-sequence-scoreboard]").addEventListener("change", (event) => {