💋 Sync 2026-06-26 20:45:50

This commit is contained in:
github-actions[bot] committed 2026-06-26 20:45:50 +08:00
1 parent abfd0b6422
commit a09b205472
20 files changed
+369 -71

No files matched your search

+3 -3
View File
@@ -5,12 +5,12 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=cloudreve PKG_NAME:=cloudreve
PKG_VERSION:=4.16.1 PKG_VERSION:=4.17.0
PKG_RELEASE:=12 PKG_RELEASE:=13
PKG_SOURCE_PROTO:=git PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://github.com/cloudreve/Cloudreve.git PKG_SOURCE_URL:=https://github.com/cloudreve/Cloudreve.git
PKG_SOURCE_VERSION:=ba2e870bbd17f1918dd2321de861e453f696d6a3 PKG_SOURCE_VERSION:=d4a145c3ac68f08b9071dec0f2ac025c6dc7362d
PKG_MIRROR_HASH:=skip PKG_MIRROR_HASH:=skip
PKG_LICENSE:=GPL-3.0-only PKG_LICENSE:=GPL-3.0-only
+1 -1
View File
@@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall PKG_NAME:=luci-app-passwall
PKG_VERSION:=26.6.2 PKG_VERSION:=26.6.2
PKG_RELEASE:=166 PKG_RELEASE:=167
PKG_PO_VERSION:=$(PKG_VERSION) PKG_PO_VERSION:=$(PKG_VERSION)
PKG_CONFIG_DEPENDS:= \ PKG_CONFIG_DEPENDS:= \
@@ -76,6 +76,20 @@ o.rewrite_option = o.option
o:depends({ [_n("obfs_type")] = "salamander" }) o:depends({ [_n("obfs_type")] = "salamander" })
o:depends({ [_n("obfs_type")] = "gecko" }) o:depends({ [_n("obfs_type")] = "gecko" })
o = s:option(Value, _n("obfs_MinPacketSize"), translate("Gecko Packet Size (min)"))
o.datatype = "uinteger"
o.placeholder = "512"
o.default = "512"
o:depends({ [_n("obfs_type")] = "gecko" })
o.rewrite_option = o.option
o = s:option(Value, _n("obfs_MaxPacketSize"), translate("Gecko Packet Size (max)"))
o.datatype = "uinteger"
o.placeholder = "1200"
o.default = "1200"
o:depends({ [_n("obfs_type")] = "gecko" })
o.rewrite_option = o.option
o = s:option(Flag, _n("fast_open"), translate("Fast Open")) o = s:option(Flag, _n("fast_open"), translate("Fast Open"))
o.default = "0" o.default = "0"
@@ -376,6 +376,18 @@ o = s:option(Value, _n("hysteria2_obfs_password"), translate("Obfs Password"))
o:depends({ [_n("hysteria2_obfs_type")] = "salamander" }) o:depends({ [_n("hysteria2_obfs_type")] = "salamander" })
o:depends({ [_n("hysteria2_obfs_type")] = "gecko" }) o:depends({ [_n("hysteria2_obfs_type")] = "gecko" })
o = s:option(Value, _n("hysteria2_obfs_MinPacketSize"), translate("Gecko Packet Size (min)"))
o.datatype = "uinteger"
o.placeholder = "512"
o.default = "512"
o:depends({ [_n("hysteria2_obfs_type")] = "gecko" })
o = s:option(Value, _n("hysteria2_obfs_MaxPacketSize"), translate("Gecko Packet Size (max)"))
o.datatype = "uinteger"
o.placeholder = "1200"
o.default = "1200"
o:depends({ [_n("hysteria2_obfs_type")] = "gecko" })
o = s:option(Value, _n("hysteria2_up_mbps"), translate("Max upload Mbps")) o = s:option(Value, _n("hysteria2_up_mbps"), translate("Max upload Mbps"))
o:depends({ [_n("protocol")] = "hysteria2" }) o:depends({ [_n("protocol")] = "hysteria2" })
@@ -400,6 +400,18 @@ if singbox_tags:find("with_quic") then
o:depends({ [_n("hysteria2_obfs_type")] = "salamander" }) o:depends({ [_n("hysteria2_obfs_type")] = "salamander" })
o:depends({ [_n("hysteria2_obfs_type")] = "gecko" }) o:depends({ [_n("hysteria2_obfs_type")] = "gecko" })
o = s:option(Value, _n("hysteria2_obfs_MinPacketSize"), translate("Gecko Packet Size (min)"))
o.datatype = "uinteger"
o.placeholder = "512"
o.default = "512"
o:depends({ [_n("hysteria2_obfs_type")] = "gecko" })
o = s:option(Value, _n("hysteria2_obfs_MaxPacketSize"), translate("Gecko Packet Size (max)"))
o.datatype = "uinteger"
o.placeholder = "1200"
o.default = "1200"
o:depends({ [_n("hysteria2_obfs_type")] = "gecko" })
o = s:option(Value, _n("hysteria2_up_mbps"), translate("Max upload Mbps")) o = s:option(Value, _n("hysteria2_up_mbps"), translate("Max upload Mbps"))
o:depends({ [_n("protocol")] = "hysteria2" }) o:depends({ [_n("protocol")] = "hysteria2" })
@@ -65,6 +65,20 @@ o.rewrite_option = o.option
o:depends({ [_n("obfs_type")] = "salamander" }) o:depends({ [_n("obfs_type")] = "salamander" })
o:depends({ [_n("obfs_type")] = "gecko" }) o:depends({ [_n("obfs_type")] = "gecko" })
o = s:option(Value, _n("obfs_MinPacketSize"), translate("Gecko Packet Size (min)"))
o.datatype = "uinteger"
o.placeholder = "512"
o.default = "512"
o:depends({ [_n("obfs_type")] = "gecko" })
o.rewrite_option = o.option
o = s:option(Value, _n("obfs_MaxPacketSize"), translate("Gecko Packet Size (max)"))
o.datatype = "uinteger"
o.placeholder = "1200"
o.default = "1200"
o:depends({ [_n("obfs_type")] = "gecko" })
o.rewrite_option = o.option
o = s:option(Flag, _n("udp"), translate("UDP")) o = s:option(Flag, _n("udp"), translate("UDP"))
o.default = "1" o.default = "1"
o.rewrite_option = o.option o.rewrite_option = o.option
@@ -155,6 +155,18 @@ o = s:option(Value, _n("hysteria2_obfs_password"), translate("Obfs Password"))
o:depends({ [_n("hysteria2_obfs_type")] = "salamander" }) o:depends({ [_n("hysteria2_obfs_type")] = "salamander" })
o:depends({ [_n("hysteria2_obfs_type")] = "gecko" }) o:depends({ [_n("hysteria2_obfs_type")] = "gecko" })
o = s:option(Value, _n("hysteria2_obfs_MinPacketSize"), translate("Gecko Packet Size (min)"))
o.datatype = "uinteger"
o.placeholder = "512"
o.default = "512"
o:depends({ [_n("hysteria2_obfs_type")] = "gecko" })
o = s:option(Value, _n("hysteria2_obfs_MaxPacketSize"), translate("Gecko Packet Size (max)"))
o.datatype = "uinteger"
o.placeholder = "1200"
o.default = "1200"
o:depends({ [_n("hysteria2_obfs_type")] = "gecko" })
o = s:option(Flag, _n("hysteria2_ignore_client_bandwidth"), translate("Client BBR Flow Control")) o = s:option(Flag, _n("hysteria2_ignore_client_bandwidth"), translate("Client BBR Flow Control"))
o.default = 0 o.default = 0
o:depends({ [_n("protocol")] = "hysteria2" }) o:depends({ [_n("protocol")] = "hysteria2" })
@@ -188,6 +188,18 @@ if singbox_tags:find("with_quic") then
o:depends({ [_n("hysteria2_obfs_type")] = "salamander" }) o:depends({ [_n("hysteria2_obfs_type")] = "salamander" })
o:depends({ [_n("hysteria2_obfs_type")] = "gecko" }) o:depends({ [_n("hysteria2_obfs_type")] = "gecko" })
o = s:option(Value, _n("hysteria2_obfs_MinPacketSize"), translate("Gecko Packet Size (min)"))
o.datatype = "uinteger"
o.placeholder = "512"
o.default = "512"
o:depends({ [_n("hysteria2_obfs_type")] = "gecko" })
o = s:option(Value, _n("hysteria2_obfs_MaxPacketSize"), translate("Gecko Packet Size (max)"))
o.datatype = "uinteger"
o.placeholder = "1200"
o.default = "1200"
o:depends({ [_n("hysteria2_obfs_type")] = "gecko" })
o = s:option(Flag, _n("hysteria2_ignore_client_bandwidth"), translate("Client BBR Flow Control"), translate("Commands the client to use the BBR flow control algorithm")) o = s:option(Flag, _n("hysteria2_ignore_client_bandwidth"), translate("Client BBR Flow Control"), translate("Commands the client to use the BBR flow control algorithm"))
o.default = 0 o.default = 0
o:depends({ [_n("protocol")] = "hysteria2" }) o:depends({ [_n("protocol")] = "hysteria2" })
@@ -39,6 +39,18 @@ function gen_config_server(node)
stunServers = node.hysteria2_realm_stun stunServers = node.hysteria2_realm_stun
} or nil } or nil
} }
if config.obfs and config.obfs.gecko then
local min = tonumber(node.hysteria2_obfs_MinPacketSize) or 512
local max = tonumber(node.hysteria2_obfs_MaxPacketSize) or 1200
if min <= 0 or min > max or max > 2048 then
min = 512
max = 1200
end
config.obfs.gecko.minPacketSize = min
config.obfs.gecko.maxPacketSize = max
end
return config return config
end end
@@ -157,6 +169,17 @@ function gen_config(var)
} or nil } or nil
} }
if config.obfs and config.obfs.gecko then
local min = tonumber(node.hysteria2_obfs_MinPacketSize) or 512
local max = tonumber(node.hysteria2_obfs_MaxPacketSize) or 1200
if min <= 0 or min > max or max > 2048 then
min = 512
max = 1200
end
config.obfs.gecko.minPacketSize = min
config.obfs.gecko.maxPacketSize = max
end
return jsonc.stringify(config, 1) return jsonc.stringify(config, 1)
end end
@@ -561,10 +561,24 @@ function gen_outbound(flag, node, tag, proxy_table)
hop_interval_max = interval_max, hop_interval_max = interval_max,
up_mbps = (node.hysteria2_up_mbps and tonumber(node.hysteria2_up_mbps)) and tonumber(node.hysteria2_up_mbps) or nil, up_mbps = (node.hysteria2_up_mbps and tonumber(node.hysteria2_up_mbps)) and tonumber(node.hysteria2_up_mbps) or nil,
down_mbps = (node.hysteria2_down_mbps and tonumber(node.hysteria2_down_mbps)) and tonumber(node.hysteria2_down_mbps) or nil, down_mbps = (node.hysteria2_down_mbps and tonumber(node.hysteria2_down_mbps)) and tonumber(node.hysteria2_down_mbps) or nil,
obfs = node.hysteria2_obfs_type and { obfs = (function(t)
type = node.hysteria2_obfs_type, if not t or t == "" then return nil end
password = node.hysteria2_obfs_password local o = {
} or nil, type = t,
password = node.hysteria2_obfs_password
}
if t == "gecko" then
local min = tonumber(node.hysteria2_obfs_MinPacketSize) or 512
local max = tonumber(node.hysteria2_obfs_MaxPacketSize) or 1200
if min <= 0 or min > max or max > 2048 then
min = 512
max = 1200
end
o.min_packet_size = min
o.max_packet_size = max
end
return o
end)(node.hysteria2_obfs_type),
password = node.hysteria2_auth_password or nil, password = node.hysteria2_auth_password or nil,
idle_timeout = (function(t) idle_timeout = (function(t)
if not version_ge_1_14_0 then return nil end if not version_ge_1_14_0 then return nil end
@@ -917,10 +931,24 @@ function gen_config_server(node)
protocol_table = { protocol_table = {
up_mbps = (node.hysteria2_ignore_client_bandwidth ~= "1" and node.hysteria2_up_mbps and tonumber(node.hysteria2_up_mbps)) and tonumber(node.hysteria2_up_mbps) or nil, up_mbps = (node.hysteria2_ignore_client_bandwidth ~= "1" and node.hysteria2_up_mbps and tonumber(node.hysteria2_up_mbps)) and tonumber(node.hysteria2_up_mbps) or nil,
down_mbps = (node.hysteria2_ignore_client_bandwidth ~= "1" and node.hysteria2_down_mbps and tonumber(node.hysteria2_down_mbps)) and tonumber(node.hysteria2_down_mbps) or nil, down_mbps = (node.hysteria2_ignore_client_bandwidth ~= "1" and node.hysteria2_down_mbps and tonumber(node.hysteria2_down_mbps)) and tonumber(node.hysteria2_down_mbps) or nil,
obfs = node.hysteria2_obfs_type and { obfs = (function(t)
type = node.hysteria2_obfs_type, if not t or t == "" then return nil end
password = node.hysteria2_obfs_password local o = {
} or nil, type = t,
password = node.hysteria2_obfs_password
}
if t == "gecko" then
local min = tonumber(node.hysteria2_obfs_MinPacketSize) or 512
local max = tonumber(node.hysteria2_obfs_MaxPacketSize) or 1200
if min <= 0 or min > max or max > 2048 then
min = 512
max = 1200
end
o.min_packet_size = min
o.max_packet_size = max
end
return o
end)(node.hysteria2_obfs_type),
users = { users = {
{ {
name = "user1", name = "user1",
@@ -284,10 +284,18 @@ function gen_outbound(flag, node, tag, proxy_table)
local o = { local o = {
type = "salamander", type = "salamander",
settings = node.hysteria2_obfs_password and { settings = node.hysteria2_obfs_password and {
password = node.hysteria2_obfs_password, password = node.hysteria2_obfs_password
packetSize = node.hysteria2_obfs_type == "gecko" and "512-1200" or nil
} or nil } or nil
} }
if node.hysteria2_obfs_type == "gecko" then
local min = tonumber(node.hysteria2_obfs_MinPacketSize) or 512
local max = tonumber(node.hysteria2_obfs_MaxPacketSize) or 1200
if min <= 0 or min > max or max > 2048 then
min = 512
max = 1200
end
o.settings.packetSize = min .. "-" .. max
end
udp[#udp+1] = o udp[#udp+1] = o
end end
if node.hysteria2_realms then if node.hysteria2_realms then
@@ -724,10 +732,18 @@ function gen_config_server(node)
local o = { local o = {
type = "salamander", type = "salamander",
settings = node.hysteria2_obfs_password and { settings = node.hysteria2_obfs_password and {
password = node.hysteria2_obfs_password, password = node.hysteria2_obfs_password
packetSize = node.hysteria2_obfs_type == "gecko" and "512-1200" or nil
} or nil } or nil
} }
if node.hysteria2_obfs_type == "gecko" then
local min = tonumber(node.hysteria2_obfs_MinPacketSize) or 512
local max = tonumber(node.hysteria2_obfs_MaxPacketSize) or 1200
if min <= 0 or min > max or max > 2048 then
min = 512
max = 1200
end
o.settings.packetSize = min .. "-" .. max
end
udp[#udp+1] = o udp[#udp+1] = o
end end
if node.hysteria2_realms then if node.hysteria2_realms then
@@ -598,10 +598,14 @@ local current_node = map:get(section)
if (v_type === "Hysteria2") { if (v_type === "Hysteria2") {
v_password = opt.get("hysteria2_auth_password"); v_password = opt.get("hysteria2_auth_password");
var dom_obfs = opt.get("hysteria2_obfs_password"); var dom_obfs_type = opt.get("hysteria2_obfs_type");
if (dom_obfs && dom_obfs.value != "") { if (dom_obfs_type && dom_obfs_type.value != "") {
params += opt.query("obfs", "hysteria2_obfs_type"); params += opt.query("obfs", "hysteria2_obfs_type");
params += opt.query("obfs-password", "hysteria2_obfs_password"); params += opt.query("obfs-password", "hysteria2_obfs_password");
if (dom_obfs_type.value === "gecko") {
params += opt.query("minPacketSize", "hysteria2_obfs_MinPacketSize");
params += opt.query("maxPacketSize", "hysteria2_obfs_MaxPacketSize");
}
} }
params += opt.query("mport", "hysteria2_hop"); params += opt.query("mport", "hysteria2_hop");
} else { } else {
@@ -610,6 +614,10 @@ local current_node = map:get(section)
if (dom_obfs_type && dom_obfs_type.value != "") { if (dom_obfs_type && dom_obfs_type.value != "") {
params += opt.query("obfs", dom_prefix + "hysteria2_obfs_type"); params += opt.query("obfs", dom_prefix + "hysteria2_obfs_type");
params += opt.query("obfs-password", dom_prefix + "hysteria2_obfs_password"); params += opt.query("obfs-password", dom_prefix + "hysteria2_obfs_password");
if (dom_obfs_type.value === "gecko") {
params += opt.query("minPacketSize", dom_prefix + "hysteria2_obfs_MinPacketSize");
params += opt.query("maxPacketSize", dom_prefix + "hysteria2_obfs_MaxPacketSize");
}
} }
params += opt.query("mport", dom_prefix + "hysteria2_hop"); params += opt.query("mport", dom_prefix + "hysteria2_hop");
if (opt.get(dom_prefix + "use_finalmask")?.checked) { if (opt.get(dom_prefix + "use_finalmask")?.checked) {
@@ -1600,6 +1608,10 @@ local current_node = map:get(section)
opt.set(dom_prefix + 'hysteria2_obfs_type', queryParam.obfs || "salamander"); opt.set(dom_prefix + 'hysteria2_obfs_type', queryParam.obfs || "salamander");
opt.set(dom_prefix + 'hysteria2_obfs_password', queryParam["obfs-password"] || queryParam["obfs_password"]); opt.set(dom_prefix + 'hysteria2_obfs_password', queryParam["obfs-password"] || queryParam["obfs_password"]);
} }
if (queryParam.obfs === "gecko") {
opt.set(dom_prefix + 'hysteria2_obfs_MinPacketSize', queryParam.minPacketSize || "512");
opt.set(dom_prefix + 'hysteria2_obfs_MaxPacketSize', queryParam.maxPacketSize || "1200");
}
opt.set(dom_prefix + 'hysteria2_hop', queryParam.mport || ""); opt.set(dom_prefix + 'hysteria2_hop', queryParam.mport || "");
opt.set(dom_prefix + 'use_finalmask', !!queryParam.fm); opt.set(dom_prefix + 'use_finalmask', !!queryParam.fm);
opt.set(dom_prefix + 'finalmask', queryParam.fm || ""); opt.set(dom_prefix + 'finalmask', queryParam.fm || "");
@@ -1611,6 +1623,10 @@ local current_node = map:get(section)
opt.set(dom_prefix + 'obfs_type', queryParam.obfs || "salamander"); opt.set(dom_prefix + 'obfs_type', queryParam.obfs || "salamander");
opt.set(dom_prefix + 'obfs_password', queryParam["obfs-password"] || queryParam["obfs_password"]); opt.set(dom_prefix + 'obfs_password', queryParam["obfs-password"] || queryParam["obfs_password"]);
} }
if (queryParam.obfs === "gecko") {
opt.set(dom_prefix + 'obfs_MinPacketSize', queryParam.minPacketSize || "512");
opt.set(dom_prefix + 'obfs_MaxPacketSize', queryParam.maxPacketSize || "1200");
}
opt.set(dom_prefix + 'hop', queryParam.mport || ""); opt.set(dom_prefix + 'hop', queryParam.mport || "");
} }
+8 -2
View File
@@ -740,10 +740,10 @@ msgid "Certificate fingerprint"
msgstr "证书指纹" msgstr "证书指纹"
msgid "Max upload Mbps" msgid "Max upload Mbps"
msgstr "最大上行(Mbps)" msgstr "最大上行(Mbps)"
msgid "Max download Mbps" msgid "Max download Mbps"
msgstr "最大下行(Mbps)" msgstr "最大下行(Mbps)"
msgid "QUIC stream receive window" msgid "QUIC stream receive window"
msgstr "QUIC 流接收窗口" msgstr "QUIC 流接收窗口"
@@ -2170,3 +2170,9 @@ msgstr "正在处理,请稍候…"
msgid "Invalid Realm URL." msgid "Invalid Realm URL."
msgstr "Realm URL 不正确。" msgstr "Realm URL 不正确。"
msgid "Gecko Packet Size (min)"
msgstr "Gecko 包大小(最小)"
msgid "Gecko Packet Size (max)"
msgstr "Gecko 包大小(最大)"
@@ -398,6 +398,8 @@ local function encode_hysteria2(node)
if node["ports"] then table.insert(p, "mport=" .. urlencode(node["ports"])) end if node["ports"] then table.insert(p, "mport=" .. urlencode(node["ports"])) end
if node.obfs then table.insert(p, "obfs=" .. node.obfs) end if node.obfs then table.insert(p, "obfs=" .. node.obfs) end
if node["obfs-password"] then table.insert(p, "obfs-password=" .. node["obfs-password"]) end if node["obfs-password"] then table.insert(p, "obfs-password=" .. node["obfs-password"]) end
if node["obfs-min-packet-size"] then table.insert(p, "minPacketSize=" .. node["obfs-min-packet-size"]) end
if node["obfs-max-packet-size"] then table.insert(p, "maxPacketSize=" .. node["obfs-max-packet-size"]) end
if node.up then table.insert(p, "upmbps=" .. node.up) end if node.up then table.insert(p, "upmbps=" .. node.up) end
if node.down then table.insert(p, "downmbps=" .. node.down) end if node.down then table.insert(p, "downmbps=" .. node.down) end
@@ -1419,6 +1419,10 @@ local function processData(szType, content, add_mode, group, sub_cfg)
result.hysteria2_obfs_type = params.obfs or "salamander" result.hysteria2_obfs_type = params.obfs or "salamander"
result.hysteria2_obfs_password = params["obfs-password"] or params["obfs_password"] result.hysteria2_obfs_password = params["obfs-password"] or params["obfs_password"]
end end
if params.obfs == "gecko" then
result.hysteria2_obfs_MinPacketSize = params.minpacketsize or "512"
result.hysteria2_obfs_MaxPacketSize = params.maxpacketsize or "1200"
end
if (sub_hysteria2_type == "sing-box" and has_singbox) or (sub_hysteria2_type == "xray" and has_xray) then if (sub_hysteria2_type == "sing-box" and has_singbox) or (sub_hysteria2_type == "xray" and has_xray) then
local is_singbox = sub_hysteria2_type == "sing-box" and has_singbox local is_singbox = sub_hysteria2_type == "sing-box" and has_singbox
+1 -1
View File
@@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-run PKG_NAME:=luci-app-run
PKG_VERSION:=1.0.0 PKG_VERSION:=1.0.0
PKG_RELEASE:=7 PKG_RELEASE:=8
LUCI_TITLE:=LuCI support for running installers and packages LUCI_TITLE:=LuCI support for running installers and packages
LUCI_DESCRIPTION:=Upload and execute .run, .sh, .ipk and .apk files from LuCI. LUCI_DESCRIPTION:=Upload and execute .run, .sh, .ipk and .apk files from LuCI.
@@ -32,7 +32,8 @@
"download_run": "下载并执行 .run", "download_run": "下载并执行 .run",
"download_url": "请输入 .run 文件的下载地址", "download_url": "请输入 .run 文件的下载地址",
"downloading": "正在下载...", "downloading": "正在下载...",
"only_run": "仅支持 .run 文件下载" "only_run": "仅支持 .run 文件下载",
"no_file": "请先选择sh文件"
}, },
"en": { "en": {
"title": "Run Installer", "title": "Run Installer",
@@ -67,6 +68,7 @@
"download_run": "Download and execute .run", "download_run": "Download and execute .run",
"download_url": "Enter .run file download URL", "download_url": "Enter .run file download URL",
"downloading": "Downloading...", "downloading": "Downloading...",
"only_run": "Only .run files are supported" "only_run": "Only .run files are supported",
"no_file": "Please select a file or enter a download URL first"
} }
} }
@@ -93,11 +93,27 @@ function getDefaultText(key) {
'download_run': '下载并执行 .run', 'download_run': '下载并执行 .run',
'download_url': '请输入 .run 文件的下载地址', 'download_url': '请输入 .run 文件的下载地址',
'downloading': '正在下载...', 'downloading': '正在下载...',
'only_run': '仅支持 .run 文件下载' 'only_run': '仅支持 .run 文件下载',
'no_file': '请先选择sh文件'
}; };
return defaults[key] || null; return defaults[key] || null;
} }
function cleanupStaleDialogs() {
var allDivs = document.getElementsByTagName('div');
for (var i = allDivs.length - 1; i >= 0; i--) {
var div = allDivs[i];
if (!div || !div.parentNode) continue;
var style = window.getComputedStyle ? window.getComputedStyle(div) : div.style;
var isFixed = style.position === 'fixed' || (div.style && div.style.position === 'fixed');
var hasHighZ = (style.zIndex && parseInt(style.zIndex) >= 9000) || (div.style.zIndex && parseInt(div.style.zIndex) >= 9000);
var isOurDialog = div.style && (div.style.zIndex === '9999' || div.style.background && div.style.background.indexOf('rgba(0,0,0,0.5)') !== -1);
if (isFixed && (hasHighZ || isOurDialog)) {
div.parentNode.removeChild(div);
}
}
}
var uploadStart = rpc.declare({ var uploadStart = rpc.declare({
object: 'luci-app-run', object: 'luci-app-run',
method: 'upload_start', method: 'upload_start',
@@ -242,6 +258,8 @@ return view.extend({
render: function (status) { render: function (status) {
var self = this; var self = this;
cleanupStaleDialogs();
var fileInput = E('input', { var fileInput = E('input', {
'type': 'file', 'type': 'file',
accept: '.run,.sh,.ipk,.apk,application/x-shellscript,application/octet-stream', accept: '.run,.sh,.ipk,.apk,application/x-shellscript,application/octet-stream',
@@ -278,6 +296,8 @@ return view.extend({
style: 'background:#333!important;background-color:#333!important;background-image:none!important;color:#fff!important;border-color:#333!important;box-shadow:none!important;text-shadow:none!important;opacity:1!important', style: 'background:#333!important;background-color:#333!important;background-image:none!important;color:#fff!important;border-color:#333!important;box-shadow:none!important;text-shadow:none!important;opacity:1!important',
click: function (ev) { click: function (ev) {
ev.preventDefault(); ev.preventDefault();
cleanupStaleDialogs();
fileInput.value = '';
fileInput.click(); fileInput.click();
} }
}, [_('choose_file')]); }, [_('choose_file')]);
@@ -287,6 +307,8 @@ return view.extend({
style: 'margin-left:10px;background:#2E7D32!important;background-color:#2E7D32!important;background-image:none!important;color:#fff!important;border-color:#2E7D32!important;box-shadow:none!important;text-shadow:none!important;opacity:1!important', style: 'margin-left:10px;background:#2E7D32!important;background-color:#2E7D32!important;background-image:none!important;color:#fff!important;border-color:#2E7D32!important;box-shadow:none!important;text-shadow:none!important;opacity:1!important',
click: function (ev) { click: function (ev) {
ev.preventDefault(); ev.preventDefault();
cleanupStaleDialogs();
ipkInput.value = '';
ipkInput.click(); ipkInput.click();
} }
}, [_('choose_ipk')]); }, [_('choose_ipk')]);
@@ -296,6 +318,8 @@ return view.extend({
style: 'margin-left:10px;background:#1565C0!important;background-color:#1565C0!important;background-image:none!important;color:#fff!important;border-color:#1565C0!important;box-shadow:none!important;text-shadow:none!important;opacity:1!important', style: 'margin-left:10px;background:#1565C0!important;background-color:#1565C0!important;background-image:none!important;color:#fff!important;border-color:#1565C0!important;box-shadow:none!important;text-shadow:none!important;opacity:1!important',
click: function (ev) { click: function (ev) {
ev.preventDefault(); ev.preventDefault();
cleanupStaleDialogs();
apkInput.value = '';
apkInput.click(); apkInput.click();
} }
}, [_('choose_apk')]); }, [_('choose_apk')]);
@@ -305,6 +329,7 @@ return view.extend({
style: 'margin-left:10px;background:#E65100!important;background-color:#E65100!important;background-image:none!important;color:#fff!important;border-color:#E65100!important;box-shadow:none!important;text-shadow:none!important;opacity:1!important', style: 'margin-left:10px;background:#E65100!important;background-color:#E65100!important;background-image:none!important;color:#fff!important;border-color:#E65100!important;box-shadow:none!important;text-shadow:none!important;opacity:1!important',
click: function (ev) { click: function (ev) {
ev.preventDefault(); ev.preventDefault();
cleanupStaleDialogs();
self.showDownloadDialog(function (url) { self.showDownloadDialog(function (url) {
if (url !== null) { if (url !== null) {
log.textContent = ''; log.textContent = '';
@@ -316,22 +341,26 @@ return view.extend({
var runButton = E('button', { var runButton = E('button', {
class: 'cbi-button cbi-button-action run-btn', class: 'cbi-button cbi-button-action run-btn',
disabled: true, disabled: false,
style: 'min-width:140px;margin-left:15px;background:#7B1FA2!important;background-color:#7B1FA2!important;background-image:none!important;color:#fff!important;border-color:#7B1FA2!important;box-shadow:none!important;text-shadow:none!important;opacity:1!important', style: 'min-width:140px;margin-left:15px;background:#7B1FA2!important;background-color:#7B1FA2!important;background-image:none!important;color:#fff!important;border-color:#7B1FA2!important;box-shadow:none!important;text-shadow:none!important;opacity:1!important;pointer-events:auto!important;cursor:pointer!important',
click: function (ev) { click: function (ev) {
ev.preventDefault(); ev.preventDefault();
ev.stopPropagation();
cleanupStaleDialogs();
log.textContent = '';
if (self.currentFileType === '.sh') { if (self.currentFileType === '.sh') {
self.showArgsDialog(function (args) { self.showArgsDialog(function (args) {
if (args !== null) { if (args !== null) {
log.textContent = '';
self.startRun(runButton, state, args.trim()); self.startRun(runButton, state, args.trim());
} }
}); });
} else { } else {
log.textContent = '';
self.startRun(runButton, state, ''); self.startRun(runButton, state, '');
} }
return false;
} }
}, [_('execute')]); }, [_('execute')]);
@@ -340,17 +369,21 @@ return view.extend({
style: 'margin-left:35px;background:#C62828!important;background-color:#C62828!important;background-image:none!important;color:#fff!important;border-color:#C62828!important;box-shadow:none!important;text-shadow:none!important;opacity:1!important', style: 'margin-left:35px;background:#C62828!important;background-color:#C62828!important;background-image:none!important;color:#fff!important;border-color:#C62828!important;box-shadow:none!important;text-shadow:none!important;opacity:1!important',
click: function (ev) { click: function (ev) {
ev.preventDefault(); ev.preventDefault();
cleanupStaleDialogs();
cleanup().then(function (res) { cleanup().then(function (res) {
if (res && res.error) if (res && res.error)
throw new Error(res.error); throw new Error(res.error);
self.currentUploadId = null; self.currentUploadId = null;
self.currentFileType = null;
self.logOffset = 0; self.logOffset = 0;
self.prevRunning = false; self.prevRunning = false;
self.autoCleanType = null; self.autoCleanType = null;
runButton.disabled = true;
log.textContent = ''; log.textContent = '';
progress.style.display = 'none'; progress.style.display = 'none';
fileInput.value = '';
ipkInput.value = '';
apkInput.value = '';
state.textContent = _('clean_done'); state.textContent = _('clean_done');
}).catch(function (err) { }).catch(function (err) {
ui.addNotification(null, E('p', [err.message || err]), 'danger'); ui.addNotification(null, E('p', [err.message || err]), 'danger');
@@ -370,6 +403,7 @@ return view.extend({
}, },
drop: function (ev) { drop: function (ev) {
ev.preventDefault(); ev.preventDefault();
cleanupStaleDialogs();
drop.style.borderStyle = 'dashed'; drop.style.borderStyle = 'dashed';
if (ev.dataTransfer.files && ev.dataTransfer.files.length) if (ev.dataTransfer.files && ev.dataTransfer.files.length)
self.uploadFile(ev.dataTransfer.files[0], progress, state, runButton); self.uploadFile(ev.dataTransfer.files[0], progress, state, runButton);
@@ -386,20 +420,37 @@ return view.extend({
]); ]);
fileInput.addEventListener('change', function () { fileInput.addEventListener('change', function () {
if (fileInput.files && fileInput.files.length) if (fileInput.files && fileInput.files.length) {
self.uploadFile(fileInput.files[0], progress, state, runButton); var selectedFile = fileInput.files[0];
fileInput.value = '';
self.uploadFile(selectedFile, progress, state, runButton);
}
}); });
ipkInput.addEventListener('change', function () { ipkInput.addEventListener('change', function () {
if (ipkInput.files && ipkInput.files.length) if (ipkInput.files && ipkInput.files.length) {
self.uploadFile(ipkInput.files[0], progress, state, runButton); var selectedFile = ipkInput.files[0];
ipkInput.value = '';
self.uploadFile(selectedFile, progress, state, runButton);
}
}); });
apkInput.addEventListener('change', function () { apkInput.addEventListener('change', function () {
if (apkInput.files && apkInput.files.length) if (apkInput.files && apkInput.files.length) {
self.uploadFile(apkInput.files[0], progress, state, runButton); var selectedFile = apkInput.files[0];
apkInput.value = '';
self.uploadFile(selectedFile, progress, state, runButton);
}
}); });
setTimeout(function () {
cleanupStaleDialogs();
runButton.disabled = false;
runButton.removeAttribute('disabled');
runButton.style.pointerEvents = 'auto';
runButton.style.cursor = 'pointer';
}, 100);
poll.add(function () { poll.add(function () {
return self.refreshLog(log, state); return self.refreshLog(log, state);
}, 1); }, 1);
@@ -434,13 +485,16 @@ return view.extend({
return Promise.reject(); return Promise.reject();
} }
// 记录文件类型 self.currentUploadId = null;
self.logOffset = 0;
self.prevRunning = false;
self.autoCleanType = null;
var ext = file.name.match(/\.(run|sh|ipk|apk)$/i); var ext = file.name.match(/\.(run|sh|ipk|apk)$/i);
self.currentFileType = ext ? ext[0].toLowerCase() : null; self.currentFileType = ext ? ext[0].toLowerCase() : null;
progress.style.display = ''; progress.style.display = '';
progress.value = 0; progress.value = 0;
runButton.disabled = true;
state.textContent = _('prepare_upload', file.name, formatBytes(file.size)); state.textContent = _('prepare_upload', file.name, formatBytes(file.size));
return uploadStart(file.name, file.size).then(function (res) { return uploadStart(file.name, file.size).then(function (res) {
@@ -473,12 +527,10 @@ return view.extend({
}; };
xhr.onerror = function () { xhr.onerror = function () {
document.querySelector('.cbi-button-action').disabled = false;
reject(new Error(_('upload_err'))); reject(new Error(_('upload_err')));
}; };
xhr.onload = function () { xhr.onload = function () {
document.querySelector('.cbi-button-action').disabled = false;
progress.value = 100; progress.value = 100;
uploadFinish(session.id).then(function () { uploadFinish(session.id).then(function () {
@@ -497,9 +549,11 @@ return view.extend({
startRun: function (runButton, state, args) { startRun: function (runButton, state, args) {
var self = this; var self = this;
if (!this.currentUploadId) return; if (!this.currentUploadId) {
ui.addNotification(null, E('p', [_('no_file')]), 'danger');
return;
}
runButton.disabled = true;
state.textContent = _('starting'); state.textContent = _('starting');
self.autoCleanType = null; self.autoCleanType = null;
@@ -521,23 +575,52 @@ return view.extend({
} }
state.textContent = _('started', res.pid); state.textContent = _('started', res.pid);
}).catch(function (err) { }).catch(function (err) {
runButton.disabled = false;
ui.addNotification(null, E('p', [err.message || err]), 'danger'); ui.addNotification(null, E('p', [err.message || err]), 'danger');
}); });
}, },
showArgsDialog: function (callback) { showArgsDialog: function (callback) {
var closed = false;
function closeDialog(result) {
if (closed) return;
closed = true;
document.removeEventListener('keydown', escHandler);
if (dialog.parentNode) {
document.body.removeChild(dialog);
}
callback(result);
}
function escHandler(ev) {
if (ev.key === 'Escape' || ev.keyCode === 27) {
closeDialog(null);
}
}
var dialog = E('div', { var dialog = E('div', {
style: 'position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.5);display:flex;align-items:center;justify-content:center;z-index:9999' style: 'position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.5);display:flex;align-items:center;justify-content:center;z-index:9999',
click: function (ev) {
if (ev.target === dialog) {
closeDialog(null);
}
}
}, [ }, [
E('div', { E('div', {
style: 'background:#fff;border-radius:8px;padding:20px;width:400px;box-shadow:0 4px 20px rgba(0,0,0,0.3)' style: 'background:#fff;border-radius:8px;padding:20px;width:400px;box-shadow:0 4px 20px rgba(0,0,0,0.3)',
click: function (ev) { ev.stopPropagation(); }
}, [ }, [
E('input', { E('input', {
type: 'text', type: 'text',
placeholder: _('args_hint'), placeholder: _('args_hint'),
style: 'width:100%;padding:10px;margin-bottom:15px;border:1px solid #ccc;border-radius:4px;box-sizing:border-box;font-size:14px', style: 'width:100%;padding:10px;margin-bottom:15px;border:1px solid #ccc;border-radius:4px;box-sizing:border-box;font-size:14px',
id: 'run-args-dialog-input' id: 'run-args-dialog-input',
keydown: function (ev) {
if (ev.key === 'Enter' || ev.keyCode === 13) {
ev.preventDefault();
var args = this.value;
closeDialog(args);
}
}
}), }),
E('div', { E('div', {
style: 'display:flex;justify-content:flex-end;gap:10px' style: 'display:flex;justify-content:flex-end;gap:10px'
@@ -546,8 +629,7 @@ return view.extend({
class: 'cbi-button cbi-button-reset', class: 'cbi-button cbi-button-reset',
style: 'padding:8px 20px;text-transform:none', style: 'padding:8px 20px;text-transform:none',
click: function () { click: function () {
document.body.removeChild(dialog); closeDialog(null);
callback(null);
} }
}, [_('cancel')]), }, [_('cancel')]),
E('button', { E('button', {
@@ -555,30 +637,62 @@ return view.extend({
style: 'padding:8px 20px;text-transform:none', style: 'padding:8px 20px;text-transform:none',
click: function () { click: function () {
var args = document.getElementById('run-args-dialog-input').value; var args = document.getElementById('run-args-dialog-input').value;
document.body.removeChild(dialog); closeDialog(args);
callback(args);
} }
}, [_('confirm')]) }, [_('confirm')])
]) ])
]) ])
]); ]);
document.addEventListener('keydown', escHandler);
document.body.appendChild(dialog); document.body.appendChild(dialog);
document.getElementById('run-args-dialog-input').focus(); setTimeout(function () {
var input = document.getElementById('run-args-dialog-input');
if (input) input.focus();
}, 50);
}, },
showDownloadDialog: function (callback) { showDownloadDialog: function (callback) {
var closed = false;
function closeDialog(result) {
if (closed) return;
closed = true;
document.removeEventListener('keydown', escHandler);
if (dialog.parentNode) {
document.body.removeChild(dialog);
}
callback(result);
}
function escHandler(ev) {
if (ev.key === 'Escape' || ev.keyCode === 27) {
closeDialog(null);
}
}
var dialog = E('div', { var dialog = E('div', {
style: 'position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.5);display:flex;align-items:center;justify-content:center;z-index:9999' style: 'position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.5);display:flex;align-items:center;justify-content:center;z-index:9999',
click: function (ev) {
if (ev.target === dialog) {
closeDialog(null);
}
}
}, [ }, [
E('div', { E('div', {
style: 'background:#fff;border-radius:8px;padding:20px;width:400px;box-shadow:0 4px 20px rgba(0,0,0,0.3)' style: 'background:#fff;border-radius:8px;padding:20px;width:400px;box-shadow:0 4px 20px rgba(0,0,0,0.3)',
click: function (ev) { ev.stopPropagation(); }
}, [ }, [
E('input', { E('input', {
type: 'text', type: 'text',
placeholder: _('download_url'), placeholder: _('download_url'),
style: 'width:100%;padding:10px;margin-bottom:15px;border:1px solid #ccc;border-radius:4px;box-sizing:border-box;font-size:14px', style: 'width:100%;padding:10px;margin-bottom:15px;border:1px solid #ccc;border-radius:4px;box-sizing:border-box;font-size:14px',
id: 'run-download-url-input' id: 'run-download-url-input',
keydown: function (ev) {
if (ev.key === 'Enter' || ev.keyCode === 13) {
ev.preventDefault();
confirmBtn.click();
}
}
}), }),
E('div', { E('div', {
style: 'display:flex;justify-content:flex-end;gap:10px' style: 'display:flex;justify-content:flex-end;gap:10px'
@@ -587,18 +701,16 @@ return view.extend({
class: 'cbi-button cbi-button-reset', class: 'cbi-button cbi-button-reset',
style: 'padding:8px 20px;text-transform:none', style: 'padding:8px 20px;text-transform:none',
click: function () { click: function () {
document.body.removeChild(dialog); closeDialog(null);
callback(null);
} }
}, [_('cancel')]), }, [_('cancel')]),
E('button', { E('button', {
class: 'cbi-button cbi-button-action', class: 'cbi-button cbi-button-action confirm-btn',
style: 'padding:8px 20px;text-transform:none', style: 'padding:8px 20px;text-transform:none',
click: function () { click: function () {
var url = document.getElementById('run-download-url-input').value.trim(); var url = document.getElementById('run-download-url-input').value.trim();
if (!url) { if (!url) {
document.body.removeChild(dialog); closeDialog(null);
callback(null);
return; return;
} }
@@ -608,22 +720,26 @@ return view.extend({
return; return;
} }
document.body.removeChild(dialog); closeDialog(url);
callback(url);
} }
}, [_('confirm')]) }, [_('confirm')])
]) ])
]) ])
]); ]);
var confirmBtn = dialog.querySelector('.confirm-btn');
document.addEventListener('keydown', escHandler);
document.body.appendChild(dialog); document.body.appendChild(dialog);
document.getElementById('run-download-url-input').focus(); setTimeout(function () {
var input = document.getElementById('run-download-url-input');
if (input) input.focus();
}, 50);
}, },
startDownload: function (runButton, state, url) { startDownload: function (runButton, state, url) {
var self = this; var self = this;
runButton.disabled = true;
state.textContent = _('downloading'); state.textContent = _('downloading');
self.prevRunning = false; self.prevRunning = false;
self.autoCleanType = null; self.autoCleanType = null;
@@ -637,7 +753,6 @@ return view.extend({
self.prevRunning = true; self.prevRunning = true;
state.textContent = _('started', res.pid); state.textContent = _('started', res.pid);
}).catch(function (err) { }).catch(function (err) {
runButton.disabled = false;
ui.addNotification(null, E('p', [err.message || err]), 'danger'); ui.addNotification(null, E('p', [err.message || err]), 'danger');
}); });
}, },
@@ -665,9 +780,19 @@ return view.extend({
// Auto-cleanup for .sh and .run files // Auto-cleanup for .sh and .run files
if (self.autoCleanType) { if (self.autoCleanType) {
self.autoCleanType = null; self.autoCleanType = null;
var oldUploadId = self.currentUploadId;
var oldFileType = self.currentFileType;
cleanup().then(function () { cleanup().then(function () {
self.currentUploadId = null; // Only clear state if user hasn't uploaded a new file in the meantime
state.textContent = _('auto_cleaned'); if (self.currentUploadId === oldUploadId) {
self.currentUploadId = null;
self.currentFileType = null;
}
if (oldFileType) {
state.textContent = _('auto_cleaned');
} else {
state.textContent = _('clean_done');
}
}).catch(function () { }).catch(function () {
state.textContent = _('clean_done'); state.textContent = _('clean_done');
}); });
+4 -4
View File
@@ -1,14 +1,14 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=mihomo-alpha PKG_NAME:=mihomo-alpha
PKG_VERSION:=2026.06.12 PKG_VERSION:=2026.06.23
PKG_RELEASE:=16 PKG_RELEASE:=17
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
PKG_SOURCE_PROTO:=git PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://github.com/MetaCubeX/mihomo.git PKG_SOURCE_URL:=https://github.com/MetaCubeX/mihomo.git
PKG_SOURCE_VERSION:=793f61ec6798e335a0f8eed3b310a084c3d68514 PKG_SOURCE_VERSION:=59ffb637343092d3fc94d6cc600b86e1f78d6c1a
PKG_MIRROR_HASH:=skip PKG_MIRROR_HASH:=skip
PKG_LICENSE:=GPL3.0+ PKG_LICENSE:=GPL3.0+
@@ -18,7 +18,7 @@ PKG_BUILD_DEPENDS:=golang/host
PKG_BUILD_PARALLEL:=1 PKG_BUILD_PARALLEL:=1
PKG_BUILD_FLAGS:=no-mips16 PKG_BUILD_FLAGS:=no-mips16
PKG_BUILD_VERSION:=alpha-793f61e PKG_BUILD_VERSION:=alpha-59ffb63
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
PKG_BUILD_TIME:=$(shell date -u -Iseconds) PKG_BUILD_TIME:=$(shell date -u -Iseconds)
+2 -2
View File
@@ -10,12 +10,12 @@ include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=natflow PKG_NAME:=natflow
PKG_VERSION:=20260531 PKG_VERSION:=20260531
PKG_RELEASE:=24 PKG_RELEASE:=25
PKG_SOURCE:=$(PKG_VERSION).tar.xz PKG_SOURCE:=$(PKG_VERSION).tar.xz
PKG_SOURCE_URL:=https://github.com/ptpt52/natflow.git PKG_SOURCE_URL:=https://github.com/ptpt52/natflow.git
PKG_SOURCE_PROTO:=git PKG_SOURCE_PROTO:=git
PKG_SOURCE_VERSION:=4ad0c8a91f950d18c1b97d055f7dd9a8d17d554c PKG_SOURCE_VERSION:=bf84c587500484bfd7f0f11cbc4dc2ff9b8ad1af
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
PKG_MAINTAINER:=Chen Minqiang <ptpt52@gmail.com> PKG_MAINTAINER:=Chen Minqiang <ptpt52@gmail.com>
PKG_LICENSE:=GPL-2.0 PKG_LICENSE:=GPL-2.0