Update On Mon May 26 20:35:53 CEST 2025

This commit is contained in:
github-action[bot]
2025-05-26 20:35:54 +02:00
parent 8b9af21a0e
commit b4f16385aa
622 changed files with 78515 additions and 7999 deletions

View File

@@ -67,11 +67,15 @@ jobs:
- name: Install OpenWrt SNAPSHPT SDK
run: |
cd ..
curl -SLk --connect-timeout 30 --retry 2 "https://downloads.openwrt.org/snapshots/targets/x86/64/openwrt-sdk-x86-64_gcc-13.3.0_musl.Linux-x86_64.tar.zst" -o "./tmp/SNAPSDK.tar.zst"
cd \tmp
mkdir -p tmp
BASE_URL="https://downloads.openwrt.org/snapshots/targets/x86/64/"
SDK_NAME=$(curl -s $BASE_URL | grep -oE 'openwrt-sdk-x86-64[^"]+\.tar\.zst' | head -n 1)
curl -SLk --connect-timeout 30 --retry 2 "$BASE_URL/$SDK_NAME" -o "./tmp/SNAPSDK.tar.zst"
cd tmp
zstd -d SNAPSDK.tar.zst
tar xf SNAPSDK.tar
mv "openwrt-sdk-x86-64_gcc-13.3.0_musl.Linux-x86_64" "SNAPSDK"
SDK_DIR=$(tar tf SNAPSDK.tar | head -n 1 | cut -d/ -f1)
mv "$SDK_DIR" "SNAPSDK"
- name: Copy OpenClash Source Codes
run: |

View File

@@ -0,0 +1,268 @@
name: Update Third-Party Resources
on:
schedule:
- cron: '30 0 */3 * *'
workflow_dispatch:
jobs:
update-resources:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: dev
- name: Set up environment
run: |
sudo apt-get update
sudo apt-get -y install curl wget unzip git jq coreutils
- name: Set file paths
run: |
echo "CHNR_PATH=luci-app-openclash/root/etc/openclash/china_ip_route.ipset" >> $GITHUB_ENV
echo "CHNR6_PATH=luci-app-openclash/root/etc/openclash/china_ip6_route.ipset" >> $GITHUB_ENV
echo "YACD_PATH=luci-app-openclash/root/usr/share/openclash/ui/yacd" >> $GITHUB_ENV
echo "ZASHBOARD_PATH=luci-app-openclash/root/usr/share/openclash/ui/zashboard" >> $GITHUB_ENV
echo "METACUBEXD_PATH=luci-app-openclash/root/usr/share/openclash/ui/metacubexd" >> $GITHUB_ENV
echo "GEOIP_PATH=luci-app-openclash/root/etc/openclash/GeoIP.dat" >> $GITHUB_ENV
echo "GEOSITE_PATH=luci-app-openclash/root/etc/openclash/GeoSite.dat" >> $GITHUB_ENV
echo "COUNTRY_MMDB_PATH=luci-app-openclash/root/etc/openclash/Country.mmdb" >> $GITHUB_ENV
- name: Update China IP Route Files
run: |
mkdir -p tmp
echo "Downloading China IP Route files..."
curl -sSL https://ispip.clang.cn/all_cn.txt -o tmp/china_ip_route.ipset
mkdir -p $(dirname $CHNR_PATH)
if [ -f "$CHNR_PATH" ]; then
if ! cmp -s tmp/china_ip_route.ipset "$CHNR_PATH"; then
echo "China IP Route list has been updated, replacing old version."
cp tmp/china_ip_route.ipset "$CHNR_PATH"
echo "CHNR_UPDATED=1" >> $GITHUB_ENV
else
echo "China IP Route list is up to date."
fi
else
echo "China IP Route list file doesn't exist, creating it."
cp tmp/china_ip_route.ipset "$CHNR_PATH"
echo "CHNR_UPDATED=1" >> $GITHUB_ENV
fi
curl -sSL https://ispip.clang.cn/all_cn_ipv6.txt -o tmp/china_ip6_route.ipset
mkdir -p $(dirname $CHNR6_PATH)
if [ -f "$CHNR6_PATH" ]; then
if ! cmp -s tmp/china_ip6_route.ipset "$CHNR6_PATH"; then
echo "China IP6 Route list has been updated, replacing old version."
cp tmp/china_ip6_route.ipset "$CHNR6_PATH"
echo "CHNR6_UPDATED=1" >> $GITHUB_ENV
else
echo "China IP6 Route list is up to date."
fi
else
echo "China IP6 Route list file doesn't exist, creating it."
cp tmp/china_ip6_route.ipset "$CHNR6_PATH"
echo "CHNR6_UPDATED=1" >> $GITHUB_ENV
fi
- name: Update MetaCubeXD UI
run: |
echo "Downloading latest MetaCubeXD UI from gh-pages branch..."
mkdir -p tmp/metacubexd
git clone --depth=1 -b gh-pages https://github.com/MetaCubeX/metacubexd.git tmp/metacubexd_clone
mkdir -p "$METACUBEXD_PATH"
if [ -d "$METACUBEXD_PATH" ]; then
if ! diff -r tmp/metacubexd_clone "$METACUBEXD_PATH" > /dev/null 2>&1; then
echo "MetaCubeXD UI has been updated, replacing old version."
rm -rf "$METACUBEXD_PATH"/*
cp -rf tmp/metacubexd_clone/* "$METACUBEXD_PATH"
echo "METACUBEXD_UPDATED=1" >> $GITHUB_ENV
else
echo "MetaCubeXD UI is up to date."
fi
else
echo "MetaCubeXD UI directory doesn't exist, creating it."
mkdir -p "$METACUBEXD_PATH"
cp -rf tmp/metacubexd_clone/* "$METACUBEXD_PATH"
echo "METACUBEXD_UPDATED=1" >> $GITHUB_ENV
fi
echo "MetaCubeXD UI update check completed."
- name: Update Yacd UI
run: |
echo "Downloading latest Yacd UI from MetaCubeX/metacubexd gh-pages branch..."
mkdir -p tmp/yacd
git clone --depth=1 -b gh-pages https://github.com/MetaCubeX/metacubexd.git tmp/yacd_clone
mkdir -p "$YACD_PATH"
if [ -d "$YACD_PATH" ]; then
if ! diff -r tmp/yacd_clone "$YACD_PATH" > /dev/null 2>&1; then
echo "Yacd UI has been updated, replacing old version."
rm -rf "$YACD_PATH"/*
cp -rf tmp/yacd_clone/* "$YACD_PATH"
echo "YACD_UPDATED=1" >> $GITHUB_ENV
else
echo "Yacd UI is up to date."
fi
else
echo "Yacd UI directory doesn't exist, creating it."
mkdir -p "$YACD_PATH"
cp -rf tmp/yacd_clone/* "$YACD_PATH"
echo "YACD_UPDATED=1" >> $GITHUB_ENV
fi
echo "Yacd UI update check completed."
- name: Update ZashBoard UI
run: |
echo "Downloading latest Clash Dashboard UI from gh-pages branch..."
mkdir -p tmp/zashboard
git clone --depth=1 -b gh-pages https://github.com/zzzgydi/clash-dashboard.git tmp/zashboard_clone
mkdir -p "$ZASHBOARD_PATH"
if [ -d "$ZASHBOARD_PATH" ]; then
if ! diff -r tmp/zashboard_clone "$ZASHBOARD_PATH" > /dev/null 2>&1; then
echo "ZashBoard UI has been updated, replacing old version."
rm -rf "$ZASHBOARD_PATH"/*
cp -rf tmp/zashboard_clone/* "$ZASHBOARD_PATH"
echo "ZASHBOARD_UPDATED=1" >> $GITHUB_ENV
else
echo "ZashBoard UI is up to date."
fi
else
echo "ZashBoard UI directory doesn't exist, creating it."
mkdir -p "$ZASHBOARD_PATH"
cp -rf tmp/zashboard_clone/* "$ZASHBOARD_PATH"
echo "ZASHBOARD_UPDATED=1" >> $GITHUB_ENV
fi
echo "ZashBoard UI update check completed."
- name: Update GeoIP and GeoSite files
run: |
RULES_RELEASE=$(curl -s https://api.github.com/repos/Loyalsoldier/v2ray-rules-dat/releases/latest | jq -r '.tag_name')
echo "Latest v2ray-rules-dat version: $RULES_RELEASE"
curl -sSL "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/download/${RULES_RELEASE}/geoip.dat" -o tmp/GeoIP.dat
mkdir -p $(dirname "$GEOIP_PATH")
if [ -f "$GEOIP_PATH" ]; then
if ! cmp -s tmp/GeoIP.dat "$GEOIP_PATH"; then
echo "GeoIP.dat has been updated, replacing old version."
cp tmp/GeoIP.dat "$GEOIP_PATH"
echo "GEOIP_UPDATED=1" >> $GITHUB_ENV
else
echo "GeoIP.dat is up to date."
fi
else
echo "GeoIP.dat file doesn't exist, creating it."
cp tmp/GeoIP.dat "$GEOIP_PATH"
echo "GEOIP_UPDATED=1" >> $GITHUB_ENV
fi
curl -sSL "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/download/${RULES_RELEASE}/geosite.dat" -o tmp/GeoSite.dat
mkdir -p $(dirname "$GEOSITE_PATH")
if [ -f "$GEOSITE_PATH" ]; then
if ! cmp -s tmp/GeoSite.dat "$GEOSITE_PATH"; then
echo "GeoSite.dat has been updated, replacing old version."
cp tmp/GeoSite.dat "$GEOSITE_PATH"
echo "GEOSITE_UPDATED=1" >> $GITHUB_ENV
else
echo "GeoSite.dat is up to date."
fi
else
echo "GeoSite.dat file doesn't exist, creating it."
cp tmp/GeoSite.dat "$GEOSITE_PATH"
echo "GEOSITE_UPDATED=1" >> $GITHUB_ENV
fi
- name: Update Country.mmdb
run: |
curl -sSL "https://github.com/alecthw/mmdb_china_ip_list/releases/latest/download/Country-lite.mmdb" -o tmp/Country.mmdb
mkdir -p $(dirname "$COUNTRY_MMDB_PATH")
if [ -f "$COUNTRY_MMDB_PATH" ]; then
if ! cmp -s tmp/Country.mmdb "$COUNTRY_MMDB_PATH"; then
echo "Country.mmdb has been updated, replacing old version."
cp tmp/Country.mmdb "$COUNTRY_MMDB_PATH"
echo "MMDB_UPDATED=1" >> $GITHUB_ENV
else
echo "Country.mmdb is up to date."
fi
else
echo "Country.mmdb file doesn't exist, creating it."
cp tmp/Country.mmdb "$COUNTRY_MMDB_PATH"
echo "MMDB_UPDATED=1" >> $GITHUB_ENV
fi
- name: Commit changes
run: |
git config user.name 'github-actions[bot]'
git config user.email 'github-actions[bot]@users.noreply.github.com'
UPDATED=0
UPDATE_MSG="Chore: update resources:"
if [ "${CHNR_UPDATED}" = "1" ]; then
UPDATE_MSG="${UPDATE_MSG} china_ip_route.ipset"
UPDATED=1
fi
if [ "${CHNR6_UPDATED}" = "1" ]; then
UPDATE_MSG="${UPDATE_MSG} china_ip6_route.ipset"
UPDATED=1
fi
if [ "${GEOIP_UPDATED}" = "1" ]; then
UPDATE_MSG="${UPDATE_MSG} GeoIP.dat"
UPDATED=1
fi
if [ "${GEOSITE_UPDATED}" = "1" ]; then
UPDATE_MSG="${UPDATE_MSG} GeoSite.dat"
UPDATED=1
fi
if [ "${MMDB_UPDATED}" = "1" ]; then
UPDATE_MSG="${UPDATE_MSG} Country.mmdb"
UPDATED=1
fi
if [ "${METACUBEXD_UPDATED}" = "1" ]; then
UPDATE_MSG="${UPDATE_MSG} MetaCubeXD"
UPDATED=1
fi
if [ "${YACD_UPDATED}" = "1" ]; then
UPDATE_MSG="${UPDATE_MSG} Yacd"
UPDATED=1
fi
if [ "${ZASHBOARD_UPDATED}" = "1" ]; then
UPDATE_MSG="${UPDATE_MSG} Zashboard"
UPDATED=1
fi
if [ $UPDATED -eq 1 ]; then
git add .
git commit -m "${UPDATE_MSG}"
git push
echo "Changes committed and pushed to repository."
else
echo "No changes to commit."
fi
rm -rf tmp

10
openclash/announcement Normal file
View File

@@ -0,0 +1,10 @@
[
{
"zh": "Smart 策略组内核现已支持 policy-priority 参数来自定义调整节点权重,请自行替换测试、使用。",
"en": "The Smart policy group core now supports the policy-priority parameter to customize node weights. Please replace it for testing and use."
},
{
"zh": "如在更新内核后出现【Parse config error: path is not subpath of home directory】的错误时请在最新版插件设置页面启用【跳过安全路径检查】选项。",
"en": "If you get [Parse config error: path is not subpath of home directory] after updating the core, please enable [Skip Safe Path Check] option in the settings page of the latest dev version of the OpenClash."
}
]

View File

@@ -1,7 +1,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-openclash
PKG_VERSION:=0.46.079
PKG_VERSION:=0.46.086
PKG_MAINTAINER:=vernesong <https://github.com/vernesong/OpenClash>
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
@@ -147,6 +147,8 @@ define Package/$(PKG_NAME)/postrm
rm -rf /tmp/dler* >/dev/null 2>&1
rm -rf /tmp/etc/openclash >/dev/null 2>&1
rm -rf /tmp/openclash_edit_file_name >/dev/null 2>&1
rm -rf /tmp/openclash_announcement >/dev/null 2>&1
rm -rf /usr/share/openclash/ui/xd >/dev/null 2>&1
sed -i '/OpenClash Append/,/OpenClash Append End/d' "/usr/lib/lua/luci/model/network.lua" >/dev/null 2>&1
sed -i '/.*kB maximum content size*/c\HTTP_MAX_CONTENT = 1024*100 -- 100 kB maximum content size' /usr/lib/lua/luci/http.lua >/dev/null 2>&1
sed -i '/.*kB maximum content size*/c\export let HTTP_MAX_CONTENT = 1024*100; // 100 kB maximum content size' /usr/share/ucode/luci/http.uc >/dev/null 2>&1

View File

@@ -26,6 +26,7 @@ function index()
entry({"admin", "services", "openclash", "lastversion"},call("action_lastversion"))
entry({"admin", "services", "openclash", "save_corever_branch"},call("action_save_corever_branch"))
entry({"admin", "services", "openclash", "update"},call("action_update"))
entry({"admin", "services", "openclash", "get_last_version"},call("action_get_last_version"))
entry({"admin", "services", "openclash", "update_info"},call("action_update_info"))
entry({"admin", "services", "openclash", "update_ma"},call("action_update_ma"))
entry({"admin", "services", "openclash", "opupdate"},call("action_opupdate"))
@@ -73,6 +74,7 @@ function index()
entry({"admin", "services", "openclash", "set_subinfo_url"}, call("set_subinfo_url"))
entry({"admin", "services", "openclash", "check_core"}, call("action_check_core"))
entry({"admin", "services", "openclash", "core_download"}, call("core_download"))
entry({"admin", "services", "openclash", "announcement"}, call("action_announcement"))
entry({"admin", "services", "openclash", "settings"},cbi("openclash/settings"),_("Plugin Settings"), 30).leaf = true
entry({"admin", "services", "openclash", "config-overwrite"},cbi("openclash/config-overwrite"),_("Overwrite Settings"), 40).leaf = true
entry({"admin", "services", "openclash", "servers"},cbi("openclash/servers"),_("Onekey Create"), 50).leaf = true
@@ -216,9 +218,9 @@ local function coremodel()
if opkg and opkg.info("libc") and opkg.info("libc")["libc"] then
return opkg.info("libc")["libc"]["Architecture"]
else
if fs.access("/bin/opkg") then
if pkg_type() == "opkg" then
return luci.sys.exec("rm -f /var/lock/opkg.lock && opkg status libc 2>/dev/null |grep 'Architecture' |awk -F ': ' '{print $2}' 2>/dev/null")
elseif fs.access("/usr/bin/apk") then
else
return luci.sys.exec("apk list libc 2>/dev/null |awk '{print $2}'")
end
end
@@ -236,13 +238,23 @@ local function coremetacv()
if not nixio.fs.access(meta_core_path) then
return "0"
else
return luci.sys.exec(string.format("%s -v 2>/dev/null |awk -F ' ' '{print $3}' |head -1", meta_core_path))
return luci.sys.exec(string.format("%s -v 2>/dev/null |awk -F ' ' '{print $3}' |head -1 |tr -d '\n'", meta_core_path))
end
end
local function corelv()
luci.sys.call("bash /usr/share/openclash/clash_version.sh")
local core_meta_lv = luci.sys.exec("sed -n 3p /tmp/clash_last_version 2>/dev/null")
local status = process_status("/usr/share/openclash/clash_version.sh")
local core_meta_lv = ""
if not status then
if fs.access("/tmp/clash_last_version") then
core_meta_lv = luci.sys.exec("sed -n 3p /tmp/clash_last_version 2>/dev/null |tr -d '\n'")
else
action_get_last_version()
core_meta_lv = "loading..."
end
else
core_meta_lv = "loading..."
end
return core_meta_lv
end
@@ -250,18 +262,28 @@ local function opcv()
if opkg and opkg.info("luci-app-openclash") and opkg.info("luci-app-openclash")["luci-app-openclash"] then
return "v" .. opkg.info("luci-app-openclash")["luci-app-openclash"]["Version"]
else
if fs.access("/bin/opkg") then
return luci.sys.exec("rm -f /var/lock/opkg.lock && opkg status luci-app-openclash 2>/dev/null |grep 'Version' |awk -F 'Version: ' '{print \"v\"$2}'")
elseif fs.access("/usr/bin/apk") then
return "v" .. luci.sys.exec("apk list luci-app-openclash 2>/dev/null|grep 'installed' | grep -oE '[0-9]+(\\.[0-9]+)*' | head -1")
if pkg_type() == "opkg" then
return luci.sys.exec("rm -f /var/lock/opkg.lock && opkg status luci-app-openclash 2>/dev/null |grep 'Version' |awk -F 'Version: ' '{print \"v\"$2}' |tr -d '\n'")
else
return "v" .. luci.sys.exec("apk list luci-app-openclash 2>/dev/null|grep 'installed' | grep -oE '[0-9]+(\\.[0-9]+)*' | head -1 |tr -d '\n'")
end
end
end
local function oplv()
local new = luci.sys.call(string.format("bash /usr/share/openclash/openclash_version.sh"))
local oplv = luci.sys.exec("sed -n 1p /tmp/openclash_last_version 2>/dev/null")
return oplv .. "," .. new
local status = process_status("/usr/share/openclash/openclash_version.sh")
local oplv = ""
if not status then
if fs.access("/tmp/openclash_last_version") then
oplv = luci.sys.exec("sed -n 1p /tmp/openclash_last_version 2>/dev/null |tr -d '\n'")
else
action_get_last_version()
oplv = "loading..."
end
else
oplv = "loading..."
end
return oplv
end
local function opup()
@@ -680,38 +702,61 @@ function sub_info_get()
if string.match(info, "expire=%d+") then
day_expire = tonumber(string.sub(string.match(info, "expire=%d+"), 8, -1)) or nil
end
expire = os.date("%Y-%m-%d", day_expire) or "null"
if day_expire and os.time() <= day_expire then
if day_expire and day_expire == 0 then
expire = luci.i18n.translate("Long-term")
elseif day_expire then
expire = os.date("%Y-%m-%d", day_expire) or "null"
else
expire = "null"
end
if day_expire and day_expire ~= 0 and os.time() <= day_expire then
day_left = math.ceil((day_expire - os.time()) / (3600*24))
if math.ceil(day_left / 365) > 50 then
day_left = ""
end
elseif day_expire and day_expire == 0 then
day_left = ""
elseif day_expire == nil then
day_left = "null"
else
day_left = 0
end
if used and total and used <= total then
percent = string.format("%.1f",((total-used)/total)*100) or nil
surplus = fs.filesize(total - used) or "null"
if used and total and used <= total and total > 0 then
percent = string.format("%.1f",((total-used)/total)*100) or "100"
surplus = fs.filesize(total - used)
elseif used and total and used > total and total > 0 then
percent = "0"
surplus = "-"..fs.filesize(total - used)
elseif used and total and used < total and total == 0.0 then
percent = "0"
surplus = fs.filesize(total - used)
elseif used and total and used == total and total == 0.0 then
percent = "0"
surplus = "0.0 KB"
elseif used and total and used > total and total == 0.0 then
percent = "100"
surplus = fs.filesize(total - used)
elseif used == nil and total and total > 0.0 then
percent = 100
surplus = total
elseif total and total == 0.0 then
surplus = fs.filesize(total)
elseif used == nil and total and total == 0.0 then
percent = 100
surplus = ""
else
percent = 0
surplus = "null"
end
if total and total > 0.0 then
total = fs.filesize(total) or "null"
if total and total > 0 then
total = fs.filesize(total)
elseif total and total == 0.0 then
total = ""
else
total = "null"
end
used = fs.filesize(used) or "null"
used = fs.filesize(used)
sub_info = "Successful"
else
sub_info = "No Sub Info Found"
@@ -1093,6 +1138,15 @@ function action_start()
})
end
function action_get_last_version()
luci.sys.call("bash /usr/share/openclash/clash_version.sh &")
luci.sys.call("bash /usr/share/openclash/openclash_version.sh &")
luci.http.prepare_content("application/json")
luci.http.write_json({
status = "success"
})
end
function action_update()
luci.http.prepare_content("application/json")
luci.http.write_json({
@@ -1177,81 +1231,87 @@ function action_download_rule()
end
function action_refresh_log()
luci.http.prepare_content("application/json")
local logfile="/tmp/openclash.log"
local file = io.open(logfile, "r+")
local info, len, line, lens, cache, ex_match, line_trans
local data = ""
local limit = 1000
local log_tb = {}
local log_len = tonumber(luci.http.formvalue("log_len")) or 0
if file == nil then
return nil
end
file:seek("set")
info = file:read("*all")
info = info:reverse()
file:close()
cache, len = string.gsub(info, '[^\n]+', "")
if len == log_len then return nil end
if log_len == 0 then
if len > limit then lens = limit else lens = len end
else
lens = len - log_len
end
string.gsub(info, '[^\n]+', function(w) table.insert(log_tb, w) end, lens)
for i=1, lens do
line = log_tb[i]:reverse()
line_trans = line
ex_match = false
core_match = false
time_format = false
while true do
ex_keys = {"UDP%-Receive%-Buffer%-Size", "^Sec%-Fetch%-Mode", "^User%-Agent", "^Access%-Control", "^Accept", "^Origin", "^Referer", "^Connection", "^Pragma", "^Cache-"}
for key=1, #ex_keys do
if string.find (line, ex_keys[key]) then
ex_match = true
break
end
luci.http.prepare_content("application/json")
local logfile = "/tmp/openclash.log"
local log_len = tonumber(luci.http.formvalue("log_len")) or 0
if not fs.access(logfile) then
luci.http.write_json({
len = 0,
update = false,
core_log = "",
oc_log = ""
})
return
end
local total_lines = tonumber(luci.sys.exec("wc -l < " .. logfile)) or 0
if total_lines == log_len and log_len > 0 then
luci.http.write_json({
len = total_lines,
update = false,
core_log = "",
oc_log = ""
})
return
end
local exclude_pattern = "UDP%-Receive%-Buffer%-Size|^Sec%-Fetch%-Mode|^User%-Agent|^Access%-Control|^Accept|^Origin|^Referer|^Connection|^Pragma|^Cache%-"
local core_pattern = " DBG | INF |level=| WRN | ERR | FTL "
local limit = 1000
local start_line = (log_len > 0 and total_lines > log_len) and (log_len + 1) or 1
local core_cmd = string.format(
"tail -n +%d '%s' | grep -v -E '%s' | grep -E '%s' | tail -n %d",
start_line, logfile, exclude_pattern, core_pattern, limit
)
local core_raw = luci.sys.exec(core_cmd)
local oc_cmd = string.format(
"tail -n +%d '%s' | grep -v -E '%s' | grep -v -E '%s' | tail -n %d",
start_line, logfile, exclude_pattern, core_pattern, limit
)
local oc_raw = luci.sys.exec(oc_cmd)
local core_log = ""
if core_raw and core_raw ~= "" then
local core_logs = {}
for line in core_raw:gmatch("[^\n]+") do
local line_trans = line
if string.match(string.sub(line, 0, 8), "%d%d:%d%d:%d%d") then
line_trans = '"'..os.date("%Y-%m-%d", os.time()).. " "..os.date("%H:%M:%S", tonumber(string.sub(line, 0, 8)))..'"'..string.sub(line, 9, -1)
end
if ex_match then break end
core_keys = {" DBG ", " INF ", "level=", " WRN ", " ERR ", " FTL "}
for key=1, #core_keys do
if string.find(string.sub(line, 0, 13), core_keys[key]) or (string.find(line, core_keys[key]) and core_keys[key] == "level=") then
core_match = true
if core_keys[key] ~= "level=" then
time_format = true
end
break
end
end
if time_format then
if string.match(string.sub(line, 0, 8), "%d%d:%d%d:%d%d") then
line_trans = '"'..os.date("%Y-%m-%d %H:%M:%S", tonumber(string.sub(line, 0, 8)))..'"'..string.sub(line, 9, -1)
end
end
if not core_match then
if not string.find (line, "") or not string.find (line, "") then
line_trans = trans_line_nolabel(line)
else
line_trans = trans_line(line)
end
end
if data == "" then
data = line_trans
elseif log_len == 0 and i == limit then
data = data .."\n" .. line_trans .. "\n..."
else
data = data .."\n" .. line_trans
end
break
end
end
luci.http.write_json({
len = len,
log = data;
})
table.insert(core_logs, line_trans)
end
if #core_logs > 0 then
core_log = table.concat(core_logs, "\n")
end
end
local oc_log = ""
if oc_raw and oc_raw ~= "" then
local oc_logs = {}
for line in oc_raw:gmatch("[^\n]+") do
local line_trans
if not string.find(line, "") or not string.find(line, "") then
line_trans = trans_line_nolabel(line)
else
line_trans = trans_line(line)
end
table.insert(oc_logs, line_trans)
end
if #oc_logs > 0 then
oc_log = table.concat(oc_logs, "\n")
end
end
luci.http.write_json({
len = total_lines,
update = true,
core_log = core_log,
oc_log = oc_log
})
end
function action_del_log()
@@ -1614,61 +1674,98 @@ function all_proxies_stream_test()
end
function trans_line_nolabel(data)
local line_trans = ""
if string.match(string.sub(data, 0, 19), "%d%d%d%d%-%d%d%-%d%d %d%d:%d%d:%d%d") then
line_trans = string.sub(data, 0, 20)..luci.i18n.translate(string.sub(data, 21, -1))
else
line_trans = luci.i18n.translate(string.sub(data, 0, -1))
end
return line_trans
if data == nil or data == "" then
return ""
end
local line_trans = ""
if string.len(data) >= 19 and string.match(string.sub(data, 0, 19), "%d%d%d%d%-%d%d%-%d%d %d%d:%d%d:%d%d") then
line_trans = string.sub(data, 0, 20)..luci.i18n.translate(string.sub(data, 21, -1))
else
line_trans = luci.i18n.translate(data)
end
return line_trans
end
function trans_line(data)
local no_trans = {}
local line_trans = ""
local a = string.find (data, "")
local b = string.find (data, "") + 2
local c = 21
local d = 0
local v
local x
while true do
table.insert(no_trans, a)
table.insert(no_trans, b)
if string.find (data, "", b+1) and string.find (data, "", b+1) then
a = string.find (data, "", b+1)
b = string.find (data, "", b+1) + 2
else
break
end
end
for k = 1, #no_trans, 2 do
x = no_trans[k]
v = no_trans[k+1]
if x <= 21 or not string.match(string.sub(data, 0, 19), "%d%d%d%d%-%d%d%-%d%d %d%d:%d%d:%d%d") then
line_trans = line_trans .. luci.i18n.translate(string.sub(data, d, x - 1)) .. string.sub(data, x, v)
d = v + 1
elseif v <= string.len(data) then
line_trans = line_trans .. luci.i18n.translate(string.sub(data, c, x - 1)) .. string.sub(data, x, v)
end
c = v + 1
end
if c > string.len(data) then
if d == 0 then
if string.match(string.sub(data, 0, 19), "%d%d%d%d%-%d%d%-%d%d %d%d:%d%d:%d%d") then
line_trans = string.sub(data, 0, 20) .. line_trans
end
end
else
if d == 0 then
if string.match(string.sub(data, 0, 19), "%d%d%d%d%-%d%d%-%d%d %d%d:%d%d:%d%d") then
line_trans = string.sub(data, 0, 20) .. line_trans .. luci.i18n.translate(string.sub(data, c, -1))
end
else
line_trans = line_trans .. luci.i18n.translate(string.sub(data, c, -1))
end
end
return line_trans
if data == nil or data == "" then
return ""
end
local no_trans = {}
local line_trans = ""
local a = string.find(data, "")
if not a then
if string.len(data) >= 19 and string.match(string.sub(data, 0, 19), "%d%d%d%d%-%d%d%-%d%d %d%d:%d%d:%d%d") then
return string.sub(data, 0, 20) .. luci.i18n.translate(string.sub(data, 21, -1))
else
return luci.i18n.translate(data)
end
end
local b_pos = string.find(data, "")
if not b_pos then
return luci.i18n.translate(data)
end
local b = b_pos + 2
local c = 21
local d = 0
local v
local x
while true do
table.insert(no_trans, a)
table.insert(no_trans, b)
local next_a = string.find(data, "", b+1)
local next_b = string.find(data, "", b+1)
if next_a and next_b then
a = next_a
b = next_b + 2
else
break
end
end
if #no_trans % 2 ~= 0 then
table.remove(no_trans)
end
for k = 1, #no_trans, 2 do
x = no_trans[k]
v = no_trans[k+1]
if x and v then
if x <= 21 or not string.match(string.sub(data, 0, 19), "%d%d%d%d%-%d%d%-%d%d %d%d:%d%d:%d%d") then
line_trans = line_trans .. luci.i18n.translate(string.sub(data, d, x - 1)) .. string.sub(data, x, v)
d = v + 1
elseif v <= string.len(data) then
line_trans = line_trans .. luci.i18n.translate(string.sub(data, c, x - 1)) .. string.sub(data, x, v)
end
c = v + 1
end
end
if c > string.len(data) then
if d == 0 then
if string.match(string.sub(data, 0, 19), "%d%d%d%d%-%d%d%-%d%d %d%d:%d%d:%d%d") then
line_trans = string.sub(data, 0, 20) .. line_trans
end
end
else
if d == 0 then
if string.match(string.sub(data, 0, 19), "%d%d%d%d%-%d%d%-%d%d %d%d:%d%d:%d%d") then
line_trans = string.sub(data, 0, 20) .. line_trans .. luci.i18n.translate(string.sub(data, c, -1))
end
else
line_trans = line_trans .. luci.i18n.translate(string.sub(data, c, -1))
end
end
return line_trans
end
function process_status(name)
@@ -1679,3 +1776,17 @@ function process_status(name)
return luci.sys.call(string.format("ps -w |grep '%s' |grep -v grep >/dev/null", name)) == 0
end
end
function action_announcement()
if not fs.access("/tmp/openclash_announcement") or fs.readfile("/tmp/openclash_announcement") == "" or fs.mtime("/tmp/openclash_announcement") < (os.time() - 86400) then
local HTTP_CODE = luci.sys.exec("curl -SsL -m 5 -w '%{http_code}' -o /tmp/openclash_announcement https://raw.githubusercontent.com/vernesong/OpenClash/dev/announcement 2>/dev/null")
if HTTP_CODE ~= "200" then
fs.unlink("/tmp/openclash_announcement")
end
end
local info = luci.sys.exec("cat /tmp/openclash_announcement 2>/dev/null") or ""
luci.http.prepare_content("application/json")
luci.http.write_json({
content = info;
})
end

View File

@@ -367,6 +367,21 @@ o:value("REJECT-DROP")
o:value("PASS")
o:value("GLOBAL")
o = s:option(ListValue, "TikTok", translate("TikTok"))
o:depends("rule_name", "lhie1")
o.rmempty = true
for groupname in string.gmatch(groupnames, "([^'##\n']+)##") do
if groupname ~= nil and groupname ~= "" then
o:value(groupname)
end
end
o:value("DIRECT")
o:value("REJECT")
o:value("REJECT-DROP")
o:value("PASS")
o:value("GLOBAL")
o = s:option(ListValue, "miHoYo", translate("miHoYo"))
o:depends("rule_name", "lhie1")
o.rmempty = true

View File

@@ -14,12 +14,12 @@ m.pageaction = false
m.description=translate("Attention:")..
"<br/>"..translate("The game proxy is a test function and does not guarantee the availability of rules")..
"<br/>"..translate("Preparation steps:")..
"<br/>"..translate("1. In the <server and policy group management> page, create the policy group and node you are going to use, and apply the configuration (when adding nodes, you must select the policy group you want to join). Policy group type suggestion: fallback, game nodes must be support UDP and not a Vmess")..
"<br/>"..translate("1. Check the policy group and node you are going to use, Policy group type suggestion: fallback, game nodes must be support UDP and not a Vmess")..
"<br/>"..translate("2. Click the <manage third party game rules> or <manage third party rule set> button to enter the rule list and download the rules you want to use")..
"<br/>"..translate("3. On this page, set the corresponding configuration file and policy group of the rule you have downloaded, and save the settings")..
"<br/>"..translate("4. Install the TUN or Meta core")..
"<br/>"..
"<br/>"..translate("When setting this page, if the groups is empty, please go to the <server and group management> page to add")..
"<br/>"..translate("When setting this page, if the groups is empty, please go to the <Onekey Create> page to add")..
"<br/>"..
"<br/>"..translate("Introduction to rule set usage: https://wiki.metacubex.one/config/rule-providers/content/")

View File

@@ -143,9 +143,13 @@ o:value("hysteria2", translate("Hysteria2 ")..translate("(Only Meta Core)"))
o:value("wireguard", translate("WireGuard")..translate("(Only Meta Core)"))
o:value("tuic", translate("Tuic")..translate("(Only Meta Core)"))
o:value("snell", translate("Snell"))
o:value("mieru", translate("Mieru"))
o:value("mieru", translate("Mieru")..translate("(Only Meta Core)"))
o:value("anytls", translate("AnyTLS")..translate("(Only Meta Core)"))
o:value("socks5", translate("Socks5"))
o:value("http", translate("HTTP(S)"))
o:value("direct", translate("DIRECT")..translate("(Only Meta Core)"))
o:value("dns", translate("DNS")..translate("(Only Meta Core)"))
o:value("ssh", translate("SSH")..translate("(Only Meta Core)"))
o.description = translate("Using incorrect encryption mothod may causes service fail to start")
@@ -156,11 +160,41 @@ o.default = "Server - "..sid
o = s:option(Value, "server", translate("Server Address"))
o.datatype = "host"
o.rmempty = true
o:depends("type", "ss")
o:depends("type", "ssr")
o:depends("type", "vmess")
o:depends("type", "trojan")
o:depends("type", "vless")
o:depends("type", "hysteria")
o:depends("type", "hysteria2")
o:depends("type", "wireguard")
o:depends("type", "tuic")
o:depends("type", "mieru")
o:depends("type", "anytls")
o:depends("type", "snell")
o:depends("type", "socks5")
o:depends("type", "http")
o:depends("type", "ssh")
o = s:option(Value, "port", translate("Server Port"))
o.datatype = "port"
o.rmempty = false
o.default = "443"
o:depends("type", "ss")
o:depends("type", "ssr")
o:depends("type", "vmess")
o:depends("type", "trojan")
o:depends("type", "vless")
o:depends("type", "hysteria")
o:depends("type", "hysteria2")
o:depends("type", "wireguard")
o:depends("type", "tuic")
o:depends("type", "mieru")
o:depends("type", "anytls")
o:depends("type", "snell")
o:depends("type", "socks5")
o:depends("type", "http")
o:depends("type", "ssh")
o = s:option(Flag, "flag_port_hopping", translate("Enable Port Hopping"))
o:depends("type", "hysteria")
@@ -184,6 +218,7 @@ o:depends("type", "ssr")
o:depends("type", "trojan")
o:depends("type", "hysteria2")
o:depends("type", "mieru")
o:depends("type", "anytls")
-- [[ Mieru ]]--
o = s:option(Value, "port_range", translate("Port Range"))
@@ -415,6 +450,8 @@ o:depends("type", "socks5")
o:depends("type", "trojan")
o:depends({type = "snell", snell_version = "3"})
o:depends("type", "wireguard")
o:depends("type", "direct")
o:depends("type", "anytls")
o = s:option(ListValue, "udp_over_tcp", translate("udp-over-tcp"))
o.rmempty = true
@@ -602,6 +639,7 @@ o:depends("type", "vless")
o:depends("type", "hysteria")
o:depends("type", "hysteria2")
o:depends("type", "tuic")
o:depends("type", "anytls")
-- [[ TLS ]]--
o = s:option(ListValue, "tls", translate("TLS"))
@@ -648,6 +686,7 @@ o:depends("type", "trojan")
o:depends("type", "http")
o:depends("type", "hysteria")
o:depends("type", "hysteria2")
o:depends("type", "anytls")
-- [[ headers ]]--
o = s:option(DynamicList, "http_headers", translate("headers"))
@@ -659,12 +698,30 @@ o:depends("type", "http")
o = s:option(Value, "auth_name", translate("Auth Username"))
o:depends("type", "socks5")
o:depends("type", "http")
o:depends("type", "ssh")
o.rmempty = true
-- 验证密码
o = s:option(Value, "auth_pass", translate("Auth Password"))
o:depends("type", "socks5")
o:depends("type", "http")
o:depends("type", "ssh")
o.rmempty = true
o = s:option(Value, "private_key", translate("private-key"))
o:depends("type", "ssh")
o.rmempty = true
o = s:option(Value, "private_key_passphrase", translate("private-key-passphrase"))
o:depends("type", "ssh")
o.rmempty = true
o = s:option(DynamicList, "host_key", translate("host-key"))
o:depends("type", "ssh")
o.rmempty = true
o = s:option(DynamicList, "host_key_algorithms", translate("host-key-algorithms"))
o:depends("type", "ssh")
o.rmempty = true
-- [[ alpn ]]--
@@ -673,6 +730,7 @@ o.rmempty = true
o:value("h2")
o:value("http/1.1")
o:depends("type", "trojan")
o:depends("type", "anytls")
-- [[ alpn ]]--
o = s:option(DynamicList, "hysteria_alpn", translate("alpn"))
@@ -822,6 +880,22 @@ o:value("true")
o:value("false")
o:depends("type", "vmess")
-- [[ AnyTLS ]]--
o = s:option(Value, "idle_session_check_interval", translate("idle-session-check-interval"))
o.rmempty = true
o.default = "30"
o:depends("type", "anytls")
o = s:option(Value, "idle_session_timeout", translate("idle-session-timeout"))
o.rmempty = true
o.default = "30"
o:depends("type", "anytls")
o = s:option(Value, "min_idle_session", translate("min-idle-session"))
o.rmempty = true
o.default = "0"
o:depends("type", "anytls")
-- [[ Fast Open ]]--
o = s:option(ListValue, "fast_open", translate("Fast Open"))
o.rmempty = true
@@ -879,6 +953,7 @@ o:depends({type = "vmess", obfs_vmess = "websocket"})
o:depends({type = "vmess", obfs_vmess = "http"})
o:depends({type = "vmess", obfs_vmess = "h2"})
o:depends({type = "vmess", obfs_vmess = "grpc"})
o:depends("type", "anytls")
-- [[ ip version ]]--
o = s:option(ListValue, "ip_version", translate("IP Version")..translate("(Only Meta Core)"))
@@ -889,6 +964,21 @@ o:value("ipv4-prefer")
o:value("ipv6")
o:value("ipv6-prefer")
o.default = "ipv4-prefer"
o:depends("type", "ss")
o:depends("type", "ssr")
o:depends("type", "vmess")
o:depends("type", "trojan")
o:depends("type", "vless")
o:depends("type", "hysteria")
o:depends("type", "hysteria2")
o:depends("type", "wireguard")
o:depends("type", "tuic")
o:depends("type", "mieru")
o:depends("type", "snell")
o:depends("type", "socks5")
o:depends("type", "http")
o:depends("type", "ssh")
o:depends("type", "direct")
-- [[ smux ]]--
o = s:option(ListValue, "multiplex", translate("Multiplex")..translate("(Only Meta Core)"))
@@ -952,11 +1042,41 @@ o:depends("multiplex", "true")
o = s:option(Value, "interface_name", translate("interface-name"))
o.rmempty = true
o.placeholder = translate("eth0")
o:depends("type", "ss")
o:depends("type", "ssr")
o:depends("type", "vmess")
o:depends("type", "trojan")
o:depends("type", "vless")
o:depends("type", "hysteria")
o:depends("type", "hysteria2")
o:depends("type", "wireguard")
o:depends("type", "tuic")
o:depends("type", "mieru")
o:depends("type", "snell")
o:depends("type", "socks5")
o:depends("type", "http")
o:depends("type", "ssh")
o:depends("type", "direct")
-- [[ routing-mark ]]--
o = s:option(Value, "routing_mark", translate("routing-mark"))
o.rmempty = true
o.placeholder = translate("2333")
o:depends("type", "ss")
o:depends("type", "ssr")
o:depends("type", "vmess")
o:depends("type", "trojan")
o:depends("type", "vless")
o:depends("type", "hysteria")
o:depends("type", "hysteria2")
o:depends("type", "wireguard")
o:depends("type", "tuic")
o:depends("type", "mieru")
o:depends("type", "snell")
o:depends("type", "socks5")
o:depends("type", "http")
o:depends("type", "ssh")
o:depends("type", "direct")
-- [[ other-setting ]]--
o = s:option(Value, "other_parameters", translate("Other Parameters"))

View File

@@ -103,6 +103,10 @@ o = s:taboption("op_mode", Flag, "disable_quic_go_gso", translate("Disable quic-
o.description = font_red..bold_on..translate("Suggestion: If Encountering Issues With QUIC UDP on The Linux Kernel Version Above 6.6, Please Try to Enable.")..bold_off..font_off
o.default = 0
o = s:taboption("op_mode", Flag, "skip_safe_path_check", translate("Skip Safe Path Check"))
o.description = font_red..bold_on..translate("Enable If You Want Using Files Not in /etc/openclash in You Config")..bold_off..font_off
o.default = 0
o = s:taboption("op_mode", Flag, "small_flash_memory", translate("Small Flash Memory"))
o.description = translate("Move Core And GEOIP Data File To /tmp/etc/openclash For Small Flash Memory Device")
o.default = 0
@@ -790,8 +794,7 @@ o.description = translate("Custom GeoIP MMDB URL, Click Button Below To Refresh
o:value("https://testingcf.jsdelivr.net/gh/alecthw/mmdb_china_ip_list@release/lite/Country.mmdb", translate("Alecthw-lite-Version")..translate("(Default mmdb)"))
o:value("https://testingcf.jsdelivr.net/gh/alecthw/mmdb_china_ip_list@release/Country.mmdb", translate("Alecthw-Version")..translate("(All Info mmdb)"))
o:value("https://testingcf.jsdelivr.net/gh/Hackl0us/GeoIP2-CN@release/Country.mmdb", translate("Hackl0us-Version")..translate("(Only CN)"))
o:value("https://geolite.clash.dev/Country.mmdb", translate("Geolite.clash.dev"))
o.default = "http://www.ideame.top/mmdb/Country.mmdb"
o.default = "https://testingcf.jsdelivr.net/gh/alecthw/mmdb_china_ip_list@release/lite/Country.mmdb"
o = s:taboption("geo_update", Button, translate("GEOIP Update"))
o.title = translate("Update GeoIP MMDB")
@@ -890,6 +893,49 @@ o.write = function()
end
o:depends("geosite_auto_update", "1")
o = s:taboption("geo_update", Flag, "geoasn_auto_update", font_red..bold_on..translate("Auto Update Geo ASN")..bold_off..font_off)
o.default = 0
o = s:taboption("geo_update", ListValue, "geoasn_update_week_time", translate("Update Time (Every Week)"))
o:value("*", translate("Every Day"))
o:value("1", translate("Every Monday"))
o:value("2", translate("Every Tuesday"))
o:value("3", translate("Every Wednesday"))
o:value("4", translate("Every Thursday"))
o:value("5", translate("Every Friday"))
o:value("6", translate("Every Saturday"))
o:value("0", translate("Every Sunday"))
o.default = "1"
o:depends("geoasn_auto_update", "1")
o = s:taboption("geo_update", ListValue, "geoasn_update_day_time", translate("Update time (every day)"))
for t = 0,23 do
o:value(t, t..":00")
end
o.default = "0"
o:depends("geoasn_auto_update", "1")
o = s:taboption("geo_update", Value, "geoasn_custom_url")
o.title = translate("Custom GeoSite URL")
o.rmempty = true
o.description = translate("Custom Geo ASN Data URL, Click Button Below To Refresh After Edit")
o:value("https://testingcf.jsdelivr.net/gh/xishang0128/geoip@release/GeoLite2-ASN.mmdb", translate("xishang0128-testingcf-jsdelivr-Version")..translate("(Default)"))
o:value("https://fastly.jsdelivr.net/gh/xishang0128/geoip@release/GeoLite2-ASN.mmdb", translate("xishang0128-fastly-jsdelivr-Version"))
o.default = "https://testingcf.jsdelivr.net/gh/xishang0128/geoip@release/GeoLite2-ASN.mmdb"
o:depends("geoasn_auto_update", "1")
o = s:taboption("geo_update", Button, translate("ASN Update"))
o.title = translate("Update Geo ASN Database")
o.inputtitle = translate("Check And Update")
o.inputstyle = "reload"
o.write = function()
m.uci:set("openclash", "config", "enable", 1)
m.uci:commit("openclash")
SYS.call("/usr/share/openclash/openclash_geoasn.sh >/dev/null 2>&1 &")
HTTP.redirect(DISP.build_url("admin", "services", "openclash"))
end
o:depends("geoasn_auto_update", "1")
o = s:taboption("chnr_update", Flag, "chnr_auto_update", translate("Auto Update"))
o.description = translate("Auto Update Chnroute Lists")
o.default = 0
@@ -917,8 +963,8 @@ o.rmempty = false
o.description = translate("Custom Chnroute Lists URL, Click Button Below To Refresh After Edit")
o:value("https://ispip.clang.cn/all_cn.txt", translate("Clang-CN")..translate("(Default)"))
o:value("https://ispip.clang.cn/all_cn_cidr.txt", translate("Clang-CN-CIDR"))
o:value("https://fastly.jsdelivr.net/gh/Hackl0us/GeoIP2-CN@release/CN-ip-cidr.txt", translate("Hackl0us-CN-CIDR-fastly-jsdelivr")..translate("(Large Size)"))
o:value("https://testingcf.jsdelivr.net/gh/Hackl0us/GeoIP2-CN@release/CN-ip-cidr.txt", translate("Hackl0us-CN-CIDR-testingcf-jsdelivr")..translate("(Large Size)"))
o:value("https://fastly.jsdelivr.net/gh/Hackl0us/GeoIP2-CN@release/CN-ip-cidr.txt", translate("Hackl0us-CN-CIDR-fastly-jsdelivr"))
o:value("https://testingcf.jsdelivr.net/gh/Hackl0us/GeoIP2-CN@release/CN-ip-cidr.txt", translate("Hackl0us-CN-CIDR-testingcf-jsdelivr"))
o.default = "https://ispip.clang.cn/all_cn.txt"
o = s:taboption("chnr_update", Value, "chnr6_custom_url")

View File

@@ -261,11 +261,14 @@ end
function filesize(e)
local t=0
local a={' KB',' MB',' GB',' TB',' PB'}
if e < 0 then
e = -e
end
repeat
e=e/1024
t=t+1
until(e<=1024)
return string.format("%.1f",e)..a[t]
return string.format("%.1f",e)..a[t] or "0.0 KB"
end
function lanip()

View File

@@ -92,8 +92,8 @@ ul{
<div id="tab" class="cbi-section">
<div id="tab-header" class="cbi-tabmenu">
<ul class="cbi-tabmenu">
<li name="tab-header" class="cbi-tab"><a><%:OpenClash Log%></a></li>
<li name="tab-header" class="cbi-tab-disabled"><a><%:Core Log%></a></li>
<li name="tab-header" class="cbi-tab"><a href="#"><%:OpenClash Log%></a></li>
<li name="tab-header" class="cbi-tab-disabled"><a href="#"><%:Core Log%></a></li>
</ul>
</div>
<div id="tab-content">
@@ -144,6 +144,8 @@ var s;
var log_len = 0;
var lv = document.getElementById('cbid.openclash.config.clog');
var cl = document.getElementById('core_log');
var animatingOC = false;
var animatingCore = false;
function get_log_level() {
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "log_level")%>', null, function(x, status) {
@@ -220,76 +222,339 @@ function p(s) {
return s < 10 ? '0' + s: s;
};
function line_tolocal(str){
var strt=new Array();
var cstrt=new Array();
var cn = 0;
var sn = 0;
str.trim().split('\n').forEach(function(v, i) {
var regex = /(time=)"([^"]*)"/g;
var res = regex.exec(v);
if (res) {
var dt = new Date(res[2]);
}
else {
var dtt = new Date(v.substring(0,19));
}
if (dt && dt != "Invalid Date"){
if (v.indexOf("level=") != -1) {
var log_info = v.substring(res[2].length + 7);
}
else {
var log_info = v.substring(res[2].length + 2);
}
cstrt[cn]=dt.getFullYear()+"-"+p(dt.getMonth()+1)+"-"+p(dt.getDate())+" "+p(dt.getHours())+":"+p(dt.getMinutes())+":"+p(dt.getSeconds())+log_info;
cn = cn + 1;
}
else if (dtt && dtt != "Invalid Date" && v.substring(28,33).indexOf(" ERR ") == -1) {
strt[sn]=v;
sn = sn + 1;
}
else{
cstrt[cn]=v;
cn = cn + 1;
}
})
return [strt,cstrt]
function line_tolocal(str) {
var trans_local = new Array();
var local_count = 0;
str.trim().split('\n').forEach(function(v, i) {
var regex = /(time=)"([^"]*)"/g;
var res = regex.exec(v);
try {
if (res) {
var dt = new Date(res[2]);
if (!isNaN(dt.getTime())) {
if (v.indexOf("level=") != -1) {
var log_info = v.substring(res[2].length + 7);
} else {
var log_info = v.substring(res[2].length + 2);
}
trans_local[local_count] = dt.getFullYear() + "-" + p(dt.getMonth() + 1) + "-" + p(dt.getDate()) + " " +
p(dt.getHours()) + ":" + p(dt.getMinutes()) + ":" + p(dt.getSeconds()) + log_info;
local_count++;
} else {
trans_local[local_count] = v;
local_count++;
}
} else {
try {
var dtt = new Date(v.substring(0, 19));
if (!isNaN(dtt.getTime()) && v.substring(0, 19).match(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/)) {
trans_local[local_count] = v;
local_count++;
} else {
trans_local[local_count] = v;
local_count++;
}
} catch (e) {
trans_local[local_count] = v;
local_count++;
}
}
} catch (e) {
trans_local[local_count] = v;
local_count++;
}
});
return trans_local;
};
function smoothlyDisplayLogs(newLines, target, isEditor, currentContent, isActiveTab) {
var scrollPosition = null;
var isAtTop = false;
var cursorPos = null;
var selectionRange = null;
var isFirstLoad = !currentContent || currentContent.trim() === "";
if (isEditor && target) {
scrollPosition = target.getScrollInfo();
isAtTop = (scrollPosition.top < 20);
if (target.hasFocus()) {
cursorPos = target.getCursor();
if (cursorPos.line === 0) {
cursorPos = null;
selectionRange = null;
} else if (target.somethingSelected()) {
selectionRange = {
from: target.getCursor(true),
to: target.getCursor(false)
};
} else {
selectionRange = null;
}
} else {
cursorPos = null;
selectionRange = null;
}
} else if (!isEditor && target) {
scrollPosition = target.scrollTop;
isAtTop = (target.scrollTop < 20);
}
if ((target === oc_editor && animatingOC) || (target === core_editor && animatingCore) || !isActiveTab) {
var content = "";
var lines = newLines.slice().reverse();
for (var i = 0; i < lines.length; i++) {
content += lines[i] + "\n";
}
content = content + (currentContent || "");
var allLines = content.split("\n");
if (allLines.length > 2000) {
allLines = allLines.slice(0, 1999);
allLines.push("...");
content = allLines.join("\n");
}
if (isEditor) {
var addedLines = lines.length;
target.setValue(content);
if (!isAtTop && scrollPosition) {
if (cursorPos) {
cursorPos.line += addedLines;
target.setCursor(cursorPos);
target.scrollIntoView({line: cursorPos.line, ch: cursorPos.ch}, 300);
} else {
target.scrollTo(scrollPosition.left, scrollPosition.top);
}
if (selectionRange) {
selectionRange.from.line += addedLines;
selectionRange.to.line += addedLines;
target.setSelection(selectionRange.from, selectionRange.to);
target.scrollIntoView({
from: selectionRange.from,
to: selectionRange.to
}, 300);
}
} else if (isAtTop) {
target.scrollTo(0, 0);
if (isFirstLoad) {
target.setCursor({line: 0, ch: 0});
}
}
target.refresh();
} else {
var oldScrollTop = scrollPosition;
target.innerHTML = content;
if (!isAtTop && oldScrollTop) {
target.scrollTop = oldScrollTop;
}
}
return;
}
if (target === oc_editor || target === lv) {
animatingOC = true;
} else {
animatingCore = true;
}
var totalLines = newLines.length;
var batchSize, interval;
if (totalLines <= 10) {
batchSize = 1;
interval = 90;
} else if (totalLines <= 50) {
batchSize = 3;
interval = 60;
} else if (totalLines <= 200) {
batchSize = 8;
interval = 35;
} else if (totalLines <= 500) {
batchSize = 15;
interval = 25;
} else if (totalLines <= 1000) {
batchSize = 25;
interval = 15;
} else {
batchSize = 40;
interval = 10;
}
var displayedContent = currentContent || "";
var logLines = newLines.slice();
var currentBatchCount = 0;
var accumulatedContent = "";
function displayNextBatch() {
if (currentBatchCount >= logLines.length) {
if (target === oc_editor || target === lv) {
animatingOC = false;
} else {
animatingCore = false;
}
if (isEditor && !isAtTop && cursorPos) {
cursorPos.line += logLines.length;
target.setCursor(cursorPos);
if (selectionRange) {
selectionRange.from.line += logLines.length;
selectionRange.to.line += logLines.length;
target.setSelection(selectionRange.from, selectionRange.to);
target.scrollIntoView({
from: selectionRange.from,
to: selectionRange.to
}, 300);
} else {
target.scrollIntoView({line: cursorPos.line, ch: cursorPos.ch}, 300);
}
}
return;
}
var nextBatchSize = Math.min(batchSize, logLines.length - currentBatchCount);
var batchLines = logLines.slice(currentBatchCount, currentBatchCount + nextBatchSize).reverse();
currentBatchCount += nextBatchSize;
if (accumulatedContent) {
accumulatedContent = batchLines.join("\n") + "\n" + accumulatedContent;
} else {
accumulatedContent = batchLines.join("\n");
}
var content = accumulatedContent + (displayedContent ? "\n" + displayedContent : "");
var contentLines = content.split("\n");
if (contentLines.length > 2000) {
contentLines = contentLines.slice(0, 1999);
contentLines.push("...");
content = contentLines.join("\n");
}
if (isEditor) {
var currentScrollInfo = isAtTop ? null : target.getScrollInfo();
target.setValue(content);
if (!isAtTop && currentScrollInfo) {
target.scrollTo(currentScrollInfo.left, currentScrollInfo.top);
}
target.refresh();
} else {
var currentScrollTop = isAtTop ? null : target.scrollTop;
target.innerHTML = content;
if (!isAtTop && currentScrollTop !== null) {
target.scrollTop = currentScrollTop;
}
}
if (currentBatchCount < logLines.length) {
setTimeout(displayNextBatch, interval);
} else {
if (target === oc_editor || target === lv) {
animatingOC = false;
} else {
animatingCore = false;
}
if (isEditor && !isAtTop && cursorPos) {
cursorPos.line += logLines.length;
target.setCursor(cursorPos);
if (selectionRange) {
selectionRange.from.line += logLines.length;
selectionRange.to.line += logLines.length;
target.setSelection(selectionRange.from, selectionRange.to);
target.scrollIntoView({
from: selectionRange.from,
to: selectionRange.to
}, 300);
} else {
target.scrollIntoView({line: cursorPos.line, ch: cursorPos.ch}, 300);
}
}
}
}
displayNextBatch();
}
function poll_log(){
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "refresh_log")%>', {log_len: log_len},
function(x, status) {
if ( x && x.status == 200 ) {
if (status && status.log != "" && lv && cl) {
var log = line_tolocal(status.log);
var lines = log[0];
var clines = log[1];
if (lines != "" || clines != "") {
if (lines != "") {
lv.innerHTML = lines.join('\n')+ (log_len != 0 ? '\n' : '') + lv.innerHTML;
oc_editor.setValue(lv.value);
oc_editor.refresh();
}
if (clines != "") {
if (lines[0] != "..." && lines[lines.length-1] != "...") {
cl.innerHTML = clines.join('\n') + (log_len != 0 ? '\n' : '') + cl.innerHTML;
}
else {
cl.innerHTML = clines.join('\n') + (log_len != 0 ? '\n' : cl.innerHTML + '\n...');
}
core_editor.setValue(cl.value);
core_editor.refresh();
}
log_len = status.len;
//lv.innerHTML = x.responseText.split('\n').reverse().join('\n')+lv.innerHTML;
}
}
}
}
);
r=setTimeout("poll_log()",1000*2);
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "refresh_log")%>',
{
log_len: log_len
},
function(x, status) {
if (x && x.status == 200) {
if (status) {
if (!status.update) {
r = setTimeout("poll_log()", 2000);
return;
}
if (status.len) {
log_len = status.len;
}
var activeTabId = 0;
var titles = document.getElementsByName('tab-header');
for(var i=0; i<titles.length; i++){
if(titles[i].className === 'cbi-tab') {
activeTabId = i;
break;
}
}
if (status.oc_log && status.oc_log !== "") {
var oc_logs = line_tolocal(status.oc_log);
if (oc_logs && oc_logs.length > 0) {
if (oc_editor) {
var currentContent = oc_editor.getValue();
smoothlyDisplayLogs(oc_logs, oc_editor, true, currentContent, activeTabId === 0);
} else if (lv) {
var currentContent = lv.innerHTML;
smoothlyDisplayLogs(oc_logs, lv, false, currentContent, activeTabId === 0);
}
}
}
if (status.core_log && status.core_log !== "") {
var core_logs = line_tolocal(status.core_log);
if (core_logs && core_logs.length > 0) {
if (core_editor) {
var currentCoreContent = core_editor.getValue();
smoothlyDisplayLogs(core_logs, core_editor, true, currentCoreContent, activeTabId === 1);
} else if (cl) {
var currentCoreContent = cl.innerHTML;
smoothlyDisplayLogs(core_logs, cl, false, currentCoreContent, activeTabId === 1);
}
}
}
}
}
r = setTimeout("poll_log()", 2000);
}
);
};
window.onload = function(){
var titles = document.getElementsByName('tab-header');
var divs = document.getElementsByClassName('dom');
@@ -297,22 +562,30 @@ window.onload = function(){
for(var i=0; i<titles.length; i++){
var li = titles[i];
li.id = i;
li.onclick = function(){
for(var j=0; j<titles.length; j++){
titles[j].className = 'cbi-tab-disabled';
divs[j].style.display = 'none';
}
this.className = 'cbi-tab';
divs[this.id].style.display = 'block';
}
li.onTouchStart = function(){
for(var j=0; j<titles.length; j++){
titles[j].className = 'cbi-tab-disabled';
divs[j].style.display = 'none';
}
this.className = 'cbi-tab';
divs[this.id].style.display = 'block';
function handleTabSwitch(tab) {
return function(e) {
for(var j=0; j<titles.length; j++){
titles[j].className = 'cbi-tab-disabled';
divs[j].style.display = 'none';
}
tab.className = 'cbi-tab';
divs[tab.id].style.display = 'block';
if(tab.id == 0 && typeof oc_editor !== 'undefined') {
setTimeout(function(){
oc_editor.refresh();
}, 10);
} else if(tab.id == 1 && typeof core_editor !== 'undefined') {
setTimeout(function(){
core_editor.refresh();
}, 10);
}
};
}
// 正确绑定事件
li.onclick = handleTabSwitch(li);
li.ontouchstart = handleTabSwitch(li);
}
get_log_level();
poll_log();

View File

@@ -32,6 +32,53 @@
.radio-button input[type="radio"]:checked+label {
background-color: #1080c1;
}
.announcement-banner {
display: none;
background-color: #1080c1;
color: white;
padding: 8px;
margin-bottom: 10px;
margin-left: auto;
margin-right: auto;
border-radius: 4px;
overflow: hidden;
position: relative;
height: 24px;
width: 70%;
}
.announcement-content {
position: absolute;
white-space: nowrap;
padding-right: 50px;
left: 30px;
top: 50%;
transform: translateY(-50%);
z-index: 1;
}
#megaphone {
position: absolute;
left: 8px;
top: 50%;
transform: translateY(-50%) scaleX(-1);
z-index: 2;
filter: brightness(0) invert(1);
}
.megaphone-container {
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 30px;
background-color: #1080c1;
z-index: 2;
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
</style>
</head>
<%
@@ -41,8 +88,12 @@
%>
<fieldset class="cbi-section">
<table width="100%">
<tr>
<td colspan="4" width="100%">
<div id="announcement-banner" class="announcement-banner">
<div class="megaphone-container"></div>
<img id="megaphone" src="/luci-static/resources/openclash/img/megaphone-simple.svg?<%=random%>" loading="lazy" alt="megaphone" width="15px" height="15px">
<div id="announcement-content" class="announcement-content"></div>
</div>
<p style="margin: 10px 0; text-align: center">
<img id="_logo" src="/luci-static/resources/openclash/img/logo.png?<%=random%>" loading="lazy" width="150px" height="150px" onload="return logo_check(this,this.src,'https://raw.githubusercontent.com/vernesong/OpenClash/<%=RELEASE_BRANCH%>/img/meta.png')" onerror="return logo_error(this,'/luci-static/resources/openclash/img/logo.png?<%=random%>')" title="Hello, World!" alt="OpenClash" onclick="return homepage()" />
</p>
@@ -450,6 +501,105 @@
clashversion_check();
check_core();
document.addEventListener('DOMContentLoaded', function() {
var userLang = navigator.language || navigator.userLanguage;
var isChineseUser = userLang.indexOf('zh') === 0;
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "announcement")%>', null, function(x, status) {
if (x && x.status == 200) {
var banner = document.getElementById('announcement-banner');
var content = document.getElementById('announcement-content');
var announcements = [];
if (status.content) {
try {
var contentData = status.content;
if (typeof contentData === 'string') {
contentData = JSON.parse(contentData);
}
if (Array.isArray(contentData)) {
if (contentData.length > 0 && (contentData[0].zh || contentData[0].en)) {
contentData.forEach(function(item) {
if (isChineseUser && item.zh) {
announcements.push(item.zh);
} else if (item.en) {
announcements.push(item.en);
} else if (item.zh) {
announcements.push(item.zh);
}
});
} else {
announcements = contentData;
}
} else if (typeof contentData === 'string' && contentData.trim() !== '') {
announcements = [contentData];
}
} catch (e) {
if (typeof status.content === 'string' && status.content.trim() !== '') {
announcements = [status.content];
}
}
}
if (announcements.length === 0) {
banner.style.display = 'none';
return;
}
banner.style.display = 'block';
var currentIndex = 0;
content.textContent = announcements[currentIndex];
var isPaused = false;
banner.addEventListener('mouseenter', function() {
isPaused = true;
});
banner.addEventListener('mouseleave', function() {
isPaused = false;
});
setTimeout(function() {
var bannerWidth = banner.offsetWidth;
var contentWidth = content.offsetWidth;
content.style.left = bannerWidth + 'px';
var speed = 3;
var position = bannerWidth;
var pauseCounter = 0;
var pauseDuration = 20;
function moveText() {
if (!isPaused) {
if (position < -contentWidth && pauseCounter >= pauseDuration) {
currentIndex = (currentIndex + 1) % announcements.length;
content.textContent = announcements[currentIndex];
contentWidth = content.offsetWidth;
position = bannerWidth;
pauseCounter = 0;
}
else if (position < -contentWidth) {
pauseCounter++;
}
else {
position -= speed;
}
content.style.left = position + 'px';
}
requestAnimationFrame(moveText);
}
moveText();
}, 100);
}
});
});
function get_rule_mode() {
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "rule_mode")%>', null, function(x, status) {
if (x && x.status == 200 && status.mode != "") {

View File

@@ -24,37 +24,73 @@
}
.sub_setting{
display: inline-block;
white-space: nowrap;
margin: 0 auto;
opacity: 1;
vertical-align: middle;
display: inline-block;
white-space: nowrap;
margin: 0 auto;
opacity: 1;
vertical-align: middle;
line-height: 0; /* 消除行高影响 */
}
.sub_div{
white-space: nowrap;
.sub_setting img {
vertical-align: middle; /* 确保图标垂直居中 */
display: inline-block;
}
/* 日间模式样式 */
.text_show{
color: #000000;
text-shadow:
-0.7px -0.7px 0 #ffffff,
0.7px -0.7px 0 #ffffff,
-0.7px 0.7px 0 #ffffff,
0.7px 0.7px 0 #ffffff;
color: #333333;
}
:root[data-darkmode="true"] {
.progress_bar_bg {
border: 1px solid #999999;
background-color: #f5f5f5;
}
#icon_wrench {
-webkit-filter: invert(1);
filter: invert(1);
}
#icon_arrow {
-webkit-filter: invert(1);
filter: invert(1);
}
.progress_bar_high {
background-color: #9edd9e;
}
.progress_bar_medium {
background-color: #ffc99f;
}
.progress_bar_low {
background-color: #ffb9b9;
}
/* 夜间模式样式 */
:root[data-darkmode="true"] {
#icon_wrench {
-webkit-filter: invert(1);
filter: invert(1);
}
#icon_arrow {
-webkit-filter: invert(1);
filter: invert(1);
}
.text_show{
color: #e0e0e0;
}
.progress_bar_bg {
border: 1px solid #666666;
background-color: #333333;
}
.progress_bar_high {
background-color: #5da05d;
}
.progress_bar_medium {
background-color: #cc8550;
}
.progress_bar_low {
background-color: #cc6262;
}
}
</style>
@@ -105,10 +141,14 @@ if (isDarkBackground(document.body)) {
function progressbar_<%=idname%>(v, m, pc, np, f, t, tr) {
return String.format(
'<div style="width:250px; max-width:500px; position:relative; border:1px solid #999999; border-radius: 6px">' +
(pc >= 50 ? '<div style="background-color:#9edd9e; width:%d%%; height:36px; border-radius: 6px">' : (pc < 50 && pc >= 20 ? '<div style="background-color:#ffc99f; width:%d%%; height:35px">' : '<div style="background-color:#ffb9b9; width:%d%%; height:35px">')) +
'<div style="position:absolute; left:0;' + (tr == "null" ? 'top:12px;' : 'top:0;') + 'text-align:center; width:100%%">' +
'<small class="text_show">%s '+ (f ? f : '/') +' %s ' + (np ? "" : '(%s%%)') + (tr == "null" ? '<div style="visibility: hidden;">' : '<div style="visibility: visible;">') + '%s (<%:Remaining%> %s <%:days%>)</small>' +
'<div class="progress_bar_bg" style="width:250px; max-width:500px; position:relative; border-radius: 6px">' +
(pc >= 50 ? '<div class="progress_bar_high" style="width:%d%%; height:36px; border-radius: 6px">' :
(pc < 50 && pc >= 20 ? '<div class="progress_bar_medium" style="width:%d%%; height:36px; border-radius: 6px">' :
'<div class="progress_bar_low" style="width:%d%%; height:36px; border-radius: 6px">')) +
'<div style="position:absolute; left:0;' + (tr == "null" ? 'top:12px;' : 'top:0px;') + 'text-align:center; width:100%%">' +
'<small class="text_show">%s '+ (f ? f : '/') +' %s ' + (np ? "" : '(%s%%)') +
(tr == "null" ? '<div style="visibility: hidden;">' : '<div style="visibility: visible;">') +
'%s (<%:Remaining%> %s <%:days%>)</small>' +
'</div>' +
'</div>' +
'</div>', pc, v, m, pc, t, tr

View File

@@ -186,6 +186,9 @@
release_branch.value = "master";
}
});
XHR.poll(300, '<%=luci.dispatcher.build_url("admin", "services", "openclash", "get_last_version")%>', null, function(x, status) {
});
XHR.poll(3, '<%=luci.dispatcher.build_url("admin", "services", "openclash", "update")%>', null, function(x, status) {
if ( x && x.status == 200 ) {
@@ -206,28 +209,38 @@
core_meta_cv.innerHTML = "<b style=color:red><%:Unknown%></b>";
}
var coremetalvis = status.corelv;
if (coremetalvis != status.coremetacv && coremetalvis != "" && coremetalvis != "\n") {
if (coremetalvis != status.coremetacv && coremetalvis != "" && coremetalvis != "loading...") {
core_meta_lv.innerHTML = "<b style=color:green>"+coremetalvis+"<%:<New>%></b>";
}
else if (coremetalvis != "" && coremetalvis == status.coremetacv && coremetalvis != "\n") {
else if (coremetalvis != "" && coremetalvis == status.coremetacv && coremetalvis != "loading...") {
core_meta_lv.innerHTML = "<b style=color:green>"+coremetalvis+"</b>";
}
else if (coremetalvis == "loading...") {
core_meta_lv.innerHTML = "<b style=color:green><%:Getting Last Version...%></b>";
}
else {
core_meta_lv.innerHTML = "<b style=color:red><%:Unknown%></b>";
}
var oplv = status.oplv;
var arr_op = oplv.split(",");
var oplvis = arr_op[0];
var new_op = arr_op[1];
op_cv.innerHTML = status.opcv ? "<b style=color:green>"+status.opcv+"</b>" : "<b style=color:red><%:Unknown%></b>";
if ( new_op == "2" && oplvis != "" && oplvis != "\n") {
op_lv.innerHTML = "<b style=color:green>"+oplvis+"<%:<New>%></b>";
if (oplv != "" && oplv != "loading..." && status.opcv) {
var oplvck = oplv.match(/\d+(\.\d+)+/)[0].replace(/\./g, "")
var opcvck = status.opcv.match(/\d+(\.\d+)+/)[0].replace(/\./g, "")
if (oplvck > opcvck) {
op_lv.innerHTML = "<b style=color:green>"+oplv+"<%:<New>%></b>";
}
else {
op_lv.innerHTML = "<b style=color:green>"+oplv+"</b>";
}
}
else if (oplvis != "" && oplvis != "\n") {
op_lv.innerHTML = "<b style=color:green>"+oplvis+"</b>";
else if (oplv != "" && oplv != "loading...") {
op_lv.innerHTML = "<b style=color:green>"+oplv+"</b>";
}
else if (oplv == "loading...") {
op_lv.innerHTML = "<b style=color:green><%:Getting Last Version...%></b>";
}
else {
op_lv.innerHTML = "<b style=color:red><%:Unknown%></b>";
op_lv.innerHTML = "<b style=color:red><%:Unknown%></b>";
}
}
});

View File

@@ -449,6 +449,12 @@ msgstr "自动更新 GeoSite 数据库"
msgid "Update GeoSite Database"
msgstr "更新 GeoSite 数据库"
msgid "Auto Update Geo ASN"
msgstr "自动更新 Geo ASN 数据库"
msgid "Update Geo ASN Database"
msgstr "更新 Geo ASN 数据库"
msgid "Auto Update Chnroute Lists"
msgstr "自动更新大陆白名单"
@@ -602,6 +608,9 @@ msgstr "查询更新失败"
msgid "<New>"
msgstr "<可更新>"
msgid "Getting Last Version..."
msgstr "最新版本获取中..."
msgid "Update Core File"
msgstr "更新内核"
@@ -1500,6 +1509,9 @@ msgstr "自定义 GeoIP MMDB 数据库的更新来源,编辑后点击下方按
msgid "Custom GeoSite Data URL, Click Button Below To Refresh After Edit"
msgstr "自定义 GeoSite 数据库的更新来源,编辑后点击下方按钮生效"
msgid "Custom Geo ASN Data URL, Click Button Below To Refresh After Edit"
msgstr "自定义 Geo ASN 数据库的更新来源,编辑后点击下方按钮生效"
msgid "Custom Chnroute Lists URL, Click Button Below To Refresh After Edit"
msgstr "自定义大陆 IP 段的更新来源,编辑后点击下方按钮生效"
@@ -1518,9 +1530,6 @@ msgstr "(全部国家且且包含官方全部信息数据)"
msgid "(Only CN)"
msgstr "(仅中国数据)"
msgid "(Large Size)"
msgstr "(18MB大文件请确保足够的剩余空间)"
msgid "Other Rules Edit"
msgstr "设置第三方规则"
@@ -1857,6 +1866,24 @@ msgstr "GEOIP 数据库版本没有更新,停止继续操作..."
msgid "Geoip Database Update Error, Please Try Again Later..."
msgstr "GEOIP 数据库下载失败,请检查网络或稍后再试..."
msgid "Start Downloading Geo ASN Database..."
msgstr "开始下载 GEO ASN 数据库..."
msgid "Geo ASN Database Download Success, Check Updated..."
msgstr "GEO ASN 数据库下载成功,检查数据库版本是否更新..."
msgid "Geo ASN Database Has Been Updated, Starting To Replace The Old Version..."
msgstr "GEO ASN 数据库版本有更新,开始替换数据库版本..."
msgid "Geo ASN Database Update Successful!"
msgstr "GEO ASN 数据库更新成功!"
msgid "Updated Geo ASN Database No Change, Do Nothing..."
msgstr "GEO ASN 数据库版本没有更新,停止继续操作..."
msgid "Geo ASN Database Update Error, Please Try Again Later..."
msgstr "GEO ASN 数据库下载失败,请检查网络或稍后再试..."
msgid "Start Getting"
msgstr "开始获取"
@@ -2079,8 +2106,8 @@ msgstr "游戏代理为测试功能,不保证规则可用性"
msgid "Preparation steps:"
msgstr "准备步骤:"
msgid "1. In the <server and policy group management> page, create the policy group and node you are going to use, and apply the configuration (when adding nodes, you must select the policy group you want to join). Policy group type suggestion: fallback, game nodes must be support UDP and not a Vmess"
msgstr "1、在《服务器与策略组管理》页面创建您准备使用的策略组和节点,并应用配置(节点添加时必须选择要加入的策略组),策略组类型建议: FallBack游戏节点必须支持 UDP 且不是 Vmess 节点"
msgid "1. Check the policy group and node you are going to use, Policy group type suggestion: fallback, game nodes must be support UDP and not a Vmess"
msgstr "1、检查您准备使用的策略组和节点,策略组类型建议: FallBack游戏节点必须支持 UDP 且不是 Vmess 节点"
msgid "2. Click the <manage third party game rules> or <manage third party rule set> button to enter the rule list and download the rules you want to use"
msgstr "2、点击《管理第三方游戏规则》或者《管理第三方规则集》按钮进入规则列表下载您要使用的规则"
@@ -2091,8 +2118,8 @@ msgstr "3、在此页面设置您已下载的规则的对应配置文件、策
msgid "4. Install the TUN or Meta core"
msgstr "4、安装 TUN 或者 Meta 内核"
msgid "When setting this page, if the groups is empty, please go to the <server and group management> page to add"
msgstr "本页设置时如策略组为空,请先到《服务器与策略组管理》页面进行添加"
msgid "When setting this page, if the groups is empty, please go to the <Onekey Create> page to add"
msgstr "本页设置时如策略组为空,请先到《一键生成》页面进行添加"
msgid "Introduction to rule set usage: https://wiki.metacubex.one/config/rule-providers/content/"
msgstr "规则集使用介绍https://wiki.metacubex.one/config/rule-providers/content/"
@@ -3478,4 +3505,10 @@ msgid "Disable quic-go GSO Support"
msgstr "禁用 quic-go GSO 支持"
msgid "Suggestion: If Encountering Issues With QUIC UDP on The Linux Kernel Version Above 6.6, Please Try to Enable."
msgstr "建议: 如果固件 Linux 核心版本在 6.6 以上时遇到 quic-go 的 UDP 连接问题,请尝试启用。"
msgstr "建议: 如果固件 Linux 核心版本在 6.6 以上时遇到 quic-go 的 UDP 连接问题,请尝试启用。"
msgid "Skip Safe Path Check"
msgstr "跳过安全路径检查"
msgid "Enable If You Want Using Files Not in /etc/openclash in You Config"
msgstr "如果您希望在配置中使用不在 /etc/openclash 中的文件,请启用该选项"

View File

@@ -62,6 +62,7 @@ config openclash 'config'
option geo_custom_url 'https://testingcf.jsdelivr.net/gh/alecthw/mmdb_china_ip_list@release/lite/Country.mmdb'
option geosite_custom_url 'https://testingcf.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geosite.dat'
option geoip_custom_url 'https://testingcf.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geoip.dat'
option geoasn_custom_url 'https://testingcf.jsdelivr.net/gh/xishang0128/geoip@release/GeoLite2-ASN.mmdb'
option chnr_custom_url 'https://ispip.clang.cn/all_cn.txt'
option chnr6_custom_url 'https://ispip.clang.cn/all_cn_ipv6.txt'

View File

@@ -648,11 +648,13 @@ start_run_core()
chown root:root /etc/openclash/core/* 2>/dev/null
kill_clash
procd_open_instance "openclash"
procd_set_param env SKIP_SAFE_PATH_CHECK="$skip_safe_path_check"
procd_append_param env SAFE_PATHS=/usr/share/openclash:/etc/ssl
procd_set_param command /bin/sh -c "$CLASH -d $CLASH_CONFIG -f \"$CONFIG_FILE\" >> $LOG_FILE 2>&1"
procd_set_param user "root"
procd_set_param group "nogroup"
procd_set_param limits nproc="unlimited" as="unlimited" memlock="unlimited" nofile="1000000 1000000"
procd_set_param respawn 3600 3 10
procd_set_param respawn 300 5 3
procd_set_param stderr 1
procd_set_param no_new_privs 1
procd_close_instance
@@ -793,7 +795,6 @@ check_core_status()
done >/dev/null 2>&1
if [ -z "$(echo ${lan_ip} | grep -Eo ${reg4})" ]; then
LOG_OUT "Error: LAN IP Address Get Error, Please Check The LAN Interface Setting or Choose the Correct Interface in the Setting!"
sleep 10
fi
if [ "$CORE_HTTP_CODE" != "200" ]; then
LOG_OUT "Error: Core Status Abnormal, Please Check The Log Infos!"
@@ -1978,7 +1979,7 @@ if [ -n "$FW4" ]; then
rule="ip6 daddr != @china_ip6_route"
fi
[ "$enable_redirect_dns" != "2" ] && rule="$rule ip6 daddr != @china_ip6_route_pass"
nft 'add rule inet fw4 openclash_mangle_output_v6 $rule counter return'
nft "add rule inet fw4 openclash_mangle_output_v6 $rule counter return"
fi
if ([ "$ipv6_mode" -eq 1 ] && [ "$enable_v6_udp_proxy" -eq 1 ]) || [ "$ipv6_mode" -eq 3 ]; then
@@ -2963,6 +2964,7 @@ get_config()
custom_fakeip_filter_mode=$(uci -q get openclash.config.custom_fakeip_filter_mode || echo "blacklist")
iptables_compat=$(iptables -m owner -h 2>/dev/null | grep "owner match options" || command -v fw4 || echo 0)
disable_quic_go_gso=$(uci -q get openclash.config.disable_quic_go_gso || echo 0)
skip_safe_path_check=$(uci -q get openclash.config.skip_safe_path_check || echo 0)
[ -z "$dns_port" ] && dns_port=7874 && uci -q set openclash.config.dns_port=7874
uci -q commit openclash
}
@@ -3057,7 +3059,6 @@ stop_service()
LOG_OUT "Step 6: Delete OpenClash Residue File..."
if [ "$enable" != "1" ]; then
rm -rf /tmp/clash_last_version >/dev/null 2>&1
rm -rf /tmp/Proxy_Group >/dev/null 2>&1
rm -rf /tmp/rules_name >/dev/null 2>&1
@@ -3067,6 +3068,7 @@ stop_service()
rm -rf /tmp/openclash.change >/dev/null 2>&1
rm -rf /tmp/openclash_debug.log >/dev/null 2>&1
rm -rf /tmp/openclash_edit_file_name >/dev/null 2>&1
rm -rf /tmp/openclash_announcement >/dev/null 2>&1
rm -rf ${DNSMASQ_CONF_DIR}/dnsmasq_openclash_chnroute_pass.conf >/dev/null 2>&1
rm -rf ${DNSMASQ_CONF_DIR}/dnsmasq_openclash_chnroute6_pass.conf >/dev/null 2>&1
rm -rf ${DNSMASQ_CONF_DIR}/dnsmasq_openclash_custom_domain.conf >/dev/null 2>&1

View File

@@ -0,0 +1,74 @@
#!/bin/bash
. /usr/share/openclash/openclash_ps.sh
. /usr/share/openclash/log.sh
. /usr/share/openclash/openclash_curl.sh
set_lock() {
exec 874>"/tmp/lock/openclash_geoasn.lock" 2>/dev/null
flock -x 874 2>/dev/null
}
del_lock() {
flock -u 874 2>/dev/null
rm -rf "/tmp/lock/openclash_geoasn.lock" 2>/dev/null
}
set_lock
small_flash_memory=$(uci get openclash.config.small_flash_memory 2>/dev/null)
GEOASN_CUSTOM_URL=$(uci get openclash.config.geoasn_custom_url 2>/dev/null)
github_address_mod=$(uci -q get openclash.config.github_address_mod || echo 0)
restart=0
if [ "$small_flash_memory" != "1" ]; then
geoasn_path="/etc/openclash/ASN.mmdb"
mkdir -p /etc/openclash
else
geoasn_path="/tmp/etc/openclash/ASN.mmdb"
mkdir -p /tmp/etc/openclash
fi
LOG_OUT "Start Downloading Geo ASN Database..."
if [ -z "$GEOASN_CUSTOM_URL" ]; then
if [ "$github_address_mod" != "0" ]; then
if [ "$github_address_mod" == "https://cdn.jsdelivr.net/" ] || [ "$github_address_mod" == "https://fastly.jsdelivr.net/" ] || [ "$github_address_mod" == "https://testingcf.jsdelivr.net/" ]; then
DOWNLOAD_URL="${github_address_mod}gh/xishang0128/geoip@release/GeoLite2-ASN.mmdb"
else
DOWNLOAD_URL="${github_address_mod}https://github.com/xishang0128/geoip/releases/latest/download/GeoLite2-ASN.mmdb"
fi
else
DOWNLOAD_URL="https://github.com/xishang0128/geoip/releases/latest/download/GeoLite2-ASN.mmdb"
fi
else
DOWNLOAD_URL=$GEOASN_CUSTOM_URL
fi
DOWNLOAD_FILE_CURL "$DOWNLOAD_URL" "/tmp/GeoLite2-ASN.mmdb"
if [ "$?" -eq 0 ] && [ -s "/tmp/GeoLite2-ASN.mmdb" ]; then
LOG_OUT "Geo ASN Database Download Success, Check Updated..."
cmp -s /tmp/GeoLite2-ASN.mmdb "$geoasn_path"
if [ "$?" -ne "0" ]; then
LOG_OUT "Geo ASN Database Has Been Updated, Starting To Replace The Old Version..."
rm -rf "/etc/openclash/GeoLite2-ASN.mmdb"
mv /tmp/GeoLite2-ASN.mmdb "$geoasn_path" >/dev/null 2>&1
LOG_OUT "Geo ASN Database Update Successful!"
restart=1
else
LOG_OUT "Updated Geo ASN Database No Change, Do Nothing..."
fi
else
LOG_OUT "Geo ASN Database Update Error, Please Try Again Later..."
fi
if [ "$restart" -eq 1 ] && [ "$(unify_ps_prevent)" -eq 0 ]; then
/etc/init.d/openclash restart >/dev/null 2>&1 &
elif [ "$restart" -eq 0 ] && [ "$(unify_ps_prevent)" -eq 0 ] && [ "$(uci -q get openclash.config.restart)" -eq 1 ]; then
/etc/init.d/openclash restart >/dev/null 2>&1 &
uci -q set openclash.config.restart=0
uci -q commit openclash
elif [ "$restart" -eq 1 ] && [ "$(unify_ps_prevent)" -eq 0 ]; then
uci -q set openclash.config.restart=1
uci -q commit openclash
fi
rm -rf /tmp/GeoLite2-ASN.mmdb >/dev/null 2>&1
SLOG_CLEAN
del_lock

View File

@@ -21,7 +21,7 @@ local unlock_cache_file = "/etc/openclash/history/streaming_unlock_cache"
local unlock_cache = FS.readfile(unlock_cache_file)
local unlock_cache_info = {}
if unlock_cache then
unlock_cache_info = JSON.parse(unlock_cache)
unlock_cache_info = JSON.parse(unlock_cache) or {}
end
local self_status = SYS.exec(string.format('ps -w |grep -v grep |grep -c "openclash_streaming_unlock.lua %s"', type))
local select_logic = UCI:get("openclash", "config", "stream_auto_select_logic") or "urltest"
@@ -146,18 +146,17 @@ function unlock_auto_select()
table.insert(tested_proxy, now_name)
group_match = true
--test now proxy
region, old_region = proxy_unlock_test()
region = proxy_unlock_test()
if table_include(groups, now_name) then
now = os.date("%Y-%m-%d %H:%M:%S").." "..type.." "..gorup_i18..""..group_show..""
else
now = os.date("%Y-%m-%d %H:%M:%S").." "..type.." "..gorup_i18..""..group_show..""..now_name..""
end
if status ~= 2 and status ~= 4 then
os.execute("sleep 3")
region, old_region = proxy_unlock_test()
region = proxy_unlock_test()
end
if status == 2 or status == 4 then
if region and region ~= "" then
if region ~= "" then
table.insert(full_support_list, {value.now, value.now, get_group_now(info, value.now), region})
print(now..full_support..""..region.."")
write_cache(type, get_group_now(info, value.now), region)
@@ -169,7 +168,7 @@ function unlock_auto_select()
if not all_test and #nodes_filter(now_name, info) ~= 0 then
if status == 4 then
status = 2
if region and region ~= "" then
if region ~= "" then
write_cache(type, "old_region", region)
end
end
@@ -181,7 +180,7 @@ function unlock_auto_select()
status = 0
end
elseif status == 3 then
if region and region ~= "" then
if region ~= "" then
table.insert(other_region_unlock, {value.now, value.now, get_group_now(info, value.now), region})
write_cache(type, get_group_now(info, value.now), region)
else
@@ -189,13 +188,13 @@ function unlock_auto_select()
write_cache(type, get_group_now(info, value.now))
end
if not all_test then
if region and region ~= "" then
if region ~= "" then
print(now..full_support..""..region..""..other_region_unlock_test_start)
else
print(now..full_support_no_area..other_region_unlock_test_start)
end
else
if region and region ~= "" then
if region ~= "" then
print(now..full_support..""..region..""..other_region_unlock_test)
else
print(now..full_support_no_area..other_region_unlock_test)
@@ -298,9 +297,9 @@ function unlock_auto_select()
break
else
SYS.exec(string.format("curl -sL -m 5 --retry 2 -w %%{http_code} -o /dev/null -H 'Authorization: Bearer %s' -H 'Content-Type:application/json' -X PUT -d '{\"name\":\"%s\"}' http://%s:%s/proxies/%s", passwd, proxy, ip, port, urlencode(group_name)))
region, old_region = proxy_unlock_test()
region = proxy_unlock_test()
if status == 2 then
if region and region ~= "" then
if region ~= "" then
table.insert(full_support_list, {value.all[i], group_name, proxy, region})
if not all_test then
print(now..full_support..""..region.."")
@@ -320,7 +319,7 @@ function unlock_auto_select()
write_cache(type, proxy)
end
elseif status == 3 then
if region and region ~= "" then
if region ~= "" then
table.insert(other_region_unlock, {value.all[i], group_name, proxy, region})
print(now..full_support..""..region..""..other_region_unlock_test)
write_cache(type, proxy, region)
@@ -330,7 +329,7 @@ function unlock_auto_select()
write_cache(type, proxy)
end
elseif status == 4 then
if region and region ~= "" then
if region ~= "" then
table.insert(no_old_region_unlock, {value.all[i], group_name, proxy, region})
print(now..full_support..""..region..""..no_old_region_unlock_old_region..""..old_region.."")
write_cache(type, proxy, region)
@@ -371,14 +370,14 @@ function unlock_auto_select()
else
table.insert(tested_proxy, now_name)
end
region, old_region = proxy_unlock_test()
region = proxy_unlock_test()
if table_include(groups, now_name) then
now = os.date("%Y-%m-%d %H:%M:%S").." "..type.." "..gorup_i18..""..group_show..""
else
now = os.date("%Y-%m-%d %H:%M:%S").." "..type.." "..gorup_i18..""..group_show..""..now_name..""
end
if status == 2 then
if region and region ~= "" then
if region ~= "" then
table.insert(full_support_list, {value.all[i], group_name, value.all[i], region})
if not all_test then
print(now..full_support..""..region.."")
@@ -398,7 +397,7 @@ function unlock_auto_select()
write_cache(type, value.all[i])
end
elseif status == 3 then
if region and region ~= "" then
if region ~= "" then
table.insert(other_region_unlock, {value.all[i], group_name, value.all[i], region})
print(now..full_support..""..region..""..other_region_unlock_no_select)
write_cache(type, value.all[i], region)
@@ -408,7 +407,7 @@ function unlock_auto_select()
write_cache(type, value.all[i])
end
elseif status == 4 then
if region and region ~= "" then
if region ~= "" then
table.insert(no_old_region_unlock, {value.all[i], group_name, value.all[i], region})
print(now..full_support..""..region..""..no_old_region_unlock_old_region..""..old_region..""..no_old_region_unlock_old_region_no_select)
write_cache(type, value.all[i], region)
@@ -504,9 +503,9 @@ function unlock_auto_select()
end
end
elseif #nodes_filter(get_group_now(info, value.name), info) ~= 0 then
region, old_region = proxy_unlock_test()
region = proxy_unlock_test()
if status == 2 then
if region and region ~= "" then
if region ~= "" then
if not all_test then
print(now..full_support..""..region.."")
end
@@ -521,13 +520,13 @@ function unlock_auto_select()
break
end
elseif status == 3 then
if region and region ~= "" then
if region ~= "" then
print(now..full_support..""..region..""..other_region_unlock_no_select)
else
print(now..full_support_no_area..other_region_unlock_no_select)
end
elseif status == 4 then
if region and region ~= "" then
if region ~= "" then
print(now..full_support..""..region..""..no_old_region_unlock_old_region..""..old_region..""..no_old_region_unlock_old_region_no_select)
else
print(now..full_support_no_area..no_old_region_unlock_no_select)
@@ -570,11 +569,8 @@ function get_old_region(stream_type)
if not stream_type then
stream_type = type
end
for k, v in pairs(unlock_cache_info) do
if v[1] == stream_type and v[2] == "old_region" and v[3] then
old_region = v[3]
break
end
if unlock_cache_info[stream_type] and unlock_cache_info[stream_type]["old_region"] then
return unlock_cache_info[stream_type]["old_region"]
end
return old_region
end
@@ -584,32 +580,25 @@ function get_old_regex(stream_type)
if not stream_type then
stream_type = type
end
for k, v in pairs(unlock_cache_info) do
if v[1] == stream_type and v[2] == "old_regex" and v[3] then
old_regex = v[3]
break
end
if unlock_cache_info[stream_type] and unlock_cache_info[stream_type]["old_regex"] then
return unlock_cache_info[stream_type]["old_regex"]
end
return old_regex
end
function write_cache(stream_type, node, region)
if not region then
region = ""
end
if not table_include(unlock_cache_info, {stream_type, node, region}) then
if table_include(unlock_cache_info, {stream_type, node, "cache"}) then
delete_cache(stream_type, node)
end
table.insert(unlock_cache_info, {stream_type, node, region})
function write_cache(stream_type, node, value)
if not value then
value = ""
end
if not unlock_cache_info[stream_type] then unlock_cache_info[stream_type] = {} end
if unlock_cache_info[stream_type][node] ~= value then
unlock_cache_info[stream_type][node] = value
end
end
function delete_cache(stream_type, node)
for k, v in pairs(unlock_cache_info) do
if v[1] == stream_type and v[2] == node then
table.remove(unlock_cache_info, k)
end
if unlock_cache_info[stream_type] and unlock_cache_info[stream_type][node] then
unlock_cache_info[stream_type][node] = nil
end
end
@@ -708,11 +697,8 @@ function table_sort_by_cache(t)
local tab = {}
local tab_b = {}
local old_region = get_old_region()
if old_region == "" then
old_region = "cache"
end
for n = 1, #(t) do
if table_include(unlock_cache_info, {type, t[n], old_region}) then
if unlock_cache_info and unlock_cache_info[type] and unlock_cache_info[type][t[n]] and unlock_cache_info[type][t[n]] == old_region then
table.insert(tab, t[n])
else
table.insert(tab_b, t[n])
@@ -735,9 +721,12 @@ function table_include(table, value)
if table_eq(v, value) then
return true
else
if v[1] == value[1] and v[2] == value[2] and value[3] == "cache" then
return true
for i = 1, #(v) do
if v[i] ~= value[i] then
return false
end
end
return true
end
else
if v == value then
@@ -863,33 +852,33 @@ function nodes_filter(t, info)
end
function proxy_unlock_test()
local region, old_region
local region = ""
if type == "Netflix" then
region, old_region = netflix_unlock_test()
region = netflix_unlock_test()
elseif type == "Disney Plus" then
region, old_region = disney_unlock_test()
region = disney_unlock_test()
elseif type == "HBO Max" then
region, old_region = hbo_max_unlock_test()
region = hbo_max_unlock_test()
elseif type == "YouTube Premium" then
region, old_region = ytb_unlock_test()
region = ytb_unlock_test()
elseif type == "TVB Anywhere+" then
region, old_region = tvb_anywhere_unlock_test()
region = tvb_anywhere_unlock_test()
elseif type == "Amazon Prime Video" then
region, old_region = prime_video_unlock_test()
region = prime_video_unlock_test()
elseif type == "DAZN" then
region, old_region = dazn_unlock_test()
region = dazn_unlock_test()
elseif type == "Paramount Plus" then
region, old_region = paramount_plus_unlock_test()
region = paramount_plus_unlock_test()
elseif type == "Discovery Plus" then
region, old_region = discovery_plus_unlock_test()
region = discovery_plus_unlock_test()
elseif type == "Bilibili" then
region, old_region = bilibili_unlock_test()
region = bilibili_unlock_test()
elseif type == "Google" then
region, old_region = google_not_cn_test()
region = google_not_cn_test()
elseif type == "OpenAI" then
region, old_region = openai_unlock_test()
region = openai_unlock_test()
end
return region, old_region
return region
end
function auto_get_policy_group(passwd, ip, port)
@@ -1113,7 +1102,7 @@ function netflix_unlock_test()
local headers = "User-Agent: "..UA
local info = SYS.exec(string.format('curl -sLI --connect-timeout 5 -m 5 --speed-time 5 --speed-limit 1 --retry 2 -o /dev/null -w %%{json} -H "Content-Type: application/json" -H "host: www.netflix.com" -H "accept-language: en-US,en;q=0.9" -H "sec-ch-ua: Google Chrome;v=125, Chromium;v=125, Not.A/Brand;v=24" -H "sec-ch-ua-mobile: ?0" -H "sec-ch-ua-platform: Windows" -H "sec-fetch-site: none" -H "sec-fetch-mode: navigate" -H "sec-fetch-user: ?1" -H "sec-fetch-dest: document" -H "%s" -XGET %s', headers, url))
local result = {}
local region
local region = ""
local old_region = get_old_region()
local old_regex = get_old_regex()
local regex = UCI:get("openclash", "config", "stream_auto_select_region_key_netflix") or ""
@@ -1124,9 +1113,8 @@ function netflix_unlock_test()
if info.http_code == 200 then
status = 2
string.gsub(info.url_effective, '[^/]+', function(w) table.insert(result, w) end)
region = string.upper(string.match(result[3], "^%a+"))
if region == "TITLE" then region = "US" end
if region then
if string.match(result[3], "^%a+") then
region = string.upper(string.match(result[3], "^%a+"))
if not datamatch(region, regex) then
status = 3
elseif old_regex ~= regex and not all_test then
@@ -1134,19 +1122,18 @@ function netflix_unlock_test()
elseif old_region ~= "" and region ~= old_region and not all_test then
status = 4
end
if status == 2 and not all_test and region ~= "" and region ~= old_region then
if status == 2 and not all_test and region ~= old_region then
write_cache(type, "old_region", region)
end
if status == 2 and not all_test and regex ~= old_regex then
write_cache(type, "old_regex", regex)
end
end
return region, old_region
elseif info.http_code == 404 or info.http_code == 403 then
status = 1
end
end
return
return region
end
function disney_unlock_test()
@@ -1157,7 +1144,8 @@ function disney_unlock_test()
local headers = '-H "Accept-Language: en" -H "Content-Type: application/json" -H "authorization: ZGlzbmV5JmJyb3dzZXImMS4wLjA.Cu56AgSfBTDag5NiRA81oLHkDZfu5L3CKadnefEAY84"'
local auth = '-H "authorization: Bearer ZGlzbmV5JmJyb3dzZXImMS4wLjA.Cu56AgSfBTDag5NiRA81oLHkDZfu5L3CKadnefEAY84"'
local body = '{"query":"mutation registerDevice($input: RegisterDeviceInput!) { registerDevice(registerDevice: $input) { grant { grantType assertion } } }","variables":{"input":{"deviceFamily":"browser","applicationRuntime":"chrome","deviceProfile":"windows","deviceLanguage":"en","attributes":{"osDeviceIds":[],"manufacturer":"microsoft","model":null,"operatingSystem":"windows","operatingSystemVersion":"10.0","browserName":"chrome","browserVersion":"96.0.4606"}}}}'
local region, assertion, data, preassertion, disneycookie, tokencontent
local region = ""
local assertion, data, preassertion, disneycookie, tokencontent
local regex = UCI:get("openclash", "config", "stream_auto_select_region_key_disney") or ""
local old_region = get_old_region()
local old_regex = get_old_regex()
@@ -1168,7 +1156,7 @@ function disney_unlock_test()
assertion = JSON.parse(preassertion).assertion
end
if not assertion then return end
if not assertion then return region end
disneycookie = "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Atoken-exchange&latitude=0&longitude=0&platform=browser&subject_token="..assertion.."&subject_token_type=urn%3Abamtech%3Aparams%3Aoauth%3Atoken-type%3Adevice"
tokencontent = SYS.exec(string.format("curl -sL --connect-timeout 5 -m 5 --speed-time 5 --speed-limit 1 --retry 2 %s -H 'User-Agent: %s' -d '%s' -XPOST %s", auth, UA, disneycookie, url2))
@@ -1176,7 +1164,7 @@ function disney_unlock_test()
if tokencontent and JSON.parse(tokencontent) then
if JSON.parse(tokencontent).error_description then
status = 1
return
return region
end
end
@@ -1184,8 +1172,8 @@ function disney_unlock_test()
if data and JSON.parse(data) then
status = 1
if JSON.parse(data).extensions and JSON.parse(data).extensions.sdk and JSON.parse(data).extensions.sdk.session then
region = JSON.parse(data).extensions.sdk.session.location.countryCode or ""
if JSON.parse(data).extensions and JSON.parse(data).extensions.sdk and JSON.parse(data).extensions.sdk.session and JSON.parse(data).extensions.sdk.session.location.countryCode then
region = JSON.parse(data).extensions.sdk.session.location.countryCode
inSupportedLocation = JSON.parse(data).extensions.sdk.session.inSupportedLocation or ""
if region == "JP" then
status = 2
@@ -1202,47 +1190,48 @@ function disney_unlock_test()
if status == 2 and not all_test and regex ~= old_regex then
write_cache(type, "old_regex", regex)
end
return region, old_region
return region
end
if region and region ~= "" and inSupportedLocation then
if region ~= "" and inSupportedLocation then
status = 2
if not datamatch(region, regex) then
status = 3
elseif old_region ~= "" and not datamatch(region, old_region) and not all_test then
status = 4
end
if status == 2 and not all_test and region ~= "" and region ~= old_region then
if status == 2 and not all_test and region ~= old_region then
write_cache(type, "old_region", region)
end
if status == 2 and not all_test and regex ~= old_regex then
write_cache(type, "old_regex", regex)
end
return region, old_region
return region
end
end
end
return
return region
end
function hbo_max_unlock_test()
status = 0
local url = "https://www.max.com/"
local data = SYS.exec(string.format("curl -sL --connect-timeout 5 -m 5 --speed-time 5 --speed-limit 1 --retry 2 -w '_TAG_%%{http_code}_TAG_' -H 'Content-Type: application/json' -H 'User-Agent: %s' %s", UA, url))
local result = {}
local region = ""
local outofregion
local old_region = get_old_region()
local old_regex = get_old_regex()
local regex = UCI:get("openclash", "config", "stream_auto_select_region_key_hbo_max") or ""
if data and tonumber(string.sub(string.match(data, "_TAG_%d+_TAG_"), 6, 8)) == 200 then
status = 1
for i in string.gmatch(data, "\"url\":\"/%a+/%a+\"") do
table.insert(result, string.sub(string.match(i, "/%a+/"), 2, -2))
if string.match(data, "\"isUserOutOfRegion\":%a+") then
outofregion = string.lower(string.sub(string.match(data, "\"isUserOutOfRegion\":%a+"), 21, -1))
end
region = string.sub(string.match(data, "\"countryCode\":\"%a+\""), 16, -2)
if region and table_include(result, region) then
if string.match(data, "\"userCountry\":\"%a+\"") then
region = string.upper(string.sub(string.match(data, "\"userCountry\":\"%a+\""), 16, -2))
end
if region ~= "" and outofregion == "false" then
status = 2
region = string.upper(region)
if not datamatch(region, regex) then
status = 3
elseif old_regex ~= regex and not all_test then
@@ -1250,16 +1239,15 @@ function hbo_max_unlock_test()
elseif old_region ~= "" and region ~= old_region and not all_test then
status = 4
end
if status == 2 and not all_test and region ~= "" and region ~= old_region then
if status == 2 and not all_test and region ~= old_region then
write_cache(type, "old_region", region)
end
if status == 2 and not all_test and regex ~= old_regex then
write_cache(type, "old_regex", regex)
end
return region, old_region
end
end
return
return region
end
function ytb_unlock_test()
@@ -1274,15 +1262,15 @@ function ytb_unlock_test()
if data and tonumber(string.sub(string.match(data, "_TAG_%d+_TAG_"), 6, 8)) == 200 then
status = 1
if string.find(data,"www%.google%.cn") or string.find(data, "is not available in your country") then
return
return region
end
region = string.sub(string.match(data, "\"GL\":\"%a+\""), 7, -2)
if region then
if string.match(data, "\"GL\":\"%a+\"") then
region = string.sub(string.match(data, "\"GL\":\"%a+\""), 7, -2)
status = 2
else
he_data = SYS.exec(string.format("curl -sIL --connect-timeout 5 -m 5 --speed-time 5 --speed-limit 1 --retry 2 -H 'Accept-Language: en' -H 'Content-Type: application/json' -H 'User-Agent: %s' %s", UA, url))
region = string.sub(string.match(he_data, "gl=%a+"), 4, -1)
if region then
if string.match(he_data, "gl=%a+") then
region = string.sub(string.match(he_data, "gl=%a+"), 4, -1)
status = 2
else
region = "US"
@@ -1302,7 +1290,7 @@ function ytb_unlock_test()
write_cache(type, "old_regex", regex)
end
end
return region, old_region
return region
end
function tvb_anywhere_unlock_test()
@@ -1321,7 +1309,7 @@ function tvb_anywhere_unlock_test()
if data.country then
region = string.upper(data.country)
end
if region then
if region ~= "" then
if not datamatch(region, regex) then
status = 3
elseif old_regex ~= regex and not all_test then
@@ -1329,7 +1317,7 @@ function tvb_anywhere_unlock_test()
elseif old_region ~= "" and region ~= old_region and not all_test then
status = 4
end
if status == 2 and not all_test and region ~= "" and region ~= old_region then
if status == 2 and not all_test and region ~= old_region then
write_cache(type, "old_region", region)
end
if status == 2 and not all_test and regex ~= old_regex then
@@ -1338,21 +1326,21 @@ function tvb_anywhere_unlock_test()
end
end
end
return region, old_region
return region
end
function prime_video_unlock_test()
status = 0
local url = "https://www.primevideo.com"
local region
local region = ""
local old_region = get_old_region()
local old_regex = get_old_regex()
local regex = UCI:get("openclash", "config", "stream_auto_select_region_key_prime_video") or ""
local data = SYS.exec(string.format("curl -sL --connect-timeout 5 -m 5 --speed-time 5 --speed-limit 1 --retry 2 -w '_TAG_%%{http_code}_TAG_' -H 'Accept-Language: en' -H 'Content-Type: application/json' -H 'User-Agent: %s' %s", UA, url))
if data and tonumber(string.sub(string.match(data, "_TAG_%d+_TAG_"), 6, 8)) == 200 then
status = 1
region = string.sub(string.match(data, "\"currentTerritory\":\"%a+\""), 21, -2)
if region then
if string.match(data, "\"currentTerritory\":\"%a+\"") then
region = string.sub(string.match(data, "\"currentTerritory\":\"%a+\""), 21, -2)
status = 2
if not datamatch(region, regex) then
status = 3
@@ -1361,22 +1349,21 @@ function prime_video_unlock_test()
elseif old_region ~= "" and region ~= old_region and not all_test then
status = 4
end
if status == 2 and not all_test and region ~= "" and region ~= old_region then
if status == 2 and not all_test and region ~= old_region then
write_cache(type, "old_region", region)
end
if status == 2 and not all_test and regex ~= old_regex then
write_cache(type, "old_regex", regex)
end
return region, old_region
end
end
return
return region
end
function dazn_unlock_test()
status = 0
local url = "https://startup.core.indazn.com/misl/v5/Startup"
local region
local region = ""
local old_region = get_old_region()
local old_regex = get_old_regex()
local regex = UCI:get("openclash", "config", "stream_auto_select_region_key_dazn") or ""
@@ -1389,7 +1376,7 @@ function dazn_unlock_test()
if data.Region.GeolocatedCountry then
region = string.upper(data.Region.GeolocatedCountry)
end
if region then
if region ~= "" then
if not datamatch(region, regex) then
status = 3
elseif old_regex ~= regex and not all_test then
@@ -1397,7 +1384,7 @@ function dazn_unlock_test()
elseif old_region ~= "" and region ~= old_region and not all_test then
status = 4
end
if status == 2 and not all_test and region ~= "" and region ~= old_region then
if status == 2 and not all_test and region ~= old_region then
write_cache(type, "old_region", region)
end
if status == 2 and not all_test and regex ~= old_regex then
@@ -1406,47 +1393,49 @@ function dazn_unlock_test()
end
end
end
return region, old_region
return region
end
function paramount_plus_unlock_test()
status = 0
local url = "https://www.paramountplus.com/"
local region
local region = ""
local old_region = get_old_region()
local old_regex = get_old_regex()
local regex = UCI:get("openclash", "config", "stream_auto_select_region_key_paramount_plus") or ""
local data = SYS.exec(string.format("curl -sL --connect-timeout 5 -m 5 --speed-time 5 --speed-limit 1 --retry 2 -w '_TAG_%%{http_code}_TAG_%%{url_effective}_TAGS_' -H 'Accept-Language: en' -H 'Content-Type: application/json' -H 'User-Agent: %s' %s", UA, url))
if data and tonumber(string.sub(string.match(data, "_TAG_%d+_TAG_"), 6, 8)) == 200 then
status = 1
if not string.find(string.match(data, "_TAG_[^\n]+_TAGS_"), "intl") then
status = 2
region = string.upper(string.sub(string.match(data, "\"siteEdition\":\"%a+|%a+\""), 19, -2)) or string.upper(string.sub(string.match(data, "property: '%a+'"), 12, -2))
if region then
if not datamatch(region, regex) then
status = 3
elseif old_regex ~= regex and not all_test then
status = 2
elseif old_region ~= "" and region ~= old_region and not all_test then
status = 4
if string.match(data, "_TAG_[^\n]+_TAGS_") then
if not string.find(string.match(data, "_TAG_[^\n]+_TAGS_"), "intl") then
status = 2
if string.match(data, "\"siteEdition\":\"%a+|%a+\"") or string.match(data, "property: '%a+'") then
region = string.upper(string.sub(string.match(data, "\"siteEdition\":\"%a+|%a+\""), 19, -2)) or string.upper(string.sub(string.match(data, "property: '%a+'"), 12, -2))
if not datamatch(region, regex) then
status = 3
elseif old_regex ~= regex and not all_test then
status = 2
elseif old_region ~= "" and region ~= old_region and not all_test then
status = 4
end
if status == 2 and not all_test and region ~= old_region then
write_cache(type, "old_region", region)
end
if status == 2 and not all_test and regex ~= old_regex then
write_cache(type, "old_regex", regex)
end
end
if status == 2 and not all_test and region ~= "" and region ~= old_region then
write_cache(type, "old_region", region)
end
if status == 2 and not all_test and regex ~= old_regex then
write_cache(type, "old_regex", regex)
end
return region, old_region
end
end
end
end
return region
end
function discovery_plus_unlock_test()
status = 0
local url = "https://us1-prod-direct.discoveryplus.com/token?deviceId=d1a4a5d25212400d1e6985984604d740&realm=go&shortlived=true"
local url1 = "https://us1-prod-direct.discoveryplus.com/users/me"
local region
local region = ""
local old_region = get_old_region()
local old_regex = get_old_regex()
local regex = UCI:get("openclash", "config", "stream_auto_select_region_key_discovery_plus") or ""
@@ -1456,9 +1445,10 @@ function discovery_plus_unlock_test()
token = JSON.parse(token).data.attributes.token
local cookie = string.format("-b \"_gcl_au=1.1.858579665.1632206782; _rdt_uuid=1632206782474.6a9ad4f2-8ef7-4a49-9d60-e071bce45e88; _scid=d154b864-8b7e-4f46-90e0-8b56cff67d05; _pin_unauth=dWlkPU1qWTRNR1ZoTlRBdE1tSXdNaTAwTW1Nd0xUbGxORFV0WWpZMU0yVXdPV1l6WldFeQ; _sctr=1|1632153600000; aam_fw=aam%%3D9354365%%3Baam%%3D9040990; aam_uuid=24382050115125439381416006538140778858; st=%s; gi_ls=0; _uetvid=a25161a01aa711ec92d47775379d5e4d; AMCV_BC501253513148ED0A490D45%%40AdobeOrg=-1124106680%%7CMCIDTS%%7C18894%%7CMCMID%%7C24223296309793747161435877577673078228%%7CMCAAMLH-1633011393%%7C9%%7CMCAAMB-1633011393%%7CRKhpRz8krg2tLO6pguXWp5olkAcUniQYPHaMWWgdJ3xzPWQmdj0y%%7CMCOPTOUT-1632413793s%%7CNONE%%7CvVersion%%7C5.2.0; ass=19ef15da-95d6-4b1d-8fa2-e9e099c9cc38.1632408400.1632406594\"", token)
local data = SYS.exec(string.format("curl -sL --connect-timeout 5 -m 5 --speed-time 5 --speed-limit 1 --retry 2 -H 'Accept-Language: en' -H 'Content-Type: application/json' -H 'User-Agent: %s' %s %s", UA, cookie, url1))
if data and JSON.parse(data) and JSON.parse(data).data and JSON.parse(data).data.attributes and JSON.parse(data).data.attributes.currentLocationSovereignTerritory then
region = string.upper(JSON.parse(data).data.attributes.currentLocationTerritory) or string.upper(JSON.parse(data).data.attributes.currentLocationSovereignTerritory)
if region then
if data and JSON.parse(data) and JSON.parse(data).data and JSON.parse(data).data.attributes and (JSON.parse(data).data.attributes.currentLocationSovereignTerritory or JSON.parse(data).data.attributes.currentLocationTerritory) then
region = JSON.parse(data).data.attributes.currentLocationTerritory or JSON.parse(data).data.attributes.currentLocationSovereignTerritory
if region ~= "" then
region = string.upper(region)
status = 2
if not datamatch(region, regex) then
status = 3
@@ -1467,22 +1457,23 @@ function discovery_plus_unlock_test()
elseif old_region ~= "" and region ~= old_region and not all_test then
status = 4
end
if status == 2 and not all_test and region ~= "" and region ~= old_region then
if status == 2 and not all_test and region ~= old_region then
write_cache(type, "old_region", region)
end
if status == 2 and not all_test and regex ~= old_regex then
write_cache(type, "old_regex", regex)
end
return region, old_region
end
end
end
return region
end
function bilibili_unlock_test()
status = 0
local randsession = SYS.exec("cat /dev/urandom 2>/dev/null | head -n 32 | md5sum | head -c 32")
local region, httpcode, data, url
local region = ""
local httpcode, data, url
local regex = UCI:get("openclash", "config", "stream_auto_select_region_key_bilibili") or "CN"
local old_region = get_old_region()
if regex == "HK/MO/TW" then
@@ -1491,7 +1482,7 @@ function bilibili_unlock_test()
elseif regex == "TW" then
url = string.format("https://api.bilibili.com/pgc/player/web/playurl?avid=50762638&cid=100279344&qn=0&type=&otype=json&ep_id=268176&fourk=1&fnver=0&fnval=16&session=%s&module=bangumi", randsession)
region = "TW"
elseif regex == "CN" then
else
url = string.format("https://api.bilibili.com/pgc/player/web/playurl?avid=82846771&qn=0&type=&otype=json&ep_id=307247&fourk=1&fnver=0&fnval=16&session=%s&module=bangumi", randsession)
region = "CN"
end
@@ -1505,22 +1496,22 @@ function bilibili_unlock_test()
if old_region ~= "" and region ~= old_region and not all_test then
status = 4
end
if status == 2 and not all_test and region ~= "" and region ~= old_region then
if status == 2 and not all_test and region ~= old_region then
write_cache(type, "old_region", region)
end
if status == 2 and not all_test and regex ~= old_regex then
write_cache(type, "old_regex", regex)
end
return region, old_region
end
end
end
return region
end
function google_not_cn_test()
status = 0
local url = "https://timeline.google.com"
local region
local region = ""
local httpcode = SYS.exec(string.format("curl -sL --connect-timeout 5 -m 5 --speed-time 5 --speed-limit 1 --retry 2 -o /dev/null -w %%{http_code} -H 'Accept-Language: en' -H 'Content-Type: application/json' -H 'User-Agent: %s' '%s'", UA, url))
if httpcode then
if tonumber(httpcode) == 200 then
@@ -1533,8 +1524,8 @@ function google_not_cn_test()
region = "CN"
status = 1
end
return region
end
return region
end
function openai_unlock_test()
@@ -1558,8 +1549,6 @@ function openai_unlock_test()
region_data = SYS.exec(string.format("curl -sL --connect-timeout 5 -m 5 --speed-time 5 --speed-limit 1 --retry 2 -H 'Accept-Language: en' -H 'Content-Type: application/json' -H 'User-Agent: %s' '%s'", UA, region_url))
if region_data and string.match(region_data, "loc=%a+") then
region = string.upper(string.sub(string.match(region_data, "loc=%a+"), 5, -1))
end
if region then
if not datamatch(region, regex) then
status = 3
elseif old_regex ~= regex and not all_test then
@@ -1567,7 +1556,7 @@ function openai_unlock_test()
elseif old_region ~= "" and region ~= old_region and not all_test then
status = 4
end
if status == 2 and not all_test and region ~= "" and region ~= old_region then
if status == 2 and not all_test and region ~= old_region then
write_cache(type, "old_region", region)
end
if status == 2 and not all_test and regex ~= old_regex then
@@ -1575,8 +1564,8 @@ function openai_unlock_test()
end
end
end
return region, old_region
end
return region
end
function network_test()

View File

@@ -45,19 +45,7 @@ if [ "$TIME" != "$CHTIME" ]; then
OP_LV=$(sed -n 1p $DOWNLOAD_FILE 2>/dev/null |awk -F 'v' '{print $2}' |awk -F '.' '{print $2$3}' 2>/dev/null)
if [ "$(expr "$OP_CV" \>= "$OP_LV")" = "1" ]; then
sed -i '/^https:/,$d' $DOWNLOAD_FILE
elif [ "$(expr "$OP_LV" \> "$OP_CV")" = "1" ] && [ -n "$OP_LV" ]; then
del_lock
exit 2
else
del_lock
exit 0
fi
fi
elif [ "$(expr "$OP_LV" \> "$OP_CV")" = "1" ] && [ -n "$OP_LV" ]; then
del_lock
exit 2
else
del_lock
exit 0
fi 2>/dev/null
fi
del_lock

View File

@@ -54,6 +54,7 @@ Discord语音,Discord-All.rules
饥荒-steam,Don't-Starve-steam.rules,Dont-Starve-steam.rules
刀塔霸业,Dota-Underlords.rules
DOTA2-日服,Dota2-jp.rules
精英-危险,Elite-Dangerous.rules
逃离塔科夫,Escape-from-Tarkov.rules
欧卡2所有分区-UU,Euro-Truck-Simulator-2.rules
Eve-online欧服,Eve-online.rules
@@ -68,6 +69,7 @@ FIFA20,FIFA20.rules
极限竞速地平线4,Forza-Horizon-4.rules
极限竞速地平线5,Forza-Horizon-5.rules
极限竞速7,Forza-Motorsport-7.rules
侠盗猎车手5,GTA-V.rules
基佬大乱斗Gang Beasts,Gang-Beasts.rules
原神-港澳台服,GenshinImpact.exe_SSTAP.rules
鹅鸭杀,Goose-Goose-Duck-HK.rules
@@ -97,6 +99,7 @@ Kurtzpel,Kurtzpel.rules
冒险岛,Maplestory-us.rules
心灵终结,MentalOmega.rules
微软模拟飞行年度版,Microsoft-Flight-Simulator-Game-Of-The-Year-Edition.rules
微软模拟飞行,Microsoft-Flight-Simulator.rules
巨硬商店,Microsoft-Srote.rules
我的世界-地下城,Minecraft-Dungeons.rules
传奇4-亚服,MIR4-asia.rules
@@ -109,6 +112,7 @@ NBA2K20,NBA2K20.rules
仁王,NIOH.rules
橘子客户端-UU,Origin.rules
Osu!,Osu!.rules
守望先锋2,Overwatch-2-Asia-Singapore.rules
守望先锋-亚服,Overwatch-Asia.rules
守望先锋-美服,Overwatch-US.rules
流亡黯道-国际服,Path Of Exile.rules
@@ -119,6 +123,7 @@ Osu!,Osu!.rules
实况足球-2018,Pro-Evolution-Soccer-2018.rules
实况足球-2019,Pro-Evolution-Soccer-2019.rules
绝地求生亚服&东南亚服,PUBG-Asia&-Southeast-Asia.rules
绝地求生亚服,PUBG-Asis.rules
绝地求生国际服,PUBG-INT.rules
绝地求生韩服,PUBG-kakao.rules
绝地求生低配版-Garena,PUBGLite-Garena.rules

View File

@@ -3,7 +3,7 @@ rules:
- RULE-SET,HTTPDNS,HTTPDNS
- RULE-SET,Special,DIRECT
- RULE-SET,Netflix,Netflix
- RULE-SET,Disney Plus,Disney
- RULE-SET,Disney Plus,Disney Plus
- RULE-SET,YouTube,YouTube
- RULE-SET,Max,Max
- RULE-SET,Spotify,Spotify
@@ -17,6 +17,7 @@ rules:
- RULE-SET,Youku,CN Mainland TV
- RULE-SET,Abema TV,Asian TV
- RULE-SET,Bahamut,Asian TV
- RULE-SET,DMM,Asian TV
- RULE-SET,Fox+,Asian TV
- RULE-SET,Hulu Japan,Asian TV
- RULE-SET,Japonx,Asian TV
@@ -40,10 +41,6 @@ rules:
- RULE-SET,PBS,Global TV
- RULE-SET,Pornhub,Global TV
- RULE-SET,Soundcloud,Global TV
- RULE-SET,Apple Music,Apple TV
- RULE-SET,Apple News,Apple TV
- RULE-SET,Apple TV,Apple TV
- RULE-SET,Apple,Apple
- RULE-SET,Telegram,Telegram
- RULE-SET,Crypto,Crypto
- RULE-SET,Discord,Discord
@@ -54,6 +51,11 @@ rules:
- RULE-SET,Scholar,Scholar
- RULE-SET,Speedtest,Speedtest
- RULE-SET,Steam,Steam
- RULE-SET,TikTok,TikTok
- RULE-SET,Apple Music,Apple TV
- RULE-SET,Apple News,Apple TV
- RULE-SET,Apple TV,Apple TV
- RULE-SET,Apple,Apple
- RULE-SET,miHoYo,miHoYo
- RULE-SET,PROXY,Proxy
- RULE-SET,Domestic,Domestic
@@ -242,6 +244,12 @@ rule-providers:
url: https://testingcf.jsdelivr.net/gh/dler-io/Rules@main/Clash/Provider/Media/Disney%20Plus.yaml
path: "./Rules/Media/Disney_Plus"
interval: 86400
DMM:
type: http
behavior: classical
url: https://testingcf.jsdelivr.net/gh/dler-io/Rules@main/Clash/Provider/Media/DMM.yaml
path: "./Rules/Media/DMM"
interval: 86400
encoreTVB:
type: http
behavior: classical
@@ -374,6 +382,12 @@ rule-providers:
url: https://testingcf.jsdelivr.net/gh/dler-io/Rules@main/Clash/Provider/Steam.yaml
path: "./Rules/Steam"
interval: 86400
TikTok:
type: http
behavior: classical
url: https://testingcf.jsdelivr.net/gh/dler-io/Rules@main/Clash/Provider/TikTok.yaml
path: "./Rules/TikTok"
interval: 86400
Speedtest:
type: http
behavior: classical

View File

@@ -345,8 +345,14 @@ threads << Thread.new {
Value['secret']='$2';
Value['bind-address']='*';
Value['external-ui']='/usr/share/openclash/ui';
Value['keep-alive-interval']=15;
Value['keep-alive-idle']=600;
Value['external-ui-name']='metacubexd';
if Value.key?('external-ui-url') then
Value.delete('external-ui-url');
end;
if not Value.key?('keep-alive-interval') and not Value.key?('keep-alive-idle') then
Value['keep-alive-interval']=15;
Value['keep-alive-idle']=600;
end;
if $6 == 1 then
Value['ipv6']=true;
else
@@ -467,6 +473,9 @@ threads << Thread.new {
if Value.key?('auto-redir') then
Value.delete('auto-redir');
end;
if Value.key?('geo-auto-update') then
Value['geo-auto-update']=false;
end;
rescue Exception => e
YAML.LOG('Error: Set General Failed,【' + e.message + '】');
end;

View File

@@ -222,6 +222,20 @@ ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e "
uci_commands << uci_set + 'policy_filter=\"' + x['filter'].to_s + '\"'
end
};
threads_g << Thread.new {
#interface-name
if x.key?('interface-name') then
uci_commands << uci_set + 'interface_name=\"' + x['interface-name'].to_s + '\"'
end
};
threads_g << Thread.new {
#routing-mark
if x.key?('routing-mark') then
uci_commands << uci_set + 'routing_mark=\"' + x['routing-mark'].to_s + '\"'
end
};
threads_g << Thread.new {
#other_group

View File

@@ -47,7 +47,7 @@ cfg_groups_set()
sed -i "s/new_servers_group \'${convert_old_name_cfg}\'/new_servers_group \'${convert_name}\'/g" $CFG_FILE 2>/dev/null
sed -i "s/relay_groups \'${convert_old_name_cfg}\'/relay_groups \'${convert_name}\'/g" $CFG_FILE 2>/dev/null
#第三方规则处理
OTHER_RULE_NAMES=("GlobalTV" "AsianTV" "MainlandTV" "Proxy" "Youtube" "Bilibili" "Bahamut" "HBOMax" "Pornhub" "Apple" "GoogleFCM" "Scholar" "Microsoft" "Netflix" "Disney" "Spotify" "Steam" "Speedtest" "Telegram" "PayPal" "Netease_Music" "AdBlock" "Domestic" "Others" "miHoYo" "AI_Suite" "AppleTV" "Crypto" "Discord" "HTTPDNS")
OTHER_RULE_NAMES=("GlobalTV" "AsianTV" "MainlandTV" "Proxy" "Youtube" "Bilibili" "Bahamut" "HBOMax" "Pornhub" "Apple" "GoogleFCM" "Scholar" "Microsoft" "Netflix" "Disney Plus" "Spotify" "Steam" "TikTok" "Speedtest" "Telegram" "PayPal" "Netease_Music" "AdBlock" "Domestic" "Others" "miHoYo" "AI_Suite" "AppleTV" "Crypto" "Discord" "HTTPDNS")
for i in ${OTHER_RULE_NAMES[@]}; do
sed -i "s/option ${i} \'${convert_old_name_cfg}\'/option ${i} \'${convert_name}\'/g" $CFG_FILE 2>/dev/null
done 2>/dev/null

View File

@@ -350,6 +350,12 @@ yml_groups_set()
[ -n "$policy_filter" ] && {
echo " filter: \"$policy_filter\"" >>$GROUP_FILE
}
[ -n "$interface_name" ] && {
echo " interface-name: \"$interface_name\"" >>$GROUP_FILE
}
[ -n "$routing_mark" ] && {
echo " routing-mark: \"$routing_mark\"" >>$GROUP_FILE
}
}
create_config=$(uci -q get openclash.config.create_config)

View File

@@ -730,7 +730,7 @@ ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e "
};
end;
#Mieru
#Mieru
if x['type'] == 'mieru' then
threads << Thread.new{
#port-range
@@ -761,6 +761,68 @@ ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e "
};
end;
#AnyTLS
if x['type'] == 'anytls' then
threads << Thread.new{
if x.key?('password') then
uci_commands << uci_set + 'password=\"' + x['password'].to_s + '\"'
end
};
threads << Thread.new{
#idle-session-check-interval
if x.key?('idle-session-check-interval') then
uci_commands << uci_set + 'idle_session_check_interval=\"' + x['idle-session-check-interval'].to_s + '\"'
end
};
threads << Thread.new{
#idle-session-timeout
if x.key?('idle-session-timeout') then
uci_commands << uci_set + 'idle_session_timeout=\"' + x['idle-session-timeout'].to_s + '\"'
end
};
threads << Thread.new{
#min-idle-session
if x.key?('min-idle-session') then
uci_commands << uci_set + 'min_idle_session=\"' + x['min-idle-session'].to_s + '\"'
end
};
threads << Thread.new{
#alpn
if x.key?('alpn') then
alpn = uci_del + 'alpn >/dev/null 2>&1'
system(alpn)
x['alpn'].each{
|x|
uci_commands << uci_add + 'alpn=\"' + x.to_s + '\"'
}
end
};
threads << Thread.new{
#sni
if x.key?('sni') then
uci_commands << uci_set + 'sni=\"' + x['sni'].to_s + '\"'
end
};
#skip-cert-verify
if x.key?('skip-cert-verify') then
uci_commands << uci_set + 'skip_cert_verify=\"' + x['skip-cert-verify'].to_s + '\"'
end
};
threads << Thread.new{
#client_fingerprint
if x.key?('client-fingerprint') then
uci_commands << uci_set + 'client_fingerprint=\"' + x['client-fingerprint'].to_s + '\"'
end
};
end;
#Tuic
if x['type'] == 'tuic' then
threads << Thread.new{
@@ -1266,6 +1328,56 @@ ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e "
};
end;
if x['type'] == 'ssh' then
threads << Thread.new{
if x.key?('username') then
uci_commands << uci_set + 'auth_name=\"' + x['username'].to_s + '\"'
end
};
threads << Thread.new{
if x.key?('password') then
uci_commands << uci_set + 'auth_pass=\"' + x['password'].to_s + '\"'
end
};
threads << Thread.new{
if x.key?('private-key') then
uci_commands << uci_set + 'private_key=\"' + x['private-key'].to_s + '\"'
end
};
threads << Thread.new{
if x.key?('private-key-passphrase') then
uci_commands << uci_set + 'private_key_passphrase=\"' + x['private-key-passphrase'].to_s + '\"'
end
};
threads << Thread.new{
#host-key-algorithms
if x.key?('host-key-algorithms') then
host_key_algorithms = uci_del + 'host_key_algorithms >/dev/null 2>&1'
system(host_key_algorithms)
x['host-key-algorithms'].each{
|x|
uci_commands << uci_add + 'host_key_algorithms=\"' + x.to_s + '\"'
}
end
};
threads << Thread.new{
#host-key
if x.key?('host-key') then
host_key = uci_del + 'host_key >/dev/null 2>&1'
system(host_key)
x['host-key'].each{
|x|
uci_commands << uci_add + 'host_key=\"' + x.to_s + '\"'
}
end
};
end;
if x['type'] == 'socks5' or x['type'] == 'http' then
threads << Thread.new{
if x.key?('username') then

View File

@@ -335,10 +335,11 @@ yml_other_set()
.gsub(/,[\s]?Apple TV$/, ',$AppleTV#delete_')
.gsub(/,[\s]?Scholar$/, ',$Scholar#delete_')
.gsub(/,[\s]?Netflix$/, ',$Netflix#delete_')
.gsub(/,[\s]?Disney$/, ',$Disney#delete_')
.gsub(/,[\s]?Disney Plus$/, ',$Disney#delete_')
.gsub(/,[\s]?Spotify$/, ',$Spotify#delete_')
.gsub(/,[\s]?AI Suite$/, ',$AI_Suite#delete_')
.gsub(/,[\s]?Steam$/, ',$Steam#delete_')
.gsub(/,[\s]?TikTok$/, ',$TikTok#delete_')
.gsub(/,[\s]?miHoYo$/, ',$miHoYo#delete_')
.gsub(/,[\s]?AdBlock$/, ',$AdBlock#delete_')
.gsub(/,[\s]?HTTPDNS$/, ',$HTTPDNS#delete_')
@@ -435,7 +436,7 @@ yml_other_set()
end;
end;
Value['rules'].to_a.collect!{|x|x.to_s
.gsub(/GEOIP,([^,]+),([^,]+)(,.*)?/, 'GEOIP,\1,DIRECT\3')
.gsub(/GEOIP,([A-Z]{2}),([^,]+)(,.*)?/, 'GEOIP,\1,DIRECT\3')
.gsub(/(^MATCH.*|^FINAL.*)/, 'MATCH,DIRECT')};
end;
rescue Exception => e
@@ -952,6 +953,7 @@ yml_other_rules_get()
config_get "Disney" "$section" "Disney" ""
config_get "Spotify" "$section" "Spotify" ""
config_get "Steam" "$section" "Steam" ""
config_get "TikTok" "$section" "TikTok" "$GlobalTV"
config_get "AdBlock" "$section" "AdBlock" ""
config_get "HTTPDNS" "$section" "HTTPDNS" "REJECT"
config_get "Netease_Music" "$section" "Netease_Music" ""
@@ -1004,6 +1006,7 @@ if [ "$1" != "0" ]; then
|| [ -z "$(grep -F "$AI_Suite" /tmp/Proxy_Group)" ]\
|| [ -z "$(grep -F "$Spotify" /tmp/Proxy_Group)" ]\
|| [ -z "$(grep -F "$Steam" /tmp/Proxy_Group)" ]\
|| [ -z "$(grep -F "$TikTok" /tmp/Proxy_Group)" ]\
|| [ -z "$(grep -F "$miHoYo" /tmp/Proxy_Group)" ]\
|| [ -z "$(grep -F "$AdBlock" /tmp/Proxy_Group)" ]\
|| [ -z "$(grep -F "$HTTPDNS" /tmp/Proxy_Group)" ]\

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M228.54,86.66l-176.06-54A16,16,0,0,0,32,48V192a16,16,0,0,0,16,16,16,16,0,0,0,4.52-.65L136,181.73V192a16,16,0,0,0,16,16h32a16,16,0,0,0,16-16v-29.9l28.54-8.75A16.09,16.09,0,0,0,240,138V102A16.09,16.09,0,0,0,228.54,86.66ZM136,165,48,192V48l88,27Zm48,27H152V176.82L184,167Zm40-54-.11,0L152,160.08V79.92l71.89,22,.11,0v36Z"></path></svg>

After

Width:  |  Height:  |  Size: 441 B