This commit is contained in:
StressOzz authored and GitHub committed 2026-10-26 00:40:28 +05:00
1 parent fb17d39526
commit f040c7fdca
1 file changed
+96 -102
+96 -102
View File
@@ -1,6 +1,6 @@
#!/bin/sh #!/bin/sh
read -r _ _ ZM_NEW_VER <<'ZM_VERSION_EOF' read -r _ _ ZM_NEW_VER <<'ZM_VERSION_EOF'
# Version: 4.61 # Version: 4.62
ZM_VERSION_EOF ZM_VERSION_EOF
set -e set -e
@@ -1929,7 +1929,7 @@ do_remove_zapret() {
/tmp/zapret /tmp/zapret.* "$YV_OFF_FLAG" "$DV_OFF_FLAG" "$JOBS_DIR/flowseal_strategies.txt" "$JOBS_DIR/youtube_strategies.txt" "$ZO_RKN_FLAG" "$ZO_USER_FLAG" "$ZO_IPID_FLAG" "$ZO_DOH_FLAG" && /tmp/zapret /tmp/zapret.* "$YV_OFF_FLAG" "$DV_OFF_FLAG" "$JOBS_DIR/flowseal_strategies.txt" "$JOBS_DIR/youtube_strategies.txt" "$ZO_RKN_FLAG" "$ZO_USER_FLAG" "$ZO_IPID_FLAG" "$ZO_DOH_FLAG" &&
echo " ✓ Файлы удалены, остатков нет" || rc=1 echo " ✓ Файлы удалены, остатков нет" || rc=1
crontab -l 2>/dev/null | awk '{ l = tolower($0) } l ~ /zapret/ && l !~ /zapret-manager|zapret2/ { next } { print }' | crontab - 2>/dev/null crontab -l 2>/dev/null | awk '{ l = tolower($0) } l ~ /zapret/ && l !~ /zapret-manager|zapret2/ { next } { print }' | crontab - 2>/dev/null
sed -i "\\|$ZA_TAG|d" "$CRON_FILE" 2>/dev/null sed -i "\\|$ZA_TAG|d; \\|$ZX_AUTO_TAG=|d" "$CRON_FILE" 2>/dev/null
echo " ✓ Задания Zapret убраны из расписания" echo " ✓ Задания Zapret убраны из расписания"
_zm_rm_listed zapret || rc=1 _zm_rm_listed zapret || rc=1
/etc/init.d/firewall reload >/dev/null 2>&1 /etc/init.d/firewall reload >/dev/null 2>&1
@@ -4207,7 +4207,7 @@ _pg_st_dir() {
} }
_pg_trace() { _pg_trace() {
case "$1" in case "$1" in
zapret) echo "pkg:luci-i18n-zapret-ru pkg:luci-app-zapret pkg:zapret /opt/zapret /etc/config/zapret /etc/config/zapret-opkg /etc/init.d/zapret /etc/rc.d/*[0-9]zapret /etc/firewall.zapret /etc/hotplug.d/*/*zapret /etc/config/zapret.apk-new /tmp/zapret $(_zm_luci_files zapret) nft:zapret cron:zm-autobest $ZO_RKN_FLAG $ZO_USER_FLAG $ZO_IPID_FLAG $ZO_DOH_FLAG $ZA_MODE_FILE $ZA_LAST $ZA_YT_FILE $ZA_LAST_YT $ZA_TS $ZA_TIME_FILE $TEST_BACKUP $ZC_FILE $ZC_BAK $ZC_AFTER $YV_OFF_FLAG $DV_OFF_FLAG $TEST_DIR $TEST_CUSTOM_FILE" ;; zapret) echo "pkg:luci-i18n-zapret-ru pkg:luci-app-zapret pkg:zapret /opt/zapret /etc/config/zapret /etc/config/zapret-opkg /etc/init.d/zapret /etc/rc.d/*[0-9]zapret /etc/firewall.zapret /etc/hotplug.d/*/*zapret /etc/config/zapret.apk-new /tmp/zapret $(_zm_luci_files zapret) nft:zapret cron:zm-autobest cron:zm-excl-auto $ZO_RKN_FLAG $ZO_USER_FLAG $ZO_IPID_FLAG $ZO_DOH_FLAG $ZA_MODE_FILE $ZA_LAST $ZA_YT_FILE $ZA_LAST_YT $ZA_TS $ZA_TIME_FILE $ZA_LOG $TEST_KEEP $TEST_BACKUP $ZC_FILE $ZC_BAK $ZC_AFTER $YV_OFF_FLAG $DV_OFF_FLAG $TEST_DIR $TEST_CUSTOM_FILE" ;;
zapret2) echo "pkg:luci-i18n-zapret2-ru pkg:luci-app-zapret2 pkg:zapret2 /opt/zapret2 /etc/config/zapret2 /etc/config/zapret2-opkg /etc/init.d/zapret2 /etc/rc.d/*zapret2 /etc/hotplug.d/*/*zapret2 /etc/config/zapret2.apk-new /tmp/zapret2* $(_zm_luci_files zapret2) nft:zapret2 cronrx:zapret2" ;; zapret2) echo "pkg:luci-i18n-zapret2-ru pkg:luci-app-zapret2 pkg:zapret2 /opt/zapret2 /etc/config/zapret2 /etc/config/zapret2-opkg /etc/init.d/zapret2 /etc/rc.d/*zapret2 /etc/hotplug.d/*/*zapret2 /etc/config/zapret2.apk-new /tmp/zapret2* $(_zm_luci_files zapret2) nft:zapret2 cronrx:zapret2" ;;
bytetube) bytetube)
echo "pkg:byedpi /usr/bin/ciadpi /etc/init.d/byedpi /etc/rc.d/*byedpi /etc/config/byedpi /etc/config/byedpi-opkg /usr/bin/bytetube /etc/config/bytetube /etc/init.d/bytetube /etc/rc.d/*bytetube /usr/libexec/bytetube /usr/share/bytetube /etc/bytetube /etc/hotplug.d/firewall/90-bytetube /usr/share/nftables.d/chain-pre/forward/50-bytetube.nft /var/etc/bytetube /var/run/bytetube.started /tmp/bytetube-test /lib/upgrade/keep.d/bytetube /tmp/dhcp.ytb.bak dnsconf:bytetube.conf cronrx:bytetube" echo "pkg:byedpi /usr/bin/ciadpi /etc/init.d/byedpi /etc/rc.d/*byedpi /etc/config/byedpi /etc/config/byedpi-opkg /usr/bin/bytetube /etc/config/bytetube /etc/init.d/bytetube /etc/rc.d/*bytetube /usr/libexec/bytetube /usr/share/bytetube /etc/bytetube /etc/hotplug.d/firewall/90-bytetube /usr/share/nftables.d/chain-pre/forward/50-bytetube.nft /var/etc/bytetube /var/run/bytetube.started /tmp/bytetube-test /lib/upgrade/keep.d/bytetube /tmp/dhcp.ytb.bak dnsconf:bytetube.conf cronrx:bytetube"
@@ -5187,44 +5187,9 @@ _mirror_upd_try() {
} }
_mirror_mark() { rm -f "$ZM_SI_STATIC"; mkdir -p "$ZM_STATE_DIR"; printf '%s\t%s\t%s\n' "$1" "$(date +%s)" "$2" > "$ZM_MIRROR_STATE"; } _mirror_mark() { rm -f "$ZM_SI_STATIC"; mkdir -p "$ZM_STATE_DIR"; printf '%s\t%s\t%s\n' "$1" "$(date +%s)" "$2" > "$ZM_MIRROR_STATE"; }
_mirror_auto() { _mirror_auto() {
local cur u dir h t list="" n=0
[ -n "$ZM_MIRROR_TRIED" ] && return 1 [ -n "$ZM_MIRROR_TRIED" ] && return 1
ZM_MIRROR_TRIED=1 ZM_MIRROR_TRIED=1
cur="$(_mirror_host)"; u="$(_mirror_feed1)" _mirror_pick_core auto
[ -n "$cur" ] && [ -n "$u" ] || return 1
echo "==> Репозиторий OpenWrt ($cur) отвечает с ошибками — подбираем рабочее зеркало"
dir="$JOBS_DIR/mirror.$$"; rm -rf "$dir"; mkdir -p "$dir"
for h in $ZM_MIRRORS; do
[ "$h" = "$cur" ] && continue
n=$((n + 1))
_mirror_probe "$h" "$u" > "$dir/$n" &
done
wait
list="$(cat "$dir"/* 2>/dev/null | sort -n | head -n 4)"
rm -rf "$dir"
if [ -z "$list" ]; then
echo " ✗ Ни одно зеркало не ответило — похоже, нет интернета. Оставляем $cur"
return 1
fi
echo " ✓ Отвечают: $(printf '%s\n' "$list" | awk '{ printf "%s%s (%d мс)", (NR > 1 ? ", " : ""), $2, $1 }')"
if printf '%s\n' "$list" | {
while read -r t h; do
[ -n "$h" ] || continue
echo " → Пробуем $h"
_mirror_write "$h" || exit 1
if _mirror_upd_try; then
_mirror_keep
_mirror_mark "$h" auto
echo " ✓ Список пакетов обновлён через зеркало $h — оно останется, вернуть основное можно в «Системе»"
exit 0
fi
_mirror_undo
echo " ✗ $h: список пакетов не обновился без ошибок"
done
exit 1
}; then return 0; fi
echo " ✗ Ни одно зеркало не помогло — оставляем $cur"
return 1
} }
mirror_status() { mirror_status() {
@@ -5277,16 +5242,16 @@ _mirror_why() {
esac esac
} }
_mirror_feed_check() { _mirror_feed_check() {
local out="$1" n p bad=0 all=0 errs local out="$1" n p bad=0 all=0 errs I="$MP_I"
errs="$(grep -iE 'error|fail|unable|warning|timed out|not found|404|network' "$out" 2>/dev/null | grep -v 'write error: Broken pipe')" errs="$(grep -iE 'error|fail|unable|warning|timed out|not found|404|network' "$out" 2>/dev/null | grep -v 'write error: Broken pipe')"
while IFS=' ' read -r n p; do while IFS=' ' read -r n p; do
[ -n "$p" ] || continue [ -n "$p" ] || continue
all=$((all + 1)) all=$((all + 1))
if printf '%s\n' "$errs" | grep -qF "$p"; then if printf '%s\n' "$errs" | grep -qF "$p"; then
bad=$((bad + 1)) bad=$((bad + 1))
echo " ✗ $n — $(_mirror_why "$(printf '%s\n' "$errs" | grep -F "$p" | head -n 1)")" echo "$I ✗ $n — $(_mirror_why "$(printf '%s\n' "$errs" | grep -F "$p" | head -n 1)")"
else else
echo " ✓ $n" echo "$I ✓ $n"
fi fi
done <<MF_EOF done <<MF_EOF
$(_mirror_feeds) $(_mirror_feeds)
@@ -5294,14 +5259,24 @@ MF_EOF
MF_ALL="$all"; MF_BAD="$bad" MF_ALL="$all"; MF_BAD="$bad"
[ "$all" -gt 0 ] && [ "$bad" = 0 ] [ "$all" -gt 0 ] && [ "$bad" = 0 ]
} }
do_mirror_pick() { _mirror_nrep() { awk -v n="$1" 'BEGIN { a = n % 100; b = n % 10; print n " " ((a >= 11 && a <= 14) ? "репозиториев" : b == 1 ? "репозиторий" : (b >= 2 && b <= 4) ? "репозитория" : "репозиториев") }'; }
local cur u dir h t p n=0 k total out rc ok_list="" name rel arch _mirror_hd() { if [ -n "$MP_I" ]; then echo " → $*"; else echo "==> $*"; fi; }
_mirror_pick_core() {
local mode="$1" cur u dir h t p n=0 k total out rc name rel arch I="" cn
cur="$(_mirror_host)"; u="$(_mirror_feed1)" cur="$(_mirror_host)"; u="$(_mirror_feed1)"
[ -n "$u" ] || { echo "ОШИБКА: в списке репозиториев ($(_confz)) нет адреса OpenWrt"; return 1; } cn="$(_mirror_label "$cur")"
rel="$(. /etc/openwrt_release 2>/dev/null; echo "$DISTRIB_RELEASE")"; arch="$(. /etc/openwrt_release 2>/dev/null; echo "$DISTRIB_ARCH")" if [ "$mode" = auto ]; then
echo "==> Подбираем зеркало OpenWrt ${rel:+$rel }${arch:+($arch) }— сейчас $(_mirror_label "$cur")" [ -n "$cur" ] && [ -n "$u" ] || return 1
I=" "
echo "==> Репозиторий OpenWrt ($cn) отвечает с ошибками — подбираем рабочее зеркало"
else
[ -n "$u" ] || { echo "ОШИБКА: в списке репозиториев ($(_confz)) нет адреса OpenWrt"; return 1; }
rel="$(. /etc/openwrt_release 2>/dev/null; echo "$DISTRIB_RELEASE")"; arch="$(. /etc/openwrt_release 2>/dev/null; echo "$DISTRIB_ARCH")"
echo "==> Подбираем зеркало OpenWrt ${rel:+$rel }${arch:+($arch) }— сейчас $cn"
fi
MP_I="$I"
dir="$JOBS_DIR/mirror-pick.$$"; rm -rf "$dir"; mkdir -p "$dir" dir="$JOBS_DIR/mirror-pick.$$"; rm -rf "$dir"; mkdir -p "$dir"
echo "==> Меряем пинг до $(echo $ZM_MIRRORS | wc -w | tr -d ' ') зеркал" _mirror_hd "Меряем пинг до $(echo $ZM_MIRRORS | wc -w | tr -d ' ') зеркал"
for h in $ZM_MIRRORS; do for h in $ZM_MIRRORS; do
n=$((n + 1)) n=$((n + 1))
( t="$(_mirror_ping "$h")" || t=- ( t="$(_mirror_ping "$h")" || t=-
@@ -5313,51 +5288,60 @@ do_mirror_pick() {
while IFS=' ' read -r t p h; do while IFS=' ' read -r t p h; do
[ -n "$h" ] || continue [ -n "$h" ] || continue
if [ "$t" != - ]; then k="пинг $t мс"; else k="на пинг не отвечает"; fi if [ "$t" != - ]; then k="пинг $t мс"; else k="на пинг не отвечает"; fi
if [ "$p" != - ]; then echo " · $(_mirror_label "$h") ($h) — $k, пакеты отдаёт за $p мс" if [ "$mode" = auto ] && [ "$h" = "$cur" ]; then echo "$I · $(_mirror_label "$h") ($h) — $k, сейчас выбрано и отвечает с ошибками"
else echo " · $(_mirror_label "$h") ($h) — $k, пакеты для этого роутера не отдаёт"; fi elif [ "$p" != - ]; then echo "$I · $(_mirror_label "$h") ($h) — $k, пакеты отдаёт за $p мс"
else echo "$I · $(_mirror_label "$h") ($h) — $k, пакеты для этого роутера не отдаёт"; fi
done < "$dir/all" done < "$dir/all"
awk -F'\t' '$2 != "-" { print ($1 == "-" ? 100000 + $2 : $1) "\t" $1 "\t" $3 }' "$dir/all" | sort -n | cut -f2- > "$dir/order" awk -F'\t' -v skip="$([ "$mode" = auto ] && echo "$cur")" '$2 != "-" && $3 != skip { print ($1 == "-" ? 100000 + $2 : $1) "\t" $1 "\t" $3 }' "$dir/all" | sort -n | cut -f2- > "$dir/order"
[ "$mode" = auto ] && { head -n 4 "$dir/order" > "$dir/o4"; mv -f "$dir/o4" "$dir/order"; }
rm -f "$dir"/[0-9]* "$dir/all" rm -f "$dir"/[0-9]* "$dir/all"
total="$(grep -c . "$dir/order")" total="$(grep -c . "$dir/order")"
if [ "$total" = 0 ]; then if [ "$total" = 0 ]; then
rm -rf "$dir" rm -rf "$dir"; MP_I=""
echo "ОШИБКА: ни одно зеркало не отдаёт пакеты для этого роутера — похоже, нет интернета. Оставляем $(_mirror_label "$cur")" if [ "$mode" = auto ]; then echo " ✗ Ни одно зеркало не отдаёт пакеты — похоже, нет интернета. Оставляем $cn"
else echo "ОШИБКА: ни одно зеркало не отдаёт пакеты для этого роутера — похоже, нет интернета. Оставляем $cn"; fi
return 1 return 1
fi fi
k=""; n=0 k=""; n=0
while IFS=' ' read -r t h; do n=$((n + 1)); k="$k${k:+, }$n) $(_mirror_label "$h")$([ "$t" != - ] && echo " $t мс")"; done < "$dir/order" while IFS=' ' read -r t h; do n=$((n + 1)); k="$k${k:+, }$n) $(_mirror_label "$h")$([ "$t" != - ] && echo " $t мс")"; done < "$dir/order"
echo "==> Порядок проверки — от быстрого к медленному: $k" _mirror_hd "Порядок проверки — от быстрого к медленному$([ "$mode" = auto ] && echo ", первые $total"): $k"
n=0 n=0
out="$dir/upd" out="$dir/upd"
while IFS=' ' read -r t h; do while IFS=' ' read -r t h; do
[ -n "$h" ] || continue [ -n "$h" ] || continue
n=$((n + 1)); name="$(_mirror_label "$h")" n=$((n + 1)); name="$(_mirror_label "$h")"
echo "==> [$n/$total] $name — $h$([ "$t" != - ] && echo ", пинг $t мс")" _mirror_hd "[$n/$total] $name — $h$([ "$t" != - ] && echo ", пинг $t мс")"
if [ "$h" != "$cur" ]; then if [ "$h" != "$cur" ]; then
_mirror_write "$h" || { echo "ОШИБКА: не удалось записать $(_confz)"; rm -rf "$dir"; return 1; } _mirror_write "$h" || { echo "ОШИБКА: не удалось записать $(_confz)"; rm -rf "$dir"; MP_I=""; return 1; }
fi fi
echo " → Обновляем список пакетов через $h" echo "$I → Обновляем список пакетов через $h"
_zm_run 150 $PKG_UPD > "$out" 2>&1; rc=$? _zm_run 150 $PKG_UPD > "$out" 2>&1; rc=$?
_zm_pkg_unlock _zm_pkg_unlock
if _mirror_feed_check "$out" && [ "$rc" = 0 ]; then if _mirror_feed_check "$out" && [ "$rc" = 0 ]; then
[ "$h" != "$cur" ] && _mirror_keep [ "$h" != "$cur" ] && _mirror_keep
if [ "$h" = downloads.openwrt.org ]; then rm -f "$ZM_MIRROR_STATE"; else _mirror_mark "$h" pick; fi if [ "$h" = downloads.openwrt.org ]; then rm -f "$ZM_MIRROR_STATE"; else _mirror_mark "$h" "$([ "$mode" = auto ] && echo auto || echo pick)"; fi
rm -rf "$dir" rm -rf "$dir"; MP_I=""
if [ "$h" = "$cur" ]; then echo "==> Готово: текущее зеркало $name — самое быстрое из рабочих, все $MF_ALL репозиториев обновились. Оставляем его" if [ "$mode" = auto ]; then echo " ✓ Список пакетов обновлён через зеркало $name ($h) — все $(_mirror_nrep "$MF_ALL"). Оно останется, вернуть основное можно в «Системе»"
else echo "==> Готово: выбрано зеркало $name ($h)$([ "$t" != - ] && echo ", пинг $t мс") — все $MF_ALL репозиториев обновились без ошибок"; fi elif [ "$h" = "$cur" ]; then echo "==> Готово: текущее зеркало $name — самое быстрое из рабочих, все $(_mirror_nrep "$MF_ALL") обновились. Оставляем его"
else echo "==> Готово: выбрано зеркало $name ($h)$([ "$t" != - ] && echo ", пинг $t мс") — все $(_mirror_nrep "$MF_ALL") обновились без ошибок"; fi
return 0 return 0
fi fi
if [ "$MF_BAD" = 0 ]; then echo " ✗ $name: обновление списка пакетов завершилось с ошибкой"; _zm_pkg_fmt < "$out" | head -n 3 if [ "$MF_BAD" = 0 ]; then echo "$I ✗ $name: обновление списка пакетов завершилось с ошибкой"; _zm_pkg_fmt < "$out" | head -n 3
else echo " ✗ $name: не обновилось репозиториев — $MF_BAD из $MF_ALL"; fi else echo "$I ✗ $name: не обновилось репозиториев — $MF_BAD из $MF_ALL"; fi
[ "$h" != "$cur" ] && _mirror_undo [ "$h" != "$cur" ] && _mirror_undo
[ "$n" -lt "$total" ] && echo " → Пробуем следующее по пингу" [ "$n" -lt "$total" ] && echo "$I → Пробуем следующее по пингу"
done < "$dir/order" done < "$dir/order"
rm -rf "$dir" rm -rf "$dir"; MP_I=""
echo "==> Возвращаем прежнее зеркало $(_mirror_label "$cur") и обновляем список пакетов" if [ "$mode" = auto ]; then
echo " ✗ Ни одно зеркало не помогло — оставляем $cn"
return 1
fi
echo "==> Возвращаем прежнее зеркало $cn и обновляем список пакетов"
_zm_run 150 $PKG_UPD >/dev/null 2>&1; _zm_pkg_unlock _zm_run 150 $PKG_UPD >/dev/null 2>&1; _zm_pkg_unlock
echo "ОШИБКА: ни через одно зеркало все репозитории не обновились. Оставлено $(_mirror_label "$cur")" echo "ОШИБКА: ни через одно зеркало все репозитории не обновились. Оставлено $cn"
return 1 return 1
} }
do_mirror_pick() { _mirror_pick_core pick; }
do_mirror_set() { do_mirror_set() {
local host="$1" u prev ms local host="$1" u prev ms
@@ -5383,7 +5367,7 @@ do_mirror_set() {
} }
mirror_set() { mirror_set() {
local id="$1" host j local id="$1" host="" j
case "$id" in case "$id" in
infra) host="mirror-03.infra.openwrt.org" ;; infra) host="mirror-03.infra.openwrt.org" ;;
brazil) host="openwrt.c3sl.ufpr.br" ;; brazil) host="openwrt.c3sl.ufpr.br" ;;
@@ -5394,12 +5378,12 @@ mirror_set() {
usa) host="openwrt.pixeldeck.net" ;; usa) host="openwrt.pixeldeck.net" ;;
germany_rwth) host="ftp.halifax.rwth-aachen.de/openwrt" ;; germany_rwth) host="ftp.halifax.rwth-aachen.de/openwrt" ;;
default) host="downloads.openwrt.org" ;; default) host="downloads.openwrt.org" ;;
pick) pick) ;;
if j="$(_zm_busy_job)"; then printf '{"error":"%s"}\n' "$(esc "идёт операция «$j» — дождитесь её окончания")"; return 1; fi
job_start mirror_set do_mirror_pick; return ;;
*) echo '{"error":"неизвестное зеркало"}'; return 1 ;; *) echo '{"error":"неизвестное зеркало"}'; return 1 ;;
esac esac
job_start mirror_set do_mirror_set "$host" if j="$(_zm_busy_job)"; then printf '{"error":"%s"}\n' "$(esc "идёт операция «$j» — дождитесь её окончания")"; return 1; fi
if [ "$id" = pick ]; then job_start mirror_set do_mirror_pick
else job_start mirror_set do_mirror_set "$host"; fi
} }
_excl_dir() { echo "/opt/zapret/init.d/openwrt/custom.d"; } _excl_dir() { echo "/opt/zapret/init.d/openwrt/custom.d"; }
@@ -16614,6 +16598,7 @@ do_steer_warp_recreate() {
do_steer_remove() { do_steer_remove() {
local rc local rc
_do_steer_remove_core "$@"; rc=$? _do_steer_remove_core "$@"; rc=$?
stl_present || rm -f "$FT_STEER_OFF"
_ft_steer_sync _ft_steer_sync
return $rc return $rc
} }
@@ -23195,8 +23180,8 @@ _fk_rs_check() {
uci -q set netshift.settings.download_lists_via_proxy=1 uci -q set netshift.settings.download_lists_via_proxy=1
uci -q set "netshift.settings.download_lists_via_proxy_section=$sec" uci -q set "netshift.settings.download_lists_via_proxy_section=$sec"
uci -q commit netshift uci -q commit netshift
logger -t zapret-manager "Forkozz: набор правил ${u##*/} не скачался напрямую ($r) — включено «Скачивать списки сервисов через VPN»" logger -t zapret-manager "Forkozz: набор правил ${u##*/} не скачался напрямую ($r) — включено «Скачивать списки сервисов через VPN», через подключение теперь обновляется и подписка"
_fk_say "Включаем «Скачивать списки сервисов через VPN»: наборы правил sing-box будет качать через подключение" _fk_say "Включаем «Скачивать списки сервисов через VPN»: наборы правил sing-box и обновления подписки пойдут через подключение (не ответит VPN — подписка скачается напрямую)"
return 0 return 0
fi fi
fi fi
@@ -32595,18 +32580,39 @@ return view.extend({
var day = new Date(n.getFullYear(), n.getMonth(), n.getDate()).getTime(), dd = new Date(t.getFullYear(), t.getMonth(), t.getDate()).getTime(); var day = new Date(n.getFullYear(), n.getMonth(), n.getDate()).getTime(), dd = new Date(t.getFullYear(), t.getMonth(), t.getDate()).getTime();
return dd === day ? 'сегодня ' + hm : day - dd === 864e5 ? 'вчера ' + hm : p2(t.getDate()) + '.' + p2(t.getMonth() + 1) + '.' + t.getFullYear(); return dd === day ? 'сегодня ' + hm : day - dd === 864e5 ? 'вчера ' + hm : p2(t.getDate()) + '.' + p2(t.getMonth() + 1) + '.' + t.getFullYear();
} }
function sysStrip(sys) {
var href = document.body.classList.contains('zmw-body') ? '#/system' : L.url('admin/services/zapret-manager/system');
var p2 = function(x) { return (x < 10 ? '0' : '') + x; };
function chip(tone, text, title) {
var go = function() { location.href = href; };
return E('span', { 'class': 'zm-badge ' + tone, 'role': 'link', 'tabindex': '0', 'title': title + '\nНажмите — откроется «Система»', 'click': go,
'keydown': function(ev) { if (ev.key === 'Enter' || ev.key === ' ') { ev.preventDefault(); go(); } } }, [ E('span', { 'class': 'zm-dot' }), text ]);
}
var fm = { hw: 'аппаратный', sw: 'программный' }[sys.flow_mode] || '', fon = !!fm;
var zf = sys.flow_offloading_fix === true, sf = sys.steer_offload_fix === true;
var c = [
chip(sys.quic_blocked ? 'zm-ok' : 'zm-off', sys.quic_blocked ? 'QUIC блокируется' : 'QUIC не блокируется', 'Блокировка QUIC (UDP 80 и 443): браузеры переходят на обычный HTTPS, его Zapret обрабатывает надёжнее'),
chip(sys.ipv6_enabled ? 'zm-ok' : 'zm-off', sys.ipv6_enabled ? 'IPv6 в Zapret' : 'IPv6 в Zapret выключен', 'Обрабатывает ли Zapret трафик IPv6'),
chip(fon ? 'zm-sx-info' : 'zm-off', 'Flow Offloading ' + (fm || 'выключен'), 'Ускорение маршрутизации/NAT (Сеть → Межсетевой экран)')
];
if (fon || zf) c.push(chip(zf ? 'zm-ok' : 'zm-bad', zf ? 'поправка для Zapret' : 'нет поправки для Zapret', zf ? 'Поправка Flow Offloading для Zapret применена' + (fon ? '' : ' — пока Flow Offloading выключен, она ни на что не влияет') : 'Flow Offloading включён, а поправки для Zapret нет — часть соединений может идти мимо Zapret'));
if (sys.steer_installed && (fon || sf)) c.push(chip(sf ? 'zm-ok' : 'zm-bad', sf ? 'поправка для Steer' : 'нет поправки для Steer', sf ? 'Поправка Flow Offloading для Steer применена' + (fon ? '' : ' — пока Flow Offloading выключен, она ни на что не влияет') : 'Flow Offloading включён, а поправки для Steer нет' + (sys.steer_offload_off ? ' (отключена вручную)' : '') + ' — соединения Steer могут перестать идти'));
var mh = String(sysInfo.mirror_host || '');
if (mh) {
var def = mh === 'downloads.openwrt.org', how = def ? '' : String(sysInfo.mirror_how || '');
var at = how && +sysInfo.mirror_at > 0 ? new Date(sysInfo.mirror_at * 1000) : null, when = at ? ' ' + p2(at.getDate()) + '.' + p2(at.getMonth() + 1) : '';
c.push(chip(def ? 'zm-off' : how === 'auto' ? 'zm-warn' : 'zm-sx-info',
def ? 'Зеркало OpenWrt · основное' : 'Зеркало ' + String(sysInfo.mirror || mh) + (how === 'auto' ? ' · автовыбор' + when : how === 'pick' ? ' · подобрано' + when : ''),
'Откуда ставятся пакеты OpenWrt: ' + mh + (how === 'auto' ? '\nОсновной репозиторий отвечал с ошибками — панель переключилась сама' : how === 'pick' ? '\nПодобрано кнопкой «Подобрать зеркало»' : how === 'manual' ? '\nВыбрано вручную' : '')));
}
return E('div', { 'class': 'zm-sysline' }, [ E('span', { 'class': 'zm-label' }, 'Система') ].concat(c));
}
function renderOverview(d, doh, hosts, sys, h, bk) { function renderOverview(d, doh, hosts, sys, h, bk) {
var hostsAi = (hosts.items || []).filter(function(it) { return /^ai_/.test(it.id); }); var hostsAi = (hosts.items || []).filter(function(it) { return /^ai_/.test(it.id); });
var hostsOther = (hosts.items || []).filter(function(it) { return !/^ai_/.test(it.id); }); var hostsOther = (hosts.items || []).filter(function(it) { return !/^ai_/.test(it.id); });
var hostsEnabled = hostsOther.filter(function(it) { return it.enabled; }).length + (hostsAi.some(function(it) { return it.enabled; }) ? 1 : 0); var hostsEnabled = hostsOther.filter(function(it) { return it.enabled; }).length + (hostsAi.some(function(it) { return it.enabled; }) ? 1 : 0);
var hostsTotal = hostsOther.length + (hostsAi.length ? 1 : 0); var hostsTotal = hostsOther.length + (hostsAi.length ? 1 : 0);
var sysFlags = [];
if (sys.quic_blocked) sysFlags.push('QUIC заблокирован');
if (sys.ipv6_enabled) sysFlags.push('IPv6 в Zapret включён');
if (sys.flow_offloading_fix) sysFlags.push('поправка Flow Offloading для Zapret');
if (sys.steer_offload_fix) sysFlags.push('поправка Flow Offloading для Steer');
var zrSt = st(h, 'zapret', d.zapret === 'installed' ? (d.zapret_running ? 1 : 2) : 0); var zrSt = st(h, 'zapret', d.zapret === 'installed' ? (d.zapret_running ? 1 : 2) : 0);
var zr2St = st(h, 'zapret2', d.zapret2 === 'installed' ? (d.zapret2_running ? 1 : 2) : 0); var zr2St = st(h, 'zapret2', d.zapret2 === 'installed' ? (d.zapret2_running ? 1 : 2) : 0);
var dohSt = st(h, 'doh', doh.installed ? 1 : 0); var dohSt = st(h, 'doh', doh.installed ? 1 : 0);
@@ -32659,7 +32665,6 @@ return view.extend({
!bk || !bk.items ? E('span', {}, '—') !bk || !bk.items ? E('span', {}, '—')
: bkItems.length ? zm.badge(true, 'копий: ' + bkItems.length + ' · последняя ' + bkWhen(bkItems[0].at), '') : offBadge('копий нет'), : bkItems.length ? zm.badge(true, 'копий: ' + bkItems.length + ' · последняя ' + bkWhen(bkItems[0].at), '') : offBadge('копий нет'),
bk && bk.items && bk.auto === false ? E('span', { 'class': 'zm-badge zm-off', 'title': 'Копия перед установкой, удалением и обновлением не сохраняется сама' }, [ E('span', { 'class': 'zm-dot' }), 'авто выкл' ]) : '' ]))); bk && bk.items && bk.auto === false ? E('span', { 'class': 'zm-badge zm-off', 'title': 'Копия перед установкой, удалением и обновлением не сохраняется сама' }, [ E('span', { 'class': 'zm-dot' }), 'авто выкл' ]) : '' ])));
if (sysFlags.length) items.push(row('Система', E('span', { 'style': 'display:flex;flex-wrap:wrap;gap:6px;flex:1 1 0;min-width:0' }, sysFlags.map(function(f) { return E('span', { 'class': 'zm-badge zm-off' }, f); }))));
var half = Math.ceil(items.length / 2); var half = Math.ceil(items.length / 2);
@@ -32668,7 +32673,8 @@ return view.extend({
E('div', { 'class': 'bt-cols' }, [ E('div', { 'class': 'bt-cols' }, [
E('div', { 'class': 'bt-col' }, items.slice(0, half)), E('div', { 'class': 'bt-col' }, items.slice(0, half)),
E('div', { 'class': 'bt-col' }, items.slice(half)) E('div', { 'class': 'bt-col' }, items.slice(half))
]) ]),
sysStrip(sys || {})
]); ]);
} }
@@ -32686,16 +32692,6 @@ return view.extend({
row('Платформа', E('span', {}, [ String(sysInfo.target || '—') ])), row('Платформа', E('span', {}, [ String(sysInfo.target || '—') ])),
row('OpenWrt', E('span', {}, [ String(sysInfo.openwrt || '—') ])) row('OpenWrt', E('span', {}, [ String(sysInfo.openwrt || '—') ]))
]; ];
if (sysInfo.mirror_host && sysInfo.mirror_host !== 'downloads.openwrt.org') {
var mAt = +sysInfo.mirror_at > 0 ? new Date(sysInfo.mirror_at * 1000) : null;
var mWhen = mAt ? ('0' + mAt.getDate()).slice(-2) + '.' + ('0' + (mAt.getMonth() + 1)).slice(-2) : '';
rows.push(row('Зеркало OpenWrt', E('span', { 'style': 'display:inline-flex; align-items:center; gap:8px; flex-wrap:wrap' }, [
E('span', { 'title': String(sysInfo.mirror_host) }, [ String(sysInfo.mirror || sysInfo.mirror_host) ]),
sysInfo.mirror_how === 'auto' ? E('span', { 'class': 'zm-badge zm-warn', 'title': 'Основной репозиторий отвечал с ошибками — панель переключилась сама' }, [ E('span', { 'class': 'zm-dot' }), 'автовыбор' + (mWhen ? ' · ' + mWhen : '') ])
: sysInfo.mirror_how === 'pick' ? E('span', { 'class': 'zm-badge zm-ok', 'title': 'Подобрано кнопкой «Подобрать зеркало»' }, [ E('span', { 'class': 'zm-dot' }), 'подобрано' + (mWhen ? ' · ' + mWhen : '') ])
: E('span', { 'class': 'zm-badge zm-off' }, [ E('span', { 'class': 'zm-dot' }), 'вручную' ])
])));
}
function meter(label, val, pct, mid, hi) { function meter(label, val, pct, mid, hi) {
pct = Math.max(0, Math.min(100, pct || 0)); pct = Math.max(0, Math.min(100, pct || 0));
return E('div', { 'class': 'zm-meter zmw-mem-row' + (pct >= hi ? ' zm-meter-hi zmw-mem-hi' : pct >= mid ? ' zm-meter-mid zmw-mem-mid' : '') }, [ return E('div', { 'class': 'zm-meter zmw-mem-row' + (pct >= hi ? ' zm-meter-hi zmw-mem-hi' : pct >= mid ? ' zm-meter-mid zmw-mem-mid' : '') }, [
@@ -32753,7 +32749,6 @@ return view.extend({
]).then(function(res) { ]).then(function(res) {
overviewEl.innerHTML = ''; overviewEl.innerHTML = '';
overviewEl.appendChild(renderOverview(res[0], res[1], res[2], res[3], res[4], res[5])); overviewEl.appendChild(renderOverview(res[0], res[1], res[2], res[3], res[4], res[5]));
renderSysFix(res[3]);
if (res[4] && typeof res[4].zapret === 'number') { if (res[4] && typeof res[4].zapret === 'number') {
try { window.dispatchEvent(new CustomEvent('zm:health', { detail: res[4] })); } catch (e) {} try { window.dispatchEvent(new CustomEvent('zm:health', { detail: res[4] })); } catch (e) {}
} }
@@ -32823,14 +32818,6 @@ return view.extend({
overviewEl.appendChild(renderOverview(data, dohData, hostsData, sysData, healthData, bkData)); overviewEl.appendChild(renderOverview(data, dohData, hostsData, sysData, healthData, bkData));
renderCards(); renderCards();
var sysFixEl = E('div', {});
function renderSysFix(d) {
if (!d || d.error) return;
sysData = d;
sysFixEl.innerHTML = '';
sysFixEl.appendChild(zm.sysFixCard(d, renderSysFix, { title: 'Настройки системы' }));
}
renderSysFix(sysData);
var updateEl = E('div', {}); var updateEl = E('div', {});
var updateLog = E('pre', { 'class': 'zm-log' }); var updateLog = E('pre', { 'class': 'zm-log' });
wrap.appendChild(updateEl); wrap.appendChild(updateEl);
@@ -32847,7 +32834,6 @@ return view.extend({
])); ]));
wrap.appendChild(overviewEl); wrap.appendChild(overviewEl);
wrap.appendChild(cards); wrap.appendChild(cards);
wrap.appendChild(sysFixEl);
wrap.appendChild(verEl); wrap.appendChild(verEl);
renderVersions(); renderVersions();
loadVersions('auto'); loadVersions('auto');
@@ -42977,6 +42963,13 @@ html.zm-theme-dark .zm-si-box { border-color: rgba(255,255,255,.12); background:
html.zm-theme-dark .zm-sx-tile { border-color: rgba(255,255,255,.12); background: rgba(255,255,255,.03); } html.zm-theme-dark .zm-sx-tile { border-color: rgba(255,255,255,.12); background: rgba(255,255,255,.03); }
html.zm-theme-dark .zm-sx-sub { background: rgba(255,255,255,.05); } html.zm-theme-dark .zm-sx-sub { background: rgba(255,255,255,.05); }
html.zm-theme-dark .zm-badge.zm-sx-info { background: rgba(88,166,255,.16); color: #79c0ff; } html.zm-theme-dark .zm-badge.zm-sx-info { background: rgba(88,166,255,.16); color: #79c0ff; }
.zm-sx-info .zm-dot { background: currentColor; }
.zm-sysline { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 8px; margin-top: 12px; padding-top: 12px; border-top: 1px solid rgba(127,127,127,.18); }
.zm-sysline > .zm-label { flex: 0 0 auto; margin-right: 6px; }
.zm-sysline .zm-badge { cursor: pointer; user-select: none; transition: filter .15s ease, transform .15s ease; }
.zm-sysline .zm-badge:hover { filter: brightness(.94); transform: translateY(-1px); }
.zm-sysline .zm-badge:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
html.zm-theme-dark .zm-sysline .zm-badge:hover { filter: brightness(1.18); }
@media (max-width: 720px) { .zm-sx-grid, .zm-sx-two { grid-template-columns: minmax(0, 1fr); } } @media (max-width: 720px) { .zm-sx-grid, .zm-sx-two { grid-template-columns: minmax(0, 1fr); } }
.zm-si-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 6px; } .zm-si-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 6px; }
.zm-si-head h4 { margin: 0; font-size: 14px; } .zm-si-head h4 { margin: 0; font-size: 14px; }
@@ -53022,6 +53015,7 @@ html[data-theme="light"] .zmw-orbs i { opacity: .28; }
#zmw-view .bt-cols { column-gap: 48px; } #zmw-view .bt-cols { column-gap: 48px; }
#zmw-view .bt-col .zm-row { padding: 6px 0; margin: 0; border-bottom: 1px dashed var(--border); } #zmw-view .bt-col .zm-row { padding: 6px 0; margin: 0; border-bottom: 1px dashed var(--border); }
#zmw-view .bt-col .zm-row:last-child { border-bottom: 0; } #zmw-view .bt-col .zm-row:last-child { border-bottom: 0; }
#zmw-view .zm-sysline { border-top-color: var(--border); }
#zmw-view .zm-hint, #zmw-view p.zm-hint, .zm-dock .zm-hint, .zm-dock p.zm-hint, .zmw-modal .zm-hint, .zmw-modal p.zm-hint { opacity: 1; color: var(--muted); font-size: 12.5px; line-height: 1.6; } #zmw-view .zm-hint, #zmw-view p.zm-hint, .zm-dock .zm-hint, .zm-dock p.zm-hint, .zmw-modal .zm-hint, .zmw-modal p.zm-hint { opacity: 1; color: var(--muted); font-size: 12.5px; line-height: 1.6; }
#zmw-view a:not(.cbi-button), .zm-dock a:not(.cbi-button), .zmw-modal a:not(.cbi-button) { color: var(--a2); text-decoration-color: rgba(59,130,246,.35); text-underline-offset: 3px; } #zmw-view a:not(.cbi-button), .zm-dock a:not(.cbi-button), .zmw-modal a:not(.cbi-button) { color: var(--a2); text-decoration-color: rgba(59,130,246,.35); text-underline-offset: 3px; }