ux(luci): render strategy auto-tuner inline inside section modal with visual textarea feedback
This commit is contained in:
@@ -7398,7 +7398,7 @@ function createSectionContent(section) {
|
||||
attachNfqws2RemoteValidation,
|
||||
);
|
||||
|
||||
/* zapret2 Strategy Tuner & Visual Builder Widget */
|
||||
/* zapret2 Strategy Tuner & Visual Builder Widget (INLINE) */
|
||||
o = section.taboption("settings", form.DummyValue, "_zapret2_tune_widget", "");
|
||||
o.modalonly = true;
|
||||
o.depends("action", "zapret2");
|
||||
@@ -7409,124 +7409,125 @@ function createSectionContent(section) {
|
||||
document.querySelector(`.cbi-option-nfqws2_opt textarea`);
|
||||
if (el) {
|
||||
el.value = val;
|
||||
el.style.transition = "border-color 0.3s ease, box-shadow 0.3s ease";
|
||||
el.style.borderColor = "#5cb85c";
|
||||
el.style.boxShadow = "0 0 8px rgba(92, 184, 92, 0.5)";
|
||||
setTimeout(() => {
|
||||
el.style.borderColor = "";
|
||||
el.style.boxShadow = "";
|
||||
}, 2000);
|
||||
el.dispatchEvent(new Event("change", { bubbles: true }));
|
||||
}
|
||||
uci.set(UCI_PACKAGE, section_id, "nfqws2_opt", val);
|
||||
};
|
||||
|
||||
const tuneStatusDiv = E("div", { class: "zapret2-tune-status", style: "margin-top: 8px; display: none;" });
|
||||
const sectionDomain = (uci.get(UCI_PACKAGE, section_id, "domain") || [])[0] || "googlevideo.com";
|
||||
const domainInput = E("input", { type: "text", class: "cbi-input-text", style: "width: 180px; font-size: 0.85em;", value: sectionDomain });
|
||||
const modeSelect = E("select", { class: "cbi-input-select", style: "width: 150px; font-size: 0.85em;" }, [
|
||||
E("option", { value: "express" }, _("Express scan (~5-10s)")),
|
||||
E("option", { value: "deep" }, _("Deep scan (~20s)"))
|
||||
]);
|
||||
const resultsContainer = E("div", { style: "margin-top: 8px; max-height: 200px; overflow-y: auto;" });
|
||||
const statusText = E("div", { style: "margin-top: 6px; font-size: 0.88em; font-weight: bold; color: var(--cbi-link-color, #3c96d4);" }, "");
|
||||
|
||||
const runTuneModal = () => {
|
||||
const sectionDomain = (uci.get(UCI_PACKAGE, section_id, "domain") || [])[0] || "googlevideo.com";
|
||||
const domainInput = E("input", { type: "text", class: "cbi-input-text", style: "width: 100%; font-size: 0.9em;", value: sectionDomain });
|
||||
const modeSelect = E("select", { class: "cbi-input-select", style: "width: 100%; font-size: 0.9em;" }, [
|
||||
E("option", { value: "express" }, _("Express scan (~5-10s)")),
|
||||
E("option", { value: "deep" }, _("Deep scan (~20s)"))
|
||||
]);
|
||||
const resultsContainer = E("div", { style: "margin-top: 12px; max-height: 220px; overflow-y: auto;" });
|
||||
const statusText = E("div", { style: "margin-top: 8px; font-weight: bold; color: var(--cbi-link-color, #3c96d4);" }, "");
|
||||
const startBtn = E("button", { class: "btn cbi-button cbi-button-action", type: "button", style: "padding: 2px 10px; font-size: 0.85em;" }, _("Start Auto-Tune"));
|
||||
|
||||
const modalContent = E("div", { style: "padding: 8px 4px;" }, [
|
||||
E("div", { class: "cbi-value", style: "margin-bottom: 8px;" }, [
|
||||
E("label", { class: "cbi-value-title", style: "font-size: 0.9em;" }, _("Test domain:")),
|
||||
E("div", { class: "cbi-value-field" }, domainInput)
|
||||
]),
|
||||
E("div", { class: "cbi-value", style: "margin-bottom: 8px;" }, [
|
||||
E("label", { class: "cbi-value-title", style: "font-size: 0.9em;" }, _("Scan mode:")),
|
||||
E("div", { class: "cbi-value-field" }, modeSelect)
|
||||
]),
|
||||
statusText,
|
||||
resultsContainer
|
||||
]);
|
||||
const inlineTuneCard = E("div", {
|
||||
class: "zapret2-inline-tuner-card",
|
||||
style: "display: none; margin-top: 8px; padding: 10px; border: 1px solid var(--cbi-border-color, #404040); background: rgba(0,0,0,0.2); border-radius: 4px;"
|
||||
}, [
|
||||
E("div", { style: "display: flex; flex-wrap: wrap; gap: 10px; align-items: center;" }, [
|
||||
E("span", { style: "font-size: 0.85em; color: #888;" }, _("Test domain:")), domainInput,
|
||||
E("span", { style: "font-size: 0.85em; color: #888;" }, _("Scan mode:")), modeSelect,
|
||||
startBtn
|
||||
]),
|
||||
statusText,
|
||||
resultsContainer
|
||||
]);
|
||||
|
||||
const startBtn = E("button", { class: "btn cbi-button cbi-button-action", type: "button" }, _("Start Auto-Tune"));
|
||||
const closeBtn = E("button", { class: "btn cbi-button cbi-button-neutral", type: "button" }, _("Close"));
|
||||
startBtn.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
const targetDomain = domainInput.value.trim() || "googlevideo.com";
|
||||
const selectedMode = modeSelect.value;
|
||||
startBtn.disabled = true;
|
||||
statusText.style.color = "var(--cbi-link-color, #3c96d4)";
|
||||
statusText.textContent = _("Running strategy probes...");
|
||||
resultsContainer.innerHTML = "";
|
||||
|
||||
startBtn.addEventListener("click", () => {
|
||||
const targetDomain = domainInput.value.trim() || "googlevideo.com";
|
||||
const selectedMode = modeSelect.value;
|
||||
startBtn.disabled = true;
|
||||
statusText.textContent = _("Running strategy probes...");
|
||||
resultsContainer.innerHTML = "";
|
||||
fs.exec("/usr/bin/tachyon", ["zapret2_tune", section_id, targetDomain, selectedMode])
|
||||
.then((res) => {
|
||||
startBtn.disabled = false;
|
||||
let data = null;
|
||||
try {
|
||||
data = JSON.parse(res.stdout || "{}");
|
||||
} catch (err) {
|
||||
statusText.style.color = "var(--cbi-color-warning, #d9534f)";
|
||||
statusText.textContent = _("Failed to parse tuner response.");
|
||||
return;
|
||||
}
|
||||
|
||||
fs.exec("/usr/bin/tachyon", ["zapret2_tune", section_id, targetDomain, selectedMode])
|
||||
.then((res) => {
|
||||
startBtn.disabled = false;
|
||||
let data = null;
|
||||
try {
|
||||
data = JSON.parse(res.stdout || "{}");
|
||||
} catch (e) {
|
||||
statusText.textContent = _("Failed to parse tuner response.");
|
||||
return;
|
||||
}
|
||||
if (!data || !data.success || !data.winning_strategy) {
|
||||
statusText.style.color = "var(--cbi-color-warning, #d9534f)";
|
||||
statusText.textContent = (data && data.message) ? data.message : _("No working desync strategy found for this domain.");
|
||||
} else {
|
||||
statusText.style.color = "var(--cbi-color-success, #5cb85c)";
|
||||
statusText.textContent = _("Auto-Tune complete! Winning strategy: ") + (data.winning_preset_name || "");
|
||||
}
|
||||
|
||||
if (!data || !data.success || !data.winning_strategy) {
|
||||
statusText.style.color = "var(--cbi-color-warning, #d9534f)";
|
||||
statusText.textContent = (data && data.message) ? data.message : _("No working desync strategy found for this domain.");
|
||||
} else {
|
||||
statusText.style.color = "var(--cbi-color-success, #5cb85c)";
|
||||
statusText.textContent = _("Auto-Tune complete! Winning strategy: ") + (data.winning_preset_name || "");
|
||||
}
|
||||
|
||||
const rows = (data.results || []).map((r) => {
|
||||
const applyBtn = E("button", { class: "btn cbi-button cbi-button-save", type: "button", style: "padding: 1px 6px; font-size: 0.8em;" }, _("Apply"));
|
||||
applyBtn.addEventListener("click", () => {
|
||||
setNfqws2OptTextarea(r.opt);
|
||||
if (typeof ui !== "undefined" && ui.addNotification) {
|
||||
ui.addNotification(null, E("p", {}, _("Strategy applied to section!")), "info");
|
||||
}
|
||||
});
|
||||
|
||||
return E("tr", { style: r.success ? "background: rgba(0,255,0,0.05);" : "opacity: 0.6;" }, [
|
||||
E("td", { style: "padding: 4px; font-size: 0.85em; font-weight: bold;" }, r.name),
|
||||
E("td", { style: "padding: 4px; font-size: 0.85em;" }, r.success ? `${r.rtt_ms} ms (${r.message})` : _("Failed")),
|
||||
E("td", { style: "padding: 4px;" }, applyBtn)
|
||||
]);
|
||||
const rows = (data.results || []).map((r) => {
|
||||
const applyBtn = E("button", { class: "btn cbi-button cbi-button-save", type: "button", style: "padding: 1px 6px; font-size: 0.8em;" }, _("Apply"));
|
||||
applyBtn.addEventListener("click", (evt) => {
|
||||
evt.preventDefault();
|
||||
setNfqws2OptTextarea(r.opt);
|
||||
if (typeof ui !== "undefined" && ui.addNotification) {
|
||||
ui.addNotification(null, E("p", {}, _("Strategy applied to section!")), "info");
|
||||
}
|
||||
});
|
||||
|
||||
const table = E("table", { class: "table", style: "width: 100%; border-collapse: collapse;" }, [
|
||||
E("thead", {}, [
|
||||
E("tr", {}, [
|
||||
E("th", { style: "text-align: left; font-size: 0.85em;" }, _("Preset")),
|
||||
E("th", { style: "text-align: left; font-size: 0.85em;" }, _("Status / RTT")),
|
||||
E("th", { style: "text-align: left; font-size: 0.85em;" }, _("Action"))
|
||||
])
|
||||
]),
|
||||
E("tbody", {}, rows)
|
||||
return E("tr", { style: r.success ? "background: rgba(0,255,0,0.05);" : "opacity: 0.6;" }, [
|
||||
E("td", { style: "padding: 4px; font-size: 0.85em; font-weight: bold;" }, r.name),
|
||||
E("td", { style: "padding: 4px; font-size: 0.85em;" }, r.success ? `${r.rtt_ms} ms (${r.message})` : _("Failed")),
|
||||
E("td", { style: "padding: 4px;" }, applyBtn)
|
||||
]);
|
||||
|
||||
resultsContainer.appendChild(table);
|
||||
|
||||
if (data.winning_strategy) {
|
||||
setNfqws2OptTextarea(data.winning_strategy);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
startBtn.disabled = false;
|
||||
statusText.textContent = _("Error running tuner: ") + err;
|
||||
});
|
||||
});
|
||||
|
||||
closeBtn.addEventListener("click", () => {
|
||||
if (typeof ui !== "undefined" && ui.hideModal) {
|
||||
ui.hideModal();
|
||||
}
|
||||
});
|
||||
const table = E("table", { class: "table", style: "width: 100%; border-collapse: collapse; margin-top: 6px;" }, [
|
||||
E("thead", {}, [
|
||||
E("tr", {}, [
|
||||
E("th", { style: "text-align: left; font-size: 0.85em;" }, _("Preset")),
|
||||
E("th", { style: "text-align: left; font-size: 0.85em;" }, _("Status / RTT")),
|
||||
E("th", { style: "text-align: left; font-size: 0.85em;" }, _("Action"))
|
||||
])
|
||||
]),
|
||||
E("tbody", {}, rows)
|
||||
]);
|
||||
|
||||
if (typeof ui !== "undefined" && ui.showModal) {
|
||||
ui.showModal(_("zapret2 Strategy Auto-Tuner"), [modalContent, E("div", { class: "right" }, [startBtn, " ", closeBtn])]);
|
||||
}
|
||||
};
|
||||
resultsContainer.appendChild(table);
|
||||
|
||||
if (data.winning_strategy) {
|
||||
setNfqws2OptTextarea(data.winning_strategy);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
startBtn.disabled = false;
|
||||
statusText.style.color = "var(--cbi-color-warning, #d9534f)";
|
||||
statusText.textContent = _("Error running tuner: ") + err;
|
||||
});
|
||||
});
|
||||
|
||||
const tuneBtn = E("button", {
|
||||
class: "btn cbi-button cbi-button-action",
|
||||
type: "button",
|
||||
style: "margin-top: 6px; margin-bottom: 10px; font-weight: bold; background-color: var(--cbi-link-color, #2b78e4); color: #fff;"
|
||||
style: "margin-top: 6px; margin-bottom: 6px; font-weight: bold; background-color: var(--cbi-link-color, #2b78e4); color: #fff;"
|
||||
}, _("Auto-Tune Strategy"));
|
||||
|
||||
tuneBtn.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
runTuneModal();
|
||||
if (inlineTuneCard.style.display === "none") {
|
||||
inlineTuneCard.style.display = "block";
|
||||
} else {
|
||||
inlineTuneCard.style.display = "none";
|
||||
}
|
||||
});
|
||||
|
||||
const methodSelect = E("select", { class: "cbi-input-select", style: "width: 140px; font-size: 0.85em;" }, [
|
||||
@@ -7582,8 +7583,8 @@ function createSectionContent(section) {
|
||||
|
||||
return E("div", { class: "zapret2-tune-field" }, [
|
||||
tuneBtn,
|
||||
builderDetails,
|
||||
tuneStatusDiv
|
||||
inlineTuneCard,
|
||||
builderDetails
|
||||
]);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user