🦄 Sync 2026-06-05 01:27:09

This commit is contained in:
github-actions[bot]
2026-06-05 01:27:09 +08:00
parent 2f80691f7d
commit f8db3e79f6
64 changed files with 75620 additions and 81561 deletions
+175 -116
View File
@@ -665,8 +665,12 @@ function get_sub_url(filename)
string.gsub(s.url, '[^\n]+', function(w) table.insert(info_tb, w) end)
end
if #info_tb == 1 then
local url, _ = parse_url_with_name(info_tb[1], filename)
sub_url = url
local url, name = parse_url_with_name(info_tb[1], filename)
if url ~= info_tb[1] then
table.insert(providers, {name = name, url = url})
else
sub_url = url
end
elseif #info_tb > 1 then
for _, raw in ipairs(info_tb) do
local url, name = parse_url_with_name(raw, filename)
@@ -798,7 +802,7 @@ function sub_info_get()
if #providers_data == 0 then
if not url_result then
luci.http.status(400, "Subscription information not found")
luci.http.status(500, "Subscription information not found")
return
end
end
@@ -841,7 +845,7 @@ function action_switch_rule_mode()
mode = luci.http.formvalue("rule_mode")
if not mode then
luci.http.status(400, "Missing parameters")
luci.http.status(500, "Missing parameters")
return
end
@@ -1098,7 +1102,7 @@ end
function action_default_dashboard()
local default_dashboard = luci.http.formvalue("name")
if not default_dashboard or (default_dashboard ~= "Dashboard" and default_dashboard ~= "Yacd" and default_dashboard ~= "Metacubexd" and default_dashboard ~= "Zashboard") then
luci.http.status(400, "Set Failed")
luci.http.status(500, "Set Failed")
return
end
if not fs.isdirectory("/usr/share/openclash/ui/" .. string.lower(default_dashboard)) then
@@ -1644,6 +1648,13 @@ function rename_file()
uci:set("openclash", s[".name"], "name", fs.filename(new_file_name))
end
end)
uci:foreach("openclash", "subscribe_info",
function(s)
if s.name == fs.filename(old_file_name) and fs.filename(new_file_name) ~= new_file_name then
uci:set("openclash", s[".name"], "name", fs.filename(new_file_name))
end
end)
uci:foreach("openclash", "groups",
function(s)
@@ -2073,114 +2084,101 @@ function action_myip_check()
luci.http.write_json(result)
end
function action_website_check()
local domain = luci.http.formvalue("domain")
local result = {
success = false,
response_time = 0,
error = ""
}
function latency_test(addr)
local result = { success = false, response_time = 0, error = "" }
if not domain then
if not addr then
result.error = "Missing domain parameter"
luci.http.prepare_content("application/json")
luci.http.write_json(result)
return
return result
end
local test_domain = domain
local test_url
if test_domain:match("^https?://") then
test_domain = test_domain:gsub("^https?://([^/]+)/?.*$", "%1")
if addr:match("^https?://") then
addr = addr:gsub("^https?://([^/]+)/?.*$", "%1")
end
if domain == "https://raw.githubusercontent.com/" or test_domain == "raw.githubusercontent.com" then
test_url = "https://raw.githubusercontent.com/vernesong/OpenClash/dev/img/logo.png"
local urls = {}
if addr == "raw.githubusercontent.com" then
table.insert(urls, "https://raw.githubusercontent.com/vernesong/OpenClash/dev/img/logo.png")
else
test_url = "https://" .. test_domain .. "/favicon.ico"
table.insert(urls, "https://" .. addr .. "/favicon.ico")
end
local cmd = string.format(
'curl -sL -m 5 --connect-timeout 3 --retry 2 -w "%%{http_code},%%{time_total},%%{time_connect},%%{time_appconnect}" "%s" -o /dev/null 2>/dev/null',
test_url
)
table.insert(urls, "https://" .. addr)
local output = luci.sys.exec(cmd)
for i, test_url in ipairs(urls) do
local cmd = string.format(
'curl -sI -m 5 --connect-timeout 3 --retry 2 -w "%%{http_code},%%{time_total},%%{time_connect},%%{time_appconnect}" "%s" -o /dev/null 2>/dev/null',
test_url
)
if output and output ~= "" then
local http_code, time_total, time_connect, time_appconnect = output:match("(%d+),([%d%.]+),([%d%.]+),([%d%.]+)")
local output = luci.sys.exec(cmd)
if output and output ~= "" then
local http_code, time_total, time_connect, time_appconnect =
output:match("(%d+),([%d%.]+),([%d%.]+),([%d%.]+)")
if http_code and tonumber(http_code) then
local code = tonumber(http_code)
local response_time = 0
if time_appconnect and tonumber(time_appconnect) and tonumber(time_appconnect) > 0 then
response_time = math.floor(tonumber(time_appconnect) * 1000)
elseif time_connect and tonumber(time_connect) then
response_time = math.floor(tonumber(time_connect) * 1000)
else
response_time = math.floor((tonumber(time_total) or 0) * 1000)
if not http_code then
http_code, time_total, time_appconnect = output:match("(%d+),([%d%.]+),([%d%.]+)")
time_connect = nil
end
if code >= 200 and code < 400 then
result.success = true
result.response_time = response_time
elseif code == 403 or code == 404 then
result.success = true
result.response_time = response_time
else
local fallback_url
if domain == "https://raw.githubusercontent.com/" or test_domain == "raw.githubusercontent.com" then
fallback_url = "https://raw.githubusercontent.com/vernesong/OpenClash/dev/img/logo.png"
if http_code and tonumber(http_code) then
local code = tonumber(http_code)
local response_time = 0
if time_appconnect and tonumber(time_appconnect) and tonumber(time_appconnect) > 0 then
response_time = math.floor(tonumber(time_appconnect) * 1000)
elseif time_connect and tonumber(time_connect) and tonumber(time_connect) > 0 then
response_time = math.floor(tonumber(time_connect) * 1000)
else
fallback_url = "https://" .. test_domain .. "/"
response_time = math.floor((tonumber(time_total) or 0) * 1000)
end
local fallback_cmd = string.format(
'curl -sI -m 5 --connect-timeout 3 -w "%%{http_code},%%{time_total},%%{time_appconnect}" "%s" -o /dev/null 2>/dev/null',
fallback_url
)
local fallback_output = luci.sys.exec(fallback_cmd)
if fallback_output and fallback_output ~= "" then
local fb_code, fb_total, fb_appconnect = fallback_output:match("(%d+),([%d%.]+),([%d%.]+)")
if fb_code and tonumber(fb_code) then
local fb_code_num = tonumber(fb_code)
local fb_response_time = 0
if fb_appconnect and tonumber(fb_appconnect) and tonumber(fb_appconnect) > 0 then
fb_response_time = math.floor(tonumber(fb_appconnect) * 1000)
else
fb_response_time = math.floor((tonumber(fb_total) or 0) * 1000)
end
if fb_code_num >= 200 and fb_code_num < 400 then
result.success = true
result.response_time = fb_response_time
elseif fb_code_num == 403 or fb_code_num == 404 then
result.success = true
result.response_time = fb_response_time
else
result.success = false
result.error = "HTTP " .. fb_code_num
result.response_time = fb_response_time
end
else
result.success = false
result.error = "Connection failed"
end
if (code >= 200 and code < 400) or code == 403 or code == 404 then
result.success = true
result.response_time = response_time
return result
else
if i == #urls then
result.success = false
result.error = "HTTP " .. code
result.response_time = response_time
return result
end
end
else
if i == #urls then
result.success = false
result.error = "Connection failed"
result.error = "Invalid response"
return result
end
end
else
result.success = false
result.error = "Invalid response"
if i == #urls then
result.success = false
result.error = "No response"
return result
end
end
else
result.success = false
result.error = "No response"
end
return result
end
function action_website_check()
local domain = luci.http.formvalue("domain")
if not domain then
luci.http.prepare_content("application/json")
luci.http.write_json({
success = false,
response_time = 0,
error = "Missing domain parameter"
})
return
end
local result = latency_test(domain)
luci.http.prepare_content("application/json")
luci.http.write_json(result)
end
@@ -2257,7 +2255,7 @@ function action_switch_oc_setting()
local value = luci.http.formvalue("value")
if not setting or not value then
luci.http.status(400, "Missing parameters")
luci.http.status(500, "Missing parameters")
return
end
@@ -2455,9 +2453,16 @@ function action_switch_oc_setting()
uci:set("openclash", "@overwrite[0]", "enable_respect_rules", tonumber(value))
uci:commit("openclash")
elseif setting == "oversea" then
oversea_v6_setting = fs.uci_get_config("config", "ipv6_enable") or "0"
if oversea_v6_setting ~= "0" then
uci:set("openclash", "config", "china_ip6_route", value)
end
uci:set("openclash", "config", "china_ip_route", value)
uci:commit("openclash")
if is_running() then
if oversea_v6_setting ~= "0" then
uci:set("openclash", "@overwrite[0]", "china_ip6_route", value)
end
uci:set("openclash", "@overwrite[0]", "china_ip_route", value)
uci:commit("openclash")
luci.sys.exec("/etc/init.d/openclash restart >/dev/null 2>&1 &")
@@ -2490,7 +2495,7 @@ function action_switch_oc_setting()
end
uci:commit("openclash")
else
luci.http.status(400, "Invalid setting")
luci.http.status(500, "Invalid setting")
return
end
@@ -2910,14 +2915,14 @@ function action_oc_action()
local config_file = luci.http.formvalue("config_file")
if not action then
luci.http.status(400, "Missing action parameter")
luci.http.status(500, "Missing action parameter")
return
end
if config_file and config_file ~= "" then
local config_path = "/etc/openclash/config/" .. config_file
if not fs.access(config_path) then
luci.http.status(404, "Config file not found")
luci.http.status(500, "Config file not found")
return
end
@@ -2952,7 +2957,7 @@ function action_oc_action()
luci.sys.call("ps | grep openclash | grep -v grep | awk '{print $1}' | xargs -r kill -9 >/dev/null 2>&1")
luci.sys.call("/etc/init.d/openclash restart >/dev/null 2>&1")
else
luci.http.status(400, "Invalid action parameter")
luci.http.status(500, "Invalid action parameter")
return
end
@@ -3111,7 +3116,7 @@ function action_config_file_read()
local config_file = luci.http.formvalue("config_file")
if not config_file then
luci.http.status(400, "Missing config_file parameter")
luci.http.status(500, "Missing config_file parameter")
return
end
@@ -3202,12 +3207,12 @@ function action_config_file_save()
end
if not config_file then
luci.http.status(400, "Missing config_file parameter")
luci.http.status(500, "Missing config_file parameter")
return
end
if not content then
luci.http.status(400, "Missing content parameter")
luci.http.status(500, "Missing content parameter")
return
end
@@ -3323,7 +3328,7 @@ end
function action_add_subscription()
local name = luci.http.formvalue("name")
local address = luci.http.formvalue("address")
local sub_ua = luci.http.formvalue("sub_ua") or "clash.meta"
local sub_ua = luci.http.formvalue("sub_ua") or "clash-verge/v2.4.5"
local sub_convert = luci.http.formvalue("sub_convert") or "0"
local convert_address = luci.http.formvalue("convert_address") or ""
local template = luci.http.formvalue("template") or ""
@@ -3351,9 +3356,10 @@ function action_add_subscription()
local is_valid_url = false
if sub_convert == "1" then
if string.find(address, "^https?://") and not string.find(address, "\n") and not string.find(address, "|") then
is_valid_url = true
elseif string.find(address, "\n") or string.find(address, "|") then
local prefixed_http_pattern = "^[^,%s]+,https?://.+"
local encoded_prefixed_http_pattern = "^[^%%%s]+%%2[Cc]https?%%3[Aa]%%2[Ff]%%2[Ff].+"
if string.find(address, "\n") or string.find(address, "|") then
local links = {}
if string.find(address, "\n") then
for line in address:gmatch("[^\n]+") do
@@ -3367,15 +3373,20 @@ function action_add_subscription()
for _, link in ipairs(links) do
if link and link ~= "" then
if string.find(link, "^https?://") or string.find(link, "^[a-zA-Z]+://") then
if string.find(link, "^https?://")
or string.find(link, "^[a-zA-Z]+://")
or string.find(link, prefixed_http_pattern)
or string.find(link, encoded_prefixed_http_pattern) then
is_valid_url = true
break
end
end
end
else
if string.find(address, "^[a-zA-Z]+://") and
not string.find(address, "\n") and not string.find(address, "|") then
if string.find(address, "^https?://")
or string.find(address, "^[a-zA-Z]+://")
or string.find(address, prefixed_http_pattern)
or string.find(address, encoded_prefixed_http_pattern) then
is_valid_url = true
end
end
@@ -3467,9 +3478,7 @@ function action_add_subscription()
end
end
if #params > 0 then
for i, param in ipairs(params) do
uci:set_list("openclash", section_id, "custom_params", param)
end
uci:set_list("openclash", section_id, "custom_params", params)
end
end
@@ -3483,9 +3492,7 @@ function action_add_subscription()
end
end
if #keywords > 0 then
for i, kw in ipairs(keywords) do
uci:set_list("openclash", section_id, "keyword", kw)
end
uci:set_list("openclash", section_id, "keyword", keywords)
end
end
@@ -3499,9 +3506,7 @@ function action_add_subscription()
end
end
if #ex_keywords > 0 then
for i, ex_kw in ipairs(ex_keywords) do
uci:set_list("openclash", section_id, "ex_keyword", ex_kw)
end
uci:set_list("openclash", section_id, "ex_keyword", ex_keywords)
end
end
@@ -3530,6 +3535,16 @@ end
function action_upload_overwrite()
local upload = luci.http.formvalue("config_file")
local filename = luci.http.formvalue("filename")
local config_values = {}
local raw_config = luci.http.formvalue("config") or ""
if raw_config ~= "" then
for line in raw_config:gmatch("[^\n]+") do
local config_value = line:match("^%s*(.-)%s*$")
if config_value and config_value ~= "" then
table.insert(config_values, config_value)
end
end
end
local enable = luci.http.formvalue("enable")
local order = luci.http.formvalue("order")
luci.http.prepare_content("application/json")
@@ -3575,6 +3590,10 @@ function action_upload_overwrite()
uci:foreach("openclash", "config_overwrite", function(s)
if s.name == section_name then
found = true
uci:delete("openclash", s[".name"], "config")
if #config_values > 0 then
uci:set_list("openclash", s[".name"], "config", config_values)
end
if s.enable == nil or (s.enable ~= nil and enable ~= nil) then
if enable == nil then
enable = 0
@@ -3600,6 +3619,10 @@ function action_upload_overwrite()
local sid = uci:add("openclash", "config_overwrite")
uci:set("openclash", sid, "name", section_name)
uci:set("openclash", sid, "type", "file")
uci:delete("openclash", sid, "config")
if #config_values > 0 then
uci:set_list("openclash", sid, "config", config_values)
end
if enable ~= nil then
uci:set("openclash", sid, "enable", tostring(enable))
else
@@ -3657,8 +3680,22 @@ function action_overwrite_subscribe_info()
local result = {}
uci:foreach("openclash", "config_overwrite", function(s)
if s.name then
local config_value = ""
if s.config then
local config_list = {}
for _, item in ipairs(s.config) do
if item and item ~= "" then
table.insert(config_list, tostring(item))
end
end
if #config_list > 0 then
config_value = config_list
end
end
result[s.name] = {
url = s.url or "",
config = config_value,
update_days = s.update_days or "",
update_hour = s.update_hour or "",
order = tonumber(s.order) or 0,
@@ -3673,7 +3710,7 @@ function action_overwrite_subscribe_info()
return
elseif method == "POST" then
if not section_name then
luci.http.status(400, "Missing filename")
luci.http.status(500, "Missing filename")
return
end
local url = luci.http.formvalue("url") or ""
@@ -3681,6 +3718,16 @@ function action_overwrite_subscribe_info()
local update_hour = luci.http.formvalue("update_hour") or ""
local order = luci.http.formvalue("order")
local param = luci.http.formvalue("param") or ""
local config_values = {}
local raw_config = luci.http.formvalue("config") or ""
if raw_config ~= "" then
for line in raw_config:gmatch("[^\n]+") do
local config_value = line:match("^%s*(.-)%s*$")
if config_value and config_value ~= "" then
table.insert(config_values, config_value)
end
end
end
typ = luci.http.formvalue("type") or typ or "file"
local enable = luci.http.formvalue("enable")
@@ -3713,6 +3760,10 @@ function action_overwrite_subscribe_info()
if s.name == old_section_name then
uci:set("openclash", s[".name"], "name", section_name)
uci:set("openclash", s[".name"], "url", url)
uci:delete("openclash", s[".name"], "config")
if #config_values > 0 then
uci:set_list("openclash", s[".name"], "config", config_values)
end
uci:set("openclash", s[".name"], "update_days", update_days)
uci:set("openclash", s[".name"], "update_hour", update_hour)
uci:set("openclash", s[".name"], "type", typ)
@@ -3754,6 +3805,10 @@ function action_overwrite_subscribe_info()
uci:foreach("openclash", "config_overwrite", function(s)
if s.name == section_name then
uci:set("openclash", s[".name"], "url", url)
uci:delete("openclash", s[".name"], "config")
if #config_values > 0 then
uci:set_list("openclash", s[".name"], "config", config_values)
end
uci:set("openclash", s[".name"], "update_days", update_days)
uci:set("openclash", s[".name"], "update_hour", update_hour)
uci:set("openclash", s[".name"], "type", typ)
@@ -3785,6 +3840,10 @@ function action_overwrite_subscribe_info()
local sid = uci:add("openclash", "config_overwrite")
uci:set("openclash", sid, "name", section_name)
uci:set("openclash", sid, "url", url)
uci:delete("openclash", sid, "config")
if #config_values > 0 then
uci:set_list("openclash", sid, "config", config_values)
end
uci:set("openclash", sid, "update_days", update_days)
uci:set("openclash", sid, "update_hour", update_hour)
uci:set("openclash", sid, "type", typ)
@@ -3835,7 +3894,7 @@ function action_overwrite_subscribe_info()
luci.http.write_json({status="success"})
return
else
luci.http.status(405, "Method Not Allowed")
luci.http.status(500, "Method Not Allowed")
end
end
@@ -3923,7 +3982,7 @@ end
function action_get_subscribe_data()
local filename = luci.http.formvalue("filename")
if not filename then
luci.http.status(400, "Bad Request")
luci.http.status(500, "Bad Request")
return
end
@@ -3941,7 +4000,7 @@ end
function action_get_subscribe_info_data()
local filename = luci.http.formvalue("filename")
if not filename then
luci.http.status(400, "Bad Request")
luci.http.status(500, "Bad Request")
return
end
luci.http.prepare_content("application/json")