From 09f43628717a3c34a54e7e0863bea3256dd606dd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 27 Jul 2026 21:05:23 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=81=20Sync=202026-07-27=2021:05:23?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dae/Makefile | 6 +- daed/Makefile | 6 +- geth/Makefile | 4 +- kaiplus/Makefile | 2 +- kaiplus/files/kaiplus.config | 3 +- kaiplus/files/kaiplus.init | 4 +- linkease/Makefile | 14 +- linkease/files/linkease-config.sh | 6 +- linkease/files/linkease.config | 1 + linkease/files/linkease.init | 42 +++- linkease/files/linkease.uci-default | 35 +++- linkeasefull/Makefile | 76 +++++++ linkeasefull/files/linkeasefull.config | 3 + linkeasefull/files/linkeasefull.init | 131 ++++++++++++ linkeasefull/files/linkeasefull.uci-default | 36 ++++ linkeaselite/Makefile | 75 +++++++ linkeaselite/files/linkeaselite-config.sh | 78 ++++++++ linkeaselite/files/linkeaselite.config | 4 + linkeaselite/files/linkeaselite.init | 68 +++++++ linkeaselite/files/linkeaselite.uci-default | 60 ++++++ linkmount/Makefile | 63 ------ luci-app-amlogic/Makefile | 4 +- .../resources/view/amlogic/info.js | 30 +-- .../root/etc/uci-defaults/luci-amlogic | 24 ++- luci-app-ddns/po/ar/ddns.po | 8 +- luci-app-ddns/po/es/ddns.po | 10 +- luci-app-ddns/po/ru/ddns.po | 9 +- luci-app-ddns/po/uk/ddns.po | 8 +- .../root/usr/share/rpcd/ucode/ddns.uc | 2 +- luci-app-dockerman/po/ar/dockerman.po | 8 +- luci-app-dockerman/po/cs/dockerman.po | 6 +- luci-app-dockerman/po/ko/dockerman.po | 10 +- luci-app-dockerman/po/ru/dockerman.po | 35 ++-- luci-app-dockerman/po/uk/dockerman.po | 6 +- luci-app-kaiplus/Makefile | 2 +- .../luasrc/controller/kaiplus.lua | 6 +- luci-app-kaiplus/luasrc/model/cbi/kaiplus.lua | 7 +- .../luasrc/view/kaiplus/kaiplus_status.htm | 9 +- luci-app-ksmbd/po/it/ksmbd.po | 8 +- luci-app-ksmbd/po/ru/ksmbd.po | 9 +- luci-app-ksmbd/po/uk/ksmbd.po | 8 +- luci-app-linkease/Makefile | 6 +- .../luasrc/controller/linkease.lua | 11 -- luci-app-linkeasefull/Makefile | 18 ++ .../luasrc/controller/linkeasefull.lua | 89 +++++++++ .../luasrc/model/cbi/linkeasefull.lua | 86 ++++++++ .../luasrc/view/linkeasefull_status.htm | 34 ++++ .../po/zh-cn/linkeasefull.po | 35 ++++ luci-app-linkeasefull/po/zh_Hans | 1 + .../etc/uci-defaults/50_luci-linkeasefull | 4 + luci-app-linkeaselite/Makefile | 18 ++ .../luasrc/controller/linkeaselite.lua | 31 +++ .../luasrc/model/cbi/linkeaselite.lua | 24 +++ .../luasrc/view/linkeaselite_status.htm | 42 ++++ .../po/zh-cn/linkeaselite.po | 35 ++++ luci-app-linkeaselite/po/zh_Hans | 1 + .../etc/uci-defaults/50_luci-linkeaselite | 4 + luci-app-passwall/Makefile | 2 +- .../root/usr/share/passwall/app.sh | 12 +- .../root/usr/share/passwall/utils.sh | 2 +- luci-app-qosmate/Makefile | 2 +- .../htdocs/luci-static/resources/view/cake.js | 8 + .../luci-static/resources/view/settings.js | 44 ++++- .../luci-static/resources/view/statistics.js | 15 ++ luci-app-samba4/po/it/samba4.po | 22 ++- luci-app-samba4/po/ru/samba4.po | 9 +- luci-app-samba4/po/uk/samba4.po | 6 +- luci-app-smartdns/Makefile | 2 +- luci-app-smartdns/po/es/smartdns.po | 33 ++-- luci-app-upnp/po/it/upnp.po | 8 +- luci-app-watchcat/po/es/watchcat.po | 35 ++-- luci-lib-linkeasefile/Makefile | 16 ++ .../linkeasefile/chunk.22632dc4.js | 0 .../linkeasefile/chunk.324cab41.js | 0 .../linkeasefile/chunk.4a114b4a.js | 0 .../linkeasefile/chunk.4ea0593d.js | 0 .../linkeasefile/chunk.6424c2fc.js | 0 .../linkeasefile/chunk.7191676b.js | 0 .../linkeasefile/chunk.a0a5dece.js | 0 .../linkeasefile/chunk.a6a47e72.js | 0 .../linkeasefile/chunk.c69499bb.js | 0 .../linkeasefile/chunk.d52f0fe8.js | 0 .../linkeasefile/chunk.dc0a1b58.js | 0 .../luci-static/linkeasefile/codicon.ttf | Bin .../linkeasefile/icons/archive.png | Bin .../luci-static/linkeasefile/icons/dir.png | Bin .../luci-static/linkeasefile/icons/doc.png | Bin .../luci-static/linkeasefile/icons/error.png | Bin .../luci-static/linkeasefile/icons/image.png | Bin .../luci-static/linkeasefile/icons/music.png | Bin .../linkeasefile/icons/notfound.png | Bin .../luci-static/linkeasefile/icons/other.png | Bin .../luci-static/linkeasefile/icons/video.png | Bin .../htdocs/luci-static/linkeasefile/index.js | 0 .../htdocs/luci-static/linkeasefile/style.css | 0 .../luasrc/controller/linkease_file.lua | 16 +- .../luasrc/view/linkease/file.htm | 0 .../etc/uci-defaults/50_luci-linkease-file | 4 + qBittorrent-Enhanced-Edition/Makefile | 3 +- qbittorrent/Makefile | 3 +- qosmate/Makefile | 2 +- qosmate/README.md | 30 ++- qosmate/etc/init.d/qosmate | 75 ++++--- qosmate/etc/init.d/qosmate-autorate | 11 +- qosmate/etc/qosmate-autorate.sh | 41 +++- qosmate/etc/qosmate.sh | 186 +++++++++++------- 106 files changed, 1561 insertions(+), 391 deletions(-) mode change 100755 => 100644 linkease/files/linkease-config.sh mode change 100755 => 100644 linkease/files/linkease.init create mode 100644 linkeasefull/Makefile create mode 100644 linkeasefull/files/linkeasefull.config create mode 100644 linkeasefull/files/linkeasefull.init create mode 100644 linkeasefull/files/linkeasefull.uci-default create mode 100644 linkeaselite/Makefile create mode 100755 linkeaselite/files/linkeaselite-config.sh create mode 100644 linkeaselite/files/linkeaselite.config create mode 100755 linkeaselite/files/linkeaselite.init create mode 100644 linkeaselite/files/linkeaselite.uci-default delete mode 100644 linkmount/Makefile create mode 100644 luci-app-linkeasefull/Makefile create mode 100644 luci-app-linkeasefull/luasrc/controller/linkeasefull.lua create mode 100644 luci-app-linkeasefull/luasrc/model/cbi/linkeasefull.lua create mode 100644 luci-app-linkeasefull/luasrc/view/linkeasefull_status.htm create mode 100644 luci-app-linkeasefull/po/zh-cn/linkeasefull.po create mode 120000 luci-app-linkeasefull/po/zh_Hans create mode 100755 luci-app-linkeasefull/root/etc/uci-defaults/50_luci-linkeasefull create mode 100644 luci-app-linkeaselite/Makefile create mode 100644 luci-app-linkeaselite/luasrc/controller/linkeaselite.lua create mode 100644 luci-app-linkeaselite/luasrc/model/cbi/linkeaselite.lua create mode 100644 luci-app-linkeaselite/luasrc/view/linkeaselite_status.htm create mode 100644 luci-app-linkeaselite/po/zh-cn/linkeaselite.po create mode 120000 luci-app-linkeaselite/po/zh_Hans create mode 100644 luci-app-linkeaselite/root/etc/uci-defaults/50_luci-linkeaselite create mode 100644 luci-lib-linkeasefile/Makefile rename {luci-app-linkease => luci-lib-linkeasefile}/htdocs/luci-static/linkeasefile/chunk.22632dc4.js (100%) rename {luci-app-linkease => luci-lib-linkeasefile}/htdocs/luci-static/linkeasefile/chunk.324cab41.js (100%) rename {luci-app-linkease => luci-lib-linkeasefile}/htdocs/luci-static/linkeasefile/chunk.4a114b4a.js (100%) rename {luci-app-linkease => luci-lib-linkeasefile}/htdocs/luci-static/linkeasefile/chunk.4ea0593d.js (100%) rename {luci-app-linkease => luci-lib-linkeasefile}/htdocs/luci-static/linkeasefile/chunk.6424c2fc.js (100%) rename {luci-app-linkease => luci-lib-linkeasefile}/htdocs/luci-static/linkeasefile/chunk.7191676b.js (100%) rename {luci-app-linkease => luci-lib-linkeasefile}/htdocs/luci-static/linkeasefile/chunk.a0a5dece.js (100%) rename {luci-app-linkease => luci-lib-linkeasefile}/htdocs/luci-static/linkeasefile/chunk.a6a47e72.js (100%) rename {luci-app-linkease => luci-lib-linkeasefile}/htdocs/luci-static/linkeasefile/chunk.c69499bb.js (100%) rename {luci-app-linkease => luci-lib-linkeasefile}/htdocs/luci-static/linkeasefile/chunk.d52f0fe8.js (100%) rename {luci-app-linkease => luci-lib-linkeasefile}/htdocs/luci-static/linkeasefile/chunk.dc0a1b58.js (100%) rename {luci-app-linkease => luci-lib-linkeasefile}/htdocs/luci-static/linkeasefile/codicon.ttf (100%) rename {luci-app-linkease => luci-lib-linkeasefile}/htdocs/luci-static/linkeasefile/icons/archive.png (100%) rename {luci-app-linkease => luci-lib-linkeasefile}/htdocs/luci-static/linkeasefile/icons/dir.png (100%) rename {luci-app-linkease => luci-lib-linkeasefile}/htdocs/luci-static/linkeasefile/icons/doc.png (100%) rename {luci-app-linkease => luci-lib-linkeasefile}/htdocs/luci-static/linkeasefile/icons/error.png (100%) rename {luci-app-linkease => luci-lib-linkeasefile}/htdocs/luci-static/linkeasefile/icons/image.png (100%) rename {luci-app-linkease => luci-lib-linkeasefile}/htdocs/luci-static/linkeasefile/icons/music.png (100%) rename {luci-app-linkease => luci-lib-linkeasefile}/htdocs/luci-static/linkeasefile/icons/notfound.png (100%) rename {luci-app-linkease => luci-lib-linkeasefile}/htdocs/luci-static/linkeasefile/icons/other.png (100%) rename {luci-app-linkease => luci-lib-linkeasefile}/htdocs/luci-static/linkeasefile/icons/video.png (100%) rename {luci-app-linkease => luci-lib-linkeasefile}/htdocs/luci-static/linkeasefile/index.js (100%) rename {luci-app-linkease => luci-lib-linkeasefile}/htdocs/luci-static/linkeasefile/style.css (100%) rename luci-app-linkease/luasrc/controller/linkease_backend.lua => luci-lib-linkeasefile/luasrc/controller/linkease_file.lua (91%) rename {luci-app-linkease => luci-lib-linkeasefile}/luasrc/view/linkease/file.htm (100%) create mode 100755 luci-lib-linkeasefile/root/etc/uci-defaults/50_luci-linkease-file diff --git a/dae/Makefile b/dae/Makefile index c988755ef..0ad8d1cee 100644 --- a/dae/Makefile +++ b/dae/Makefile @@ -5,10 +5,10 @@ include $(TOPDIR)/rules.mk PKG_NAME:=dae -PKG_VERSION:=2026.07.26 -PKG_RELEASE:=22 +PKG_VERSION:=2026.07.27 +PKG_RELEASE:=23 -PKG_SOURCE:=dae-src-2026.07.26-92a3fbf117a3.tar.gz +PKG_SOURCE:=dae-src-2026.07.27-c8388938b36a.tar.gz PKG_SOURCE_URL:=https://github.com/kenzok8/openwrt-daede/releases/download/dae-src PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_HASH:=skip diff --git a/daed/Makefile b/daed/Makefile index d6f3e7c85..b73c08c53 100644 --- a/daed/Makefile +++ b/daed/Makefile @@ -5,10 +5,10 @@ include $(TOPDIR)/rules.mk PKG_NAME:=daed -PKG_VERSION:=2026.07.26 -PKG_RELEASE:=30 +PKG_VERSION:=2026.07.27 +PKG_RELEASE:=31 -PKG_SOURCE:=daed-src-2026.07.26-ecbc5c99d632.tar.gz +PKG_SOURCE:=daed-src-2026.07.27-ed986932608b.tar.gz PKG_SOURCE_URL:=https://github.com/kenzok8/openwrt-daede/releases/download/daed-src PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_HASH:=skip diff --git a/geth/Makefile b/geth/Makefile index 503370a6e..c09130ab1 100644 --- a/geth/Makefile +++ b/geth/Makefile @@ -8,8 +8,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=go-ethereum -PKG_VERSION:=1.17.4 -PKG_RELEASE:=7 +PKG_VERSION:=1.17.5 +PKG_RELEASE:=8 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/ethereum/go-ethereum/tar.gz/v${PKG_VERSION}? diff --git a/kaiplus/Makefile b/kaiplus/Makefile index 2ca8128be..70d2f29a4 100644 --- a/kaiplus/Makefile +++ b/kaiplus/Makefile @@ -10,7 +10,7 @@ PKG_ARCH_kaiplus:=$(ARCH) PKG_NAME:=kaiplus PKG_VERSION:=1.0.5 -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_SOURCE:=$(PKG_NAME)-binary-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://github.com/linkease/istore-packages/releases/download/kaiplus/ PKG_HASH:=skip diff --git a/kaiplus/files/kaiplus.config b/kaiplus/files/kaiplus.config index d81691147..b9ddd2bf7 100644 --- a/kaiplus/files/kaiplus.config +++ b/kaiplus/files/kaiplus.config @@ -1,5 +1,6 @@ config kaiplus option 'enabled' '0' option 'data_dir' '' - option 'port' '8198' + option 'port' '8189' + option 'base_path' '/apps/kaiplus/' option 'system_role' 'istoreos' diff --git a/kaiplus/files/kaiplus.init b/kaiplus/files/kaiplus.init index 22200d2e7..96c05683c 100644 --- a/kaiplus/files/kaiplus.init +++ b/kaiplus/files/kaiplus.init @@ -6,7 +6,8 @@ USE_PROCD=1 get_config() { config_get_bool enabled "$1" enabled 1 config_get data_dir "$1" data_dir "" - config_get port "$1" port "8198" + config_get port "$1" port "8189" + config_get base_path "$1" base_path "/apps/kaiplus/" config_get system_role "$1" system_role "istoreos" } @@ -61,6 +62,7 @@ start_service() { procd_append_param command --data-dir "$data_dir" procd_append_param command --static-dir /usr/share/kaiplus/www procd_append_param command --defaults-dir /usr/share/kaiplus/defaults + procd_append_param command --base-path "$base_path" procd_append_param command --system-role "$system_role" procd_set_param stdout 1 procd_set_param stderr 1 diff --git a/linkease/Makefile b/linkease/Makefile index da9478794..582cb75cb 100644 --- a/linkease/Makefile +++ b/linkease/Makefile @@ -10,9 +10,9 @@ include $(TOPDIR)/rules.mk PKG_ARCH_LINKEASE:=$(ARCH) PKG_NAME:=linkease -# use PKG_SOURCE_DATE instead of PKG_VERSION for compitable PKG_SOURCE_DATE:=1.7.5 -PKG_RELEASE:=1 +PKG_RELEASE:=2 + ARCH_HEXCODE:= ifeq ($(ARCH),x86_64) ARCH_HEXCODE=8664 @@ -23,11 +23,11 @@ ARCH_HEXCODE=aa32 else ifeq ($(ARCH),mipsel) ARCH_HEXCODE=1b0c endif -PKG_SOURCE_VERSION:=$(ARCH_HEXCODE) -PKG_SOURCE:=$(PKG_NAME)-binary-$(PKG_SOURCE_DATE).tar.gz -PKG_SOURCE_URL:=http://dl.istoreos.com/binary/LinkEase/LinuxStorage/ -PKG_HASH:=skip +PKG_SOURCE_VERSION:=$(ARCH_HEXCODE) +PKG_SOURCE:=linkease-binary-$(PKG_SOURCE_DATE).tar.gz +PKG_SOURCE_URL:=https://dl.istoreos.com/binary/LinkEase/LinuxStorage/ +PKG_HASH:=skip PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-binary-$(PKG_SOURCE_DATE) PKG_BUILD_PARALLEL:=1 @@ -40,7 +40,7 @@ define Package/$(PKG_NAME) CATEGORY:=Network SUBMENU:=Web Servers/Proxies TITLE:=LinkEase - the file cloud - DEPENDS:=@(arm||x86_64||aarch64) +linkmount + DEPENDS:=@(arm||x86_64||aarch64) PKGARCH:=all URL:=https://www.linkease.com/ endef diff --git a/linkease/files/linkease-config.sh b/linkease/files/linkease-config.sh old mode 100755 new mode 100644 index 5427faa49..62015a855 --- a/linkease/files/linkease-config.sh +++ b/linkease/files/linkease-config.sh @@ -1,6 +1,6 @@ #!/bin/sh -source /lib/functions.sh +. /lib/functions.sh case "$1" in save) @@ -40,7 +40,6 @@ case "$1" in config_get PUB_DIR main pub_dir "" config_get DL_DIR main dl_dir "" config_get TMP_DIR main tmp_dir "" - # echo "$MAIN_DIR $CONF_DIR $PUB_DIR $DL_DIR $TMP_DIR" if [ "$ROOT_DIR" = "$MAIN_DIR" ]; then exit 0 fi @@ -83,7 +82,6 @@ case "$1" in ;; *) - echo "Usage: $0 {save|load|status}" + echo "Usage: $0 {save|load|local_save|local_load|status}" exit 1 esac - diff --git a/linkease/files/linkease.config b/linkease/files/linkease.config index 5ece093b2..ee982437c 100644 --- a/linkease/files/linkease.config +++ b/linkease/files/linkease.config @@ -1,3 +1,4 @@ config linkease option port '8897' option enabled '1' + option allowPublic '0' diff --git a/linkease/files/linkease.init b/linkease/files/linkease.init old mode 100755 new mode 100644 index 0c51d6cf5..ef2cbf275 --- a/linkease/files/linkease.init +++ b/linkease/files/linkease.init @@ -3,24 +3,48 @@ START=99 USE_PROCD=1 +PROG=/usr/sbin/linkease +LOCAL_API=/var/run/linkease.sock + get_config() { - config_get_bool enabled $1 enabled 1 - config_get_bool logger $1 logger - config_get_bool allowPublic $1 allowPublic - config_get port $1 port 8897 + config_get_bool enabled "$1" enabled 1 + config_get_bool logger "$1" logger 0 + config_get_bool allowPublic "$1" allowPublic 0 + config_get port "$1" port 8897 +} + +stop_linkeaselite_runtime() { + [ -x /etc/init.d/linkeaselite ] && /etc/init.d/linkeaselite stop >/dev/null 2>&1 + if uci -q get linkeaselite.@linkeaselite[0] >/dev/null 2>&1; then + uci -q set linkeaselite.@linkeaselite[0].enabled="0" + uci -q commit linkeaselite + fi +} + +stop_linkeasefull_runtime() { + [ -x /etc/init.d/linkeasefull ] && /etc/init.d/linkeasefull stop >/dev/null 2>&1 + if uci -q get linkeasefull.@linkeasefull[0] >/dev/null 2>&1; then + uci -q set linkeasefull.@linkeasefull[0].enabled="0" + uci -q commit linkeasefull + fi } start_service() { config_load linkease config_foreach get_config linkease - [ $enabled != 1 ] && return 1 + [ "$enabled" != "1" ] && return 1 + [ -x "$PROG" ] || return 1 + + stop_linkeaselite_runtime + stop_linkeasefull_runtime + rm -f "$LOCAL_API" procd_open_instance procd_set_param limits nofile="65535 65535" - procd_set_param command /usr/sbin/linkease - [ -n "$port" ] && procd_append_param command --deviceAddr ":$port" --localApi /var/run/linkease.sock - [ "$allowPublic" == 1 ] && procd_append_param command --allowPublic - [ "$logger" == 1 ] && procd_set_param stderr 1 + procd_set_param command "$PROG" + procd_append_param command --deviceAddr ":$port" --localApi "$LOCAL_API" + [ "$allowPublic" = "1" ] && procd_append_param command --allowPublic + [ "$logger" = "1" ] && procd_set_param stderr 1 procd_set_param respawn procd_close_instance } diff --git a/linkease/files/linkease.uci-default b/linkease/files/linkease.uci-default index 873545db6..225dd09e7 100644 --- a/linkease/files/linkease.uci-default +++ b/linkease/files/linkease.uci-default @@ -8,23 +8,52 @@ EEOF } +if ! uci -q get linkease.@linkease[0] >/dev/null; then + uci -q add linkease linkease >/dev/null +fi + +set_default() { + key="$1" + value="$2" + current="$(uci -q get "linkease.@linkease[0].$key" 2>/dev/null || true)" + [ -n "$current" ] && return 0 + uci -q set "linkease.@linkease[0].$key=$value" +} + +set_default enabled 1 +set_default port 8897 +set_default allowPublic 0 +uci -q commit linkease +port="$(uci -q get linkease.@linkease[0].port 2>/dev/null || true)" +[ -n "$port" ] || port=8897 +allow_public="$(uci -q get linkease.@linkease[0].allowPublic 2>/dev/null || true)" + uci -q batch <<-EOF >/dev/null delete ucitrack.@linkease[-1] add ucitrack linkease set ucitrack.@linkease[-1].init=linkease commit ucitrack +EOF +if [ "$allow_public" = "1" ]; then + uci -q batch <<-EOF >/dev/null delete firewall.linkease set firewall.linkease=rule set firewall.linkease.name="linkease" set firewall.linkease.target="ACCEPT" set firewall.linkease.src="wan" set firewall.linkease.proto="tcp" - set firewall.linkease.dest_port="8897" + set firewall.linkease.dest_port="$port" commit firewall EOF +else + uci -q batch <<-EOF >/dev/null + delete firewall.linkease + commit firewall +EOF +fi /etc/init.d/linkease enable -/etc/init.d/linkease start +/etc/init.d/linkease restart -exit 0 \ No newline at end of file +exit 0 diff --git a/linkeasefull/Makefile b/linkeasefull/Makefile new file mode 100644 index 000000000..2ffad84c9 --- /dev/null +++ b/linkeasefull/Makefile @@ -0,0 +1,76 @@ +# +# Copyright (C) 2026 iStoreOS +# +# This is free software, licensed under the GNU General Public License v3. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=linkeasefull +PKG_SOURCE_DATE:=3.0.4 +PKG_RELEASE:=1 + +ifeq ($(ARCH),x86_64) +LINKEASE_RUNTIME_ARCH:=amd64 +PKG_HASH:=skip +else ifeq ($(ARCH),aarch64) +LINKEASE_RUNTIME_ARCH:=arm64 +PKG_HASH:=skip +endif + +PKG_SOURCE:=linkease-runtime-$(PKG_SOURCE_DATE)-linux-$(LINKEASE_RUNTIME_ARCH).tar.gz +PKG_SOURCE_URL:=https://github.com/linkease/linkease-desktop/releases/download/linkease-runtime-v$(PKG_SOURCE_DATE)/ +PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-binary-$(PKG_SOURCE_DATE) + +PKG_BUILD_PARALLEL:=1 +PKG_USE_MIPS16:=0 +TAR_CMD=$(HOST_TAR) -C $(PKG_BUILD_DIR) --strip-components=1 $(TAR_OPTIONS) + +include $(INCLUDE_DIR)/package.mk + +define Package/$(PKG_NAME) + SECTION:=net + CATEGORY:=Network + SUBMENU:=Web Servers/Proxies + TITLE:=LinkEase Full - the local web desktop + DEPENDS:=@(x86_64||aarch64) +linkease +ca-bundle + URL:=https://www.linkease.com/ +endef + +define Package/$(PKG_NAME)/description + LinkEase Full provides the local web desktop entry for LinkEase and reuses the standard LinkEase LuCI file entry. +endef + +define Package/$(PKG_NAME)/conffiles +/etc/config/linkeasefull +endef + +define Package/$(PKG_NAME)/postinst +#!/bin/sh +if [ -z "$${IPKG_INSTROOT}" ]; then + [ -f /etc/uci-defaults/linkeasefull ] && /etc/uci-defaults/linkeasefull && rm -f /etc/uci-defaults/linkeasefull + exit 0 +fi +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/$(PKG_NAME)/install + $(INSTALL_DIR) $(1)/usr/bin $(1)/usr/libexec/linkeasefull/linkmount_bin $(1)/usr/libexec/linkeasefull/scripts $(1)/etc/config $(1)/etc/init.d $(1)/etc/uci-defaults + $(INSTALL_BIN) $(PKG_BUILD_DIR)/bin/linkease-full $(1)/usr/bin/linkease-full + $(INSTALL_BIN) $(PKG_BUILD_DIR)/bin/linkremote-agent $(1)/usr/bin/linkremote-agent + $(INSTALL_BIN) $(PKG_BUILD_DIR)/bin/hostlink $(1)/usr/bin/hostlink + $(INSTALL_BIN) $(PKG_BUILD_DIR)/linkmount_bin/linkmount_bin $(1)/usr/libexec/linkeasefull/linkmount_bin/linkmount_bin + $(CP) $(PKG_BUILD_DIR)/linkmount_bin/lib $(1)/usr/libexec/linkeasefull/linkmount_bin/lib + $(CP) $(PKG_BUILD_DIR)/linkmount_bin/ver.json $(1)/usr/libexec/linkeasefull/linkmount_bin/ver.json + $(CP) $(PKG_BUILD_DIR)/scripts/. $(1)/usr/libexec/linkeasefull/scripts/ + $(INSTALL_CONF) ./files/linkeasefull.config $(1)/etc/config/linkeasefull + $(INSTALL_BIN) ./files/linkeasefull.init $(1)/etc/init.d/linkeasefull + $(INSTALL_BIN) ./files/linkeasefull.uci-default $(1)/etc/uci-defaults/linkeasefull +endef + +$(eval $(call BuildPackage,$(PKG_NAME))) diff --git a/linkeasefull/files/linkeasefull.config b/linkeasefull/files/linkeasefull.config new file mode 100644 index 000000000..b8fe9b57a --- /dev/null +++ b/linkeasefull/files/linkeasefull.config @@ -0,0 +1,3 @@ +config linkeasefull + option enabled '1' + option data_root_parent '' diff --git a/linkeasefull/files/linkeasefull.init b/linkeasefull/files/linkeasefull.init new file mode 100644 index 000000000..8c95e8013 --- /dev/null +++ b/linkeasefull/files/linkeasefull.init @@ -0,0 +1,131 @@ +#!/bin/sh /etc/rc.common + +START=100 +STOP=10 +USE_PROCD=1 + +PROG=/usr/bin/linkease-full +LINKEASE_LIBEXEC=/usr/libexec/linkeasefull +LINKEASE_FULL_PORT=19290 +LINKEASE_BASE_PATH=/apps/ +LINKEASE_LEGACY_ADDR=0.0.0.0:8897 + +is_persistent_data_root_parent() { + [ -n "$1" ] || return 1 + case "$1" in + /tmp|/tmp/*|/var|/var/*|/run|/run/*|/dev|/dev/*|/proc|/proc/*|/sys|/sys/*|/rom|/rom/*|/overlay|/overlay/*) return 1 ;; + esac + [ -d "$1" ] || return 1 + return 0 +} + +resolve_data_root_parent() { + if [ -n "$data_root_parent" ]; then + is_persistent_data_root_parent "$data_root_parent" + return $? + fi + + local_home="$(uci -q get linkease.@linkease[0].local_home || true)" + if is_persistent_data_root_parent "$local_home"; then + data_root_parent="$local_home" + return 0 + fi + + if [ -f /etc/config/quickstart ]; then + quickstart_main_dir="$(uci -q get quickstart.main.main_dir || true)" + if [ -n "$quickstart_main_dir" ]; then + if is_persistent_data_root_parent "$quickstart_main_dir"; then + data_root_parent="$quickstart_main_dir" + return 0 + fi + fi + fi + + return 1 +} + +stop_other_linkease_runtimes() { + [ -x /etc/init.d/linkease ] && /etc/init.d/linkease stop >/dev/null 2>&1 + [ -x /etc/init.d/linkeaselite ] && /etc/init.d/linkeaselite stop >/dev/null 2>&1 + + if uci -q get linkease.@linkease[0] >/dev/null 2>&1; then + uci -q set linkease.@linkease[0].enabled="0" + uci -q commit linkease + fi + if uci -q get linkeaselite.@linkeaselite[0] >/dev/null 2>&1; then + uci -q set linkeaselite.@linkeaselite[0].enabled="0" + uci -q commit linkeaselite + fi +} + +read_config() { + section="$1" + config_get_bool enabled "$section" enabled 1 + config_get data_root_parent "$section" data_root_parent "" + + if ! resolve_data_root_parent; then + data_root_parent="" + return 1 + fi + data_root="$data_root_parent/.linkease_data" + recycle_root="$data_root_parent/.linkease_recycle" +} + +start_service() { + config_load linkeasefull + config_foreach read_config linkeasefull + [ "$enabled" = "1" ] || return 1 + [ -x "$PROG" ] || return 1 + if [ -z "$data_root_parent" ]; then + echo "linkeasefull: please choose a persistent disk storage path in LuCI" >&2 + return 1 + fi + + stop_other_linkease_runtimes + mkdir -p "$data_root/users/admin" "$data_root/system" "$data_root/tmp" "$recycle_root" + mkdir -p "$data_root/apptunnel" "$data_root/mountremote" "$data_root/logs" + + procd_open_instance linkeasefull + procd_set_param limits nofile="65535 65535" + procd_set_param command "$PROG" + procd_set_param env \ + "SERVER_HOST=0.0.0.0" \ + "SERVER_PORT=$LINKEASE_FULL_PORT" \ + "SERVER_MODE=release" \ + "SERVER_BASE_PATH=$LINKEASE_BASE_PATH" \ + "LINKEASE_AUTH_PROVIDER=openwrt_luci" \ + "LINKEASE_EDITION=nas-full" \ + "KAIPLUS_ENABLED=0" \ + "LINKEASE_DATA_ROOT=$data_root" \ + "LINKEASE_RECYCLE_ROOT=$recycle_root" \ + "LINKEASE_APPTUNNEL_INTERNAL_ADDR=127.0.0.1:19810" \ + "LINKEASE_APPTUNNEL_LEGACY_ADDR=$LINKEASE_LEGACY_ADDR" \ + "LINKEASE_APPTUNNEL_DATA_DIR=$data_root/apptunnel" \ + "LINKEASE_APPTUNNEL_CACHE_DIR=$data_root/apptunnel/cache" \ + "LINKEASE_APPTUNNEL_RUNTIME_DIR=$data_root/apptunnel/runtime" \ + "LINKEASE_APPTUNNEL_LOG_DIR=$data_root/logs" \ + "APPTUNNEL_MOUNTREMOTE_MODE=real" \ + "APPTUNNEL_MOUNTREMOTE_LINKREMOTE_AGENT_BINARY=/usr/bin/linkremote-agent" \ + "APPTUNNEL_MOUNTREMOTE_SMBD_BINARY=$LINKEASE_LIBEXEC/linkmount_bin/linkmount_bin" \ + "APPTUNNEL_MOUNTREMOTE_WORK_DIR=$data_root/mountremote" \ + "APPTUNNEL_MOUNTREMOTE_SOCKET_DIR=$data_root/mountremote" \ + "APPTUNNEL_MOUNTREMOTE_SAMBA_DIR=$data_root/mountremote/samba" \ + "APPTUNNEL_MOUNTREMOTE_STORE_PATH=$data_root/mountremote/mounts.json" \ + "APPTUNNEL_MOUNTREMOTE_STARTUP_RECONCILE=true" \ + "APPTUNNEL_MOUNTREMOTE_ROOT_WATCH_DIR=$data_root/mountremote/root-watch" \ + "APPTUNNEL_MOUNTREMOTE_ALLOWED_MOUNT_PREFIX=$data_root_parent" \ + "MOUNTREMOTE_ALLOWED_MOUNT_PREFIX=$data_root_parent" \ + "LINKEASE_LINKMOUNT_BIN=$LINKEASE_LIBEXEC/linkmount_bin/linkmount_bin" \ + "LINKEASE_LINKMOUNT_LIB_DIR=$LINKEASE_LIBEXEC/linkmount_bin/lib" \ + "USER_DATA_PATH=$data_root/users/admin" \ + "SYSTEM_DATA_PATH=$data_root/system" \ + "TEMP_PATH=$data_root/tmp" + procd_set_param respawn + procd_set_param stdout 1 + procd_set_param stderr 1 + procd_close_instance +} + +service_triggers() { + procd_add_reload_trigger "linkeasefull" +} diff --git a/linkeasefull/files/linkeasefull.uci-default b/linkeasefull/files/linkeasefull.uci-default new file mode 100644 index 000000000..e178bf1ed --- /dev/null +++ b/linkeasefull/files/linkeasefull.uci-default @@ -0,0 +1,36 @@ +#!/bin/sh +[ ! -f "/usr/share/ucitrack/luci-app-linkeasefull.json" ] && { + cat > /usr/share/ucitrack/luci-app-linkeasefull.json << EEOF +{ + "config": "linkeasefull", + "init": "linkeasefull" +} +EEOF +} + +if ! uci -q get linkeasefull.@linkeasefull[0] >/dev/null; then + uci -q add linkeasefull linkeasefull >/dev/null +fi + +set_default() { + key="$1" + value="$2" + current="$(uci -q get "linkeasefull.@linkeasefull[0].$key" 2>/dev/null || true)" + [ -n "$current" ] && return 0 + uci -q set "linkeasefull.@linkeasefull[0].$key=$value" +} + +set_default enabled 1 +uci -q commit linkeasefull + +uci -q batch <<-EOF >/dev/null + delete ucitrack.@linkeasefull[-1] + add ucitrack linkeasefull + set ucitrack.@linkeasefull[-1].init=linkeasefull + commit ucitrack +EOF + +/etc/init.d/linkeasefull enable +/etc/init.d/linkeasefull restart + +exit 0 diff --git a/linkeaselite/Makefile b/linkeaselite/Makefile new file mode 100644 index 000000000..ee21775a4 --- /dev/null +++ b/linkeaselite/Makefile @@ -0,0 +1,75 @@ +# +# Copyright (C) 2015-2016 OpenWrt.org +# Copyright (C) 2026 LinkEaseLite Contributors +# +# This is free software, licensed under the GNU General Public License v3. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=linkeaselite +PKG_SOURCE_DATE:=3.0.0 +PKG_RELEASE:=1 + +PKG_SOURCE:=linkeaselite-binary-$(PKG_SOURCE_DATE).tar.gz +PKG_SOURCE_URL:=https://github.com/linkease/istore-packages/releases/download/linkeaselite-v$(PKG_SOURCE_DATE)/ +PKG_HASH:=skip +PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-binary-$(PKG_SOURCE_DATE) + +PKG_BUILD_PARALLEL:=1 +PKG_USE_MIPS16:=0 +TAR_CMD=$(HOST_TAR) -C $(PKG_BUILD_DIR) $(TAR_OPTIONS) + +include $(INCLUDE_DIR)/package.mk + +define Package/$(PKG_NAME) + SECTION:=net + CATEGORY:=Network + SUBMENU:=Web Servers/Proxies + TITLE:=LinkEaseLite - the file cloud + DEPENDS:=@(arm||x86_64||aarch64) +ca-bundle + URL:=https://www.linkease.com/ +endef + +define Package/$(PKG_NAME)/description + LinkEaseLite is a lightweight LinkEase runtime for small-memory OpenWrt devices. +endef + +define Package/$(PKG_NAME)/conffiles +/etc/config/linkeaselite +endef + +define Package/$(PKG_NAME)/postinst +#!/bin/sh +if [ -z "$${IPKG_INSTROOT}" ]; then + [ -f /etc/uci-defaults/linkeaselite ] && /etc/uci-defaults/linkeaselite && rm -f /etc/uci-defaults/linkeaselite + exit 0 +fi +endef + +define Package/$(PKG_NAME)/postrm +#!/bin/sh +if [ -z "$${IPKG_INSTROOT}" ]; then + uci -q delete firewall.linkeaselite + uci -q commit firewall + /etc/init.d/firewall reload +fi +exit 0 +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/$(PKG_NAME)/install + $(INSTALL_DIR) $(1)/usr/sbin $(1)/etc/config $(1)/etc/init.d $(1)/etc/uci-defaults + $(INSTALL_BIN) $(PKG_BUILD_DIR)/linkease-lite.$(ARCH) $(1)/usr/sbin/linkease-lite + $(INSTALL_BIN) ./files/linkeaselite-config.sh $(1)/usr/sbin/linkeaselite-config.sh + $(INSTALL_CONF) ./files/linkeaselite.config $(1)/etc/config/linkeaselite + $(INSTALL_BIN) ./files/linkeaselite.init $(1)/etc/init.d/linkeaselite + $(INSTALL_BIN) ./files/linkeaselite.uci-default $(1)/etc/uci-defaults/linkeaselite +endef + +$(eval $(call BuildPackage,$(PKG_NAME))) diff --git a/linkeaselite/files/linkeaselite-config.sh b/linkeaselite/files/linkeaselite-config.sh new file mode 100755 index 000000000..7dc6c7aea --- /dev/null +++ b/linkeaselite/files/linkeaselite-config.sh @@ -0,0 +1,78 @@ +#!/bin/sh + +. /lib/functions.sh + +case "$1" in + save) + if [ -n "$2" ]; then + uci set "linkeaselite.@linkeaselite[0].preconfig=$2" + uci commit linkeaselite + fi + ;; + + load) + data="`uci -q get linkeaselite.@linkeaselite[0].preconfig`" + if [ -z "${data}" ]; then + echo "nil" + else + echo "${data}" + fi + ;; + + local_save) + if [ -n "$2" ]; then + uci set "linkeaselite.@linkeaselite[0].local_home=$2" + uci commit linkeaselite + ROOT_DIR="$2" + if [ -f "/etc/config/quickstart" ]; then + config_load quickstart + config_get MAIN_DIR main main_dir "" + config_get CONF_DIR main conf_dir "" + config_get PUB_DIR main pub_dir "" + config_get DL_DIR main dl_dir "" + config_get TMP_DIR main tmp_dir "" + [ "$ROOT_DIR" = "$MAIN_DIR" ] && exit 0 + uci set "quickstart.main.main_dir=$ROOT_DIR" + if [ -z "$CONF_DIR" ] || [ "$CONF_DIR" = "$MAIN_DIR/Configs" ]; then + uci set "quickstart.main.conf_dir=$ROOT_DIR/Configs" + fi + if [ -z "$PUB_DIR" ] || [ "$PUB_DIR" = "$MAIN_DIR/Public" ]; then + uci set "quickstart.main.pub_dir=$ROOT_DIR/Public" + fi + if [ -z "$DL_DIR" ] || [ "$DL_DIR" = "$MAIN_DIR/Public/Downloads" ]; then + uci set "quickstart.main.dl_dir=$ROOT_DIR/Public/Downloads" + fi + if [ -z "$TMP_DIR" ] || [ "$TMP_DIR" = "$MAIN_DIR/Caches" ]; then + uci set "quickstart.main.tmp_dir=$ROOT_DIR/Caches" + fi + uci commit quickstart + fi + fi + ;; + + local_load) + if [ -f "/etc/config/quickstart" ]; then + data="`uci -q get quickstart.main.main_dir`" + fi + if [ -z "$data" ]; then + data="`uci -q get linkeaselite.@linkeaselite[0].local_home`" + fi + if [ -z "${data}" ]; then + echo "nil" + else + echo "${data}" + fi + ;; + + status) + if pidof linkease-lite >/dev/null 2>&1; then + echo "running" + else + echo "stopped" + fi + ;; + + *) + echo "Usage: $0 {save|load|local_save|local_load|status}" + exit 1 +esac diff --git a/linkeaselite/files/linkeaselite.config b/linkeaselite/files/linkeaselite.config new file mode 100644 index 000000000..1e610c0f2 --- /dev/null +++ b/linkeaselite/files/linkeaselite.config @@ -0,0 +1,4 @@ +config linkeaselite + option enabled '1' + option port '8897' + option allowPublic '0' diff --git a/linkeaselite/files/linkeaselite.init b/linkeaselite/files/linkeaselite.init new file mode 100755 index 000000000..276d6fd53 --- /dev/null +++ b/linkeaselite/files/linkeaselite.init @@ -0,0 +1,68 @@ +#!/bin/sh /etc/rc.common + +START=99 +STOP=10 +USE_PROCD=1 + +PROG=/usr/sbin/linkease-lite +LOCAL_API=/var/run/linkeaselite.sock + +read_config() { + section="$1" + config_get_bool enabled "$section" enabled 1 + config_get port "$section" port 8897 + config_get_bool allowPublic "$section" allowPublic 0 +} + +sync_firewall() { + uci -q delete firewall.linkeaselite + if [ "$allowPublic" = "1" ]; then + uci -q set firewall.linkeaselite=rule + uci -q set firewall.linkeaselite.name="linkeaselite" + uci -q set firewall.linkeaselite.target="ACCEPT" + uci -q set firewall.linkeaselite.src="wan" + uci -q set firewall.linkeaselite.proto="tcp" + uci -q set firewall.linkeaselite.dest_port="$port" + fi + uci -q commit firewall + /etc/init.d/firewall reload +} + +stop_linkease_runtimes() { + [ -x /etc/init.d/linkeasefull ] && /etc/init.d/linkeasefull stop >/dev/null 2>&1 + [ -x /etc/init.d/linkease ] && /etc/init.d/linkease stop >/dev/null 2>&1 + + if uci -q get linkease.@linkease[0] >/dev/null 2>&1; then + uci -q set linkease.@linkease[0].enabled="0" + uci -q commit linkease + fi + if uci -q get linkeasefull.@linkeasefull[0] >/dev/null 2>&1; then + uci -q set linkeasefull.@linkeasefull[0].enabled="0" + uci -q commit linkeasefull + fi +} + +start_service() { + config_load linkeaselite + config_foreach read_config linkeaselite + sync_firewall + [ "$enabled" = "1" ] || return 1 + [ -x "$PROG" ] || return 1 + + stop_linkease_runtimes + rm -f "$LOCAL_API" + + procd_open_instance linkeaselite + procd_set_param limits nofile="65535 65535" + procd_set_param command "$PROG" + procd_append_param command --deviceAddr ":$port" --localApi "$LOCAL_API" + [ "$allowPublic" = "1" ] && procd_append_param command --allowPublic + procd_set_param respawn + procd_set_param stdout 1 + procd_set_param stderr 1 + procd_close_instance +} + +service_triggers() { + procd_add_reload_trigger "linkeaselite" +} diff --git a/linkeaselite/files/linkeaselite.uci-default b/linkeaselite/files/linkeaselite.uci-default new file mode 100644 index 000000000..6ebed20d0 --- /dev/null +++ b/linkeaselite/files/linkeaselite.uci-default @@ -0,0 +1,60 @@ +#!/bin/sh +[ ! -f "/usr/share/ucitrack/luci-app-linkeaselite.json" ] && { + cat > /usr/share/ucitrack/luci-app-linkeaselite.json << EEOF +{ + "config": "linkeaselite", + "init": "linkeaselite" +} +EEOF +} + +if ! uci -q get linkeaselite.@linkeaselite[0] >/dev/null; then + uci -q add linkeaselite linkeaselite >/dev/null +fi + +set_default() { + key="$1" + value="$2" + current="$(uci -q get "linkeaselite.@linkeaselite[0].$key" 2>/dev/null || true)" + [ -n "$current" ] && return 0 + uci -q set "linkeaselite.@linkeaselite[0].$key=$value" +} + +set_default enabled 1 +set_default port 8897 +set_default allowPublic 0 +uci -q commit linkeaselite + +port="$(uci -q get linkeaselite.@linkeaselite[0].port 2>/dev/null || true)" +[ -n "$port" ] || port=8897 +allow_public="$(uci -q get linkeaselite.@linkeaselite[0].allowPublic 2>/dev/null || true)" + +uci -q batch <<-EOF >/dev/null + delete ucitrack.@linkeaselite[-1] + add ucitrack linkeaselite + set ucitrack.@linkeaselite[-1].init=linkeaselite + commit ucitrack +EOF + +if [ "$allow_public" = "1" ]; then + uci -q batch <<-EOF >/dev/null + delete firewall.linkeaselite + set firewall.linkeaselite=rule + set firewall.linkeaselite.name="linkeaselite" + set firewall.linkeaselite.target="ACCEPT" + set firewall.linkeaselite.src="wan" + set firewall.linkeaselite.proto="tcp" + set firewall.linkeaselite.dest_port="$port" + commit firewall +EOF +else + uci -q batch <<-EOF >/dev/null + delete firewall.linkeaselite + commit firewall +EOF +fi + +/etc/init.d/linkeaselite enable +/etc/init.d/linkeaselite restart + +exit 0 diff --git a/linkmount/Makefile b/linkmount/Makefile deleted file mode 100644 index e4fa726f0..000000000 --- a/linkmount/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# -# This is free software, licensed under the GNU General Public License v2. -# See /LICENSE for more information. -# - -include $(TOPDIR)/rules.mk - -PKG_ARCH_LINKEASE:=$(ARCH) - -PKG_NAME:=linkmount -# use PKG_SOURCE_DATE instead of PKG_VERSION for compitable -PKG_SOURCE_DATE:=1.0.3 -PKG_RELEASE:=1 -ARCH_HEXCODE:= -ifeq ($(ARCH),x86_64) -ARCH_HEXCODE=8664 -else ifeq ($(ARCH),aarch64) -ARCH_HEXCODE=aa64 -else ifeq ($(ARCH),arm) -ARCH_HEXCODE=aa32 -else ifeq ($(ARCH),mipsel) -ARCH_HEXCODE=1b0c -endif -PKG_SOURCE_VERSION:=$(ARCH_HEXCODE) -PKG_SOURCE:=$(PKG_NAME)-binary-$(PKG_SOURCE_DATE).tar.gz -PKG_SOURCE_URL:=https://dl.istoreos.com/binary/LinkEase/AutoUpgrade/linkmount/ -PKG_HASH:=skip - -PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-binary-$(PKG_SOURCE_DATE) - -PKG_BUILD_PARALLEL:=1 -PKG_USE_MIPS16:=0 - -include $(INCLUDE_DIR)/package.mk - -define Package/$(PKG_NAME) - SECTION:=net - CATEGORY:=Network - SUBMENU:=Web Servers/Proxies - TITLE:=LinkMount - the file cloud - DEPENDS:=@(arm||x86_64||aarch64) - PKGARCH:=all - URL:=https://www.linkease.com/ -endef - -define Package/$(PKG_NAME)/description - LinkMount is used by LinkEase -endef - -define Build/Configure -endef - -define Build/Compile -endef - -define Package/$(PKG_NAME)/install - $(INSTALL_DIR) $(1)/usr/sbin/linkmount - $(INSTALL_BIN) $(PKG_BUILD_DIR)/$(PKG_ARCH_LINKEASE)/bin/linkmount_bin $(1)/usr/sbin/linkmount/linkmount_bin - $(CP) $(PKG_BUILD_DIR)/$(PKG_ARCH_LINKEASE)/bin/lib $(1)/usr/sbin/linkmount/lib -endef - -$(eval $(call BuildPackage,$(PKG_NAME))) - diff --git a/luci-app-amlogic/Makefile b/luci-app-amlogic/Makefile index 79249fbcf..b7ec4e508 100644 --- a/luci-app-amlogic/Makefile +++ b/luci-app-amlogic/Makefile @@ -16,8 +16,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-amlogic -PKG_VERSION:=3.1.319 -PKG_RELEASE:=16 +PKG_VERSION:=3.1.320 +PKG_RELEASE:=17 PKG_LICENSE:=GPL-2.0 License PKG_MAINTAINER:=ophub diff --git a/luci-app-amlogic/htdocs/luci-static/resources/view/amlogic/info.js b/luci-app-amlogic/htdocs/luci-static/resources/view/amlogic/info.js index cec86c7ce..b05ffd3bc 100644 --- a/luci-app-amlogic/htdocs/luci-static/resources/view/amlogic/info.js +++ b/luci-app-amlogic/htdocs/luci-static/resources/view/amlogic/info.js @@ -57,22 +57,24 @@ return view.extend({ handleSaveApply: null, handleReset: null, - // On load, call sync_menu to update sidebar menu flags from runtime platform detection. If the install menu becomes - // visible but is not in the current nav, reload once to pick up the new menu (guarded by #menu-synced hash). - load: function () { - // Call sync_menu; if the install menu is now visible on the server but - // absent in the browser nav, reload once (guarded by #menu-synced hash). + // On load, call sync_menu to update sidebar menu flags from runtime platform detection. If the sidebar nav is out of + // sync with the server-side menu flags, reload once to pick up the new menu (guarded by #menu-synced hash). + load: function () { + // Call sync_menu; reload once when the sidebar nav disagrees with the + // server-side menu flags in either direction (guarded by #menu-synced hash). const alreadyReloaded = window.location.hash === '#menu-synced'; const syncMenuPromise = callSyncMenu().then(function (res) { - if (alreadyReloaded) return; - if (res && res.show_install === 'yes') { - // Check if the sidebar navigation already contains the install link. - const installLink = document.querySelector('a[href*="amlogic/install"]'); - if (!installLink) { - // Server-side index cache updated; reload to pick up new nav. - window.location.replace(window.location.pathname + '#menu-synced'); - window.location.reload(); - } + if (alreadyReloaded || !res) return; + // Check if the sidebar navigation already contains the install link. + const installLink = document.querySelector('a[href*="amlogic/install"]'); + // Menu became visible on the server but is absent in the browser nav. + const needShow = (res.show_install === 'yes' && !installLink); + // Menu became hidden on the server but is still present in the browser nav. + const needHide = (res.show_install === 'no' && installLink); + if (needShow || needHide) { + // Server-side index cache updated; reload to pick up new nav. + window.location.replace(window.location.pathname + '#menu-synced'); + window.location.reload(); } }).catch(function () {}); return Promise.all([callAuthor(), syncMenuPromise]).then(function (r) { return r[0]; }); diff --git a/luci-app-amlogic/root/etc/uci-defaults/luci-amlogic b/luci-app-amlogic/root/etc/uci-defaults/luci-amlogic index b357fa6ef..74bdbb830 100644 --- a/luci-app-amlogic/root/etc/uci-defaults/luci-amlogic +++ b/luci-app-amlogic/root/etc/uci-defaults/luci-amlogic @@ -20,10 +20,28 @@ PLATFORM=$(grep -E '^PLATFORM=' /etc/flippy-openwrt-release 2>/dev/null | \ SHOW_INSTALL=$(grep -E '^SHOW_INSTALL_MENU=' /etc/flippy-openwrt-release 2>/dev/null | \ awk -F= '{print $2}' | tr -d '"' | xargs) -case "$PLATFORM" in - *amlogic*) MENU_INSTALL=yes ;; - *) [ "$SHOW_INSTALL" = "yes" ] && MENU_INSTALL=yes || MENU_INSTALL=no ;; +# Detect whether the root fs is already on eMMC (mmcblk*p* with device/type == "MMC"). +# Mirrors root_on_internal_storage() in luci.amlogic: all other boot media +# (TF/SD, NVMe, SATA, USB) keep the install menu visible. +ROOT_PT=$(df / | tail -n1 | awk '{print $1}' | awk -F '/' '{print $3}') +IS_INSTALLED=0 +case "$ROOT_PT" in + mmcblk*p*) + BASE_DEV="${ROOT_PT%p*}" + [ "$(cat /sys/block/${BASE_DEV}/device/type 2>/dev/null | xargs)" = "MMC" ] && IS_INSTALLED=1 + ;; esac + +case "$PLATFORM" in + *amlogic*|*allwinner*) CAN_INSTALL=yes ;; + *) [ "$SHOW_INSTALL" = "yes" ] && CAN_INSTALL=yes || CAN_INSTALL=no ;; +esac +if [ "$CAN_INSTALL" = "yes" ] && [ "$IS_INSTALLED" = "0" ]; then + MENU_INSTALL=yes +else + MENU_INSTALL=no +fi + case "$PLATFORM" in *qemu*) MENU_ARMCPU=no ;; *) MENU_ARMCPU=yes ;; diff --git a/luci-app-ddns/po/ar/ddns.po b/luci-app-ddns/po/ar/ddns.po index 8f99ab433..005397298 100644 --- a/luci-app-ddns/po/ar/ddns.po +++ b/luci-app-ddns/po/ar/ddns.po @@ -1,7 +1,7 @@ msgid "" msgstr "" -"PO-Revision-Date: 2026-04-24 15:14+0000\n" -"Last-Translator: \"د.عبدالعزيز الجهني\" \n" +"PO-Revision-Date: 2026-07-03 15:29+0000\n" +"Last-Translator: Develper openmn \n" "Language-Team: Arabic \n" "Language: ar\n" @@ -9,7 +9,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 " "&& n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n" -"X-Generator: Weblate 5.17.1-dev\n" +"X-Generator: Weblate 2026.7.1.dev0\n" #: applications/luci-app-ddns/htdocs/luci-static/resources/view/ddns/overview.js:423 msgid "\"../\" not allowed in path for Security Reason." @@ -74,7 +74,7 @@ msgstr "" #: applications/luci-app-ddns/htdocs/luci-static/resources/view/ddns/overview.js:532 msgid "Cancel" -msgstr "الغاء" +msgstr "إلغاء" #: applications/luci-app-ddns/htdocs/luci-static/resources/view/ddns/overview.js:981 msgid "Check Interval" diff --git a/luci-app-ddns/po/es/ddns.po b/luci-app-ddns/po/es/ddns.po index f07a2998a..0976c3ff7 100644 --- a/luci-app-ddns/po/es/ddns.po +++ b/luci-app-ddns/po/es/ddns.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: luci-app-ddns 2.4.0-1\n" "POT-Creation-Date: 2016-01-30 11:07+0100\n" -"PO-Revision-Date: 2026-04-18 17:10+0000\n" -"Last-Translator: Franco Castillo \n" +"PO-Revision-Date: 2026-06-26 11:18+0000\n" +"Last-Translator: apemay \n" "Language-Team: Spanish \n" "Language: es\n" @@ -11,7 +11,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.17.1-dev\n" +"X-Generator: Weblate 2026.7.dev0\n" #: applications/luci-app-ddns/htdocs/luci-static/resources/view/ddns/overview.js:423 msgid "\"../\" not allowed in path for Security Reason." @@ -691,8 +691,8 @@ msgid "" "Source URL for services file. Defaults to the master openwrt ddns package " "repo." msgstr "" -"URL utilizada para descargar el archivo de servicios. De forma " -"predeterminada, es el repositorio principal del paquete ddns de openwrt ." +"URL de origen del archivo de servicios. De forma predeterminada, es el " +"repositorio principal del paquete DDNS de OpenWrt." #: applications/luci-app-ddns/htdocs/luci-static/resources/view/ddns/overview.js:201 msgid "Start DDNS" diff --git a/luci-app-ddns/po/ru/ddns.po b/luci-app-ddns/po/ru/ddns.po index 57c21978d..080107f03 100644 --- a/luci-app-ddns/po/ru/ddns.po +++ b/luci-app-ddns/po/ru/ddns.po @@ -2,9 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: LuCI: ddns\n" "POT-Creation-Date: 2017-10-17 21:00+0300\n" -"PO-Revision-Date: 2026-04-25 09:44+0000\n" -"Last-Translator: SnIPeRSnIPeR " -"\n" +"PO-Revision-Date: 2026-07-03 15:28+0000\n" +"Last-Translator: chigelo \n" "Language-Team: Russian \n" "Language: ru\n" @@ -13,7 +12,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" -"X-Generator: Weblate 5.17.1-dev\n" +"X-Generator: Weblate 2026.7.1.dev0\n" "Project-Info: Это технический перевод, не дословный. Главное-удобный русский " "интерфейс, все проверялось в графическом режиме, совместим с другими apps\n" @@ -447,7 +446,7 @@ msgstr "" #: applications/luci-app-ddns/htdocs/luci-static/resources/view/ddns/overview.js:491 #: applications/luci-app-ddns/htdocs/luci-static/resources/view/ddns/overview.js:1124 msgid "Name" -msgstr "Название" +msgstr "Имя" #: applications/luci-app-ddns/htdocs/luci-static/resources/view/ddns/overview.js:333 msgid "" diff --git a/luci-app-ddns/po/uk/ddns.po b/luci-app-ddns/po/uk/ddns.po index 18598c8d2..7fed6067a 100644 --- a/luci-app-ddns/po/uk/ddns.po +++ b/luci-app-ddns/po/uk/ddns.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: luci-app-ddns 2.4.0-1\n" "POT-Creation-Date: 2016-01-30 11:07+0100\n" -"PO-Revision-Date: 2026-05-12 09:07+0000\n" -"Last-Translator: Oleksandr Yurov \n" +"PO-Revision-Date: 2026-07-08 15:16+0000\n" +"Last-Translator: Dan \n" "Language-Team: Ukrainian \n" "Language: uk\n" @@ -12,7 +12,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" -"X-Generator: Weblate 2026.5-dev\n" +"X-Generator: Weblate 2026.7.1.dev0\n" #: applications/luci-app-ddns/htdocs/luci-static/resources/view/ddns/overview.js:423 msgid "\"../\" not allowed in path for Security Reason." @@ -437,7 +437,7 @@ msgstr "" #: applications/luci-app-ddns/htdocs/luci-static/resources/view/ddns/overview.js:491 #: applications/luci-app-ddns/htdocs/luci-static/resources/view/ddns/overview.js:1124 msgid "Name" -msgstr "Імʼя" +msgstr "Назва" #: applications/luci-app-ddns/htdocs/luci-static/resources/view/ddns/overview.js:333 msgid "" diff --git a/luci-app-ddns/root/usr/share/rpcd/ucode/ddns.uc b/luci-app-ddns/root/usr/share/rpcd/ucode/ddns.uc index c7b5a38b0..d7b0af2f1 100644 --- a/luci-app-ddns/root/usr/share/rpcd/ucode/ddns.uc +++ b/luci-app-ddns/root/usr/share/rpcd/ucode/ddns.uc @@ -228,7 +228,7 @@ const methods = { const hasWget = () => { return cache.has_wget ??= hasCommand('wget'); - } + }; const hasWgetSsl = () => { return cache.has_wgetssl ??= hasWget() && system(`wget 2>&1 | grep -iqF 'https'`) == 0 ? true : false; diff --git a/luci-app-dockerman/po/ar/dockerman.po b/luci-app-dockerman/po/ar/dockerman.po index 26e5c013e..f68891989 100644 --- a/luci-app-dockerman/po/ar/dockerman.po +++ b/luci-app-dockerman/po/ar/dockerman.po @@ -1,7 +1,7 @@ msgid "" msgstr "" -"PO-Revision-Date: 2026-04-24 15:13+0000\n" -"Last-Translator: \"د.عبدالعزيز الجهني\" \n" +"PO-Revision-Date: 2026-07-03 15:29+0000\n" +"Last-Translator: Develper openmn \n" "Language-Team: Arabic \n" "Language: ar\n" @@ -9,7 +9,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 " "&& n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n" -"X-Generator: Weblate 5.17.1-dev\n" +"X-Generator: Weblate 2026.7.1.dev0\n" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/container_new.js:505 msgid "/mnt/path" @@ -224,7 +224,7 @@ msgstr "وحدات المعالجة المركزية" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/container.js:1933 #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/container_new.js:517 msgid "Cancel" -msgstr "الغاء" +msgstr "إلغاء" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/configuration.js:35 msgid "Causes errors when a chosen API > Docker endpoint API support." diff --git a/luci-app-dockerman/po/cs/dockerman.po b/luci-app-dockerman/po/cs/dockerman.po index 3ccd2e938..e757576df 100644 --- a/luci-app-dockerman/po/cs/dockerman.po +++ b/luci-app-dockerman/po/cs/dockerman.po @@ -1,6 +1,6 @@ msgid "" msgstr "" -"PO-Revision-Date: 2026-06-11 08:15+0000\n" +"PO-Revision-Date: 2026-07-13 02:01+0000\n" "Last-Translator: Pavel Borecki \n" "Language-Team: Czech \n" @@ -8,7 +8,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=((n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2);\n" -"X-Generator: Weblate 2026.6\n" +"X-Generator: Weblate 2026.7.1.dev0\n" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/container_new.js:505 msgid "/mnt/path" @@ -2195,7 +2195,7 @@ msgstr "obraz" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/container_new.js:755 msgid "json-file" -msgstr "" +msgstr "json soubor" #: applications/luci-app-dockerman/htdocs/luci-static/resources/dockerman/common.js:336 msgid "kill" diff --git a/luci-app-dockerman/po/ko/dockerman.po b/luci-app-dockerman/po/ko/dockerman.po index bdfe0c9c1..c97ecbde9 100644 --- a/luci-app-dockerman/po/ko/dockerman.po +++ b/luci-app-dockerman/po/ko/dockerman.po @@ -1,6 +1,6 @@ msgid "" msgstr "" -"PO-Revision-Date: 2026-06-05 19:02+0000\n" +"PO-Revision-Date: 2026-06-27 12:02+0000\n" "Last-Translator: Hyeonjeong Lee \n" "Language-Team: Korean \n" @@ -8,7 +8,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 2026.6\n" +"X-Generator: Weblate 2026.7.dev0\n" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/container_new.js:505 msgid "/mnt/path" @@ -1376,7 +1376,7 @@ msgstr "" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/containers.js:351 msgid "Open in browser" -msgstr "" +msgstr "브라우저에서 열기" #: applications/luci-app-dockerman/htdocs/luci-static/resources/dockerman/common.js:899 msgid "Operation failed" @@ -1598,11 +1598,11 @@ msgstr "" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/images.js:535 msgid "Remove tag" -msgstr "" +msgstr "태그 제거" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/images.js:625 msgid "Repository" -msgstr "" +msgstr "저장소" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/images.js:658 msgid "Repository cannot be empty" diff --git a/luci-app-dockerman/po/ru/dockerman.po b/luci-app-dockerman/po/ru/dockerman.po index d94814fad..9e4fe08c8 100644 --- a/luci-app-dockerman/po/ru/dockerman.po +++ b/luci-app-dockerman/po/ru/dockerman.po @@ -1,8 +1,7 @@ msgid "" msgstr "" -"PO-Revision-Date: 2026-04-25 12:14+0000\n" -"Last-Translator: SnIPeRSnIPeR " -"\n" +"PO-Revision-Date: 2026-07-05 14:58+0000\n" +"Last-Translator: Deni Dgabiev \n" "Language-Team: Russian \n" "Language: ru\n" @@ -10,7 +9,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" -"X-Generator: Weblate 5.17.1-dev\n" +"X-Generator: Weblate 2026.7.1.dev0\n" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/container_new.js:505 msgid "/mnt/path" @@ -67,11 +66,11 @@ msgstr "Дополнительно" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/container.js:590 msgid "Aliases" -msgstr "" +msgstr "Псевдонимы" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/container.js:1923 msgid "Aliases (optional):" -msgstr "" +msgstr "Псевдонимы (опционально):" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/events.js:342 msgid "All Subtypes" @@ -489,7 +488,7 @@ msgstr "Отладка" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/container_new.js:753 msgid "Default (daemon)" -msgstr "" +msgstr "По умолчанию (демон)" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/configuration.js:57 msgid "Default bridge" @@ -892,7 +891,7 @@ msgstr "IPv4-адрес" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/container.js:1919 msgid "IPv4 Address (optional):" -msgstr "" +msgstr "IPv4-адрес (опционально):" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/network.js:64 msgid "IPv6" @@ -906,7 +905,7 @@ msgstr "IPv6‑адрес" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/container.js:1921 msgid "IPv6 Address (optional):" -msgstr "" +msgstr "IPv6-адрес (опционально):" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/container.js:586 #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/network_new.js:134 @@ -1102,7 +1101,7 @@ msgstr "Опции журналирования" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/container_new.js:751 msgid "Log driver" -msgstr "" +msgstr "Драйвер логирования" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/container_new.js:745 msgid "Log driver options" @@ -1214,7 +1213,7 @@ msgstr "Монтирования/Привязки" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/volumes.js:121 #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/volumes.js:241 msgid "Name" -msgstr "Название" +msgstr "Имя" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/container_new.js:213 msgid "Name of the container that can be selected during container creation" @@ -1230,7 +1229,7 @@ msgstr "Статистика сети" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/container_new.js:282 msgid "Network Aliases" -msgstr "" +msgstr "Сетевые псевдонимы" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/network.js:100 msgid "Network Configurations" @@ -1401,7 +1400,7 @@ msgstr "Только для пользовательских сетей" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/containers.js:351 msgid "Open in browser" -msgstr "" +msgstr "Открыть в браузере" #: applications/luci-app-dockerman/htdocs/luci-static/resources/dockerman/common.js:899 msgid "Operation failed" @@ -1755,7 +1754,7 @@ msgstr "" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/container.js:354 #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/container.js:1801 msgid "Start" -msgstr "Запустить" +msgstr "Начало" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/containers.js:208 msgid "Start this container" @@ -2200,7 +2199,7 @@ msgstr "образ" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/container_new.js:755 msgid "json-file" -msgstr "" +msgstr "json-файл" #: applications/luci-app-dockerman/htdocs/luci-static/resources/dockerman/common.js:336 msgid "kill" @@ -2212,7 +2211,7 @@ msgstr "загрузить" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/container_new.js:754 msgid "local" -msgstr "" +msgstr "локальный" #: applications/luci-app-dockerman/htdocs/luci-static/resources/dockerman/common.js:383 msgid "mount" @@ -2228,7 +2227,7 @@ msgstr "узел" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/container_new.js:757 msgid "none" -msgstr "" +msgstr "отсутствует" #: applications/luci-app-dockerman/htdocs/luci-static/resources/dockerman/common.js:337 msgid "oom" @@ -2297,7 +2296,7 @@ msgstr "остановить" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/container_new.js:756 msgid "syslog" -msgstr "" +msgstr "syslog" #: applications/luci-app-dockerman/htdocs/luci-static/resources/dockerman/common.js:364 msgid "tag" diff --git a/luci-app-dockerman/po/uk/dockerman.po b/luci-app-dockerman/po/uk/dockerman.po index e05c073a9..474613477 100644 --- a/luci-app-dockerman/po/uk/dockerman.po +++ b/luci-app-dockerman/po/uk/dockerman.po @@ -1,6 +1,6 @@ msgid "" msgstr "" -"PO-Revision-Date: 2026-05-21 05:04+0000\n" +"PO-Revision-Date: 2026-07-08 15:16+0000\n" "Last-Translator: Dan \n" "Language-Team: Ukrainian \n" @@ -9,7 +9,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" -"X-Generator: Weblate 2026.6.dev0\n" +"X-Generator: Weblate 2026.7.1.dev0\n" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/container_new.js:505 msgid "/mnt/path" @@ -1211,7 +1211,7 @@ msgstr "Монтування/Привʼязки" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/volumes.js:121 #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/volumes.js:241 msgid "Name" -msgstr "Імʼя" +msgstr "Назва" #: applications/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/container_new.js:213 msgid "Name of the container that can be selected during container creation" diff --git a/luci-app-kaiplus/Makefile b/luci-app-kaiplus/Makefile index 964873081..1cd0a30f4 100644 --- a/luci-app-kaiplus/Makefile +++ b/luci-app-kaiplus/Makefile @@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=KaiPlus PKG_VERSION:=1.0.0 -PKG_RELEASE:=1 +PKG_RELEASE:=2 LUCI_DEPENDS:=+kaiplus +luci-compat LUCI_MINIFY_CSS:=0 LUCI_MINIFY_JS:=0 diff --git a/luci-app-kaiplus/luasrc/controller/kaiplus.lua b/luci-app-kaiplus/luasrc/controller/kaiplus.lua index 769bd8056..9a0c080b1 100644 --- a/luci-app-kaiplus/luasrc/controller/kaiplus.lua +++ b/luci-app-kaiplus/luasrc/controller/kaiplus.lua @@ -15,10 +15,12 @@ end function kaiplus_status() local sys = require "luci.sys" local uci = require "luci.model.uci".cursor() - local port = uci:get_first("kaiplus", "kaiplus", "port", "8198") + local port = uci:get_first("kaiplus", "kaiplus", "port", "8189") + local base_path = uci:get_first("kaiplus", "kaiplus", "base_path", "/apps/kaiplus/") local status = { running = (sys.call("pidof kaiplus_bin >/dev/null") == 0), - port = port + port = port, + base_path = base_path } luci.http.prepare_content("application/json") luci.http.write_json(status) diff --git a/luci-app-kaiplus/luasrc/model/cbi/kaiplus.lua b/luci-app-kaiplus/luasrc/model/cbi/kaiplus.lua index 91de5648e..15a3a29d1 100644 --- a/luci-app-kaiplus/luasrc/model/cbi/kaiplus.lua +++ b/luci-app-kaiplus/luasrc/model/cbi/kaiplus.lua @@ -5,7 +5,10 @@ m = Map("kaiplus", translate("KaiPlus"), translate("KaiPlus is an AI workspace a m:section(SimpleSection).template = "kaiplus/kaiplus_status" m.on_after_commit = function(self) - sys.call("/etc/init.d/kaiplus restart >/dev/null 2>&1 &") + sys.call("/etc/init.d/kaiplus restart >/dev/null 2>&1") + if sys.call("[ -x /etc/init.d/linkease ]") == 0 then + sys.call("/etc/init.d/linkease restart >/dev/null 2>&1 &") + end end s = m:section(TypedSection, "kaiplus", translate("Global settings")) @@ -29,7 +32,7 @@ end data_dir.default = default_path local port = s:option(Value, "port", translate("Web port")) -port.default = "8198" +port.default = "8189" port.rmempty = false port.datatype = "port" port.description = translate("Port for the KaiPlus web service.") diff --git a/luci-app-kaiplus/luasrc/view/kaiplus/kaiplus_status.htm b/luci-app-kaiplus/luasrc/view/kaiplus/kaiplus_status.htm index 147688eba..7fb4da6fd 100644 --- a/luci-app-kaiplus/luasrc/view/kaiplus/kaiplus_status.htm +++ b/luci-app-kaiplus/luasrc/view/kaiplus/kaiplus_status.htm @@ -6,8 +6,15 @@ XHR.poll(5, '<%=url("admin/services/kaiplus_status")%>', null, function(x, st) { el.innerHTML = '
<%:The KaiPlus service is not running.%>'; } if (st.running) { + var basePath = st.base_path || "/apps/kaiplus/"; + if (basePath.charAt(0) !== "/") { + basePath = "/" + basePath; + } + if (basePath.charAt(basePath.length - 1) !== "/") { + basePath = basePath + "/"; + } el.innerHTML = '
<%:The KaiPlus service is running.%>' - + "

\" onclick=\"window.open('http://" + window.location.hostname + ":" + st.port + "/')\"/>"; + + "

\" onclick=\"window.open('http://' + window.location.hostname + ':' + st.port + basePath)\"/>"; } } }); diff --git a/luci-app-ksmbd/po/it/ksmbd.po b/luci-app-ksmbd/po/it/ksmbd.po index cef5f45d5..fe3f4c97b 100644 --- a/luci-app-ksmbd/po/it/ksmbd.po +++ b/luci-app-ksmbd/po/it/ksmbd.po @@ -1,14 +1,14 @@ msgid "" msgstr "" -"PO-Revision-Date: 2026-01-21 18:32+0000\n" -"Last-Translator: niky1987 \n" +"PO-Revision-Date: 2026-07-23 06:18+0000\n" +"Last-Translator: Random \n" "Language-Team: Italian \n" "Language: it\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.16-dev\n" +"X-Generator: Weblate 2026.8.dev0\n" #: applications/luci-app-ksmbd/htdocs/luci-static/resources/view/ksmbd.js:58 msgid "Add optional guest access to IPC$ share, disabled by default" @@ -82,7 +82,7 @@ msgstr "" #: applications/luci-app-ksmbd/htdocs/luci-static/resources/view/ksmbd.js:109 msgid "Inherit owner" -msgstr "" +msgstr "Eredita il proprietario" #: applications/luci-app-ksmbd/htdocs/luci-static/resources/view/ksmbd.js:36 msgid "Interface" diff --git a/luci-app-ksmbd/po/ru/ksmbd.po b/luci-app-ksmbd/po/ru/ksmbd.po index da21f335d..7423722f0 100644 --- a/luci-app-ksmbd/po/ru/ksmbd.po +++ b/luci-app-ksmbd/po/ru/ksmbd.po @@ -1,8 +1,7 @@ msgid "" msgstr "" -"PO-Revision-Date: 2026-04-25 12:14+0000\n" -"Last-Translator: SnIPeRSnIPeR " -"\n" +"PO-Revision-Date: 2026-07-03 15:29+0000\n" +"Last-Translator: chigelo \n" "Language-Team: Russian \n" "Language: ru\n" @@ -10,7 +9,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" -"X-Generator: Weblate 5.17.1-dev\n" +"X-Generator: Weblate 2026.7.1.dev0\n" #: applications/luci-app-ksmbd/htdocs/luci-static/resources/view/ksmbd.js:58 msgid "Add optional guest access to IPC$ share, disabled by default" @@ -96,7 +95,7 @@ msgstr "Слушать только на данном интерфейсе ил #: applications/luci-app-ksmbd/htdocs/luci-static/resources/view/ksmbd.js:81 msgid "Name" -msgstr "Название" +msgstr "Имя" #: applications/luci-app-ksmbd/htdocs/luci-static/resources/view/ksmbd.js:22 #: applications/luci-app-ksmbd/root/usr/share/luci/menu.d/luci-app-ksmbd.json:3 diff --git a/luci-app-ksmbd/po/uk/ksmbd.po b/luci-app-ksmbd/po/uk/ksmbd.po index 07a332fc4..74724a994 100644 --- a/luci-app-ksmbd/po/uk/ksmbd.po +++ b/luci-app-ksmbd/po/uk/ksmbd.po @@ -1,7 +1,7 @@ msgid "" msgstr "" -"PO-Revision-Date: 2026-05-12 09:06+0000\n" -"Last-Translator: Oleksandr Yurov \n" +"PO-Revision-Date: 2026-07-08 15:16+0000\n" +"Last-Translator: Dan \n" "Language-Team: Ukrainian \n" "Language: uk\n" @@ -9,7 +9,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" -"X-Generator: Weblate 2026.5-dev\n" +"X-Generator: Weblate 2026.7.1.dev0\n" #: applications/luci-app-ksmbd/htdocs/luci-static/resources/view/ksmbd.js:58 msgid "Add optional guest access to IPC$ share, disabled by default" @@ -98,7 +98,7 @@ msgstr "" #: applications/luci-app-ksmbd/htdocs/luci-static/resources/view/ksmbd.js:81 msgid "Name" -msgstr "Імʼя" +msgstr "Назва" #: applications/luci-app-ksmbd/htdocs/luci-static/resources/view/ksmbd.js:22 #: applications/luci-app-ksmbd/root/usr/share/luci/menu.d/luci-app-ksmbd.json:3 diff --git a/luci-app-linkease/Makefile b/luci-app-linkease/Makefile index dc76cfa5a..3ad83d030 100644 --- a/luci-app-linkease/Makefile +++ b/luci-app-linkease/Makefile @@ -6,11 +6,11 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=LuCI support for linkease -LUCI_DEPENDS:=+linkease +LUCI_DEPENDS:=+luci-lib-linkeasefile LUCI_PKGARCH:=all -PKG_VERSION:=2.1.70-r3 +PKG_VERSION:=2.1.70-r4 # PKG_RELEASE MUST be empty for luci.mk -PKG_RELEASE:=1 +PKG_RELEASE:=2 LUCI_MINIFY_CSS:=0 LUCI_MINIFY_JS:=0 diff --git a/luci-app-linkease/luasrc/controller/linkease.lua b/luci-app-linkease/luasrc/controller/linkease.lua index a71b80b82..ca1cd6cf5 100644 --- a/luci-app-linkease/luasrc/controller/linkease.lua +++ b/luci-app-linkease/luasrc/controller/linkease.lua @@ -9,7 +9,6 @@ function index() entry({"admin", "services", "linkease_status"}, call("linkease_status")) - entry({"admin", "services", "linkease", "file"}, call("linkease_file_template")).leaf = true end @@ -27,13 +26,3 @@ function linkease_status() luci.http.write_json(status) end -function get_params(name) - local data = { - prefix=luci.dispatcher.build_url(unpack({"admin", "services", "linkease", name})), - } - return data -end - -function linkease_file_template() - luci.template.render("linkease/file", get_params("file")) -end diff --git a/luci-app-linkeasefull/Makefile b/luci-app-linkeasefull/Makefile new file mode 100644 index 000000000..5bf69195f --- /dev/null +++ b/luci-app-linkeasefull/Makefile @@ -0,0 +1,18 @@ +# +# Copyright (C) 2026 iStoreOS +# +# This is free software, licensed under the Apache License, Version 2.0 . +# + +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=LuCI support for linkeasefull +LUCI_DEPENDS:=+linkeasefull +luci-lib-linkeasefile +LUCI_PKGARCH:=all + +PKG_VERSION:=1.0.1 +PKG_RELEASE:=1 + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-linkeasefull/luasrc/controller/linkeasefull.lua b/luci-app-linkeasefull/luasrc/controller/linkeasefull.lua new file mode 100644 index 000000000..bed1f88f3 --- /dev/null +++ b/luci-app-linkeasefull/luasrc/controller/linkeasefull.lua @@ -0,0 +1,89 @@ +module("luci.controller.linkeasefull", package.seeall) + +function index() + if not nixio.fs.access("/etc/config/linkeasefull") then + return + end + + entry({"admin", "services", "linkeasefull"}, cbi("linkeasefull"), _("LinkEase Full"), 21).dependent = true + entry({"admin", "services", "linkeasefull_status"}, call("linkeasefull_status")) + entry({"admin", "services", "linkeasefull", "auth"}, call("linkeasefull_auth")).leaf = true +end + +local function uhttpd_has_apps_proxy_prefix() + local uci = require "luci.model.uci".cursor() + local mappings = uci:get_list("uhttpd", "main", "proxy_prefix") or {} + + for _, mapping in ipairs(mappings) do + if mapping == "/apps=http://127.0.0.1:19290" then + return true + end + end + return false +end + +function linkeasefull_status() + local sys = require "luci.sys" + local uci = require "luci.model.uci".cursor() + + local status = { + running = (sys.call("pidof linkease-full >/dev/null") == 0), + full_port = 19290, + legacy_port = 8897, + base_path = "/apps/", + lan_ip = uci:get("network", "lan", "ipaddr") or "", + proxy_prefix_enabled = uhttpd_has_apps_proxy_prefix() + } + + luci.http.prepare_content("application/json") + luci.http.write_json(status) +end + +local function retrieve_luci_session() + local http = require "luci.http" + local util = require "luci.util" + + for _, key in ipairs({"sysauth_https", "sysauth_http", "sysauth"}) do + local sid = http.getcookie(key) + if sid and sid ~= "" then + local sdat = util.ubus("session", "get", { ubus_rpc_session = sid }) + if sdat and type(sdat.values) == "table" then + return sid + end + end + end + return nil +end + +local function valid_apps_return(value) + if not value or value == "" then + return false + end + if value == "/apps" then + return true + end + local prefix = value:sub(1, 6) + return prefix == "/apps/" or prefix == "/apps?" or prefix == "/apps#" +end + +local function valid_cookie_value(value) + return value and value:match("^[A-Za-z0-9._%-_]+$") ~= nil +end + +function linkeasefull_auth() + local http = require "luci.http" + local sid = retrieve_luci_session() + + if not valid_cookie_value(sid) then + http.status(403, "Forbidden") + return + end + + local target = http.formvalue("return") or "/apps/" + if not valid_apps_return(target) then + target = "/apps/" + end + + http.header("Set-Cookie", "linkease_openwrt_sid=" .. sid .. "; Path=/apps; HttpOnly; SameSite=Lax") + http.redirect(target) +end diff --git a/luci-app-linkeasefull/luasrc/model/cbi/linkeasefull.lua b/luci-app-linkeasefull/luasrc/model/cbi/linkeasefull.lua new file mode 100644 index 000000000..23950bc46 --- /dev/null +++ b/luci-app-linkeasefull/luasrc/model/cbi/linkeasefull.lua @@ -0,0 +1,86 @@ +local fs = require "nixio.fs" + +local m, s + +local function starts_with(value, prefix) + return value:sub(1, #prefix) == prefix +end + +local function decode_mount_path(value) + return value:gsub("\\040", " "):gsub("\\011", "\t"):gsub("\\012", "\n"):gsub("\\134", "\\") +end + +local function is_persistent_mount(path, fstype) + if path == "" or path == "/" then + return false + end + if starts_with(path, "/tmp") or starts_with(path, "/var") or starts_with(path, "/run") then + return false + end + if starts_with(path, "/dev") or starts_with(path, "/proc") or starts_with(path, "/sys") then + return false + end + if starts_with(path, "/rom") or starts_with(path, "/overlay") then + return false + end + if fstype == "tmpfs" or fstype == "devtmpfs" or fstype == "overlay" or fstype == "squashfs" then + return false + end + return true +end + +local function storage_mounts() + local mounts = {} + for line in io.lines("/proc/mounts") do + local device, path, fstype = line:match("^(%S+)%s+(%S+)%s+(%S+)") + path = path and decode_mount_path(path) or "" + if device and fstype and is_persistent_mount(path, fstype) then + mounts[#mounts + 1] = { + path = path, + label = string.format("%s (%s)", path, fstype) + } + end + end + table.sort(mounts, function(a, b) return a.path < b.path end) + return mounts +end + +m = Map("linkeasefull", translate("LinkEase Full"), translate("LinkEase Full uses fixed entries at port 19290 /apps/ and legacy port 8897.")) + +m:section(SimpleSection).template = "linkeasefull_status" + +s = m:section(TypedSection, "linkeasefull", translate("Storage")) +s.addremove = false +s.anonymous = true + +s:option(Flag, "enabled", translate("Enable")).rmempty = false + +local data = s:option(ListValue, "data_root_parent", translate("Storage path"), translate("Choose a mounted persistent disk. /tmp is not allowed.")) +data.rmempty = false + +local current = m.uci:get_first("linkeasefull", "linkeasefull", "data_root_parent") or "" +local has_current = false +for _, mount in ipairs(storage_mounts()) do + data:value(mount.path, mount.label) + if mount.path == current then + has_current = true + end +end +if current ~= "" and not has_current and fs.stat(current, "type") == "dir" and is_persistent_mount(current, "") then + data:value(current, current) +end + +function data.validate(self, value) + if value == nil or value == "" then + return nil, translate("Please choose a mounted persistent disk.") + end + if not is_persistent_mount(value, "") then + return nil, translate("/tmp and system paths cannot be used for LinkEase Full storage.") + end + if fs.stat(value, "type") ~= "dir" then + return nil, translate("The selected storage path does not exist.") + end + return value +end + +return m diff --git a/luci-app-linkeasefull/luasrc/view/linkeasefull_status.htm b/luci-app-linkeasefull/luasrc/view/linkeasefull_status.htm new file mode 100644 index 000000000..9637232e0 --- /dev/null +++ b/luci-app-linkeasefull/luasrc/view/linkeasefull_status.htm @@ -0,0 +1,34 @@ + + +
+ <%:LinkEase Full Status%> +

+ <%:Collecting data...%> +

+
diff --git a/luci-app-linkeasefull/po/zh-cn/linkeasefull.po b/luci-app-linkeasefull/po/zh-cn/linkeasefull.po new file mode 100644 index 000000000..b7d3e7a76 --- /dev/null +++ b/luci-app-linkeasefull/po/zh-cn/linkeasefull.po @@ -0,0 +1,35 @@ +msgid "LinkEase Full" +msgstr "易有云完整版" + +msgid "LinkEase Full provides the local web desktop entry for LinkEase." +msgstr "易有云完整版提供本地 Web 桌面入口。" + +msgid "Global settings" +msgstr "全局设置" + +msgid "Enable" +msgstr "启用" + +msgid "Port" +msgstr "端口" + +msgid "Base Path" +msgstr "基础路径" + +msgid "Data Root Parent" +msgstr "数据根目录父路径" + +msgid "The LinkEase Full service is running." +msgstr "易有云完整版服务已启动" + +msgid "The LinkEase Full service is not running." +msgstr "易有云完整版服务未启动" + +msgid "Click to open LinkEase Full" +msgstr "点击打开易有云完整版" + +msgid "LinkEase Full Status" +msgstr "易有云完整版服务状态" + +msgid "Collecting data..." +msgstr "收集数据..." diff --git a/luci-app-linkeasefull/po/zh_Hans b/luci-app-linkeasefull/po/zh_Hans new file mode 120000 index 000000000..41451e4a1 --- /dev/null +++ b/luci-app-linkeasefull/po/zh_Hans @@ -0,0 +1 @@ +zh-cn \ No newline at end of file diff --git a/luci-app-linkeasefull/root/etc/uci-defaults/50_luci-linkeasefull b/luci-app-linkeasefull/root/etc/uci-defaults/50_luci-linkeasefull new file mode 100755 index 000000000..048f3caf5 --- /dev/null +++ b/luci-app-linkeasefull/root/etc/uci-defaults/50_luci-linkeasefull @@ -0,0 +1,4 @@ +#!/bin/sh + +rm -f /tmp/luci-indexcache /tmp/luci-indexcache.* +exit 0 diff --git a/luci-app-linkeaselite/Makefile b/luci-app-linkeaselite/Makefile new file mode 100644 index 000000000..f91f1600f --- /dev/null +++ b/luci-app-linkeaselite/Makefile @@ -0,0 +1,18 @@ +# Copyright (C) 2016 Openwrt.org +# +# This is free software, licensed under the Apache License, Version 2.0 . +# + +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=LuCI support for linkeaselite +LUCI_DEPENDS:=+linkeaselite +LUCI_PKGARCH:=all +PKG_VERSION:=1.0.0 +PKG_RELEASE:=1 +LUCI_MINIFY_CSS:=0 +LUCI_MINIFY_JS:=0 + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-linkeaselite/luasrc/controller/linkeaselite.lua b/luci-app-linkeaselite/luasrc/controller/linkeaselite.lua new file mode 100644 index 000000000..b66b26c7a --- /dev/null +++ b/luci-app-linkeaselite/luasrc/controller/linkeaselite.lua @@ -0,0 +1,31 @@ +module("luci.controller.linkeaselite", package.seeall) + +function index() + if not nixio.fs.access("/etc/config/linkeaselite") then + return + end + + local page = entry({"admin", "services", "linkeaselite"}, firstchild(), _("LinkEaseLite"), 20) + page.dependent = true + entry({"admin", "services", "linkeaselite", "config"}, cbi("linkeaselite"), _("Settings"), 10).leaf = true + entry({"admin", "services", "linkeaselite_status"}, call("linkeaselite_status")) + entry({"admin", "services", "linkeaselite", "file"}, call("linkeaselite_file_removed")).leaf = true +end + +function linkeaselite_status() + local sys = require "luci.sys" + local uci = require "luci.model.uci".cursor() + local port = tonumber(uci:get_first("linkeaselite", "linkeaselite", "port")) + + local status = { + running = (sys.call("pidof linkease-lite >/dev/null") == 0), + port = (port or 8897) + } + + luci.http.prepare_content("application/json") + luci.http.write_json(status) +end + +function linkeaselite_file_removed() + luci.http.status(404, "Not Found") +end diff --git a/luci-app-linkeaselite/luasrc/model/cbi/linkeaselite.lua b/luci-app-linkeaselite/luasrc/model/cbi/linkeaselite.lua new file mode 100644 index 000000000..c1387f8bd --- /dev/null +++ b/luci-app-linkeaselite/luasrc/model/cbi/linkeaselite.lua @@ -0,0 +1,24 @@ +local m, s +local sys = require "luci.sys" + +m = Map("linkeaselite", translate("LinkEaseLite"), translate("LinkEaseLite is an efficient data transfer tool for small-memory devices.")) +m:section(SimpleSection).template = "linkeaselite_status" + +m.on_after_commit = function(self) + sys.call("/etc/init.d/linkeaselite restart >/dev/null 2>&1") +end + +s = m:section(TypedSection, "linkeaselite", translate("Global settings")) +s.addremove = false +s.anonymous = true + +s:option(Flag, "enabled", translate("Enable")).rmempty = false + +local port = s:option(Value, "port", translate("Port")) +port.rmempty = false +port.datatype = "port" +port.default = "8897" + +s:option(Flag, "allowPublic", translate("AllowPublic"), translate("Allowing access via public IP addresses can lead to insufficient security.")).rmempty = false + +return m diff --git a/luci-app-linkeaselite/luasrc/view/linkeaselite_status.htm b/luci-app-linkeaselite/luasrc/view/linkeaselite_status.htm new file mode 100644 index 000000000..34a0e0c3d --- /dev/null +++ b/luci-app-linkeaselite/luasrc/view/linkeaselite_status.htm @@ -0,0 +1,42 @@ + + +
+ <%:LinkEaseLite Status%> +

+ <%:Collecting data...%> +

+
diff --git a/luci-app-linkeaselite/po/zh-cn/linkeaselite.po b/luci-app-linkeaselite/po/zh-cn/linkeaselite.po new file mode 100644 index 000000000..93b611b72 --- /dev/null +++ b/luci-app-linkeaselite/po/zh-cn/linkeaselite.po @@ -0,0 +1,35 @@ +msgid "LinkEaseLite" +msgstr "易有云Lite" + +msgid "LinkEaseLite is an efficient data transfer tool for small-memory devices." +msgstr "易有云Lite是面向小内存设备的轻量数据传输工具。" + +msgid "Global settings" +msgstr "全局设置" + +msgid "Enable" +msgstr "启用" + +msgid "Port" +msgstr "端口" + +msgid "AllowPublic" +msgstr "公网访问" + +msgid "Allowing access via public IP addresses can lead to insufficient security." +msgstr "允许公网IP访问,会导致不够安全。" + +msgid "Click to open LinkEaseLite" +msgstr "点击打开易有云Lite" + +msgid "The LinkEaseLite service is running." +msgstr "易有云Lite服务已启动" + +msgid "The LinkEaseLite service is not running." +msgstr "易有云Lite服务未启动" + +msgid "LinkEaseLite Status" +msgstr "易有云Lite服务状态" + +msgid "Collecting data..." +msgstr "收集数据..." diff --git a/luci-app-linkeaselite/po/zh_Hans b/luci-app-linkeaselite/po/zh_Hans new file mode 120000 index 000000000..41451e4a1 --- /dev/null +++ b/luci-app-linkeaselite/po/zh_Hans @@ -0,0 +1 @@ +zh-cn \ No newline at end of file diff --git a/luci-app-linkeaselite/root/etc/uci-defaults/50_luci-linkeaselite b/luci-app-linkeaselite/root/etc/uci-defaults/50_luci-linkeaselite new file mode 100644 index 000000000..048f3caf5 --- /dev/null +++ b/luci-app-linkeaselite/root/etc/uci-defaults/50_luci-linkeaselite @@ -0,0 +1,4 @@ +#!/bin/sh + +rm -f /tmp/luci-indexcache /tmp/luci-indexcache.* +exit 0 diff --git a/luci-app-passwall/Makefile b/luci-app-passwall/Makefile index f42f9292a..c7006ad8a 100644 --- a/luci-app-passwall/Makefile +++ b/luci-app-passwall/Makefile @@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall PKG_VERSION:=26.7.24 -PKG_RELEASE:=194 +PKG_RELEASE:=195 PKG_PO_VERSION:=$(PKG_VERSION) PKG_CONFIG_DEPENDS:= \ diff --git a/luci-app-passwall/root/usr/share/passwall/app.sh b/luci-app-passwall/root/usr/share/passwall/app.sh index 4af75e6a1..e1337dd88 100755 --- a/luci-app-passwall/root/usr/share/passwall/app.sh +++ b/luci-app-passwall/root/usr/share/passwall/app.sh @@ -1754,9 +1754,9 @@ acl_app() { run_${type} flag=$tcp_node node=$tcp_node tcp_redir_port=$redir_port ${_extra_param} config_file=$config_file log_file=$log_file loglevel=$loglevel else config_file="acl/${tcp_node}_SOCKS_${socks_port}.json" - run_socks flag=$tcp_node node=$tcp_node bind=127.0.0.1 socks_port=$socks_port config_file=$config_file - # local log_file=$TMP_ACL_PATH/ipt2socks_${tcp_node}_${redir_port}.log - # log_file="/dev/null" + run_socks flag=$tcp_node node=$tcp_node bind=127.0.0.1 socks_port=$socks_port config_file=$config_file log_file=$log_file + # log_file=$TMP_ACL_PATH/ipt2socks_${tcp_node}_${redir_port}.log + log_file="/dev/null" run_ipt2socks flag=acl_${tcp_node} tcp_tproxy=${is_tproxy} local_port=$redir_port socks_address=127.0.0.1 socks_port=$socks_port log_file=$log_file fi run_dns ${_dns_port} @@ -1828,9 +1828,9 @@ acl_app() { run_${type} flag=$udp_node node=$udp_node udp_redir_port=$redir_port config_file=$config_file log_file=$log_file loglevel=$loglevel else config_file="acl/${udp_node}_SOCKS_${socks_port}.json" - run_socks flag=$udp_node node=$udp_node bind=127.0.0.1 socks_port=$socks_port config_file=$config_file - # local log_file=$TMP_ACL_PATH/ipt2socks_${udp_node}_${redir_port}.log - # log_file="/dev/null" + run_socks flag=$udp_node node=$udp_node bind=127.0.0.1 socks_port=$socks_port config_file=$config_file log_file=$log_file + # log_file=$TMP_ACL_PATH/ipt2socks_${udp_node}_${redir_port}.log + log_file="/dev/null" run_ipt2socks flag=acl_${udp_node} local_port=$redir_port socks_address=127.0.0.1 socks_port=$socks_port log_file=$log_file fi fi diff --git a/luci-app-passwall/root/usr/share/passwall/utils.sh b/luci-app-passwall/root/usr/share/passwall/utils.sh index e9b5aebaf..c5fc72759 100755 --- a/luci-app-passwall/root/usr/share/passwall/utils.sh +++ b/luci-app-passwall/root/usr/share/passwall/utils.sh @@ -476,7 +476,7 @@ ln_run() { fi #echo "${file_func} $*" >&2 [ -n "${file_func}" ] || echolog " - 找不到 ${ln_name},无法启动..." - [ "${output}" != "/dev/null" ] && [ "${ln_name}" != "chinadns-ng" ] && { + [ "${output}" != "/dev/null" ] && [ -n "$(echo "${output}" | grep -E "default|SOCKS_")" ] && [ "${ln_name}" != "chinadns-ng" ] && { local persist_log_path=$(config_t_get global persist_log_path) local sys_log=$(config_t_get global sys_log "0") } diff --git a/luci-app-qosmate/Makefile b/luci-app-qosmate/Makefile index d2c4e16f9..1083bcde3 100644 --- a/luci-app-qosmate/Makefile +++ b/luci-app-qosmate/Makefile @@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-qosmate PKG_VERSION:=1.0.14 -PKG_RELEASE:=2 +PKG_RELEASE:=3 PKG_MAINTAINER:=Markus Hütter PKG_LICENSE:=GPL-3.0-or-later diff --git a/luci-app-qosmate/htdocs/luci-static/resources/view/cake.js b/luci-app-qosmate/htdocs/luci-static/resources/view/cake.js index 6f2a8c4ef..912e7005b 100644 --- a/luci-app-qosmate/htdocs/luci-static/resources/view/cake.js +++ b/luci-app-qosmate/htdocs/luci-static/resources/view/cake.js @@ -10,6 +10,14 @@ function addRelevanceInfo(description, settingName, rootQdisc) { var isRelevant = true; var note = ''; + + // A rate of 0 disables that direction, which makes its options ineffective + if (/INGRESS/.test(settingName) && parseInt(uci.get('qosmate', 'settings', 'DOWNRATE') || '0') === 0) { + return description + ' ⚠ Not used: ingress shaping is disabled (DOWNRATE=0)'; + } + if (/EGRESS/.test(settingName) && parseInt(uci.get('qosmate', 'settings', 'UPRATE') || '0') === 0) { + return description + ' ⚠ Not used: egress shaping is disabled (UPRATE=0)'; + } // Check basic ROOT_QDISC relevance if (rootQdisc !== 'cake' && rootQdisc !== 'hybrid') { diff --git a/luci-app-qosmate/htdocs/luci-static/resources/view/settings.js b/luci-app-qosmate/htdocs/luci-static/resources/view/settings.js index c7ab299cb..c654db646 100644 --- a/luci-app-qosmate/htdocs/luci-static/resources/view/settings.js +++ b/luci-app-qosmate/htdocs/luci-static/resources/view/settings.js @@ -7,7 +7,6 @@ 'require fs'; 'require poll'; 'require tools.widgets as widgets'; - const UI_VERSION = '1.2.0'; const UI_UPD_CHANNEL = 'release'; @@ -554,7 +553,7 @@ return view.extend({ } statusHtml.appendChild( - E('div', { 'style': 'display: flex; align-items: center; gap: 4px;' }, [ + E('div', { 'style': 'display: flex; align-items: center; gap: 4px;', 'title': detail }, [ E('span', { 'style': 'color: ' + color + '; font-size: 15px; font-weight: bold; min-width: 20px;' }, icon), @@ -780,11 +779,7 @@ return view.extend({ opt.validate = function(section_id, value) { if (value === '' || value === null) return true; if (!/^\d+$/.test(value)) return _('Must be a non-negative integer or empty'); - var intValue = parseInt(value, 10); - var rootQdisc = this.section.formvalue(section_id, 'ROOT_QDISC'); - if (intValue === 0 && rootQdisc === 'hfsc') { - return _('Value must be greater than 0 for HFSC'); - } + // 0 is valid for every qdisc: it disables shaping for that direction return true; }; } @@ -797,8 +792,8 @@ return view.extend({ o.editable = true; o.default = wanInterface; - createOption('DOWNRATE', _('Download Rate (kbps)'), _('Set the download rate in kbps'), _('Default: 90000'), 'uinteger'); - createOption('UPRATE', _('Upload Rate (kbps)'), _('Set the upload rate in kbps'), _('Default: 45000'), 'uinteger'); + createOption('DOWNRATE', _('Download Rate (kbps)'), _('Set the download rate in kbps. 0 disables ingress shaping (no IFB device is created).'), _('Default: 90000'), 'uinteger'); + createOption('UPRATE', _('Upload Rate (kbps)'), _('Set the upload rate in kbps. 0 disables egress shaping.'), _('Default: 45000'), 'uinteger'); // Function to get QDisc description based on value function getQdiscDescriptionForValue(value) { @@ -880,6 +875,37 @@ return view.extend({ } }; + // Notice when a direction is not shaped (rate 0, same convention as sqm-scripts) + o = s_basic.option(form.DummyValue, '_shaping_direction', _('Shaping Direction')); + o.rawhtml = true; + o.render = function(section_id) { + var downrate = parseInt(uci.get('qosmate', 'settings', 'DOWNRATE') || '0'); + var uprate = parseInt(uci.get('qosmate', 'settings', 'UPRATE') || '0'); + if (downrate > 0 && uprate > 0) return E('div'); + + var lines = []; + if (downrate === 0 && uprate === 0) { + lines.push(E('strong', {}, _('No shaping active: both rates are 0'))); + lines.push(E('br')); + lines.push(_('Only nftables DSCP marking is applied, no queues are created.')); + } else if (downrate === 0) { + lines.push(E('strong', {}, _('Download shaping disabled (DOWNRATE=0)'))); + lines.push(E('br')); + lines.push(_('No IFB device is created. TCP bulk detection is off because its thresholds derive from the download rate, CAKE ingress options have no effect, and incoming packets carry no DSCP.')); + lines.push(E('br')); + lines.push(_('Set ACK_FILTER_EGRESS explicitly in the CAKE tab: "auto" cannot decide without a download rate.')); + } else { + lines.push(E('strong', {}, _('Upload shaping disabled (UPRATE=0)'))); + lines.push(E('br')); + lines.push(_('No egress qdisc is created, so traffic classification only affects the download queue.')); + } + + return E('div', { 'class': 'cbi-value' }, [ + E('label', { 'class': 'cbi-value-title' }, E('span', { 'style': 'color: orange; font-weight: bold;' }, '⚠')), + E('div', { 'class': 'cbi-value-field', 'style': 'color: orange;' }, lines) + ]); + }; + // Warning for bandwidth ratio o = s_basic.option(form.DummyValue, '_ratio_warning', _('Bandwidth Ratio Warning')); o.rawhtml = true; diff --git a/luci-app-qosmate/htdocs/luci-static/resources/view/statistics.js b/luci-app-qosmate/htdocs/luci-static/resources/view/statistics.js index 5fe3e6766..3dbfa44bf 100644 --- a/luci-app-qosmate/htdocs/luci-static/resources/view/statistics.js +++ b/luci-app-qosmate/htdocs/luci-static/resources/view/statistics.js @@ -1492,6 +1492,21 @@ return view.extend({ infoContainer.appendChild(row); } + // A rate of 0 disables that direction, so one of the tabs stays empty on purpose + var statsUpRate = parseInt(uci.get('qosmate', 'settings', 'UPRATE') || '0'); + var statsDownRate = parseInt(uci.get('qosmate', 'settings', 'DOWNRATE') || '0'); + if (statsUpRate === 0 || statsDownRate === 0) { + var dirText = statsUpRate === 0 && statsDownRate === 0 + ? _('disabled in both directions (both rates are 0)') + : (statsDownRate === 0 ? _('egress only (DOWNRATE=0, no ingress statistics)') + : _('ingress only (UPRATE=0, no egress statistics)')); + var row = E('div', { 'style': 'margin-right: 1.5em; margin-bottom: 0.3em; color: orange;' }); + row.appendChild(E('span', { 'style': 'font-weight: bold;' }, _('Shaping:'))); + row.appendChild(document.createTextNode(' ')); + row.appendChild(E('span', {}, dirText)); + infoContainer.appendChild(row); + } + // Add CAKE-specific or HFSC-specific info if (qosStats.root_qdisc === 'cake') { if (qosStats.priority_queue_ingress) { diff --git a/luci-app-samba4/po/it/samba4.po b/luci-app-samba4/po/it/samba4.po index 2a07925d0..e93d9e70c 100644 --- a/luci-app-samba4/po/it/samba4.po +++ b/luci-app-samba4/po/it/samba4.po @@ -3,8 +3,8 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2009-05-19 19:36+0200\n" -"PO-Revision-Date: 2025-11-28 22:04+0000\n" -"Last-Translator: niky1987 \n" +"PO-Revision-Date: 2026-07-23 06:18+0000\n" +"Last-Translator: Random \n" "Language-Team: Italian \n" "Language: it\n" @@ -12,7 +12,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.15-dev\n" +"X-Generator: Weblate 2026.8.dev0\n" #: applications/luci-app-samba4/htdocs/luci-static/resources/view/samba4.js:120 msgid "Allow guests" @@ -60,11 +60,11 @@ msgstr "Disattiva Controller di Dominio Active Directory" #: applications/luci-app-samba4/htdocs/luci-static/resources/view/samba4.js:71 msgid "Disable Netbios" -msgstr "" +msgstr "Disabilita Netbios" #: applications/luci-app-samba4/htdocs/luci-static/resources/view/samba4.js:77 msgid "Disable Winbind" -msgstr "" +msgstr "Disabilita Winbind" #: applications/luci-app-samba4/htdocs/luci-static/resources/view/samba4.js:32 msgid "Edit Template" @@ -81,7 +81,7 @@ msgstr "" #: applications/luci-app-samba4/htdocs/luci-static/resources/view/samba4.js:64 msgid "Enable macOS compatible shares" -msgstr "" +msgstr "Abilita condivisioni compatibili con macOS" #: applications/luci-app-samba4/htdocs/luci-static/resources/view/samba4.js:58 msgid "" @@ -95,6 +95,8 @@ msgid "" "Enables Apple's AAPL extension globally and adds macOS compatibility options " "to all shares." msgstr "" +"Abilita globalmente le estensioni AAPL di Apple ed aggiunge le opzioni di " +"compatibilità con macOS in tutte le condivisioni." #: applications/luci-app-samba4/htdocs/luci-static/resources/view/samba4.js:115 msgid "Force Root" @@ -114,11 +116,11 @@ msgstr "" #: applications/luci-app-samba4/htdocs/luci-static/resources/view/samba4.js:126 msgid "Guests only" -msgstr "" +msgstr "Solo ospiti" #: applications/luci-app-samba4/htdocs/luci-static/resources/view/samba4.js:131 msgid "Inherit owner" -msgstr "" +msgstr "Eredita il proprietario" #: applications/luci-app-samba4/htdocs/luci-static/resources/view/samba4.js:34 msgid "Interface" @@ -177,11 +179,11 @@ msgstr "" #: applications/luci-app-samba4/htdocs/luci-static/resources/view/samba4.js:153 msgid "Time-machine size in GB" -msgstr "" +msgstr "Dimensioni in GB di Time-machine" #: applications/luci-app-samba4/htdocs/luci-static/resources/view/samba4.js:148 msgid "Vfs objects" -msgstr "" +msgstr "Oggetti Vfs" #: applications/luci-app-samba4/htdocs/luci-static/resources/view/samba4.js:51 msgid "Workgroup" diff --git a/luci-app-samba4/po/ru/samba4.po b/luci-app-samba4/po/ru/samba4.po index c9b752a2f..369ea0f93 100644 --- a/luci-app-samba4/po/ru/samba4.po +++ b/luci-app-samba4/po/ru/samba4.po @@ -2,9 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: LuCI: samba\n" "POT-Creation-Date: 2009-05-19 19:36+0200\n" -"PO-Revision-Date: 2026-04-25 12:14+0000\n" -"Last-Translator: SnIPeRSnIPeR " -"\n" +"PO-Revision-Date: 2026-07-03 15:28+0000\n" +"Last-Translator: chigelo \n" "Language-Team: Russian \n" "Language: ru\n" @@ -13,7 +12,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" -"X-Generator: Weblate 5.17.1-dev\n" +"X-Generator: Weblate 2026.7.1.dev0\n" "Project-Info: Это технический перевод, не дословный. Главное-удобный русский " "интерфейс, все проверялось в графическом режиме, совместим с другими apps\n" @@ -139,7 +138,7 @@ msgstr "Слушать только на данном интерфейсе ил #: applications/luci-app-samba4/htdocs/luci-static/resources/view/samba4.js:98 msgid "Name" -msgstr "Название" +msgstr "Имя" #: applications/luci-app-samba4/htdocs/luci-static/resources/view/samba4.js:23 #: applications/luci-app-samba4/root/usr/share/luci/menu.d/luci-app-samba4.json:3 diff --git a/luci-app-samba4/po/uk/samba4.po b/luci-app-samba4/po/uk/samba4.po index f1fb711ca..9242ec1af 100644 --- a/luci-app-samba4/po/uk/samba4.po +++ b/luci-app-samba4/po/uk/samba4.po @@ -1,7 +1,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"PO-Revision-Date: 2026-05-15 10:43+0000\n" +"PO-Revision-Date: 2026-07-08 15:16+0000\n" "Last-Translator: Dan \n" "Language-Team: Ukrainian \n" @@ -11,7 +11,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" -"X-Generator: Weblate 2026.5.dev0\n" +"X-Generator: Weblate 2026.7.1.dev0\n" #: applications/luci-app-samba4/htdocs/luci-static/resources/view/samba4.js:120 msgid "Allow guests" @@ -136,7 +136,7 @@ msgstr "" #: applications/luci-app-samba4/htdocs/luci-static/resources/view/samba4.js:98 msgid "Name" -msgstr "Імʼя" +msgstr "Назва" #: applications/luci-app-samba4/htdocs/luci-static/resources/view/samba4.js:23 #: applications/luci-app-samba4/root/usr/share/luci/menu.d/luci-app-samba4.json:3 diff --git a/luci-app-smartdns/Makefile b/luci-app-smartdns/Makefile index 4e036e1e8..2b06d42cc 100644 --- a/luci-app-smartdns/Makefile +++ b/luci-app-smartdns/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk PKG_LICENSE:=GPL-3.0-or-later PKG_MAINTAINER:=Nick Peng PKG_VERSION:=1.2025.47.2 -PKG_RELEASE:=10 +PKG_RELEASE:=11 LUCI_TITLE:=LuCI for smartdns LUCI_DESCRIPTION:=Provides Luci for smartdns diff --git a/luci-app-smartdns/po/es/smartdns.po b/luci-app-smartdns/po/es/smartdns.po index 6e2069714..3822be228 100644 --- a/luci-app-smartdns/po/es/smartdns.po +++ b/luci-app-smartdns/po/es/smartdns.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: 2020-07-02 17:20-0300\n" -"PO-Revision-Date: 2026-06-25 19:51+0000\n" +"PO-Revision-Date: 2026-06-26 11:19+0000\n" "Last-Translator: apemay \n" "Language-Team: Spanish \n" @@ -170,7 +170,7 @@ msgstr "Descripción" #: applications/luci-app-smartdns/htdocs/luci-static/resources/view/smartdns/smartdns.js:75 msgid "Dnsmasq Forwarded To Smartdns Failure" -msgstr "Error de reenvío de Dnsmasq a Smartdns" +msgstr "Error de reenvío de Dnsmasq a SmartDNS" #: applications/luci-app-smartdns/htdocs/luci-static/resources/view/smartdns/smartdns.js:718 msgid "Do not check certificate." @@ -419,8 +419,8 @@ msgid "" "Include other config files from /etc/smartdns/conf.d or custom path, can be " "downloaded from the download page." msgstr "" -"Incluye otros archivos de configuración desde /etc/smartdns/conf.d o una " -"ruta personalizada, se puede obtener desde la página de descarga." +"Incluir otros archivos de configuración desde /etc/smartdns/conf.d o una " +"ruta personalizada. Se pueden descargar desde la página de descargas." #: applications/luci-app-smartdns/htdocs/luci-static/resources/view/smartdns/smartdns.js:282 msgid "Ipset name, Add domain result to ipset when speed check fails." @@ -730,9 +730,8 @@ msgid "" "SmartDNS is a local high-performance DNS server, supports finding fastest " "IP, supports ad filtering, and supports avoiding DNS poisoning." msgstr "" -"SmartDNS es un servidor DNS local de alto rendimiento, admite la búsqueda de " -"la IP más rápida, admite el filtrado de anuncios y evita el envenenamiento " -"de DNS." +"SmartDNS es un servidor DNS local de alto rendimiento. Admite la búsqueda de " +"la IP más rápida, el filtrado de anuncios y evita el envenenamiento de DNS." #: applications/luci-app-smartdns/htdocs/luci-static/resources/view/smartdns/smartdns.js:1141 msgid "SmartDNS official website" @@ -740,7 +739,7 @@ msgstr "Sitio web oficial de SmartDNS" #: applications/luci-app-smartdns/htdocs/luci-static/resources/view/smartdns/smartdns.js:376 msgid "Smartdns local server port" -msgstr "Puerto del servidor local Smartdns" +msgstr "Puerto del servidor local de SmartDNS" #: applications/luci-app-smartdns/htdocs/luci-static/resources/view/smartdns/smartdns.js:153 msgid "" @@ -755,18 +754,18 @@ msgid "" "Smartdns response mode, First Ping: return the first ping IP, Fastest IP: " "return the fastest IP, Fastest Response: return the fastest DNS response." msgstr "" -"Modo de respuesta de SmartDNS, Primer Ping: devuelve la primera IP que " -"responde al ping, IP Más Rápida: devuelve la IP más rápida, Respuesta Más " -"Rápida: devuelve la respuesta DNS más rápida." +"Modo de respuesta de SmartDNS. Primer Ping: devuelve la primera IP que " +"responde al ping; IP más rápida: devuelve la IP más rápida; Respuesta más " +"rápida: devuelve la respuesta DNS más rápida." #: applications/luci-app-smartdns/htdocs/luci-static/resources/view/smartdns/smartdns.js:146 msgid "Smartdns server name" -msgstr "Nombre del servidor de Smartdns" +msgstr "Nombre del servidor de SmartDNS" #: applications/luci-app-smartdns/htdocs/luci-static/resources/view/smartdns/smartdns.js:168 #: applications/luci-app-smartdns/htdocs/luci-static/resources/view/smartdns/smartdns.js:1015 msgid "Smartdns speed check mode." -msgstr "Modo de verificación de velocidad de smartdns." +msgstr "Modo de verificación de velocidad de SmartDNS." #: applications/luci-app-smartdns/htdocs/luci-static/resources/view/smartdns/smartdns.js:1118 msgid "" @@ -844,7 +843,7 @@ msgstr "Cargar el archivo de lista de dominios" #: applications/luci-app-smartdns/htdocs/luci-static/resources/view/smartdns/smartdns.js:507 msgid "Upload domain list file to /etc/smartdns/domain-set" -msgstr "Cargue el archivo de lista de dominios en /etc/smartdns/domain-set" +msgstr "Cargar el archivo de lista de dominios en /etc/smartdns/domain-set" #: applications/luci-app-smartdns/htdocs/luci-static/resources/view/smartdns/smartdns.js:891 #: applications/luci-app-smartdns/htdocs/luci-static/resources/view/smartdns/smartdns.js:991 @@ -861,7 +860,7 @@ msgstr "Cargar el archivo de lista de dominios." #: applications/luci-app-smartdns/htdocs/luci-static/resources/view/smartdns/smartdns.js:500 msgid "Upload smartdns config file to /etc/smartdns/conf.d" -msgstr "Cargue el archivo de configuración de smartdns en /etc/smartdns/conf.d" +msgstr "Cargar el archivo de configuración de SmartDNS en /etc/smartdns/conf.d" #: applications/luci-app-smartdns/htdocs/luci-static/resources/view/smartdns/smartdns.js:630 msgid "Upstream Servers" @@ -929,11 +928,11 @@ msgstr "abrir sitio web" #: applications/luci-app-smartdns/htdocs/luci-static/resources/view/smartdns/smartdns.js:555 msgid "smartdns config (/etc/smartdns/conf.d)" -msgstr "Configuración de smartdns (/etc/smartdns/conf.d)" +msgstr "Configuración de SmartDNS (/etc/smartdns/conf.d)" #: applications/luci-app-smartdns/htdocs/luci-static/resources/view/smartdns/smartdns.js:584 msgid "smartdns custom settings" -msgstr "configuraciones personalizadas de smartdns" +msgstr "configuraciones personalizadas de SmartDNS" #: applications/luci-app-smartdns/htdocs/luci-static/resources/view/smartdns/smartdns.js:667 msgid "tcp" diff --git a/luci-app-upnp/po/it/upnp.po b/luci-app-upnp/po/it/upnp.po index 50c308e40..e13dda534 100644 --- a/luci-app-upnp/po/it/upnp.po +++ b/luci-app-upnp/po/it/upnp.po @@ -3,8 +3,8 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2009-05-19 19:36+0200\n" -"PO-Revision-Date: 2025-11-28 22:04+0000\n" -"Last-Translator: niky1987 \n" +"PO-Revision-Date: 2026-07-23 06:18+0000\n" +"Last-Translator: Random \n" "Language-Team: Italian \n" "Language: it\n" @@ -12,7 +12,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.15-dev\n" +"X-Generator: Weblate 2026.8.dev0\n" #: applications/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js:180 msgctxt "" @@ -115,7 +115,7 @@ msgstr "Velocità di download" #: applications/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js:144 msgid "Enable PCP/NAT-PMP protocols" -msgstr "Abilita il protocollo PCP/NAT-PMP" +msgstr "Attiva i protocolli PCP/NAT-PMP" #: applications/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js:141 msgid "Enable UPnP IGD protocol" diff --git a/luci-app-watchcat/po/es/watchcat.po b/luci-app-watchcat/po/es/watchcat.po index 3a363feb4..fea6dc2d4 100644 --- a/luci-app-watchcat/po/es/watchcat.po +++ b/luci-app-watchcat/po/es/watchcat.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2026-03-29 19:31+0000\n" -"Last-Translator: Franco Castillo \n" +"PO-Revision-Date: 2026-06-27 12:01+0000\n" +"Last-Translator: apemay \n" "Language-Team: Spanish \n" "Language: es\n" @@ -11,7 +11,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.17-dev\n" +"X-Generator: Weblate 2026.7.dev0\n" #: applications/luci-app-watchcat/htdocs/luci-static/resources/view/watchcat.js:94 msgid "" @@ -21,12 +21,12 @@ msgid "" "to fail. Enter the number of seconds to wait for the soft reboot to fail or " "use 0 to disable the forced reboot delay." msgstr "" -"Se aplica a los modos de Reinicio por Ping y Reinicio periódico
" -"Al reiniciar el enrutador, el servicio desencadenará un reinicio suave. " -"Poniendo un valor distinto de cero aquí, se desencadenará un reinicio " -"completo retrasado si falla el reinicio suave. Ponga el número de segundos " -"que hay que esperar a que el reinicio suave falle o use 0 para desactivar el " -"retraso de reinicio forzado." +"Se aplica a los modos Reinicio por ping y Reinicio periódico
Al " +"reiniciar el enrutador, el servicio activará un reinicio suave. Introducir " +"aquí un valor distinto de cero activará un reinicio completo retrasado si el " +"reinicio suave falla. Introduzca el número de segundos que esperar a que " +"falle el reinicio suave o use 0 para desactivar el retraso del reinicio " +"forzado." #: applications/luci-app-watchcat/htdocs/luci-static/resources/view/watchcat.js:111 msgid "" @@ -73,7 +73,7 @@ msgstr "Ajustes generales" #: applications/luci-app-watchcat/root/usr/share/rpcd/acl.d/luci-app-watchcat.json:3 msgid "Grant access to LuCI app watchcat" -msgstr "Otorgar acceso a la aplicación LuCI watchcat" +msgstr "Conceder acceso a la aplicación LuCI watchcat" #: applications/luci-app-watchcat/htdocs/luci-static/resources/view/watchcat.js:12 msgid "" @@ -191,14 +191,13 @@ msgid "" "time.
Run Script: Run a script if a ping to a specified host fails " "for a specified duration of time.
" msgstr "" -"Reinicio de ping: si el ping al host especificado siempre falla dentro del " -"tiempo especificado, el dispositivo se reiniciará.
Reinicio " -"programado: reinicia el dispositivo después de un intervalo de tiempo " -"específico.
Reiniciar interfaz: si dentro del tiempo especificado, el " -"ping del host especificado siempre falla, reinicie la interfaz de red " -"específica.
Ejecutar secuencia de comandos: si dentro del tiempo " -"especificado, el ping del host especificado siempre falla, ejecute una " -"secuencia de comandos específica.
" +"Reinicio por ping: reinicia este dispositivo si un ping al host especificado " +"falla durante un periodo de tiempo especificado.
Reinicio periódico: " +"reinicia este dispositivo después de un intervalo de tiempo especificado. " +"
Reiniciar interfaz: reinicia una interfaz de red si un ping al host " +"especificado falla durante un periodo de tiempo especificado.
Ejecutar " +"script: ejecuta un script si un ping al host especificado falla durante un " +"periodo de tiempo especificado.
" #: applications/luci-app-watchcat/htdocs/luci-static/resources/view/watchcat.js:29 msgid "Restart Interface" diff --git a/luci-lib-linkeasefile/Makefile b/luci-lib-linkeasefile/Makefile new file mode 100644 index 000000000..48bcaafd4 --- /dev/null +++ b/luci-lib-linkeasefile/Makefile @@ -0,0 +1,16 @@ + +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=LuCI support for linkease file +LUCI_DEPENDS:=+linkease +LUCI_PKGARCH:=all +PKG_VERSION:=2.1.70-r3 +# PKG_RELEASE MUST be empty for luci.mk +PKG_RELEASE:=1 +LUCI_MINIFY_CSS:=0 +LUCI_MINIFY_JS:=0 + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature + diff --git a/luci-app-linkease/htdocs/luci-static/linkeasefile/chunk.22632dc4.js b/luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/chunk.22632dc4.js similarity index 100% rename from luci-app-linkease/htdocs/luci-static/linkeasefile/chunk.22632dc4.js rename to luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/chunk.22632dc4.js diff --git a/luci-app-linkease/htdocs/luci-static/linkeasefile/chunk.324cab41.js b/luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/chunk.324cab41.js similarity index 100% rename from luci-app-linkease/htdocs/luci-static/linkeasefile/chunk.324cab41.js rename to luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/chunk.324cab41.js diff --git a/luci-app-linkease/htdocs/luci-static/linkeasefile/chunk.4a114b4a.js b/luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/chunk.4a114b4a.js similarity index 100% rename from luci-app-linkease/htdocs/luci-static/linkeasefile/chunk.4a114b4a.js rename to luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/chunk.4a114b4a.js diff --git a/luci-app-linkease/htdocs/luci-static/linkeasefile/chunk.4ea0593d.js b/luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/chunk.4ea0593d.js similarity index 100% rename from luci-app-linkease/htdocs/luci-static/linkeasefile/chunk.4ea0593d.js rename to luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/chunk.4ea0593d.js diff --git a/luci-app-linkease/htdocs/luci-static/linkeasefile/chunk.6424c2fc.js b/luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/chunk.6424c2fc.js similarity index 100% rename from luci-app-linkease/htdocs/luci-static/linkeasefile/chunk.6424c2fc.js rename to luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/chunk.6424c2fc.js diff --git a/luci-app-linkease/htdocs/luci-static/linkeasefile/chunk.7191676b.js b/luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/chunk.7191676b.js similarity index 100% rename from luci-app-linkease/htdocs/luci-static/linkeasefile/chunk.7191676b.js rename to luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/chunk.7191676b.js diff --git a/luci-app-linkease/htdocs/luci-static/linkeasefile/chunk.a0a5dece.js b/luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/chunk.a0a5dece.js similarity index 100% rename from luci-app-linkease/htdocs/luci-static/linkeasefile/chunk.a0a5dece.js rename to luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/chunk.a0a5dece.js diff --git a/luci-app-linkease/htdocs/luci-static/linkeasefile/chunk.a6a47e72.js b/luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/chunk.a6a47e72.js similarity index 100% rename from luci-app-linkease/htdocs/luci-static/linkeasefile/chunk.a6a47e72.js rename to luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/chunk.a6a47e72.js diff --git a/luci-app-linkease/htdocs/luci-static/linkeasefile/chunk.c69499bb.js b/luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/chunk.c69499bb.js similarity index 100% rename from luci-app-linkease/htdocs/luci-static/linkeasefile/chunk.c69499bb.js rename to luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/chunk.c69499bb.js diff --git a/luci-app-linkease/htdocs/luci-static/linkeasefile/chunk.d52f0fe8.js b/luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/chunk.d52f0fe8.js similarity index 100% rename from luci-app-linkease/htdocs/luci-static/linkeasefile/chunk.d52f0fe8.js rename to luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/chunk.d52f0fe8.js diff --git a/luci-app-linkease/htdocs/luci-static/linkeasefile/chunk.dc0a1b58.js b/luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/chunk.dc0a1b58.js similarity index 100% rename from luci-app-linkease/htdocs/luci-static/linkeasefile/chunk.dc0a1b58.js rename to luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/chunk.dc0a1b58.js diff --git a/luci-app-linkease/htdocs/luci-static/linkeasefile/codicon.ttf b/luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/codicon.ttf similarity index 100% rename from luci-app-linkease/htdocs/luci-static/linkeasefile/codicon.ttf rename to luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/codicon.ttf diff --git a/luci-app-linkease/htdocs/luci-static/linkeasefile/icons/archive.png b/luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/icons/archive.png similarity index 100% rename from luci-app-linkease/htdocs/luci-static/linkeasefile/icons/archive.png rename to luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/icons/archive.png diff --git a/luci-app-linkease/htdocs/luci-static/linkeasefile/icons/dir.png b/luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/icons/dir.png similarity index 100% rename from luci-app-linkease/htdocs/luci-static/linkeasefile/icons/dir.png rename to luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/icons/dir.png diff --git a/luci-app-linkease/htdocs/luci-static/linkeasefile/icons/doc.png b/luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/icons/doc.png similarity index 100% rename from luci-app-linkease/htdocs/luci-static/linkeasefile/icons/doc.png rename to luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/icons/doc.png diff --git a/luci-app-linkease/htdocs/luci-static/linkeasefile/icons/error.png b/luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/icons/error.png similarity index 100% rename from luci-app-linkease/htdocs/luci-static/linkeasefile/icons/error.png rename to luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/icons/error.png diff --git a/luci-app-linkease/htdocs/luci-static/linkeasefile/icons/image.png b/luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/icons/image.png similarity index 100% rename from luci-app-linkease/htdocs/luci-static/linkeasefile/icons/image.png rename to luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/icons/image.png diff --git a/luci-app-linkease/htdocs/luci-static/linkeasefile/icons/music.png b/luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/icons/music.png similarity index 100% rename from luci-app-linkease/htdocs/luci-static/linkeasefile/icons/music.png rename to luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/icons/music.png diff --git a/luci-app-linkease/htdocs/luci-static/linkeasefile/icons/notfound.png b/luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/icons/notfound.png similarity index 100% rename from luci-app-linkease/htdocs/luci-static/linkeasefile/icons/notfound.png rename to luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/icons/notfound.png diff --git a/luci-app-linkease/htdocs/luci-static/linkeasefile/icons/other.png b/luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/icons/other.png similarity index 100% rename from luci-app-linkease/htdocs/luci-static/linkeasefile/icons/other.png rename to luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/icons/other.png diff --git a/luci-app-linkease/htdocs/luci-static/linkeasefile/icons/video.png b/luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/icons/video.png similarity index 100% rename from luci-app-linkease/htdocs/luci-static/linkeasefile/icons/video.png rename to luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/icons/video.png diff --git a/luci-app-linkease/htdocs/luci-static/linkeasefile/index.js b/luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/index.js similarity index 100% rename from luci-app-linkease/htdocs/luci-static/linkeasefile/index.js rename to luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/index.js diff --git a/luci-app-linkease/htdocs/luci-static/linkeasefile/style.css b/luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/style.css similarity index 100% rename from luci-app-linkease/htdocs/luci-static/linkeasefile/style.css rename to luci-lib-linkeasefile/htdocs/luci-static/linkeasefile/style.css diff --git a/luci-app-linkease/luasrc/controller/linkease_backend.lua b/luci-lib-linkeasefile/luasrc/controller/linkease_file.lua similarity index 91% rename from luci-app-linkease/luasrc/controller/linkease_backend.lua rename to luci-lib-linkeasefile/luasrc/controller/linkease_file.lua index 576ba42ea..76bb0fc88 100644 --- a/luci-app-linkease/luasrc/controller/linkease_backend.lua +++ b/luci-lib-linkeasefile/luasrc/controller/linkease_file.lua @@ -7,13 +7,27 @@ local ltn12 = require "luci.ltn12" local table = require "table" local util = require "luci.util" -module("luci.controller.linkease_backend", package.seeall) +module("luci.controller.linkease_file", package.seeall) local BLOCKSIZE = 2048 local LINKEASE_UNIX = "/var/run/linkease.sock" function index() entry({"linkease"}, call("linkease_backend")).leaf=true + local e = entry({"admin", "services", "linkease", "file"}, call("linkease_file_template")) + e.leaf = true + e.dependent = false +end + +function get_params(name) + local data = { + prefix=luci.dispatcher.build_url(unpack({"admin", "services", "linkease", name})), + } + return data +end + +function linkease_file_template() + luci.template.render("linkease/file", get_params("file")) end local function sink_socket(sock, io_err) diff --git a/luci-app-linkease/luasrc/view/linkease/file.htm b/luci-lib-linkeasefile/luasrc/view/linkease/file.htm similarity index 100% rename from luci-app-linkease/luasrc/view/linkease/file.htm rename to luci-lib-linkeasefile/luasrc/view/linkease/file.htm diff --git a/luci-lib-linkeasefile/root/etc/uci-defaults/50_luci-linkease-file b/luci-lib-linkeasefile/root/etc/uci-defaults/50_luci-linkease-file new file mode 100755 index 000000000..048f3caf5 --- /dev/null +++ b/luci-lib-linkeasefile/root/etc/uci-defaults/50_luci-linkease-file @@ -0,0 +1,4 @@ +#!/bin/sh + +rm -f /tmp/luci-indexcache /tmp/luci-indexcache.* +exit 0 diff --git a/qBittorrent-Enhanced-Edition/Makefile b/qBittorrent-Enhanced-Edition/Makefile index b076ed194..c0c073f29 100644 --- a/qBittorrent-Enhanced-Edition/Makefile +++ b/qBittorrent-Enhanced-Edition/Makefile @@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=qBittorrent-Enhanced-Edition PKG_VERSION:=5.2.3.10 -PKG_RELEASE:=12 +PKG_RELEASE:=13 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/c0re100/qBittorrent-Enhanced-Edition/tar.gz/release-$(PKG_VERSION)? @@ -14,6 +14,7 @@ PKG_LICENSE_FILES:=COPYING PKG_CPE_ID:=cpe:/a:qbittorrent:qbittorrent PKG_BUILD_DEPENDS:=qt6tools/host +PKG_BUILD_FLAGS:=no-mips16 PKG_BUILD_PARALLEL:=1 include $(INCLUDE_DIR)/package.mk diff --git a/qbittorrent/Makefile b/qbittorrent/Makefile index db5b25a85..f84ee8648 100644 --- a/qbittorrent/Makefile +++ b/qbittorrent/Makefile @@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=qBittorrent PKG_VERSION:=5.2.3 -PKG_RELEASE:=4 +PKG_RELEASE:=5 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/qbittorrent/qBittorrent/tar.gz/release-$(PKG_VERSION)? @@ -14,6 +14,7 @@ PKG_LICENSE_FILES:=COPYING PKG_CPE_ID:=cpe:/a:qbittorrent:qbittorrent PKG_BUILD_DEPENDS:=qt6tools/host +PKG_BUILD_FLAGS:=no-mips16 PKG_BUILD_PARALLEL:=1 include $(INCLUDE_DIR)/package.mk diff --git a/qosmate/Makefile b/qosmate/Makefile index 35c523b81..7498b291f 100644 --- a/qosmate/Makefile +++ b/qosmate/Makefile @@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=qosmate PKG_VERSION:=0.5.48 -PKG_RELEASE:=4 +PKG_RELEASE:=5 PKG_MAINTAINER:=Markus Hütter PKG_LICENSE:=GPL-3.0-or-later diff --git a/qosmate/README.md b/qosmate/README.md index 70a9ecd48..c4e046c65 100644 --- a/qosmate/README.md +++ b/qosmate/README.md @@ -157,10 +157,36 @@ Remember that these are starting points - optimal settings may depend on your sp | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------- | ------- | | enabled | Enables or disables QoSmate. Set to 1 to enable, 0 to disable. | boolean | 1 | | WAN | Specifies the WAN interface. This is crucial for applying QoS rules to the correct network interface. It's typically the interface connected to your ISP. | string | eth1 | -| DOWNRATE | Download rate in kbps. Set this to about 80-90% of your actual download speed to allow for overhead and prevent bufferbloat. This creates a buffer that helps maintain low latency even when the connection is fully utilized. | integer | 90000 | -| UPRATE | Upload rate in kbps. Set this to about 80-90% of your actual upload speed for the same reasons as DOWNRATE. | integer | 45000 | +| DOWNRATE | Download rate in kbps. Set this to about 80-90% of your actual download speed to allow for overhead and prevent bufferbloat. This creates a buffer that helps maintain low latency even when the connection is fully utilized. Set to 0 to disable ingress shaping, see [One-Directional Shaping](#one-directional-shaping). | integer | 90000 | +| UPRATE | Upload rate in kbps. Set this to about 80-90% of your actual upload speed for the same reasons as DOWNRATE. Set to 0 to disable egress shaping. | integer | 45000 | | ROOT_QDISC | Specifies the root queueing discipline. Options are 'hfsc', 'cake', 'hybrid', or 'htb' | enum (hfsc, cake, hybrid, htb) | hfsc | +### One-Directional Shaping + +Setting a rate to `0` disables shaping for that direction, the same convention `sqm-scripts` uses. + +| Configuration | Effect | +| ------------- | ------ | +| `DOWNRATE` and `UPRATE` greater than 0 | Both directions are shaped (default) | +| `DOWNRATE=0` | Upload only. No IFB device, no ingress hook and no redirect are created, so the download path is left untouched | +| `UPRATE=0` | Download only. No egress qdisc is created; classification still works because the DSCP is stored in conntrack and restored on the IFB | +| both `0` | Nothing is shaped, only the nftables rules are applied | + +What `DOWNRATE=0` costs you: + +- **TCP bulk detection** (`TCP_DOWNPRIO_INITIAL_ENABLED`, `TCP_DOWNPRIO_SUSTAINED_ENABLED`) is + switched off, because its byte thresholds are derived from the download rate. +- **`ACK_FILTER_EGRESS=auto`** cannot compute the download/upload ratio and therefore stays off. Set + it to `1` or `0` explicitly for a defined behaviour. +- **Incoming packets carry no DSCP**, because the restore happens on the IFB. Devices behind the + router, for example an access point applying WMM, will not see any marking. +- **CAKE ingress options** have no effect, and so does `WASHDSCPDOWN` in CAKE mode. With HFSC, + Hybrid and HTB, `WASHDSCPDOWN` keeps working because it is implemented in nftables. + +`status` and `health_check` report a disabled direction as such, so it stays distinguishable from a +broken setup. Autorate adjusts only the direction that is actually shaped and does not start when +both rates are 0. + ### HFSC + Hybrid Specific Settings | Config option | Description | Type | Default | diff --git a/qosmate/etc/init.d/qosmate b/qosmate/etc/init.d/qosmate index d83cd0220..743ce2e4c 100644 --- a/qosmate/etc/init.d/qosmate +++ b/qosmate/etc/init.d/qosmate @@ -5,7 +5,6 @@ START=99 STOP=99 USE_PROCD=1 - VERSION="dev" UPD_CHANNEL="release" @@ -1419,19 +1418,22 @@ try_load_and_fix_config() { IFS="$DEFAULT_IFS" # Ensure valid values for DOWNRATE, UPRATE - case "$ROOT_QDISC" in hfsc|hybrid) - local opt val commit_req='' min_val=1000 - for opt in DOWNRATE UPRATE; do - eval "val=\"\${${opt}}\"" - if ! [ "$val" -gt 0 ]; then - log_msg -warn "$opt is '$val' for $ROOT_QDISC. Setting to minimum value of $min_val kbps." - eval "$opt=$min_val" - uci set "qosmate.settings.${opt}=${min_val}" - commit_req=1 - fi - done - [ -z "$commit_req" ] || uci commit qosmate || return 1 - esac + # A rate of 0 is valid and means "do not shape this direction" (same convention as + # sqm-scripts and ACKRATE=0): actually shaping to 0 would kill the link. Empty, + # negative and non-numeric values still fall back to the minimum. + local opt val commit_req='' min_val=1000 + for opt in DOWNRATE UPRATE; do + eval "val=\"\${${opt}}\"" + case "$val" in + ''|*[!0-9]*) ;; # empty or non-numeric: fixed below + *) continue # numeric, including 0 + esac + log_msg -warn "$opt is '$val'. Setting to minimum value of $min_val kbps." + eval "$opt=$min_val" + uci set "qosmate.settings.${opt}=${min_val}" + commit_req=1 + done + [ -z "$commit_req" ] || uci commit qosmate || return 1 # Limit DOWNRATE based on BWMAXRATIO if [ "$UPRATE" -gt 0 ] && [ $((DOWNRATE > UPRATE*BWMAXRATIO)) -eq 1 ]; then @@ -1439,6 +1441,9 @@ try_load_and_fix_config() { DOWNRATE=$((BWMAXRATIO*UPRATE)) fi + # A rate of 0 disables shaping for that direction; all components derive from these + export SHAPE_EGRESS=$((UPRATE > 0)) SHAPE_INGRESS=$((DOWNRATE > 0)) + return $parse_rv } @@ -2028,15 +2033,20 @@ status_service() { fi print_msg "qosmate global:enabled is $config_enabled." - local dir dev qdisc qdiscs active_qdisc \ + local dir dev shape rate_opt qdisc qdiscs active_qdisc \ IFB="ifb-$WAN" # Check and report if traffic shaping is active for dir in egress ingress; do case "$dir" in - egress) dev="$WAN" ;; - ingress) dev="$IFB" ;; + egress) dev="$WAN" shape="$SHAPE_EGRESS" rate_opt=UPRATE ;; + ingress) dev="$IFB" shape="$SHAPE_INGRESS" rate_opt=DOWNRATE ;; esac + # A rate of 0 disables that direction: report the intent instead of a missing qdisc + [ "$shape" = 1 ] || { + print_msg "Traffic shaping on the $dir interface is disabled by configuration ($rate_opt=0)." + continue + } qdiscs="$(tc qdisc show dev "$dev" 2>/dev/null | sed -n 's/^qdisc\s\s*\([^ \t]*\).* root .*/\1/p')" qdiscs="${qdiscs//$'\n'/ }" active_qdisc='' @@ -2059,10 +2069,13 @@ status_service() { fi done - # Show summary of current settings + # Show summary of current settings; a rate of 0 means the direction is not shaped + local up_print="$UPRATE kbps" down_print="$DOWNRATE kbps" + [ "$SHAPE_EGRESS" = 1 ] || up_print="$UPRATE kbps (shaping disabled)" + [ "$SHAPE_INGRESS" = 1 ] || down_print="$DOWNRATE kbps (shaping disabled)" print_msg "" "==== Current Settings ====" \ - "Upload rate: $UPRATE kbps" \ - "Download rate: $DOWNRATE kbps" \ + "Upload rate: $up_print" \ + "Download rate: $down_print" \ "Game traffic upload: $GAMEUP kbps" \ "Game traffic download: $GAMEDOWN kbps" if [ "$ROOT_QDISC" = "cake" ]; then @@ -2599,12 +2612,26 @@ health_check() { errors=$((errors + 1)) fi - # Check tc configuration on WAN interface - if [ -n "$WAN" ] && tc qdisc show dev "$WAN" 2>/dev/null | grep -E -q "hfsc|cake|htb"; then - status="${status}tc:ok;" - else + # Check tc configuration for every direction that is configured to be shaped. + # A rate of 0 disables that direction, so its absence must not count as a failure. + local tc_dev tc_devs='' tc_ok=1 + if [ -z "$WAN" ]; then status="${status}tc:failed;" errors=$((errors + 1)) + else + [ "$SHAPE_EGRESS" = 1 ] && tc_devs="$WAN" + [ "$SHAPE_INGRESS" = 1 ] && tc_devs="$tc_devs ifb-$WAN" + for tc_dev in $tc_devs; do + tc qdisc show dev "$tc_dev" 2>/dev/null | grep -E -q "hfsc|cake|htb" || tc_ok=0 + done + if [ -z "$tc_devs" ]; then + status="${status}tc:off;" + elif [ "$tc_ok" = 1 ]; then + status="${status}tc:ok;" + else + status="${status}tc:failed;" + errors=$((errors + 1)) + fi fi status="${status}config:${config_status};" diff --git a/qosmate/etc/init.d/qosmate-autorate b/qosmate/etc/init.d/qosmate-autorate index 2baa771cf..62e68176f 100644 --- a/qosmate/etc/init.d/qosmate-autorate +++ b/qosmate/etc/init.d/qosmate-autorate @@ -12,7 +12,7 @@ AUTORATE_SCRIPT=/etc/qosmate-autorate.sh . /lib/functions.sh start_service() { - local enabled wan + local enabled wan downrate config_load qosmate || return 1 config_get_bool enabled autorate enabled 0 @@ -20,10 +20,15 @@ start_service() { [ "$enabled" != "1" ] && return 0 [ ! -x "$AUTORATE_SCRIPT" ] && return 1 - # Check if qosmate is running (WAN configured and IFB exists) + # Check if qosmate is running. A DOWNRATE of 0 disables ingress shaping, so no IFB + # exists in that case and the egress root qdisc is what proves qosmate is up. config_get wan settings WAN + config_get downrate settings DOWNRATE [ -z "$wan" ] && return 1 - ip link show "ifb-$wan" >/dev/null 2>&1 || return 1 + case "${downrate:-0}" in + 0|*[!0-9]*) tc qdisc show dev "$wan" 2>/dev/null | grep -E -q "hfsc|cake|htb" || return 1 ;; + *) ip link show "ifb-$wan" >/dev/null 2>&1 || return 1 ;; + esac logger -t qosmate-autorate "Starting autorate daemon via procd" diff --git a/qosmate/etc/qosmate-autorate.sh b/qosmate/etc/qosmate-autorate.sh index 25e0c0849..e5fb9dbcb 100644 --- a/qosmate/etc/qosmate-autorate.sh +++ b/qosmate/etc/qosmate-autorate.sh @@ -39,6 +39,13 @@ load_autorate_config() { config_get UPRATE settings UPRATE config_get DOWNRATE settings DOWNRATE config_get ROOT_QDISC settings ROOT_QDISC + + # A rate of 0 means "do not shape this direction", so that direction is not adjusted. + # Guard against empty or non-numeric values to keep the arithmetic below safe. + case "$UPRATE" in ''|*[!0-9]*) UPRATE=0 ;; esac + case "$DOWNRATE" in ''|*[!0-9]*) DOWNRATE=0 ;; esac + SHAPE_EGRESS=$((UPRATE > 0)) + SHAPE_INGRESS=$((DOWNRATE > 0)) # HFSC section config_get GAMEUP hfsc GAMEUP @@ -242,13 +249,19 @@ run_daemon() { [ -z "$WAN" ] && { log_autorate "ERROR: WAN not configured"; exit 1; } + # Nothing to adjust when neither direction is shaped + if [ "$SHAPE_EGRESS" != 1 ] && [ "$SHAPE_INGRESS" != 1 ]; then + log_autorate "ERROR: neither direction is shaped (UPRATE=0 and DOWNRATE=0)" + exit 1 + fi + # Read active cake qdisc type (written by qosmate.sh at setup time) CAKE_TYPE=$(cat /tmp/qosmate/cake_type 2>/dev/null) : "${CAKE_TYPE:=cake}" local wan_iface="$WAN" lan_iface="ifb-$WAN" local ul_rate="$AUTORATE_BASE_UL" dl_rate="$AUTORATE_BASE_DL" - local prev_ul_bytes prev_dl_bytes curr_ul_bytes curr_dl_bytes + local prev_ul_bytes=0 prev_dl_bytes=0 curr_ul_bytes=0 curr_dl_bytes=0 local achieved_ul=0 achieved_dl=0 baseline_latency=0 baseline_samples=0 local last_ul_change=0 last_dl_change=0 current_time loop_count=0 local _time_cs_result=0 prev_time_cs=0 delta_ms @@ -306,14 +319,14 @@ run_daemon() { fi # Keep live qdisc rates aligned with restored daemon state after restart. - if [ -n "$restored_ul_rate" ] && [ "$restored_ul_rate" != "$ul_rate" ]; then + if [ "$SHAPE_EGRESS" = 1 ] && [ -n "$restored_ul_rate" ] && [ "$restored_ul_rate" != "$ul_rate" ]; then if autorate_update_bandwidth "$restored_ul_rate" "$wan_iface" "egress"; then ul_rate=$restored_ul_rate else log_autorate "WARNING: Failed to restore UL rate $restored_ul_rate kbps on $wan_iface, using base $ul_rate kbps" fi fi - if [ -n "$restored_dl_rate" ] && [ "$restored_dl_rate" != "$dl_rate" ]; then + if [ "$SHAPE_INGRESS" = 1 ] && [ -n "$restored_dl_rate" ] && [ "$restored_dl_rate" != "$dl_rate" ]; then if autorate_update_bandwidth "$restored_dl_rate" "$lan_iface" "ingress"; then dl_rate=$restored_dl_rate else @@ -323,12 +336,20 @@ run_daemon() { # Initialize byte counters and timestamp for first rate calculation read_bytes "$wan_iface" tx; prev_ul_bytes=$_bytes_result - read_bytes "$lan_iface" tx; prev_dl_bytes=$_bytes_result + [ "$SHAPE_INGRESS" = 1 ] && { read_bytes "$lan_iface" tx; prev_dl_bytes=$_bytes_result; } get_uptime; prev_time_cs=$_time_cs_result log_autorate "Daemon started (WAN=$wan_iface, interval=${AUTORATE_INTERVAL}ms)" - log_autorate "UL: min=$AUTORATE_MIN_UL base=$AUTORATE_BASE_UL max=$AUTORATE_MAX_UL (start=${ul_rate})" - log_autorate "DL: min=$AUTORATE_MIN_DL base=$AUTORATE_BASE_DL max=$AUTORATE_MAX_DL (start=${dl_rate})" + if [ "$SHAPE_EGRESS" = 1 ]; then + log_autorate "UL: min=$AUTORATE_MIN_UL base=$AUTORATE_BASE_UL max=$AUTORATE_MAX_UL (start=${ul_rate})" + else + log_autorate "UL: not shaped (UPRATE=0) - upload rate is not adjusted" + fi + if [ "$SHAPE_INGRESS" = 1 ]; then + log_autorate "DL: min=$AUTORATE_MIN_DL base=$AUTORATE_BASE_DL max=$AUTORATE_MAX_DL (start=${dl_rate})" + else + log_autorate "DL: not shaped (DOWNRATE=0) - download rate is not adjusted" + fi # Signal handling: TERM/INT exit cleanly, state file kept for recovery trap '_handle_signal' TERM INT @@ -344,7 +365,7 @@ run_daemon() { # Check if interfaces still exist (avoid race condition during restart) [ ! -d "/sys/class/net/$wan_iface" ] && break - [ ! -d "/sys/class/net/$lan_iface" ] && break + [ "$SHAPE_INGRESS" = 1 ] && [ ! -d "/sys/class/net/$lan_iface" ] && break # Get current time from /proc/uptime (seconds + centiseconds in one read) get_uptime @@ -353,7 +374,7 @@ run_daemon() { # Read current byte counters read_bytes "$wan_iface" tx; curr_ul_bytes=$_bytes_result - read_bytes "$lan_iface" tx; curr_dl_bytes=$_bytes_result + [ "$SHAPE_INGRESS" = 1 ] && { read_bytes "$lan_iface" tx; curr_dl_bytes=$_bytes_result; } # Calculate achieved rates using real elapsed time delta_ms=$(( (_time_cs_result - prev_time_cs) * 10 )) @@ -422,7 +443,7 @@ run_daemon() { fi # Apply upload rate change - if [ "$new_ul_rate" != "$ul_rate" ]; then + if [ "$SHAPE_EGRESS" = 1 ] && [ "$new_ul_rate" != "$ul_rate" ]; then ul_change_pct=$(( (new_ul_rate - ul_rate) * 100 / ul_rate )) [ "$ul_change_pct" -lt 0 ] && ul_change_pct=$((-ul_change_pct)) if [ "$AUTORATE_LOG_CHANGES" = "1" ] || [ "$ul_change_pct" -ge 5 ]; then @@ -437,7 +458,7 @@ run_daemon() { fi # Apply download rate change - if [ "$new_dl_rate" != "$dl_rate" ]; then + if [ "$SHAPE_INGRESS" = 1 ] && [ "$new_dl_rate" != "$dl_rate" ]; then dl_change_pct=$(( (new_dl_rate - dl_rate) * 100 / dl_rate )) [ "$dl_change_pct" -lt 0 ] && dl_change_pct=$((-dl_change_pct)) if [ "$AUTORATE_LOG_CHANGES" = "1" ] || [ "$dl_change_pct" -ge 5 ]; then diff --git a/qosmate/etc/qosmate.sh b/qosmate/etc/qosmate.sh index a60576695..f940aad2f 100644 --- a/qosmate/etc/qosmate.sh +++ b/qosmate/etc/qosmate.sh @@ -106,20 +106,25 @@ get_tc_overhead_params() { } # Get CAKE parameters from common link settings -# $1 = "hybrid" to force manual overhead for consistency with HFSC +# $1 = "hybrid": CAKE runs below an HFSC root that already accounts for the overhead get_cake_link_params() { local preset="$COMMON_LINK_PRESETS" local oh="${OVERHEAD}" local base="" + # The HFSC root carries a tc stab, which rewrites qdisc_pkt_len for the whole + # hierarchy. "raw" makes CAKE bill that already adjusted length instead of + # adding the overhead a second time. + [ "$1" = "hybrid" ] && { printf 'raw'; return; } + # Determine base keyword and default overhead case "$preset" in *atm*|*adsl*|*pppoa*|*pppoe*|*bridged*|*ipoa*|conservative) - [ "$1" = "hybrid" ] && base="atm" || base="${preset}" + base="${preset}" : "${oh:=44}" ;; docsis) base="docsis"; : "${oh:=25}" ;; - cake-ethernet) base="ethernet"; [ "$1" != "hybrid" ] && oh="" || : "${oh:=38}" ;; + cake-ethernet) base="ethernet"; oh="" ;; raw) base="raw"; : "${oh:=0}" ;; ethernet|*) base="ethernet"; : "${oh:=40}" ;; esac @@ -1007,21 +1012,28 @@ else fi # Conditionally defining TCP down-prioritization rules based on enabled flags -if [ "$TCP_DOWNPRIO_INITIAL_ENABLED" -eq 1 ]; then +# Both thresholds are derived from DOWNRATE. With DOWNRATE=0 first10s would be 0 and the +# rule would down-prioritize every TCP connection, so the rules are skipped in that case. +if [ "$TCP_DOWNPRIO_INITIAL_ENABLED" -eq 1 ] && [ "$DOWNRATE" -gt 0 ]; then downprio_initial_rules="meta l4proto tcp ct bytes < \$first500ms jump mark_500ms" else downprio_initial_rules="# Initial TCP down-prioritization disabled" fi -if [ "$TCP_DOWNPRIO_SUSTAINED_ENABLED" -eq 1 ]; then +if [ "$TCP_DOWNPRIO_SUSTAINED_ENABLED" -eq 1 ] && [ "$DOWNRATE" -gt 0 ]; then downprio_sustained_rules="meta l4proto tcp ct bytes > \$first10s jump mark_10s" else downprio_sustained_rules="# Sustained TCP down-prioritization disabled" fi -# Conditionally defining TCPMSS rules based on UPRATE and DOWNRATE +if [ "$DOWNRATE" -eq 0 ] && { [ "$TCP_DOWNPRIO_INITIAL_ENABLED" -eq 1 ] || [ "$TCP_DOWNPRIO_SUSTAINED_ENABLED" -eq 1 ]; }; then + log_msg -warn "TCP down-prioritization disabled: its byte thresholds are derived from DOWNRATE, which is 0." +fi -if [ "$UPRATE" -lt 3000 ]; then +# Conditionally defining TCPMSS rules based on UPRATE and DOWNRATE +# A rate of 0 means "this direction is not shaped", not "slow link", so no clamping then + +if [ "$UPRATE" -gt 0 ] && [ "$UPRATE" -lt 3000 ]; then # Clamp MSS between 536 and 1500 # Use iifname (ingress from WAN) to clamp SYN-ACK from server, limiting our upload packet size SAFE_MSS=$(( MSS > 1500 ? 1500 : (MSS < 536 ? 536 : MSS) )) @@ -1030,7 +1042,7 @@ else RULE_SET_TCPMSS_UP='' fi -if [ "$DOWNRATE" -lt 3000 ]; then +if [ "$DOWNRATE" -gt 0 ] && [ "$DOWNRATE" -lt 3000 ]; then # Clamp MSS between 536 and 1500 # Use oifname (egress to WAN) to clamp SYN to server, limiting our download packet size SAFE_MSS=$(( MSS > 1500 ? 1500 : (MSS < 536 ? 536 : MSS) )) @@ -1234,25 +1246,40 @@ DSCPEOF ## Set up ctinfo downstream shaping -print_msg "" "Setting up ctinfo downstream shaping..." +if [ "$SHAPE_INGRESS" = 1 ]; then + print_msg "" "Setting up ctinfo downstream shaping..." -# Set up ingress handle for WAN interface -tc qdisc add dev "$WAN" handle ffff: ingress + # Set up ingress handle for WAN interface + tc qdisc add dev "$WAN" handle ffff: ingress -# Create IFB interface (multi-queue when USE_MQ is enabled for cake_mq ingress support) -# Match the WAN TX queue count so egress and ingress CAKE instances are symmetric -ifb_mq_args="" -if [ "$USE_MQ" = "1" ]; then - wan_tx_queues=$(find /sys/class/net/"$WAN"/queues/ -maxdepth 1 -type d -name 'tx-*' 2>/dev/null | wc -l) - [ "$wan_tx_queues" -gt 1 ] && ifb_mq_args="numtxqueues $wan_tx_queues" + # Create IFB interface (multi-queue when USE_MQ is enabled for cake_mq ingress support) + # Match the WAN TX queue count so egress and ingress CAKE instances are symmetric + ifb_mq_args="" + if [ "$USE_MQ" = "1" ]; then + wan_tx_queues=$(find /sys/class/net/"$WAN"/queues/ -maxdepth 1 -type d -name 'tx-*' 2>/dev/null | wc -l) + [ "$wan_tx_queues" -gt 1 ] && ifb_mq_args="numtxqueues $wan_tx_queues" + fi + # shellcheck disable=SC2086 # ifb_mq_args needs word splitting (e.g. "numtxqueues 4" → two args) + ip link add name "ifb-$WAN" $ifb_mq_args type ifb + ip link set "ifb-$WAN" up + + # Redirect ingress traffic from WAN to IFB and restore DSCP from conntrack + tc filter add dev "$WAN" parent ffff: protocol all matchall action ctinfo dscp 63 128 mirred egress redirect dev "ifb-$WAN" + LAN=ifb-$WAN +else + # Rate 0 disables this direction: drop a previously created ingress path + print_msg "" "Ingress shaping disabled (DOWNRATE=0) - removing ingress path." + LAN='' + tc qdisc del dev "ifb-$WAN" root > /dev/null 2>&1 + tc qdisc del dev "$WAN" ingress > /dev/null 2>&1 + ip link del "ifb-$WAN" > /dev/null 2>&1 fi -# shellcheck disable=SC2086 # ifb_mq_args needs word splitting (e.g. "numtxqueues 4" → two args) -ip link add name "ifb-$WAN" $ifb_mq_args type ifb -ip link set "ifb-$WAN" up -# Redirect ingress traffic from WAN to IFB and restore DSCP from conntrack -tc filter add dev "$WAN" parent ffff: protocol all matchall action ctinfo dscp 63 128 mirred egress redirect dev "ifb-$WAN" -LAN=ifb-$WAN +# Minimum jitter estimate; only meaningful for a direction that is actually shaped +jitter_up="not shaped (UPRATE=0)" +jitter_down="not shaped (DOWNRATE=0)" +[ "$SHAPE_EGRESS" = 1 ] && jitter_up="$(((1500*8)*3/UPRATE)) ms" +[ "$SHAPE_INGRESS" = 1 ] && jitter_down="$(((1500*8)*3/DOWNRATE)) ms" cat <= 15 )) ;; - *[!0-9]*|'') qdisc_setup_failed "Invalid value '$ACK_FILTER_EGRESS' for ACK_FILTER_EGRESS." ;; - *) ack_filter_egress_val=$ACK_FILTER_EGRESS ;; - esac + if [ "$SHAPE_EGRESS" = 1 ]; then + case "$ACK_FILTER_EGRESS" in + # 'auto' needs a known download rate; keep the filter off without ingress shaping + auto) ack_filter_egress_val=$(( DOWNRATE > 0 && (DOWNRATE / UPRATE) >= 15 )) ;; + *[!0-9]*|'') qdisc_setup_failed "Invalid value '$ACK_FILTER_EGRESS' for ACK_FILTER_EGRESS." ;; + *) ack_filter_egress_val=$ACK_FILTER_EGRESS ;; + esac - local CAKE_OPTS="bandwidth ${UPRATE}kbit" - # shellcheck disable=SC2086 - append_cake_opt "$PRIORITY_QUEUE_EGRESS" "1" && - append_cake_opt "dual-srchost" "$HOST_ISOLATION" && - append_cake_opt "rtt ${RTT}ms" "${RTT:+1}" && - append_cake_opt "$cake_link_params" "1" && - append_cake_opt "$LINK_COMPENSATION" "1" && - append_cake_opt "$EXTRA_PARAMETERS_EGRESS" "1" && - append_cake_opt "nat" "$NAT_EGRESS" && - append_cake_opt "wash" "$WASHDSCPUP" && - append_cake_opt "ack-filter" "$ack_filter_egress_val" && - tc qdisc add dev "$WAN" root handle 1: "$CAKE_QDISC_EGR" $CAKE_OPTS || qdisc_setup_failed -debug_log "EGRESS $CAKE_QDISC_EGR opts: '$CAKE_OPTS'" + CAKE_OPTS="bandwidth ${UPRATE}kbit" + # shellcheck disable=SC2086 + append_cake_opt "$PRIORITY_QUEUE_EGRESS" "1" && + append_cake_opt "dual-srchost" "$HOST_ISOLATION" && + append_cake_opt "rtt ${RTT}ms" "${RTT:+1}" && + append_cake_opt "$cake_link_params" "1" && + append_cake_opt "$LINK_COMPENSATION" "1" && + append_cake_opt "$EXTRA_PARAMETERS_EGRESS" "1" && + append_cake_opt "nat" "$NAT_EGRESS" && + append_cake_opt "wash" "$WASHDSCPUP" && + append_cake_opt "ack-filter" "$ack_filter_egress_val" && + tc qdisc add dev "$WAN" root handle 1: "$CAKE_QDISC_EGR" $CAKE_OPTS || qdisc_setup_failed + debug_log "EGRESS $CAKE_QDISC_EGR opts: '$CAKE_OPTS'" + fi # Ingress (Download) CAKE setup - CAKE_OPTS="bandwidth ${DOWNRATE}kbit ingress" - # shellcheck disable=SC2086 - append_cake_opt "autorate-ingress" "$AUTORATE_INGRESS" && - append_cake_opt "$PRIORITY_QUEUE_INGRESS" "1" && - append_cake_opt "dual-dsthost" "$HOST_ISOLATION" && - append_cake_opt "rtt ${RTT}ms" "${RTT:+1}" && - append_cake_opt "$cake_link_params" "1" && - append_cake_opt "$LINK_COMPENSATION" "1" && - append_cake_opt "$EXTRA_PARAMETERS_INGRESS" "1" && - append_cake_opt "nat" "$NAT_INGRESS" && - append_cake_opt "wash" "$WASHDSCPDOWN" && - tc qdisc add dev "$LAN" root "$CAKE_QDISC_IGR" $CAKE_OPTS || qdisc_setup_failed -debug_log "INGRESS $CAKE_QDISC_IGR opts: '$CAKE_OPTS'" + if [ "$SHAPE_INGRESS" = 1 ]; then + CAKE_OPTS="bandwidth ${DOWNRATE}kbit ingress" + # shellcheck disable=SC2086 + append_cake_opt "autorate-ingress" "$AUTORATE_INGRESS" && + append_cake_opt "$PRIORITY_QUEUE_INGRESS" "1" && + append_cake_opt "dual-dsthost" "$HOST_ISOLATION" && + append_cake_opt "rtt ${RTT}ms" "${RTT:+1}" && + append_cake_opt "$cake_link_params" "1" && + append_cake_opt "$LINK_COMPENSATION" "1" && + append_cake_opt "$EXTRA_PARAMETERS_INGRESS" "1" && + append_cake_opt "nat" "$NAT_INGRESS" && + append_cake_opt "wash" "$WASHDSCPDOWN" && + tc qdisc add dev "$LAN" root "$CAKE_QDISC_IGR" $CAKE_OPTS || qdisc_setup_failed + debug_log "INGRESS $CAKE_QDISC_IGR opts: '$CAKE_OPTS'" + fi # Write active cake qdisc type for autorate daemon printf '%s\n' "$CAKE_QDISC_EGR" > /tmp/qosmate/cake_type @@ -1920,19 +1952,28 @@ if [ "$ROOT_QDISC" = "hfsc" ] || [ "$ROOT_QDISC" = "hybrid" ]; then esac fi +# A rate of 0 disables that direction. Remove leftovers of a disabled direction so that +# switching a rate to 0 takes effect even without a full service restart. +[ "$SHAPE_EGRESS" = 1 ] || { + print_msg "" "Egress shaping disabled (UPRATE=0) - removing root qdisc on $WAN." + tc qdisc del dev "$WAN" root > /dev/null 2>&1 +} +[ "$SHAPE_EGRESS" = 1 ] || [ "$SHAPE_INGRESS" = 1 ] || + log_msg -warn "No shaping active: both UPRATE and DOWNRATE are 0. Only nftables DSCP marking is applied." + # Main logic for selecting and applying the QoS system case "$ROOT_QDISC" in hfsc) print_msg "Applying HFSC queueing discipline." # Call the renamed function (formerly setqdisc) - setup_hfsc "$WAN" "$UPRATE" "$GAMEUP" "$gameqdisc" wan - setup_hfsc "$LAN" "$DOWNRATE" "$GAMEDOWN" "$gameqdisc" lan + [ "$SHAPE_EGRESS" = 1 ] && setup_hfsc "$WAN" "$UPRATE" "$GAMEUP" "$gameqdisc" wan + [ "$SHAPE_INGRESS" = 1 ] && setup_hfsc "$LAN" "$DOWNRATE" "$GAMEDOWN" "$gameqdisc" lan ;; hybrid) print_msg "Applying Hybrid (HFSC+CAKE) queueing discipline." # Setup WAN (egress/upload) and LAN (ingress/download) directly - setup_hybrid "$WAN" "$UPRATE" "$GAMEUP" "wan" - setup_hybrid "$LAN" "$DOWNRATE" "$GAMEDOWN" "lan" + [ "$SHAPE_EGRESS" = 1 ] && setup_hybrid "$WAN" "$UPRATE" "$GAMEUP" "wan" + [ "$SHAPE_INGRESS" = 1 ] && setup_hybrid "$LAN" "$DOWNRATE" "$GAMEDOWN" "lan" # cake_mq not supported as child qdisc under HFSC printf '%s\n' "cake" > /tmp/qosmate/cake_type ;; @@ -1942,8 +1983,8 @@ case "$ROOT_QDISC" in ;; htb) print_msg "Applying HTB queueing discipline." - setup_htb "$WAN" "$UPRATE" "wan" - setup_htb "$LAN" "$DOWNRATE" "lan" + [ "$SHAPE_EGRESS" = 1 ] && setup_htb "$WAN" "$UPRATE" "wan" + [ "$SHAPE_INGRESS" = 1 ] && setup_htb "$LAN" "$DOWNRATE" "lan" ;; *) # Fallback for unsupported ROOT_QDISC print_msg -err "Unsupported ROOT_QDISC: '$ROOT_QDISC'. Check /etc/config/qosmate." @@ -1951,8 +1992,8 @@ case "$ROOT_QDISC" in ROOT_QDISC="hfsc" gameqdisc="pfifo" # Safe default for fallback # Apply the fallback configuration using the renamed function - setup_hfsc "$WAN" "$UPRATE" "$GAMEUP" "$gameqdisc" wan - setup_hfsc "$LAN" "$DOWNRATE" "$GAMEDOWN" "$gameqdisc" lan + [ "$SHAPE_EGRESS" = 1 ] && setup_hfsc "$WAN" "$UPRATE" "$GAMEUP" "$gameqdisc" wan + [ "$SHAPE_INGRESS" = 1 ] && setup_hfsc "$LAN" "$DOWNRATE" "$GAMEDOWN" "$gameqdisc" lan ;; esac @@ -1960,8 +2001,13 @@ esac # Restore DSCP values from conntrack for egress packets # Only needed when Software Flow Offloading is active if [ "$SFO_ENABLED" = "1" ]; then - print_msg "" "Software Flow Offloading detected - enabling SFO compatibility mode..." - tc filter add dev "$WAN" parent 1: prio 1 protocol all matchall action ctinfo dscp 63 128 continue + if [ "$SHAPE_EGRESS" = 1 ]; then + print_msg "" "Software Flow Offloading detected - enabling SFO compatibility mode..." + tc filter add dev "$WAN" parent 1: prio 1 protocol all matchall action ctinfo dscp 63 128 continue + else + # The filter attaches to the egress root qdisc, which does not exist without egress shaping + print_msg "" "Software Flow Offloading detected, but egress shaping is disabled - skipping SFO filter." + fi else print_msg "" "Software Flow Offloading disabled - dynamic rules fully functional..." fi @@ -1977,10 +2023,8 @@ elif [ "$ROOT_QDISC" = "hybrid" ] && [ "$gameqdisc" = "red" ]; then else # Check if tc command exists before trying to run it if command -v tc >/dev/null; then - print_msg "--- Egress ($WAN) ---" - tc -s qdisc show dev "$WAN" - print_msg "--- Ingress ($LAN) ---" - tc -s qdisc show dev "$LAN" + [ "$SHAPE_EGRESS" = 1 ] && { print_msg "--- Egress ($WAN) ---"; tc -s qdisc show dev "$WAN"; } + [ "$SHAPE_INGRESS" = 1 ] && { print_msg "--- Ingress ($LAN) ---"; tc -s qdisc show dev "$LAN"; } else print_msg "Warning: 'tc' command not found. Cannot display QoS status." fi