Fix typos and improve comments in ZapretManager_LuCI.sh

This commit is contained in:
StressOzz authored and GitHub committed 2026-09-13 20:14:16 +05:00
1 parent d8468bd153
commit 74b0045a3f
1 file changed
+2 -68
+2 -68
View File
@@ -1,5 +1,5 @@
#!/bin/sh #!/bin/sh
# Zapret Manager by Stressozz LuCI installer — самодостаточный скрипт (все файлы зашиты внутри). # Zapret Manager by StressOzz LuCI installer — самодостаточный скрипт (все файлы зашиты внутри).
set -e set -e
GREEN="\033[1;32m"; CYAN="\033[1;36m"; YELLOW="\033[1;33m"; MAGENTA="\033[1;35m"; BLUE="\033[0;34m"; NC="\033[0m"; DGRAY="\033[38;5;244m" GREEN="\033[1;32m"; CYAN="\033[1;36m"; YELLOW="\033[1;33m"; MAGENTA="\033[1;35m"; BLUE="\033[0;34m"; NC="\033[0m"; DGRAY="\033[38;5;244m"
@@ -1480,12 +1480,6 @@ tg_status() {
fi fi
[ -f "$TG_SECRET_MT_FILE" ] && secret_mt=$(grep '^SECRET=' "$TG_SECRET_MT_FILE" | cut -d= -f2) [ -f "$TG_SECRET_MT_FILE" ] && secret_mt=$(grep '^SECRET=' "$TG_SECRET_MT_FILE" | cut -d= -f2)
# Ключ Rust-прокси. Оригинальный консольный скрипт никогда не писал его в
# отдельный файл — он всегда встроен прямо в команду запуска init.d-скрипта
# (--secret <hex>). Если установка была сделана через SSH оригинальным
# скриптом (а не через эту панель), нашего файла $TG_SECRET_RS_FILE попросту
# не существует — поэтому читаем ключ из самого init.d-скрипта, это работает
# независимо от того, чем ставили: нашей панелью или оригинальным SSH-скриптом.
if [ -f "$TG_INIT_RS" ]; then if [ -f "$TG_INIT_RS" ]; then
secret_rs=$(sed -n 's/.*--secret[[:space:]]*\([0-9a-fA-F]\{32\}\).*/\1/p' "$TG_INIT_RS" | head -n1) secret_rs=$(sed -n 's/.*--secret[[:space:]]*\([0-9a-fA-F]\{32\}\).*/\1/p' "$TG_INIT_RS" | head -n1)
fi fi
@@ -2034,21 +2028,13 @@ var callDohInstall = rpc.declare({ object: 'zapret-manager', method: 'doh_instal
var callDohRemove = rpc.declare({ object: 'zapret-manager', method: 'doh_remove', expect: {} }); var callDohRemove = rpc.declare({ object: 'zapret-manager', method: 'doh_remove', expect: {} });
var callDohSet = rpc.declare({ object: 'zapret-manager', method: 'doh_set', params: ['provider'], expect: {} }); var callDohSet = rpc.declare({ object: 'zapret-manager', method: 'doh_set', params: ['provider'], expect: {} });
// Некоторые прошивки (например FriendlyWrt) переписывают тему LuCI целиком
// и не объявляют переменную --background-color-medium вообще — тогда наш
// var(--background-color-medium, #fff) молча берёт запасное значение #fff,
// и карточки становятся белыми посреди тёмной страницы. Если же переменная
// объявлена (как на ванильной OpenWrt) — она уже работает правильно сама,
// трогать вообще ничего не нужно.
function detectMissingThemeVar() { function detectMissingThemeVar() {
if (document.documentElement.hasAttribute('data-zm-theme-checked')) return; if (document.documentElement.hasAttribute('data-zm-theme-checked')) return;
document.documentElement.setAttribute('data-zm-theme-checked', '1'); document.documentElement.setAttribute('data-zm-theme-checked', '1');
try { try {
var declared = getComputedStyle(document.documentElement).getPropertyValue('--background-color-medium').trim(); var declared = getComputedStyle(document.documentElement).getPropertyValue('--background-color-medium').trim();
if (declared) return; // тема сама её объявляет — ничего не делаем, это уже рабочий случай if (declared) return;
// переменная не объявлена этой темой — определяем реальный цвет фона
// страницы и, если он тёмный, включаем свой запасной тёмный вид
var el = document.body, bg = '', hops = 0; var el = document.body, bg = '', hops = 0;
while (el && hops < 6) { while (el && hops < 6) {
var c = getComputedStyle(el).backgroundColor; var c = getComputedStyle(el).backgroundColor;
@@ -2081,9 +2067,6 @@ function badge(ok, textOk, textBad) {
]); ]);
} }
// Раскрашивает построчный вывод (==> сообщения) для читаемости: стрелки —
// голубым, обычные шаги — жёлтым, успешные/готово — зелёным, ошибки — красным,
// !! предупреждения — оранжевым; необработанный вывод команд — приглушённым серым.
function renderLog(logEl, text) { function renderLog(logEl, text) {
logEl.innerHTML = ''; logEl.innerHTML = '';
var lines = (text || '').split('\n'); var lines = (text || '').split('\n');
@@ -2129,11 +2112,6 @@ function pollJob(job, logEl, onDone, onTick) {
onDone(st.rc === '0'); onDone(st.rc === '0');
} }
}).catch(function() { }).catch(function() {
// Одиночная неудача опроса (роутер занят распаковкой/установкой —
// временная заминка) не должна навсегда останавливать поллинг:
// сама операция на роутере продолжает идти в фоне независимо от
// того, отвечает ли сейчас веб-интерфейс. Останавливаемся только
// после нескольких подряд неудач и явно предупреждаем.
failCount++; failCount++;
if (failCount >= 8) { if (failCount >= 8) {
clearInterval(timer); clearInterval(timer);
@@ -2149,11 +2127,6 @@ function refreshBanner(message) {
E('button', { E('button', {
'class': 'cbi-button cbi-button-positive', 'class': 'cbi-button cbi-button-positive',
'click': function() { 'click': function() {
// Разрываем сессию в фоне, затем перезагружаем ИМЕННО текущую
// страницу (а не отдельный URL logout) — LuCI при недействительной
// сессии сама показывает форму входа прямо на этом адресе и после
// успешного входа возвращает сюда же (штатное поведение при
// истечении сессии, тут просто используем его напрямую).
fetch(L.url('admin/logout'), { credentials: 'same-origin' }).catch(function() {}).then(function() { fetch(L.url('admin/logout'), { credentials: 'same-origin' }).catch(function() {}).then(function() {
location.reload(); location.reload();
}); });
@@ -2162,7 +2135,6 @@ function refreshBanner(message) {
]); ]);
} }
// ---------- собственные всплывающие уведомления (не системные LuCI) ----------
function toastContainer() { function toastContainer() {
var c = document.getElementById('zm-toast-container'); var c = document.getElementById('zm-toast-container');
@@ -3266,10 +3238,6 @@ cat > '/www/luci-static/resources/view/zapret-manager/style.css' << 'ZM_INSTALLE
transition: box-shadow .15s; transition: box-shadow .15s;
} }
/* Запасной тёмный вид — включается через JS ТОЛЬКО если тема прошивки не
объявляет переменную --background-color-medium сама (тогда выше сработал
бы статичный светлый запасной #fff даже на тёмной странице). Если тема
объявляет переменную — этот блок вообще не применяется, ничего не меняется. */
html.zm-theme-dark .zm-card { html.zm-theme-dark .zm-card {
background: #1c2128; background: #1c2128;
border-color: rgba(255,255,255,.10); border-color: rgba(255,255,255,.10);
@@ -3279,8 +3247,6 @@ html.zm-theme-dark .zm-card {
.zm-card h3 { margin: 0 0 12px 0; font-size: 15px; font-weight: 600; display: flex; align-items: center; gap: 8px; } .zm-card h3 { margin: 0 0 12px 0; font-size: 15px; font-weight: 600; display: flex; align-items: center; gap: 8px; }
/* Строка "подпись: значение" — подпись и значение стоят РЯДОМ (умеренный
отступ), а не растянуты в разные концы широкой карточки. */
.zm-row { display: flex; align-items: center; gap: 12px; margin: 7px 0; font-size: 13px; flex-wrap: wrap; } .zm-row { display: flex; align-items: center; gap: 12px; margin: 7px 0; font-size: 13px; flex-wrap: wrap; }
.zm-row .zm-label { opacity: .65; flex-shrink: 0; } .zm-row .zm-label { opacity: .65; flex-shrink: 0; }
.zm-row > span:last-child { overflow-wrap: anywhere; } .zm-row > span:last-child { overflow-wrap: anywhere; }
@@ -3300,8 +3266,6 @@ html.zm-theme-dark .zm-card {
.zm-actions { display: flex; gap: 12px; flex-wrap: wrap; align-items: center; margin: 14px 0; } .zm-actions { display: flex; gap: 12px; flex-wrap: wrap; align-items: center; margin: 14px 0; }
.zm-actions .cbi-button { margin: 0; } .zm-actions .cbi-button { margin: 0; }
/* Плитки: flex вместо grid — компактные "чипы" по контенту, а не растянутые
на всю колонку, аккуратно переносятся на новую строку. */
.zm-grid { display: flex; flex-wrap: wrap; gap: 9px; } .zm-grid { display: flex; flex-wrap: wrap; gap: 9px; }
.zm-tile { .zm-tile {
@@ -3319,10 +3283,6 @@ html.zm-theme-dark .zm-card {
transition: border-color .15s, background .15s, transform .1s; transition: border-color .15s, background .15s, transform .1s;
background: var(--background-color-low, #fafafa); background: var(--background-color-low, #fafafa);
} }
/* Только для нейтрального состояния плитки — активные (.zm-active) и
выключенные (.zm-tile-off) уже раскрашены полупрозрачным зелёным/красным
поверх фона и одинаково хорошо читаются что на светлом, что на тёмном
фоне, поэтому их сюда специально не включаем. */
html.zm-theme-dark .zm-tile:not(.zm-active):not(.zm-tile-off) { html.zm-theme-dark .zm-tile:not(.zm-active):not(.zm-tile-off) {
background: #22272e; background: #22272e;
border-color: rgba(255,255,255,.12); border-color: rgba(255,255,255,.12);
@@ -3335,8 +3295,6 @@ html.zm-theme-dark .zm-tile:not(.zm-active):not(.zm-tile-off) {
} }
.zm-tile.zm-active::before { content: "✓ "; } .zm-tile.zm-active::before { content: "✓ "; }
/* Отдельное состояние для "выключено/не исключено" (например, Исключения IP) —
красным с крестиком, отличное от обычного нейтрального "не активно". */
.zm-tile.zm-tile-off { .zm-tile.zm-tile-off {
border-color: rgba(207,34,46,.35); background: rgba(207,34,46,.08); border-color: rgba(207,34,46,.35); background: rgba(207,34,46,.08);
color: #cf222e; font-weight: 600; color: #cf222e; font-weight: 600;
@@ -3346,10 +3304,6 @@ html.zm-theme-dark .zm-tile:not(.zm-active):not(.zm-tile-off) {
.zm-tile.zm-tile-pending { opacity: .55; border-style: dashed; cursor: not-allowed; } .zm-tile.zm-tile-pending { opacity: .55; border-style: dashed; cursor: not-allowed; }
.zm-tile.zm-tile-pending:hover { border-color: rgba(0,0,0,.1); transform: none; } .zm-tile.zm-tile-pending:hover { border-color: rgba(0,0,0,.1); transform: none; }
/* Живой вывод действий (установка/тест/и т.д.) — большая, ясно видимая
консоль вместо мелкой полоски: крупнее шрифт, больше высоты, чёткая рамка.
white-space: pre-wrap — длинные строки (URL и т.п.) переносятся ВНИЗ,
а не вылезают вправо за пределы карточки. */
.zm-log { .zm-log {
background: #0d1117; color: #e6edf3; background: #0d1117; color: #e6edf3;
font-family: ui-monospace, "SF Mono", "Cascadia Code", Consolas, "Liberation Mono", monospace; font-family: ui-monospace, "SF Mono", "Cascadia Code", Consolas, "Liberation Mono", monospace;
@@ -3365,7 +3319,6 @@ html.zm-theme-dark .zm-tile:not(.zm-active):not(.zm-tile-off) {
.zm-log.zm-show { display: block; } .zm-log.zm-show { display: block; }
.zm-log:empty::before { content: "Ожидание вывода..."; opacity: .4; } .zm-log:empty::before { content: "Ожидание вывода..."; opacity: .4; }
/* Раскраска построчного вывода (==> сообщения) для читаемости. */
.zm-log-arrow { color: #56d4dd; font-weight: 700; } .zm-log-arrow { color: #56d4dd; font-weight: 700; }
.zm-log-msg-info { color: #e3c04a; } .zm-log-msg-info { color: #e3c04a; }
.zm-log-msg-ok { color: #3fb950; font-weight: 600; } .zm-log-msg-ok { color: #3fb950; font-weight: 600; }
@@ -3375,8 +3328,6 @@ html.zm-theme-dark .zm-tile:not(.zm-active):not(.zm-tile-off) {
.zm-hint { font-size: 12px; opacity: .65; margin-top: 6px; line-height: 1.5; overflow-wrap: break-word; } .zm-hint { font-size: 12px; opacity: .65; margin-top: 6px; line-height: 1.5; overflow-wrap: break-word; }
/* Уведомление о необходимости обновить страницу LuCI после установки/удаления
пакетов, добавляющих собственные меню (luci-app-*). */
.zm-refresh-banner { .zm-refresh-banner {
display: flex; align-items: center; justify-content: space-between; gap: 14px; display: flex; align-items: center; justify-content: space-between; gap: 14px;
background: rgba(191,135,0,.12); border: 2px solid rgba(191,135,0,.35); background: rgba(191,135,0,.12); border: 2px solid rgba(191,135,0,.35);
@@ -3385,8 +3336,6 @@ html.zm-theme-dark .zm-tile:not(.zm-active):not(.zm-tile-off) {
} }
.zm-refresh-banner button { flex-shrink: 0; } .zm-refresh-banner button { flex-shrink: 0; }
/* Собственные всплывающие уведомления — вместо системных баннеров LuCI.
Сделаны крупными и заметными по запросу (увеличены повторно). */
#zm-toast-container { #zm-toast-container {
position: fixed; top: 20px; right: 20px; z-index: 10000; position: fixed; top: 20px; right: 20px; z-index: 10000;
display: flex; flex-direction: column; gap: 14px; display: flex; flex-direction: column; gap: 14px;
@@ -3411,8 +3360,6 @@ html.zm-theme-dark .zm-tile:not(.zm-active):not(.zm-tile-off) {
.zm-toast-warning .zm-toast-icon { color: #e3b341; } .zm-toast-warning .zm-toast-icon { color: #e3b341; }
.zm-toast-text { overflow-wrap: anywhere; } .zm-toast-text { overflow-wrap: anywhere; }
/* Крупная плитка со ссылкой для вставки в Telegram (tg://proxy / tg://socks) —
отдельно от узких карточек статуса, чтобы длинная ссылка помещалась целиком. */
.zm-tg-link-card { .zm-tg-link-card {
background: rgba(26,127,55,.06); background: rgba(26,127,55,.06);
border: 1px solid rgba(26,127,55,.25); border: 1px solid rgba(26,127,55,.25);
@@ -3433,8 +3380,6 @@ html.zm-theme-dark .zm-tile:not(.zm-active):not(.zm-tile-off) {
.zm-tg-link-row { display: flex; align-items: flex-start; gap: 10px; } .zm-tg-link-row { display: flex; align-items: flex-start; gap: 10px; }
.zm-tg-link-row .zm-tg-link-box { flex: 1 1 auto; } .zm-tg-link-row .zm-tg-link-box { flex: 1 1 auto; }
/* Заметный индикатор "что сейчас используется/применено" на страницах
стратегий/DoH/hosts/fake. */
.zm-current-banner { .zm-current-banner {
display: flex; align-items: center; gap: 10px; flex-wrap: wrap; display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
background: rgba(26,127,55,.07); border: 1px solid rgba(26,127,55,.22); background: rgba(26,127,55,.07); border: 1px solid rgba(26,127,55,.22);
@@ -3445,12 +3390,6 @@ html.zm-theme-dark .zm-tile:not(.zm-active):not(.zm-tile-off) {
background: rgba(110,118,129,.08); border-color: rgba(110,118,129,.2); background: rgba(110,118,129,.08); border-color: rgba(110,118,129,.2);
} }
/* Наши страницы не используют UCI-формы LuCI (никакие uci.set/save не
вызываются) — стандартная панель "Save & Apply / Save / Reset" здесь
ничего не делает и только сбивает с толку. Скрываем её, пока наш CSS
загружен (то есть только на страницах Zapret Manager — при переходе на
любую другую страницу LuCI загружается заново без нашего style.css, и
панель снова появится там, где она реально нужна). */
.cbi-page-actions { display: none !important; } .cbi-page-actions { display: none !important; }
ZM_INSTALLER_EOF ZM_INSTALLER_EOF
@@ -3691,9 +3630,6 @@ function copyToClipboard(text) {
} }
function fallbackCopy(text) { function fallbackCopy(text) {
// LuCI обычно открыт по обычному http:// (не https), а Clipboard API работает
// только в защищённом контексте — используем старый, но надёжный способ через
// скрытое текстовое поле + document.execCommand('copy'), он работает и по http.
var ta = document.createElement('textarea'); var ta = document.createElement('textarea');
ta.value = text; ta.value = text;
ta.setAttribute('readonly', ''); ta.setAttribute('readonly', '');
@@ -3778,8 +3714,6 @@ return view.extend({
'class': 'cbi-button cbi-button-remove', 'class': 'cbi-button cbi-button-remove',
'click': function() { doAction(v.id, 'remove'); } 'click': function() { doAction(v.id, 'remove'); }
}, 'Удалить')); }, 'Удалить'));
// "Обновить" показываем только если реально есть более новая версия —
// иначе кнопка вводит в заблуждение, будто обновляться есть на что.
if (st.version && st.latest && st.version !== st.latest) { if (st.version && st.latest && st.version !== st.latest) {
actions.push(E('button', { actions.push(E('button', {
'class': 'cbi-button', 'class': 'cbi-button',