diff --git a/.github/workflows/Create-NewReleases.yml b/.github/workflows/Create-NewReleases.yml
index bb9b258..22a07b4 100644
--- a/.github/workflows/Create-NewReleases.yml
+++ b/.github/workflows/Create-NewReleases.yml
@@ -19,7 +19,7 @@ jobs:
steps:
# 1--- Check out master so we tag the exact merge commit
- name: Checkout source code
- uses: actions/checkout@v6.0.2
+ uses: actions/checkout@v7.0.1
with:
fetch-depth: 0
ref: 'master'
@@ -97,7 +97,7 @@ jobs:
# 7--- Publish a GitHub Release with auto-generated notes
- name: Create Release with Automated Release Notes
- uses: softprops/action-gh-release@v2.6.1
+ uses: softprops/action-gh-release@v3.0.2
with:
token: ${{ secrets.GITHUB_TOKEN }}
tag_name: ${{ steps.nextver.outputs.tag }}
diff --git a/README.md b/README.md
index f5f6d77..515a9fe 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
# spdMerlin
-## v4.4.19
-### Updated on 2026-Apr-11
+## v4.4.20
+### Updated on 2026-Aug-10
## About
spdMerlin is an internet speedtest and monitoring tool for AsusWRT Merlin with charts for daily, weekly and monthly summaries. It tracks download/upload bandwidth as well as latency, jitter and packet loss.
diff --git a/spdmerlin.sh b/spdmerlin.sh
index c33b3ec..1f86b8c 100644
--- a/spdmerlin.sh
+++ b/spdmerlin.sh
@@ -14,7 +14,7 @@
## Forked from https://github.com/jackyaz/spdMerlin ##
## ##
##############################################################
-# Last Modified: 2026-Apr-11
+# Last Modified: 2026-Aug-09
#-------------------------------------------------------------
############## Shellcheck directives #############
@@ -38,9 +38,9 @@
### Start of script variables ###
readonly SCRIPT_NAME="spdMerlin"
readonly SCRIPT_NAME_LOWER="$(echo "$SCRIPT_NAME" | tr 'A-Z' 'a-z')"
-readonly SCRIPT_VERSION="v4.4.19"
-readonly SCRIPT_VERSTAG="26041103"
-SCRIPT_BRANCH="master"
+readonly SCRIPT_VERSION="v4.4.20"
+readonly SCRIPT_VERSTAG="26080922"
+SCRIPT_BRANCH="develop"
SCRIPT_REPO="https://raw.githubusercontent.com/AMTM-OSR/$SCRIPT_NAME/$SCRIPT_BRANCH"
readonly SCRIPT_DIR="/jffs/addons/$SCRIPT_NAME_LOWER.d"
readonly SCRIPT_WEBPAGE_DIR="$(readlink -f /www/user)"
@@ -49,11 +49,21 @@ readonly SHARED_DIR="/jffs/addons/shared-jy"
readonly SHARED_REPO="https://raw.githubusercontent.com/AMTM-OSR/shared-jy/master"
readonly SHARED_WEB_DIR="$SCRIPT_WEBPAGE_DIR/shared-jy"
readonly TEMP_MENU_TREE="/tmp/menuTree.js"
-
readonly HOME_DIR="/home/root"
-readonly OOKLA_DIR="$SCRIPT_DIR/ookla"
-readonly OOKLA_LICENSE_DIR="$SCRIPT_DIR/ooklalicense"
-readonly OOKLA_HOME_DIR="$HOME_DIR/.config/ookla"
+
+# For F/W built-in Ookla CLI Speed Test Binaries #
+readonly BUILTIN_OOKLA_PROC="ookla"
+readonly BUILTIN_OOKLA_BINARY="/usr/sbin/$BUILTIN_OOKLA_PROC"
+readonly BUILTIN_OOKLA_CONFIG1="https://www.speedtest.net/api/embed/vz0azjarf5enop8a/config"
+readonly BUILTIN_OOKLA_CONFIG2="https://config.speedtest.net/v1/embed/4tiouex6gsnzq55o/config"
+
+# For external Ookla CLI Speed Test Binaries #
+readonly OOKLA_DIR="${SCRIPT_DIR}/ookla"
+readonly OOKLA_HOME_DIR="${HOME_DIR}/.config/ookla"
+readonly OOKLA_LICENSE_DIR="${SCRIPT_DIR}/ooklalicense"
+readonly EXTERNL_OOKLA_PROC="speedtest"
+readonly EXTERNL_OOKLA_BINARY="${OOKLA_DIR}/$EXTERNL_OOKLA_PROC"
+
readonly FULL_IFACELIST="WAN VPNC1 VPNC2 VPNC3 VPNC4 VPNC5 WGVPN1 WGVPN2 WGVPN3 WGVPN4 WGVPN5"
[ -z "$(nvram get odmpid)" ] && ROUTER_MODEL="$(nvram get productid)" || ROUTER_MODEL="$(nvram get odmpid)"
@@ -75,6 +85,14 @@ readonly branchxStr_TAG="[Branch: $SCRIPT_BRANCH]"
readonly versionDev_TAG="${SCRIPT_VERSION}_${SCRIPT_VERSTAG}"
readonly versionMod_TAG="$SCRIPT_VERSION on $ROUTER_MODEL"
+##-------------------------------------##
+## Added by Martinski W. [2026-Jul-12] ##
+##-------------------------------------##
+readonly fwInstalledBaseVers="$(nvram get firmver | sed 's/\.//g')"
+readonly fwInstalledBuildVers="$(nvram get buildno)"
+readonly fwInstalledBuildLong="${fwInstalledBaseVers}.$fwInstalledBuildVers"
+readonly fwInstalledBuildShrt="${fwInstalledBaseVers}.$(echo "$fwInstalledBuildVers" | awk -F'.' '{print $1}')"
+
# To support automatic script updates from AMTM #
doScriptUpdateFromAMTM=true
@@ -106,7 +124,8 @@ unset LD_LIBRARY_PATH
# Give priority to built-in binaries #
export PATH="/bin:/usr/bin:/sbin:/usr/sbin:$PATH"
-if [ "$(uname -m)" = "aarch64" ]; then
+if [ "$(uname -m)" = "aarch64" ]
+then
ARCH="aarch64"
else
/bin/grep -Eq 'Features\s*:.*\s+v?fp\s+' /proc/cpuinfo && ARCH="arm" || ARCH="armel"
@@ -229,8 +248,25 @@ Clear_Lock()
return 0
}
-Check_Swap(){
- if [ "$(wc -l < /proc/swaps)" -ge 2 ]; then return 0; else return 1; fi
+##-------------------------------------##
+## Added by Martinski W. [2026-Jul-08] ##
+##-------------------------------------##
+_HasRouterMoreThan256MBtotalRAM_()
+{
+ local totalRAM_KB
+ totalRAM_KB="$(awk -F ' ' '/^MemTotal:/{print $2}' /proc/meminfo)"
+ if [ -n "$totalRAM_KB" ] && [ "$totalRAM_KB" -gt 262144 ]
+ then return 0
+ else return 1
+ fi
+}
+
+Check_Swap()
+{
+ if [ "$(wc -l < /proc/swaps)" -ge 2 ]
+ then return 0
+ else return 1
+ fi
}
##----------------------------------------##
@@ -410,19 +446,55 @@ ScriptUpdateFromAMTM()
##-------------------------------------##
## Added by Martinski W. [2025-Jun-11] ##
##-------------------------------------##
-_GetSpeedtestBinaryVersion_()
+_GetExternalSpeedTestBinVersion_()
{
- if [ ! -x "$OOKLA_DIR/speedtest" ] ; then echo "[N/A]" ; return 1 ; fi
+ if [ ! -x "$EXTERNL_OOKLA_BINARY" ]
+ then echo "[N/A]" ; return 1
+ fi
local verLine verStr="[N/A]"
- verLine="$("$OOKLA_DIR"/speedtest -V | grep -E '^Speedtest by Ookla [1-9]+[.].*')"
+ verLine="$($EXTERNL_OOKLA_BINARY -V | grep -E '^Speedtest by Ookla [1-9]+[.].*')"
if [ -n "$verLine" ]
- then
- verStr="$(echo "$verLine" | awk -F ' ' '{print $4}')"
+ then verStr="$(echo "$verLine" | awk -F ' ' '{print $4}')"
+ fi
+ echo "$verStr"
+}
+
+##-------------------------------------##
+## Added by Martinski W. [2026-Jul-12] ##
+##-------------------------------------##
+_GetBuiltInSpeedTestBinVersion_()
+{
+ if [ ! -x "$BUILTIN_OOKLA_BINARY" ]
+ then echo "[N/A]" ; return 1
+ fi
+ local verLine verStr="[N/A]"
+
+ verLine="$($BUILTIN_OOKLA_BINARY -V | grep -E '^ookla [1-9]+[.].*')"
+ if [ -n "$verLine" ]
+ then verStr="$(echo "$verLine" | awk -F ' ' '{print $2}')"
fi
echo "$verStr"
}
+_FWVersionStrToNum_()
+{ echo "$1" | awk -F '.' '{ printf ("%d%03d%02d%02d\n", $1,$2,$3,$4); }' ; }
+
+##-------------------------------------##
+## Added by Martinski W. [2026-Jul-12] ##
+##-------------------------------------##
+_GetBuiltInSpeedTestConfigURL_()
+{
+ local configURL="$BUILTIN_OOKLA_CONFIG1"
+
+ if [ "$fwInstalledBuildShrt" = "3006.102" ] && \
+ [ "$(_FWVersionStrToNum_ "$fwInstalledBuildLong")" -ge "$(_FWVersionStrToNum_ "3006.102.8")" ]
+ then
+ configURL="$BUILTIN_OOKLA_CONFIG2"
+ fi
+ echo "$configURL"
+}
+
##-------------------------------------##
## Added by Martinski W. [2025-Jun-19] ##
##-------------------------------------##
@@ -437,21 +509,21 @@ Update_File()
if [ "$1" = "$ARCH.tar.gz" ]
then
tmpfile="/tmp/$1"
- Download_File "$SCRIPT_REPO/$1" "$tmpfile"
+ Download_File "${SCRIPT_REPO}/$1" "$tmpfile"
tar -xzf "$tmpfile" -C "/tmp"
rm -f "$tmpfile"
- localmd5="$(md5sum "$OOKLA_DIR/speedtest" | awk '{print $1}')"
+ localmd5="$(md5sum "$EXTERNL_OOKLA_BINARY" | awk '{print $1}')"
tmpmd5="$(md5sum /tmp/speedtest | awk '{print $1}')"
if [ "$localmd5" != "$tmpmd5" ]
then
- rm -f "$OOKLA_DIR"/*
- Download_File "$SCRIPT_REPO/$1" "$OOKLA_DIR/$1"
- tar -xzf "$OOKLA_DIR/$1" -C "$OOKLA_DIR"
- rm -f "$OOKLA_DIR/$1"
- chmod 0755 "$OOKLA_DIR/speedtest"
- chown "${theUserName}:root" "$OOKLA_DIR"/*
- spdTestVer="$(_GetSpeedtestBinaryVersion_)"
- Print_Output true "Speedtest CLI $spdTestVer version was downloaded." "$PASS"
+ rm -f "${OOKLA_DIR}"/*
+ Download_File "${SCRIPT_REPO}/$1" "${OOKLA_DIR}/$1"
+ tar -xzf "${OOKLA_DIR}/$1" -C "$OOKLA_DIR"
+ rm -f "${OOKLA_DIR}/$1"
+ chmod 0755 "$EXTERNL_OOKLA_BINARY"
+ chown "${theUserName}:root" "${OOKLA_DIR}"/*
+ spdTestVer="$(_GetExternalSpeedTestBinVersion_)"
+ Print_Output true "Ookla Speedtest CLI $spdTestVer version was downloaded." "$PASS"
fi
rm -f /tmp/speedtest*
elif [ "$1" = "spdstats_www.asp" ]
@@ -459,19 +531,19 @@ Update_File()
tmpfile="/tmp/$1"
if [ -f "$SCRIPT_DIR/$1" ]
then
- Download_File "$SCRIPT_REPO/$1" "$tmpfile"
+ Download_File "${SCRIPT_REPO}/$1" "$tmpfile"
if ! diff -q "$tmpfile" "$SCRIPT_DIR/$1" >/dev/null 2>&1
then
Get_WebUI_Page "$SCRIPT_DIR/$1"
sed -i "\\~$MyWebPage~d" "$TEMP_MENU_TREE"
rm -f "$SCRIPT_WEBPAGE_DIR/$MyWebPage" 2>/dev/null
- Download_File "$SCRIPT_REPO/$1" "$SCRIPT_DIR/$1"
+ Download_File "${SCRIPT_REPO}/$1" "$SCRIPT_DIR/$1"
Print_Output true "New version of $1 downloaded" "$PASS"
Mount_WebUI
fi
rm -f "$tmpfile"
else
- Download_File "$SCRIPT_REPO/$1" "$SCRIPT_DIR/$1"
+ Download_File "${SCRIPT_REPO}/$1" "$SCRIPT_DIR/$1"
Print_Output true "New version of $1 downloaded" "$PASS"
Mount_WebUI
fi
@@ -1016,7 +1088,7 @@ Interfaces_FromSettings()
##-------------------------------------##
_GetDefaultSpeedTestBinary_()
{
- if [ -f /usr/sbin/ookla ]
+ if [ -x "$BUILTIN_OOKLA_BINARY" ]
then echo "builtin"
else echo "external"
fi
@@ -1058,7 +1130,7 @@ Conf_Exists()
{
local AUTOMATEDopt delCRON=false
- if [ -f "$SCRIPT_CONF" ]
+ if [ -s "$SCRIPT_CONF" ]
then
dos2unix "$SCRIPT_CONF"
chmod 0644 "$SCRIPT_CONF"
@@ -1248,7 +1320,7 @@ Auto_ServiceEvent()
local theScriptFilePath="/jffs/scripts/$SCRIPT_NAME_LOWER"
case $1 in
create)
- if [ -f /jffs/scripts/service-event ]
+ if [ -s /jffs/scripts/service-event ]
then
STARTUPLINECOUNT="$(grep -c '# '"$SCRIPT_NAME" /jffs/scripts/service-event)"
STARTUPLINECOUNTEX="$(grep -cx 'if echo "$2" | /bin/grep -qE "('"$SCRIPT_NAME_LOWER"'|vpnclient)" ; then { '"$theScriptFilePath"' service_event "$@" & }; fi # '"$SCRIPT_NAME" /jffs/scripts/service-event)"
@@ -1269,14 +1341,15 @@ Auto_ServiceEvent()
echo 'if echo "$2" | /bin/grep -qE "('"$SCRIPT_NAME_LOWER"'|vpnclient)" ; then { '"$theScriptFilePath"' service_event "$@" & }; fi # '"$SCRIPT_NAME"
echo
} > /jffs/scripts/service-event
- chmod 0755 /jffs/scripts/service-event
fi
+ chmod 0755 /jffs/scripts/service-event
;;
delete)
- if [ -f /jffs/scripts/service-event ]
+ if [ -s /jffs/scripts/service-event ]
then
STARTUPLINECOUNT="$(grep -c '# '"$SCRIPT_NAME" /jffs/scripts/service-event)"
- if [ "$STARTUPLINECOUNT" -gt 0 ]; then
+ if [ "$STARTUPLINECOUNT" -gt 0 ]
+ then
sed -i -e '/# '"$SCRIPT_NAME"'/d' /jffs/scripts/service-event
fi
fi
@@ -1318,9 +1391,11 @@ Auto_OpenVPN_Event()
case $1 in
create)
# Check if any OpenVPN Client is set up/available in NVRAM #
- if ! _CheckForOpenVPN_ClientsAvailable_ ; then return 1 ; fi
+ if ! _CheckForOpenVPN_ClientsAvailable_
+ then return 1
+ fi
- if [ -f /jffs/scripts/openvpn-event ]
+ if [ -s /jffs/scripts/openvpn-event ]
then
STARTUPLINECOUNT="$(grep -c '# '"$SCRIPT_NAME" /jffs/scripts/openvpn-event)"
STARTUPLINECOUNTEX="$(grep -cx '\[ -x '"$theScriptFilePath"' \] && '"$theScriptFilePath"' openvpn_event "$1" "$script_type" & # '"$SCRIPT_NAME" /jffs/scripts/openvpn-event)"
@@ -1341,14 +1416,15 @@ Auto_OpenVPN_Event()
echo '[ -x '"$theScriptFilePath"' ] && '"$theScriptFilePath"' openvpn_event "$1" "$script_type" & # '"$SCRIPT_NAME"
echo
} > /jffs/scripts/openvpn-event
- chmod 0755 /jffs/scripts/openvpn-event
fi
+ chmod 0755 /jffs/scripts/openvpn-event
;;
delete)
- if [ -f /jffs/scripts/openvpn-event ]
+ if [ -s /jffs/scripts/openvpn-event ]
then
STARTUPLINECOUNT="$(grep -c '# '"$SCRIPT_NAME" /jffs/scripts/openvpn-event)"
- if [ "$STARTUPLINECOUNT" -gt 0 ]; then
+ if [ "$STARTUPLINECOUNT" -gt 0 ]
+ then
sed -i -e '/# '"$SCRIPT_NAME"'/d' /jffs/scripts/openvpn-event
fi
fi
@@ -1396,12 +1472,14 @@ Auto_WG_ClientEvent()
case $1 in
create)
# Check if any WireGuard Client is set up/available in NVRAM #
- if ! _CheckForWireGuard_ClientsAvailable_ ; then return 1 ; fi
+ if ! _CheckForWireGuard_ClientsAvailable_
+ then return 1
+ fi
for wgClientEvent in stop start
do
wgClientFilePath="/jffs/scripts/wgclient-$wgClientEvent"
- if [ -f "$wgClientFilePath" ]
+ if [ -s "$wgClientFilePath" ]
then
STARTUPLINECOUNT="$(grep -c '# '"$SCRIPT_NAME" "$wgClientFilePath")"
STARTUPLINECOUNTEX="$(grep -cx '\[ -x '"$theScriptFilePath"' \] && '"$theScriptFilePath"' wgclient_event '"$wgClientEvent"' "$@" & # '"$SCRIPT_NAME" "$wgClientFilePath")"
@@ -1422,18 +1500,19 @@ Auto_WG_ClientEvent()
echo '[ -x '"$theScriptFilePath"' ] && '"$theScriptFilePath"' wgclient_event '"$wgClientEvent"' "$@" & # '"$SCRIPT_NAME"
echo
} > "$wgClientFilePath"
- chmod 0755 "$wgClientFilePath"
fi
+ chmod 0755 "$wgClientFilePath"
done
;;
delete)
for wgClientEvent in stop start
do
wgClientFilePath="/jffs/scripts/wgclient-$wgClientEvent"
- if [ -f "$wgClientFilePath" ]
+ if [ -s "$wgClientFilePath" ]
then
STARTUPLINECOUNT="$(grep -c '# '"$SCRIPT_NAME" "$wgClientFilePath")"
- if [ "$STARTUPLINECOUNT" -gt 0 ]; then
+ if [ "$STARTUPLINECOUNT" -gt 0 ]
+ then
sed -i -e '/# '"$SCRIPT_NAME"'/d' "$wgClientFilePath"
fi
fi
@@ -1450,14 +1529,15 @@ Auto_Startup()
local theScriptFilePath="/jffs/scripts/$SCRIPT_NAME_LOWER"
case $1 in
create)
- if [ -f /jffs/scripts/services-start ]
+ if [ -s /jffs/scripts/services-start ]
then
STARTUPLINECOUNT="$(grep -c '# '"$SCRIPT_NAME" /jffs/scripts/services-start)"
- if [ "$STARTUPLINECOUNT" -gt 0 ]; then
+ if [ "$STARTUPLINECOUNT" -gt 0 ]
+ then
sed -i -e '/# '"$SCRIPT_NAME"'/d' /jffs/scripts/services-start
fi
fi
- if [ -f /jffs/scripts/post-mount ]
+ if [ -s /jffs/scripts/post-mount ]
then
STARTUPLINECOUNT="$(grep -c '# '"$SCRIPT_NAME" /jffs/scripts/post-mount)"
STARTUPLINECOUNTEX="$(grep -cx '\[ -x "${1}/entware/bin/opkg" \] && \[ -x '"$theScriptFilePath"' \] && '"$theScriptFilePath"' startup "$@" & # '"$SCRIPT_NAME" /jffs/scripts/post-mount)"
@@ -1479,21 +1559,23 @@ Auto_Startup()
echo '[ -x "${1}/entware/bin/opkg" ] && [ -x '"$theScriptFilePath"' ] && '"$theScriptFilePath"' startup "$@" & # '"$SCRIPT_NAME"
echo
} > /jffs/scripts/post-mount
- chmod 0755 /jffs/scripts/post-mount
fi
+ chmod 0755 /jffs/scripts/post-mount
;;
delete)
- if [ -f /jffs/scripts/services-start ]
+ if [ -s /jffs/scripts/services-start ]
then
STARTUPLINECOUNT="$(grep -c '# '"$SCRIPT_NAME" /jffs/scripts/services-start)"
- if [ "$STARTUPLINECOUNT" -gt 0 ]; then
+ if [ "$STARTUPLINECOUNT" -gt 0 ]
+ then
sed -i -e '/# '"$SCRIPT_NAME"'/d' /jffs/scripts/services-start
fi
fi
- if [ -f /jffs/scripts/post-mount ]
+ if [ -s /jffs/scripts/post-mount ]
then
STARTUPLINECOUNT="$(grep -c '# '"$SCRIPT_NAME" /jffs/scripts/post-mount)"
- if [ "$STARTUPLINECOUNT" -gt 0 ]; then
+ if [ "$STARTUPLINECOUNT" -gt 0 ]
+ then
sed -i -e '/# '"$SCRIPT_NAME"'/d' /jffs/scripts/post-mount
fi
fi
@@ -1510,9 +1592,11 @@ Auto_Cron()
case $1 in
create)
STARTUPLINECOUNT="$(cru l | grep -c "#${SCRIPT_NAME}#")"
- if [ "$STARTUPLINECOUNT" -gt 0 ]; then
+ if [ "$STARTUPLINECOUNT" -gt 0 ]
+ then
cru d "${SCRIPT_NAME}"
fi
+
STARTUPLINECOUNTGEN="$(cru l | grep -c "${SCRIPT_NAME}_generate")"
CRU_SCHHOUR="$(_GetConfigParam_ SCHHOURS '*')"
CRU_SCHMINS="$(_GetConfigParam_ SCHMINS '12,42')"
@@ -1535,27 +1619,55 @@ Auto_Cron()
cru d "${SCRIPT_NAME}_trimDB"
STARTUPLINECOUNTTRIM="$(cru l | grep -c "${SCRIPT_NAME}_trimDB")"
fi
- if [ "$STARTUPLINECOUNTTRIM" -eq 0 ]; then
+ if [ "$STARTUPLINECOUNTTRIM" -eq 0 ]
+ then
cru a "${SCRIPT_NAME}_trimDB" "$defTrimDB_Mins $defTrimDB_Hour * * * $theScriptFilePath trimdb"
fi
;;
delete)
STARTUPLINECOUNT="$(cru l | grep -c "#${SCRIPT_NAME}#")"
- if [ "$STARTUPLINECOUNT" -gt 0 ]; then
+ if [ "$STARTUPLINECOUNT" -gt 0 ]
+ then
cru d "$SCRIPT_NAME"
fi
STARTUPLINECOUNTGEN="$(cru l | grep -c "#${SCRIPT_NAME}_generate#")"
- if [ "$STARTUPLINECOUNTGEN" -gt 0 ]; then
+ if [ "$STARTUPLINECOUNTGEN" -gt 0 ]
+ then
cru d "${SCRIPT_NAME}_generate"
fi
STARTUPLINECOUNTTRIM="$(cru l | grep -c "#${SCRIPT_NAME}_trimDB#")"
- if [ "$STARTUPLINECOUNTTRIM" -gt 0 ]; then
+ if [ "$STARTUPLINECOUNTTRIM" -gt 0 ]
+ then
cru d "${SCRIPT_NAME}_trimDB"
fi
;;
esac
}
+##-------------------------------------##
+## Added by Martinski W. [2026-Jul-15] ##
+##-------------------------------------##
+_Get_Interface_IPv4address_()
+{
+ if [ $# -eq 0 ] || [ -z "$1" ] || \
+ ! echo "$1" | grep -qE "^(wgc|tun1)[1-5]$"
+ then echo ; return 1
+ fi
+ local addrRegExp="[[:blank:]]+inet[[:blank:]]+.*[[:blank:]]+global[[:blank:]]+${1}$"
+ local routRegExp="[[:blank:]]+dev[[:blank:]]+${1}[[:blank:]]+proto[[:blank:]]+.*[[:blank:]]+src[[:blank:]]+"
+
+ if echo "$1" | grep -qE "^tun1[1-5]$"
+ then
+ ip route show | grep -E "$routRegExp" | awk -F' ' '{print $NF}'
+ return 0
+ fi
+ if echo "$1" | grep -qE "^wgc[1-5]$"
+ then
+ ip addr show "$1" | grep -E "$addrRegExp" | awk -F' ' '{print $2}' | awk -F'/' '{print $1}'
+ return 0
+ fi
+}
+
##----------------------------------------##
## Modified by Martinski W. [2025-Jun-27] ##
##----------------------------------------##
@@ -1572,9 +1684,9 @@ Get_Interface_From_Name()
elif [ "$wanProto" = "l2tp" ] || \
[ "$wanProto" = "pptp" ] || \
[ "$wanProto" = "pppoe" ]
- then
+ then #(e.g. 'ppp0')#
IFACEname="$(nvram get "${wanPrefix}_pppoe_ifname")"
- else
+ else #(e.g. 'eth0')#
IFACEname="$(nvram get "${wanPrefix}_ifname")"
fi
;;
@@ -2092,21 +2204,21 @@ SpeedtestBinary()
case "$1" in
builtin)
- if [ -f /usr/sbin/ookla ]
+ if [ -x "$BUILTIN_OOKLA_BINARY" ]
then
sed -i 's/^SPEEDTESTBINARY=.*$/SPEEDTESTBINARY=builtin/' "$SCRIPT_CONF"
else
retCode=1
- Print_Output true "The built-in Speedtest binary is NOT found." "$ERR"
+ Print_Output true "The F/W built-in Ookla speedtest binary is NOT found." "$ERR"
fi
;;
external)
- if [ -f "$OOKLA_DIR/speedtest" ]
+ if [ -x "$EXTERNL_OOKLA_BINARY" ]
then
sed -i 's/^SPEEDTESTBINARY=.*$/SPEEDTESTBINARY=external/' "$SCRIPT_CONF"
else
retCode=1
- Print_Output true "The external Speedtest binary is NOT found." "$ERR"
+ Print_Output true "The external Ookla Speedtest binary is NOT found." "$ERR"
fi
;;
check)
@@ -2382,11 +2494,13 @@ WriteStats_ToJS()
}
##----------------------------------------##
-## Modified by Martinski W. [2026-Jan-05] ##
+## Modified by Martinski W. [2026-Jul-15] ##
##----------------------------------------##
GenerateServerList()
{
- local serverMsgStr maxServerCount serverCount serverIndx COUNTER
+ local serverMsgStr maxServerCount serverCount serverIndx
+ local IFACE_NAME IFACE_LOWER IFACE_IPv4A COUNTER serverList
+ local errorLogFile="/tmp/${SCRIPT_NAME}.DEBUG.Servers.LOG"
if [ ! -f /opt/bin/jq ] && [ -x /opt/bin/opkg ]
then
@@ -2398,30 +2512,45 @@ GenerateServerList()
else promptforservername="$2"
fi
- printf " Generating list of closest servers for ${GRNct}${1}${CLRct} interface.\n"
+ rm -f "$errorLogFile"
+ IFACE_NAME="$1"
+ IFACE_LOWER="$(Get_Interface_From_Name "$IFACE_NAME" | tr 'A-Z' 'a-z')"
+ IFACE_IPv4A="" ##DO NOT SET##
+ ##OFF## IFACE_IPv4A="$(_Get_Interface_IPv4address_ "$IFACE_LOWER")"
+
+ printf " Generating list of closest servers for ${GRNct}${IFACE_NAME} [$IFACE_LOWER]${CLRct} interface.\n"
printf " Please wait...\n\n"
+
+ serverList=""
CONFIG_STRING=""
- LICENSE_STRING="--accept-license --accept-gdpr"
+ LICENSE_STRING=""
SPEEDTEST_BINARY=""
if [ "$(SpeedtestBinary check)" = "builtin" ]
then
- SPEEDTEST_BINARY="/usr/sbin/ookla"
+ SPEEDTEST_BINARY="$BUILTIN_OOKLA_BINARY"
+ CONFIG_STRING="-c $(_GetBuiltInSpeedTestConfigURL_)"
elif [ "$(SpeedtestBinary check)" = "external" ]
then
- SPEEDTEST_BINARY="$OOKLA_DIR/speedtest"
+ SPEEDTEST_BINARY="$EXTERNL_OOKLA_BINARY"
+ LICENSE_STRING="--accept-license --accept-gdpr"
fi
- if [ "$SPEEDTEST_BINARY" = "/usr/sbin/ookla" ]
+
+ serverList="$("$SPEEDTEST_BINARY" $CONFIG_STRING --interface="$IFACE_LOWER" --servers --format="json" $LICENSE_STRING)" 2>"$errorLogFile"
+ if [ -z "$serverList" ] && [ -n "$IFACE_IPv4A" ]
then
- CONFIG_STRING="-c http://www.speedtest.net/api/embed/vz0azjarf5enop8a/config"
- LICENSE_STRING=""
+ serverList="$("$SPEEDTEST_BINARY" $CONFIG_STRING --ip="$IFACE_IPv4A" --servers --format="json" $LICENSE_STRING)" 2>"$errorLogFile"
fi
- serverList="$("$SPEEDTEST_BINARY" $CONFIG_STRING --interface="$(Get_Interface_From_Name "$1")" --servers --format="json" $LICENSE_STRING)" 2>/dev/null
if [ -z "$serverList" ]
then
- Print_Output true "Error retrieving server list for $1 interface" "$CRIT"
+ Print_Output true "ERROR retrieving server list for $IFACE_NAME [$IFACE_LOWER] interface" "$CRIT"
serverNum="ERROR"
+ if [ -s "$errorLogFile" ]
+ then cat "$errorLogFile" ; echo
+ fi
+ rm -f "$errorLogFile"
return 1
fi
+
serverCount="$(echo "$serverList" | jq '.servers | length')"
COUNTER=1
until [ "$COUNTER" -gt "${serverCount:=0}" ]
@@ -2445,9 +2574,9 @@ GenerateServerList()
while true
do
- printf "\n${BOLD}Select a %s from the list above [${GRNct}1-%d${CLRct}].${CLRct}" "$serverMsgStr" "$maxServerCount"
- printf "\n${BOLD}Or press ${GRNct}C${CLRct} key to enter a known speed test server ID.${CLRct}"
- printf "\n${BOLD}Enter answer:${CLRct} "
+ printf "\n ${BOLD}Select a %s from the list above [${GRNct}1-%d${CLRct}].${CLRct}" "$serverMsgStr" "$maxServerCount"
+ printf "\n ${BOLD}Or press ${GRNct}C${CLRct} key to enter a known speed test server ID.${CLRct}"
+ printf "\n ${BOLD}Enter answer:${CLRct} "
read -r serverIndx
if echo "$serverIndx" | grep -qE "^(e|E)$"
@@ -2463,7 +2592,7 @@ GenerateServerList()
then
while true
do
- printf "\n${BOLD}Please enter server ID (WARNING: ID is NOT validated) or ${GRNct}e${CLRct} to go back.${CLRct} "
+ printf "\n ${BOLD}Please enter server ID (${MGNTct}WARNING: ID is NOT validated${CLRct}) or ${GRNct}e${CLRct} to go back.${CLRct} "
read -r customserver
if [ "$customserver" = "e" ]
then
@@ -2478,19 +2607,19 @@ GenerateServerList()
then
while true
do
- printf "\n${BOLD}Would you like to enter a name for this server? (default: Custom) (y/n)?${CLRct} "
+ printf "\n ${BOLD}Would you like to enter a name for this server? (default: Custom) (y/n)?${CLRct} "
read -r servername_select
- if [ "$servername_select" = "n" ] || [ "$servername_select" = "N" ]
+ if echo "$servername_select" | grep -qE '^(n|N)$'
then
serverName="Custom"
break
- elif [ "$servername_select" = "y" ] || [ "$servername_select" = "Y" ]
+ elif echo "$servername_select" | grep -qE '^(y|Y)$'
then
- printf "\n${BOLD}Please enter the name for this server:${CLRct} "
+ printf "\n ${BOLD}Please enter the name for this server:${CLRct} "
read -r serverName
- printf "\n${BOLD}%s${CLRct}\n" "$serverName"
- printf "\n${BOLD}Is that correct (y/n)?${CLRct} "
+ printf "\n ${BOLD}${GRNct}%s${CLRct}\n" "$serverName"
+ printf "\n ${BOLD}Is that correct (y/n)?${CLRct} "
read -r servername_confirm
if [ "$servername_confirm" = "y" ] || \
[ "$servername_confirm" = "Y" ]
@@ -2506,8 +2635,7 @@ GenerateServerList()
else
serverName="Custom"
fi
- printf "\n"
- return 0
+ echo ; return 0
fi
done
elif ! Validate_Number "$serverIndx"
@@ -2527,32 +2655,31 @@ GenerateServerList()
}
##----------------------------------------##
-## Modified by Martinski W. [2025-Oct-12] ##
+## Modified by Martinski W. [2026-Jul-15] ##
##----------------------------------------##
GenerateServerList_WebUI()
{
- local setIFaceUserStatus=false
+ local setIFaceUserStatus=false serverList
+ local IFACE_NAME IFACE_LOWER IFACE_IPv4A COUNTER
spdifacename="$1"
serverlistfile="$2"
rm -f "/tmp/${serverlistfile}.txt"
rm -f "/tmp/${serverlistfile}.tmp"
- rm -f "$SCRIPT_WEB_DIR/${serverlistfile}.htm"
+ rm -f "${SCRIPT_WEB_DIR}/${serverlistfile}.htm"
+ serverList=""
+ CONFIG_STRING=""
+ LICENSE_STRING=""
SPEEDTEST_BINARY=""
if [ "$(SpeedtestBinary check)" = "builtin" ]
then
- SPEEDTEST_BINARY="/usr/sbin/ookla"
+ SPEEDTEST_BINARY="$BUILTIN_OOKLA_BINARY"
+ CONFIG_STRING="-c $(_GetBuiltInSpeedTestConfigURL_)"
elif [ "$(SpeedtestBinary check)" = "external" ]
then
- SPEEDTEST_BINARY="$OOKLA_DIR/speedtest"
- fi
- CONFIG_STRING=""
- LICENSE_STRING="--accept-license --accept-gdpr"
- if [ "$SPEEDTEST_BINARY" = "/usr/sbin/ookla" ]
- then
- CONFIG_STRING="-c http://www.speedtest.net/api/embed/vz0azjarf5enop8a/config"
- LICENSE_STRING=""
+ SPEEDTEST_BINARY="$EXTERNL_OOKLA_BINARY"
+ LICENSE_STRING="--accept-license --accept-gdpr"
fi
if [ ! -f /opt/bin/jq ] && [ -x /opt/bin/opkg ]
@@ -2582,10 +2709,17 @@ GenerateServerList_WebUI()
for IFACE_NAME in $IFACELIST
do
- serverList="$("$SPEEDTEST_BINARY" $CONFIG_STRING --interface="$(Get_Interface_From_Name "$IFACE_NAME")" --servers --format="json" $LICENSE_STRING)" 2>/dev/null
+ IFACE_LOWER="$(Get_Interface_From_Name "$IFACE_NAME" | tr 'A-Z' 'a-z')"
+ IFACE_IPv4A="" ##DO NOT SET##
+ ##OFF## IFACE_IPv4A="$(_Get_Interface_IPv4address_ "$IFACE_LOWER")"
+ serverList="$("$SPEEDTEST_BINARY" $CONFIG_STRING --interface="$IFACE_LOWER" --servers --format="json" $LICENSE_STRING)" 2>/dev/null
+ if [ -z "$serverList" ] && [ -n "$IFACE_IPv4A" ]
+ then
+ serverList="$("$SPEEDTEST_BINARY" $CONFIG_STRING --ip="$IFACE_IPv4A" --servers --format="json" $LICENSE_STRING)" 2>/dev/null
+ fi
if [ -z "$serverList" ]
then
- Print_Output true "Error retrieving server list for $IFACE_NAME interface" "$CRIT"
+ Print_Output true "ERROR retrieving server list for $IFACE_NAME [$IFACE_LOWER] interface" "$CRIT"
{
echo "0|**ERROR**: Unable to retrieve server list." ; echo "-----"
} >> "/tmp/${serverlistfile}.tmp"
@@ -2604,10 +2738,17 @@ GenerateServerList_WebUI()
echo "-----" >> "/tmp/${serverlistfile}.tmp"
done
else
- serverList="$("$SPEEDTEST_BINARY" $CONFIG_STRING --interface="$(Get_Interface_From_Name "$spdifacename")" --servers --format="json" $LICENSE_STRING)" 2>/dev/null
+ IFACE_LOWER="$(Get_Interface_From_Name "$spdifacename" | tr 'A-Z' 'a-z')"
+ IFACE_IPv4A="" ##DO NOT SET##
+ ##OFF## IFACE_IPv4A="$(_Get_Interface_IPv4address_ "$IFACE_LOWER")"
+ serverList="$("$SPEEDTEST_BINARY" $CONFIG_STRING --interface="$IFACE_LOWER" --servers --format="json" $LICENSE_STRING)" 2>/dev/null
+ if [ -z "$serverList" ] && [ -n "$IFACE_IPv4A" ]
+ then
+ serverList="$("$SPEEDTEST_BINARY" $CONFIG_STRING --ip="$IFACE_IPv4A" --servers --format="json" $LICENSE_STRING)" 2>/dev/null
+ fi
if [ -z "$serverList" ]
then
- Print_Output true "Error retrieving server list for $spdifacename interface" "$CRIT"
+ Print_Output true "ERROR retrieving server list for $spdifacename [$IFACE_LOWER] interface" "$CRIT"
serverCount=0
else
serverCount="$(echo "$serverList" | jq '.servers | length')"
@@ -3216,7 +3357,7 @@ _Trim_Database_()
}
##----------------------------------------##
-## Modified by Martinski W. [2025-Oct-30] ##
+## Modified by Martinski W. [2026-Jul-15] ##
##----------------------------------------##
Run_Speedtest()
{
@@ -3226,7 +3367,8 @@ Run_Speedtest()
opkg update
opkg install findutils
fi
- if [ -n "$PPID" ]; then
+ if [ -n "$PPID" ]
+ then
ps | grep -v grep | grep -v $$ | grep -v "$PPID" | grep -i "$SCRIPT_NAME_LOWER" | grep generate | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1
else
ps | grep -v grep | grep -v $$ | grep -i "$SCRIPT_NAME_LOWER" | grep generate | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1
@@ -3235,10 +3377,10 @@ Run_Speedtest()
Conf_Exists
if [ "$(SpeedtestBinary check)" = "builtin" ]
then
- echo "/usr/sbin/ookla" > /tmp/spdmerlin-binary
+ echo "$BUILTIN_OOKLA_BINARY" > /tmp/spdmerlin-binary
elif [ "$(SpeedtestBinary check)" = "external" ]
then
- echo "$OOKLA_DIR/speedtest" > /tmp/spdmerlin-binary
+ echo "$EXTERNL_OOKLA_BINARY" > /tmp/spdmerlin-binary
fi
Auto_Startup create 2>/dev/null
if AutomaticMode check
@@ -3264,68 +3406,83 @@ Run_Speedtest()
local stoppedQoS nvramQoSenable nvramQoStype
local spdIndx spdTestOK verboseNUM verboseARG
local serverLine serverIDno
+ local IFACE_NAME IFACE_LOWER IFACE_IPv4A
verboseNUM="$(_GetConfigParam_ VERBOSE_TEST 0)"
if ! echo "$verboseNUM" | grep -qE "^[0-3]$"
then verboseNUM=0
fi
+ PROC_NAME=""
CONFIG_STRING=""
- LICENSE_STRING="--accept-license --accept-gdpr"
- PROC_NAME="speedtest"
+ LICENSE_STRING=""
SPEEDTEST_BINARY=""
if [ "$(SpeedtestBinary check)" = "builtin" ]
then
- SPEEDTEST_BINARY="/usr/sbin/ookla"
+ PROC_NAME="$BUILTIN_OOKLA_PROC"
+ SPEEDTEST_BINARY="$BUILTIN_OOKLA_BINARY"
+ CONFIG_STRING="-c $(_GetBuiltInSpeedTestConfigURL_)"
elif [ "$(SpeedtestBinary check)" = "external" ]
then
- SPEEDTEST_BINARY="$OOKLA_DIR/speedtest"
- fi
- if [ "$SPEEDTEST_BINARY" = "/usr/sbin/ookla" ]
- then
- CONFIG_STRING="-c http://www.speedtest.net/api/embed/vz0azjarf5enop8a/config"
- LICENSE_STRING=""
- PROC_NAME="ookla"
+ PROC_NAME="$EXTERNL_OOKLA_PROC"
+ SPEEDTEST_BINARY="$EXTERNL_OOKLA_BINARY"
+ LICENSE_STRING="--accept-license --accept-gdpr"
fi
-
echo 'var spdteststatus = "InProgress";' > /tmp/detect_spdtest.js
tmpfile=/tmp/spd-stats.txt
resultfile=/tmp/spd-result.txt
- spdTestLogFile="/tmp/${SCRIPT_NAME}.DEBUG.log"
+ errorLogFile="/tmp/${SCRIPT_NAME}.DEBUG.LOG"
spdTestDBGFile="/tmp/${SCRIPT_NAME}.DEBUG.txt"
- rm -f "$tmpfile" "$resultfile" "$spdTestLogFile"
+ rm -f "$tmpfile" "$resultfile" "$errorLogFile"
- if [ -n "$(pidof "$PROC_NAME")" ]; then
- killall -q "$PROC_NAME"
+ if [ -n "$(pidof "$PROC_NAME")" ]
+ then killall -q "$PROC_NAME"
fi
- if Check_Swap
+ if ! _HasRouterMoreThan256MBtotalRAM_ && ! Check_Swap
+ then
+ echo 'var spdteststatus = "NoSwap";' > /tmp/detect_spdtest.js
+ Print_Output true "Total RAM is less than 512MB and SWAP file NOT detected. Exiting" "$CRIT"
+ Clear_Lock
+ return 1
+ fi
+
+ _WaitForSpeedTestProcess_()
+ {
+ sleep 2 ; speedTestSecs=0
+ while [ -n "$(pidof "$PROC_NAME")" ] && \
+ [ "$speedTestSecs" -lt "$MAXwaitTestSecs" ]
+ do speedTestSecs="$((speedTestSecs + 1))" ; sleep 1
+ done
+ }
+
+ IFACELIST=""
+ if [ -z "$specificiface" ]
then
- IFACELIST=""
- if [ -z "$specificiface" ]
- then
while IFS='' read -r line || [ -n "$line" ]
do
- if [ "$(echo "$line" | grep -c "#")" -eq 0 ]; then
+ if [ "$(echo "$line" | grep -c "#")" -eq 0 ]
+ then
IFACELIST="$IFACELIST $(echo "$line" | cut -f1 -d"#" | sed 's/ *$//')"
fi
done < "$SCRIPT_INTERFACES_USER"
IFACELIST="$(echo "$IFACELIST" | cut -c2-)"
- elif [ "$specificiface" = "All" ]
- then
+ elif [ "$specificiface" = "All" ]
+ then
while IFS='' read -r line || [ -n "$line" ]
do
- if [ "$(echo "$line" | grep -c "interface not up")" -eq 0 ]; then
+ if [ "$(echo "$line" | grep -c "interface not up")" -eq 0 ]
+ then
IFACELIST="$IFACELIST $(echo "$line" | cut -f1 -d"#" | sed 's/ *$//')"
fi
done < "$SCRIPT_INTERFACES_USER"
IFACELIST="$(echo "$IFACELIST" | cut -c2-)"
- else
+ else
IFACELIST="$specificiface"
- fi
+ fi
- if [ "$IFACELIST" != "" ]
- then
+ if [ -n "$IFACELIST" ]
+ then
stoppedQoS=false
if [ "$(ExcludeFromQoS check)" = "true" ]
then
@@ -3377,9 +3534,7 @@ Run_Speedtest()
for IFACE_NAME in $IFACELIST
do
- IFACE="$(Get_Interface_From_Name "$IFACE_NAME")"
- IFACE_LOWER="$(echo "$IFACE" | tr "A-Z" "a-z")"
-
+ IFACE_LOWER="$(Get_Interface_From_Name "$IFACE_NAME" | tr 'A-Z' 'a-z')"
interface_UP=false
if echo "$IFACE_NAME" | grep -q "^WGVPN"
then
@@ -3392,9 +3547,11 @@ Run_Speedtest()
if ! "$interface_UP"
then
- Print_Output true "$IFACE not up, please check. Skipping speedtest for $IFACE_NAME" "$WARN"
+ Print_Output true "$IFACE_LOWER is not up, please check. Skipping speedtest for $IFACE_NAME" "$WARN"
continue
else
+ IFACE_IPv4A="" ##DO NOT SET##
+ ##OFF## IFACE_IPv4A="$(_Get_Interface_IPv4address_ "$IFACE_LOWER")"
if [ "$mode" = "webui_user" ]; then
mode="user"
elif [ "$mode" = "webui_auto" ]; then
@@ -3430,57 +3587,72 @@ Run_Speedtest()
fi
echo 'var spdteststatus = "InProgress_'"$IFACE_NAME"'";' > /tmp/detect_spdtest.js
- printf '' > "$tmpfile"
+ printf '' > "$tmpfile" ; printf '' > "$errorLogFile"
if [ "$mode" = "auto" ]
then
- Print_Output true "Starting speedtest using auto-selected server for $IFACE_NAME interface. Please wait..." "$PASS"
- "$SPEEDTEST_BINARY" $verboseARG $CONFIG_STRING --interface="$IFACE" --format="human-readable" --unit="Mbps" -p $LICENSE_STRING 2>"$spdTestLogFile" | tee "$tmpfile" &
- sleep 2
- speedTestSecs=0
- while [ -n "$(pidof "$PROC_NAME")" ] && [ "$speedTestSecs" -lt "$MAXwaitTestSecs" ]
- do
- speedTestSecs="$((speedTestSecs + 1))" ; sleep 1
- done
+ Print_Output true "Starting speedtest using auto-selected server for $IFACE_NAME [$IFACE_LOWER] interface. Please wait..." "$PASS"
+ ("$SPEEDTEST_BINARY" $verboseARG $CONFIG_STRING --interface="$IFACE_LOWER" --format="human-readable" --unit="Mbps" -p $LICENSE_STRING | tee "$tmpfile") 2>"$errorLogFile" &
+ _WaitForSpeedTestProcess_
+
+ if [ "$speedTestSecs" -lt "$MAXwaitTestSecs" ] && \
+ [ ! -s "$tmpfile" ] && [ -s "$errorLogFile" ] && [ -n "$IFACE_IPv4A" ]
+ then
+ printf '' > "$errorLogFile"
+ ("$SPEEDTEST_BINARY" $verboseARG $CONFIG_STRING --ip="$IFACE_IPv4A" --format="human-readable" --unit="Mbps" -p $LICENSE_STRING | tee "$tmpfile") 2>"$errorLogFile" &
+ _WaitForSpeedTestProcess_
+ fi
if [ "$speedTestSecs" -ge "$MAXwaitTestSecs" ]
then
- Print_Output true "Speedtest for $IFACE_NAME hung (> 2 mins), killing process" "$CRIT"
+ Print_Output true "Speedtest for $IFACE_NAME [$IFACE_LOWER] hung (> 2 mins), killing process" "$CRIT"
killall -q "$PROC_NAME"
- if [ -s "$spdTestLogFile" ] ; then echo ; cat "$spdTestLogFile" ; echo ; fi
+ if [ -s "$errorLogFile" ]
+ then cat "$errorLogFile" ; echo
+ fi
continue
fi
else
if [ "$speedtestServerIDx" -ne 0 ]
then
- Print_Output true "Starting speedtest using $speedtestServerName for $IFACE_NAME interface. Please wait..." "$PASS"
- "$SPEEDTEST_BINARY" $verboseARG $CONFIG_STRING --interface="$IFACE" --server-id="$speedtestServerIDx" --format="human-readable" --unit="Mbps" -p $LICENSE_STRING 2>"$spdTestLogFile" | tee "$tmpfile" &
- sleep 2
- speedTestSecs=0
- while [ -n "$(pidof "$PROC_NAME")" ] && [ "$speedTestSecs" -lt "$MAXwaitTestSecs" ]
- do
- speedTestSecs="$((speedTestSecs + 1))" ; sleep 1
- done
+ Print_Output true "Starting speedtest using $speedtestServerName for $IFACE_NAME [$IFACE_LOWER] interface. Please wait..." "$PASS"
+ ("$SPEEDTEST_BINARY" $verboseARG $CONFIG_STRING --interface="$IFACE_LOWER" --server-id="$speedtestServerIDx" --format="human-readable" --unit="Mbps" -p $LICENSE_STRING | tee "$tmpfile") 2>"$errorLogFile" &
+ _WaitForSpeedTestProcess_
+
+ if [ "$speedTestSecs" -lt "$MAXwaitTestSecs" ] && \
+ [ ! -s "$tmpfile" ] && [ -s "$errorLogFile" ] && [ -n "$IFACE_IPv4A" ]
+ then
+ printf '' > "$errorLogFile"
+ ("$SPEEDTEST_BINARY" $verboseARG $CONFIG_STRING --ip="$IFACE_IPv4A" --server-id="$speedtestServerIDx" --format="human-readable" --unit="Mbps" -p $LICENSE_STRING | tee "$tmpfile") 2>"$errorLogFile" &
+ _WaitForSpeedTestProcess_
+ fi
if [ "$speedTestSecs" -ge "$MAXwaitTestSecs" ]
then
- Print_Output true "Speedtest for $IFACE_NAME hung (> 2 mins), killing process" "$CRIT"
+ Print_Output true "Speedtest for $IFACE_NAME [$IFACE_LOWER] hung (> 2 mins), killing process" "$CRIT"
killall -q "$PROC_NAME"
- if [ -s "$spdTestLogFile" ] ; then echo ; cat "$spdTestLogFile" ; echo ; fi
+ if [ -s "$errorLogFile" ]
+ then cat "$errorLogFile" ; echo
+ fi
continue
fi
else
- Print_Output true "Starting speedtest using auto-selected server for $IFACE_NAME interface. Please wait..." "$PASS"
- "$SPEEDTEST_BINARY" $verboseARG $CONFIG_STRING --interface="$IFACE" --format="human-readable" --unit="Mbps" -p $LICENSE_STRING 2>"$spdTestLogFile" | tee "$tmpfile" &
- sleep 2
- speedTestSecs=0
- while [ -n "$(pidof "$PROC_NAME")" ] && [ "$speedTestSecs" -lt "$MAXwaitTestSecs" ]
- do
- speedTestSecs="$((speedTestSecs + 1))" ; sleep 1
- done
+ Print_Output true "Starting speedtest using auto-selected server for $IFACE_NAME [$IFACE_LOWER] interface. Please wait..." "$PASS"
+ ("$SPEEDTEST_BINARY" $verboseARG $CONFIG_STRING --interface="$IFACE_LOWER" --format="human-readable" --unit="Mbps" -p $LICENSE_STRING | tee "$tmpfile") 2>"$errorLogFile" &
+ _WaitForSpeedTestProcess_
+
+ if [ "$speedTestSecs" -lt "$MAXwaitTestSecs" ] && \
+ [ ! -s "$tmpfile" ] && [ -s "$errorLogFile" ] && [ -n "$IFACE_IPv4A" ]
+ then
+ printf '' > "$errorLogFile"
+ ("$SPEEDTEST_BINARY" $verboseARG $CONFIG_STRING --ip="$IFACE_IPv4A" --format="human-readable" --unit="Mbps" -p $LICENSE_STRING | tee "$tmpfile") 2>"$errorLogFile" &
+ _WaitForSpeedTestProcess_
+ fi
if [ "$speedTestSecs" -ge "$MAXwaitTestSecs" ]
then
- Print_Output true "Speedtest for $IFACE_NAME hung (> 2 mins), killing process" "$CRIT"
+ Print_Output true "Speedtest for $IFACE_NAME [$IFACE_LOWER] hung (> 2 mins), killing process" "$CRIT"
killall -q "$PROC_NAME"
- if [ -s "$spdTestLogFile" ] ; then echo ; cat "$spdTestLogFile" ; echo ; fi
+ if [ -s "$errorLogFile" ]
+ then cat "$errorLogFile" ; echo
+ fi
continue
fi
fi
@@ -3488,8 +3660,10 @@ Run_Speedtest()
if [ ! -s "$tmpfile" ] || [ -z "$(cat "$tmpfile")" ] || [ "$(grep -c 'FAILED' "$tmpfile")" -gt 0 ]
then
- Print_Output true "ERROR running speedtest for $IFACE_NAME [No Results]" "$CRIT"
- if [ -s "$spdTestLogFile" ] ; then echo ; cat "$spdTestLogFile" ; echo ; fi
+ Print_Output true "ERROR running speedtest for $IFACE_NAME [$IFACE_LOWER] [No Results]" "$CRIT"
+ if [ -s "$errorLogFile" ]
+ then cat "$errorLogFile" ; echo
+ fi
continue
fi
@@ -3506,7 +3680,7 @@ Run_Speedtest()
serverName="$(echo "$serverLine" | sed 's/^Server: *//' | sed 's/ *(id[: =]\+ [0-9]\+)$//')"
serverIDno="$(echo "$serverLine" | grep -Eo '[(]id(:| =)[[:blank:]]+[0-9]+[)]' | awk -F' ' '{print $NF}' | tr -d ')')"
- ## if-then-else block added to with ookla output when buffer bloat has been added to the human readable output ##
+ ## if-then-else block added to with Ookla output when buffer bloat has been added to the human readable output ##
BUFFBLOAT="$(grep "Idle Latency:" "$tmpfile")"
if [ -n "$BUFFBLOAT" ]
then
@@ -3543,8 +3717,10 @@ Run_Speedtest()
[ -z "$datadownload" ] || [ -z "$dataupload" ]
then
cp -fp "$tmpfile" "$spdTestDBGFile"
- Print_Output true "ERROR running speedtest for $IFACE_NAME [Empty or Bad Values]" "$CRIT"
- if [ -s "$spdTestLogFile" ] ; then echo ; cat "$spdTestLogFile" ; echo ; fi
+ Print_Output true "ERROR running speedtest for $IFACE_NAME [$IFACE_LOWER] [Empty or Bad Values]" "$CRIT"
+ if [ -s "$errorLogFile" ]
+ then cat "$errorLogFile" ; echo
+ fi
continue
fi
@@ -3703,18 +3879,11 @@ Run_Speedtest()
rm -f "$tmpfile" /tmp/spdstatstitle.txt
Clear_Lock
- else
+ else
echo 'var spdteststatus = "Error";' > /tmp/detect_spdtest.js
- Print_Output true "No interfaces enabled, exiting" "$CRIT"
+ Print_Output true "No interfaces enabled. Exiting" "$CRIT"
Clear_Lock
return 1
- fi
- Clear_Lock
- else
- echo 'var spdteststatus = "NoSwap";' > /tmp/detect_spdtest.js
- Print_Output true "Swap file not active, exiting" "$CRIT"
- Clear_Lock
- return 1
fi
}
@@ -3812,16 +3981,16 @@ Process_Upgrade()
{
local foundError foundLocked resultStr doUpdateDB=false
- if [ ! -f "$OOKLA_DIR/speedtest" ]
+ if [ ! -x "$EXTERNL_OOKLA_BINARY" ]
then
- rm -f "$OOKLA_DIR"/*
- Download_File "$SCRIPT_REPO/$ARCH.tar.gz" "$OOKLA_DIR/$ARCH.tar.gz"
- tar -xzf "$OOKLA_DIR/$ARCH.tar.gz" -C "$OOKLA_DIR"
- rm -f "$OOKLA_DIR/$ARCH.tar.gz"
- chmod 0755 "$OOKLA_DIR/speedtest"
- chown "${theUserName}:root" "$OOKLA_DIR"/*
- spdTestVer="$(_GetSpeedtestBinaryVersion_)"
- Print_Output true "Speedtest CLI $spdTestVer version was downloaded." "$PASS"
+ rm -f "${OOKLA_DIR}"/*
+ Download_File "${SCRIPT_REPO}/$ARCH.tar.gz" "${OOKLA_DIR}/$ARCH.tar.gz"
+ tar -xzf "${OOKLA_DIR}/$ARCH.tar.gz" -C "$OOKLA_DIR"
+ rm -f "${OOKLA_DIR}/$ARCH.tar.gz"
+ chmod 0755 "$EXTERNL_OOKLA_BINARY"
+ chown "${theUserName}:root" "${OOKLA_DIR}"/*
+ spdTestVer="$(_GetExternalSpeedTestBinVersion_)"
+ Print_Output true "Ookla Speedtest CLI $spdTestVer version was downloaded." "$PASS"
fi
rm -f "$SCRIPT_STORAGE_DIR/spdjs.js"
rm -f "$SCRIPT_STORAGE_DIR/.tableupgraded"*
@@ -3977,7 +4146,6 @@ Process_Upgrade()
##----------------------------------------##
## Modified by Martinski W. [2025-Jun-20] ##
##----------------------------------------##
-#$1 IFACE Name
Generate_LastXResults()
{
local foundError foundLocked resultStr sqlProcSuccess
@@ -4447,11 +4615,11 @@ _HandleInvalidMenuOption_()
}
##----------------------------------------##
-## Modified by Martinski W. [2026-Jan-05] ##
+## Modified by Martinski W. [2026-Jul-12] ##
##----------------------------------------##
_Menu_SpeedTestOptions_()
{
- local menuOption exitMenu=false
+ local menuOption exitMenu=false speedTestBinaryType="[N/A]"
local OPTION_FOR_QOS TEST_SCHED_LINE TEST_SCHED_DAYS
local TEST_SCHED_MENU CRON_SCHED_DAYS CRON_SCHED_HOUR CRON_SCHED_MINS
@@ -4460,6 +4628,12 @@ _Menu_SpeedTestOptions_()
else OPTION_FOR_QOS="included in"
fi
+ if [ "$(SpeedtestBinary check)" = "builtin" ]
+ then speedTestBinaryType="F/W ${SETTING}built-in${CLRct} Ookla speedtest binary"
+ elif [ "$(SpeedtestBinary check)" = "external" ]
+ then speedTestBinaryType="${SETTING}external${CLRct} Ookla binary installed by $SCRIPT_NAME"
+ fi
+
TEST_SCHED_LINE="$(CronTestSchedule check)"
CRON_SCHED_DAYS="$(echo "$TEST_SCHED_LINE" | cut -f1 -d'|')"
CRON_SCHED_HOUR="$(echo "$TEST_SCHED_LINE" | cut -f2 -d'|')"
@@ -4477,7 +4651,7 @@ _Menu_SpeedTestOptions_()
printf " ${GRNct}2${CLRct}. Set schedule for automatic speed tests\n"
printf " Currently: ${SETTING}%s - %s${CLRct}\n\n" "$TEST_SCHED_MENU" "$TEST_SCHED_DAYS"
printf " ${GRNct}3${CLRct}. Toggle between built-in Ookla speedtest and speedtest-cli\n"
- printf " Currently: ${SETTING}%s${CLRct} binary will be used for speed tests${CLRct}\n\n" "$(SpeedtestBinary check)"
+ printf " [The ${speedTestBinaryType} will be used${CLRct}]\n\n"
printf " ${GRNct}q${CLRct}. Toggle exclusion of %s speed tests from QoS\n" "$SCRIPT_NAME"
printf " Currently: %s speed tests are ${SETTING}%s${CLRct} QoS\n\n" "$SCRIPT_NAME" "$OPTION_FOR_QOS"
printf " ${GRNct}c${CLRct}. Customise list of interfaces for automatic speed tests\n"
@@ -4801,9 +4975,12 @@ MainMenu()
MainMenu
}
+##----------------------------------------##
+## Modified by Martinski W. [2026-Jul-08] ##
+##----------------------------------------##
Check_Requirements()
{
- CHECKSFAILED="false"
+ local CHECKSFAILED=false
if [ "$(nvram get jffs2_scripts)" -ne 1 ]
then
@@ -4812,37 +4989,34 @@ Check_Requirements()
Print_Output true "Custom JFFS Scripts enabled" "$WARN"
fi
- if ! Check_Swap
+ if ! _HasRouterMoreThan256MBtotalRAM_ && ! Check_Swap
then
- Print_Output false "No Swap file detected!" "$ERR"
- CHECKSFAILED="true"
+ Print_Output false "Total RAM is less than 512MB and SWAP file NOT detected!" "$ERR"
+ CHECKSFAILED=true
fi
if [ ! -f /opt/bin/opkg ]
then
Print_Output false "Entware NOT detected!" "$CRIT"
- CHECKSFAILED="true"
+ CHECKSFAILED=true
fi
if ! Firmware_Version_Check
then
Print_Output false "Unsupported firmware version detected" "$CRIT"
Print_Output false "$SCRIPT_NAME requires Merlin 384.15/384.13_4 or Fork 43E5 (or later)" "$ERR"
- CHECKSFAILED="true"
+ CHECKSFAILED=true
fi
- if [ "$CHECKSFAILED" = "false" ]
- then
- Print_Output false "Installing required packages from Entware" "$PASS"
- opkg update
- opkg install sqlite3-cli
- opkg install jq
- opkg install p7zip
- opkg install findutils
- return 0
- else
- return 1
- fi
+ "$CHECKSFAILED" && return 1
+
+ Print_Output false "Installing required packages from Entware" "$PASS"
+ opkg update
+ opkg install sqlite3-cli
+ opkg install jq
+ opkg install p7zip
+ opkg install findutils
+ return 0
}
##----------------------------------------##
@@ -4885,24 +5059,24 @@ Menu_Install()
Conf_Exists
if [ "$(SpeedtestBinary check)" = "builtin" ]
then
- echo "/usr/sbin/ookla" > /tmp/spdmerlin-binary
+ echo "$BUILTIN_OOKLA_BINARY" > /tmp/spdmerlin-binary
elif [ "$(SpeedtestBinary check)" = "external" ]
then
- echo "$OOKLA_DIR/speedtest" > /tmp/spdmerlin-binary
+ echo "$EXTERNL_OOKLA_BINARY" > /tmp/spdmerlin-binary
fi
Set_Version_Custom_Settings local "$SCRIPT_VERSION"
Set_Version_Custom_Settings server "$SCRIPT_VERSION"
ScriptStorageLocation load
Create_Symlinks
- rm -f "$OOKLA_DIR"/*
- Download_File "$SCRIPT_REPO/$ARCH.tar.gz" "$OOKLA_DIR/$ARCH.tar.gz"
- tar -xzf "$OOKLA_DIR/$ARCH.tar.gz" -C "$OOKLA_DIR"
- rm -f "$OOKLA_DIR/$ARCH.tar.gz"
- chmod 0755 "$OOKLA_DIR/speedtest"
- chown "${theUserName}:root" "$OOKLA_DIR"/*
- spdTestVer="$(_GetSpeedtestBinaryVersion_)"
- Print_Output true "Speedtest CLI $spdTestVer version was downloaded." "$PASS"
+ rm -f "${OOKLA_DIR}"/*
+ Download_File "${SCRIPT_REPO}/$ARCH.tar.gz" "${OOKLA_DIR}/$ARCH.tar.gz"
+ tar -xzf "${OOKLA_DIR}/$ARCH.tar.gz" -C "$OOKLA_DIR"
+ rm -f "${OOKLA_DIR}/$ARCH.tar.gz"
+ chmod 0755 "$EXTERNL_OOKLA_BINARY"
+ chown "${theUserName}:root" "${OOKLA_DIR}"/*
+ spdTestVer="$(_GetExternalSpeedTestBinVersion_)"
+ Print_Output true "Ookla Speedtest CLI $spdTestVer version was downloaded." "$PASS"
Update_File README.md
Update_File spdstats_www.asp
@@ -4980,10 +5154,10 @@ Menu_Startup()
Conf_Exists
if [ "$(SpeedtestBinary check)" = "builtin" ]
then
- echo "/usr/sbin/ookla" > /tmp/spdmerlin-binary
+ echo "$BUILTIN_OOKLA_BINARY" > /tmp/spdmerlin-binary
elif [ "$(SpeedtestBinary check)" = "external" ]
then
- echo "$OOKLA_DIR/speedtest" > /tmp/spdmerlin-binary
+ echo "$EXTERNL_OOKLA_BINARY" > /tmp/spdmerlin-binary
fi
ScriptStorageLocation load true
Auto_Startup create 2>/dev/null
@@ -5027,25 +5201,28 @@ _Reset_Interface_States_()
##----------------------------------------##
Menu_RunSpeedtest()
{
- exitmenu=""
- validselection=""
- useiface=""
- usepreferred=""
- ScriptHeader
+ local exitmenu="" validSelection=false ifaceCountMAX=0
+ local useiface="" usepreferred="" iface_choice ifaceID
+
while true
do
- printf "Choose an interface to speedtest:\n\n"
- printf "1. All\n"
- COUNTER="2"
- while IFS='' read -r line || [ -n "$line" ]
+ ScriptHeader
+ printf " Choose an interface to run a speed test:\n\n"
+ printf " ${GRNct}1${CLRct}) All\n"
+ COUNTER=2
+ while IFS='' read -r theLINE || [ -n "$theLINE" ]
do
- if [ "$(echo "$line" | grep -c "interface not up")" -eq 0 ]
+ if [ "$(echo "$theLINE" | grep -c "interface not up")" -eq 0 ]
then
- printf "%s. %s\n" "$COUNTER" "$(echo "$line" | cut -f1 -d"#" | sed 's/ *$//')"
- COUNTER="$((COUNTER+1))"
+ ifaceID="$(echo "$theLINE" | cut -d'#' -f1 | sed 's/ *$//')"
+ printf " ${GRNct}%2d${CLRct}) %s\n" "$COUNTER" "$ifaceID"
+ COUNTER="$((COUNTER + 1))"
fi
done < "$SCRIPT_INTERFACES_USER"
- printf "\nChoose an option (e=Exit): "
+ printf "\n ${GRNct}e${CLRct}) Return to Main Menu\n"
+ ifaceCountMAX="$((COUNTER - 1))"
+
+ printf "\n Choose an option: "
read -r iface_choice
if [ "$iface_choice" = "e" ]
@@ -5054,34 +5231,37 @@ Menu_RunSpeedtest()
break
elif ! Validate_Number "$iface_choice"
then
- printf "\n${ERR}Please enter a valid number [1-%s].${CLEARFORMAT}\n" "$((COUNTER-1))"
- validselection="false"
+ validSelection=false
+ printf "\n${ERR}Please enter a valid number [1-%s].${CLRct}\n" "$ifaceCountMAX"
+ PressEnter ; continue
else
- if [ "$iface_choice" -lt 1 ] || [ "$iface_choice" -gt "$((COUNTER-1))" ]
+ if [ "$iface_choice" -lt 1 ] || [ "$iface_choice" -gt "$ifaceCountMAX" ]
then
- printf "\n${ERR}Please enter a number between 1 and %s.${CLEARFORMAT}\n" "$((COUNTER-1))"
- validselection="false"
+ validSelection=false
+ printf "\n${ERR}Please enter a number between 1 and %s.${CLRct}\n" "$ifaceCountMAX"
+ PressEnter ; continue
else
- if [ "$iface_choice" -gt "1" ]
+ if [ "$iface_choice" -gt 1 ]
then
useiface="$(grep -v "interface not up" "$SCRIPT_INTERFACES_USER" | sed -n $((iface_choice-1))p | cut -f1 -d"#" | sed 's/ *$//')"
else
useiface="All"
fi
- validselection="true"
+ validSelection=true
fi
fi
- printf "\n"
+ echo
- if [ "$exitmenu" != "exit" ] && [ "$validselection" != "false" ]
+ if [ "$exitmenu" != "exit" ] && "$validSelection"
then
while true
do
- printf "What mode would you like to use?\n\n"
- printf "1. Auto-select\n"
- printf "2. Preferred server\n"
- printf "3. Choose a server\n"
- printf "\nChoose an option (e=Exit): "
+ printf "\n What mode would you like to use?\n\n"
+ printf " ${GRNct}1${CLRct}. Auto-select\n"
+ printf " ${GRNct}2${CLRct}. Preferred server\n"
+ printf " ${GRNct}3${CLRct}. Choose a server\n\n"
+ printf " ${GRNct}e${CLRct}. Return to Main Menu\n"
+ printf "\n Choose an option: "
read -r usepref_choice
if [ "$usepref_choice" = "e" ]
@@ -5090,42 +5270,47 @@ Menu_RunSpeedtest()
break
elif ! Validate_Number "$usepref_choice"
then
- printf "\n${ERR}Please enter a valid number [1-3].${CLEARFORMAT}\n"
- validselection="false" ; echo
+ validSelection=false
+ printf "\n${ERR}Please enter a valid number [1-3].${CLRct}\n"
+ PressEnter ; echo
else
if [ "$usepref_choice" -lt 1 ] || [ "$usepref_choice" -gt 3 ]
then
- printf "\n${ERR}Please enter a number between 1 and 3.${CLEARFORMAT}\n"
- validselection="false" ; echo
+ validSelection=false
+ printf "\n${ERR}Please enter a number between 1 and 3.${CLRct}\n"
+ PressEnter ; echo
else
case "$usepref_choice" in
1) usepreferred="auto" ;;
2) usepreferred="user" ;;
3) usepreferred="onetime" ;;
esac
- validselection="true" ; echo
+ validSelection=true ; echo
break
fi
fi
done
fi
- if [ "$exitmenu" != "exit" ] && [ "$validselection" != "false" ]
+
+ if [ "$exitmenu" = "exit" ]
+ then break ; fi
+
+ if "$validSelection"
then
- if Check_Lock menu; then
+ if Check_Lock menu
+ then
Run_Speedtest "$usepreferred" "$useiface"
Clear_Lock
fi
- elif [ "$exitmenu" = "exit" ]; then
- break
fi
- printf "\n"
- PressEnter
- ScriptHeader
+ echo ; PressEnter
done
if [ "$exitmenu" != "exit" ]
- then return 0
- else echo ; return 1
+ then
+ return 0
+ else
+ echo ; return 1
fi
}
@@ -6568,21 +6753,20 @@ Menu_Uninstall()
ps | grep -v grep | grep -v $$ | grep -i "$SCRIPT_NAME_LOWER" | grep generate | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1
fi
+ PROC_NAME=""
SPEEDTEST_BINARY=""
if [ "$(SpeedtestBinary check)" = "builtin" ]
then
- SPEEDTEST_BINARY="/usr/sbin/ookla"
+ PROC_NAME="$BUILTIN_OOKLA_PROC"
+ SPEEDTEST_BINARY="$BUILTIN_OOKLA_BINARY"
elif [ "$(SpeedtestBinary check)" = "external" ]
then
- SPEEDTEST_BINARY="$OOKLA_DIR/speedtest"
+ PROC_NAME="$EXTERNL_OOKLA_PROC"
+ SPEEDTEST_BINARY="$EXTERNL_OOKLA_BINARY"
fi
- PROC_NAME="speedtest"
- if [ "$SPEEDTEST_BINARY" = "/usr/sbin/ookla" ]
- then
- PROC_NAME="ookla"
- fi
- if [ -n "$(pidof "$PROC_NAME")" ]; then
- killall -q "$PROC_NAME"
+
+ if [ -n "$(pidof "$PROC_NAME")" ]
+ then killall -q "$PROC_NAME"
fi
Print_Output true "Removing $SCRIPT_NAME..." "$PASS"
Auto_Startup delete 2>/dev/null
@@ -6815,10 +6999,10 @@ then
Conf_Exists
if [ "$(SpeedtestBinary check)" = "builtin" ]
then
- echo "/usr/sbin/ookla" > /tmp/spdmerlin-binary
+ echo "$BUILTIN_OOKLA_BINARY" > /tmp/spdmerlin-binary
elif [ "$(SpeedtestBinary check)" = "external" ]
then
- echo "$OOKLA_DIR/speedtest" > /tmp/spdmerlin-binary
+ echo "$EXTERNL_OOKLA_BINARY" > /tmp/spdmerlin-binary
fi
ScriptStorageLocation load
Create_Symlinks
@@ -6999,10 +7183,10 @@ case "$1" in
Conf_Exists
if [ "$(SpeedtestBinary check)" = "builtin" ]
then
- echo "/usr/sbin/ookla" > /tmp/spdmerlin-binary
+ echo "$BUILTIN_OOKLA_BINARY" > /tmp/spdmerlin-binary
elif [ "$(SpeedtestBinary check)" = "external" ]
then
- echo "$OOKLA_DIR/speedtest" > /tmp/spdmerlin-binary
+ echo "$EXTERNL_OOKLA_BINARY" > /tmp/spdmerlin-binary
fi
ScriptStorageLocation load true
Create_Symlinks
diff --git a/spdstats_www.asp b/spdstats_www.asp
index 0da58e4..a6467bd 100644
--- a/spdstats_www.asp
+++ b/spdstats_www.asp
@@ -30,9 +30,9 @@ p{font-weight:bolder;}thead.collapsible-jquery{color:white;padding:0;width:100%;
diff --git a/spdstats_www.js b/spdstats_www.js
index 219690e..59bbb0e 100644
--- a/spdstats_www.js
+++ b/spdstats_www.js
@@ -1,5 +1,5 @@
/**----------------------------**/
-/** Last Modified: 2025-Oct-14 **/
+/** Last Modified: 2026-Jun-24 **/
/**----------------------------**/
var daysofweek = ['Mon','Tues','Wed','Thurs','Fri','Sat','Sun'];
@@ -814,6 +814,35 @@ function getTimeFormat(value,format){
return timeformat;
}
+/**----------------------------------------------------------------**
+ ** Compatibility layer for the latest AsusWRT6 routers, such as
+ ** the GT-BE19000AI, where the previous global 'cookie' helper
+ ** functions defined in the 'state.js' file are now removed in
+ ** favour of using the "window.localStorage" property.
+ **----------------------------------------------------------------**/
+if (typeof window.cookie === "undefined" ||
+ typeof window.cookie.get !== "function" ||
+ typeof window.cookie.set !== "function")
+{
+ window.cookie = {
+ get: function (key) {
+ return window.localStorage.getItem(key);
+ },
+
+ /** In the previous 'cookie' function a 3rd argument was given for 'days' **/
+ /** Here, we ignore the value because there is no expiration date anymore **/
+ set: function (key, value, days) {
+ window.localStorage.setItem(key, String(value));
+ },
+
+ unset: function (key) {
+ window.localStorage.removeItem(key);
+ }
+ };
+
+ console.log("Installed localStorage compatibility for cookie API.");
+}
+
function GetCookie(cookiename,returntype){
if(cookie.get('spd_'+cookiename) != null){
return cookie.get('spd_'+cookiename);