Ver código fonte

luci-app-ssr-plus: Smart core select and import/subscribe stability enhance.

zxlhhyccc 3 dias atrás
pai
commit
43cbe97bbf

+ 97 - 27
luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua

@@ -5,6 +5,7 @@ require "nixio.fs"
 require "luci.sys"
 require "luci.http"
 require "luci.jsonc"
+local nixio = require "nixio"
 require "luci.model.uci"
 local uci = require "luci.model.uci".cursor()
 
@@ -146,11 +147,11 @@ local function set_apply_on_parse(map)
 	end
 end
 
-local has_xray = is_finded("xray")
-local has_hysteria2 = is_finded("hysteria")
-
 local has_ss_rust = is_finded("sslocal") or is_finded("ssserver")
 local has_ss_libev = is_finded("ss-redir") or is_finded("ss-local")
+local has_trojan = is_finded("trojan")
+local has_xray = is_finded("xray")
+local has_hysteria2 = is_finded("hysteria")
 
 local server_table = {}
 local encrypt_methods = {
@@ -277,25 +278,63 @@ o.value = sid
 -- 新增一个选择框,用于选择 Xray 或 Hysteria2 核心
 o = s:option(ListValue, "_xray_hy2_type", string.format("<b><span style='color:red;'>%s</span></b>", translatef("%s Node Use Type", "Hysteria2")))
 o.description = translate("The configured type also applies to the core specified when manually importing nodes.")
--- 设置默认 Xray 或 Hysteria2 核心
--- 动态添加选项
+-- 注意:Auto 选项使用特殊字符串 "__auto__" 而不是空字符串
+o:value("__auto__", translate("Auto"))
+if has_hysteria2 then
+    o:value("hysteria2", translate("Hysteria2"))
+end
 if has_xray then
-	o:value("v2ray", translate("Xray (Hysteria2)"))
+    o:value("v2ray", translate("Xray (Hysteria2)"))
+end
+-- 读取全局 xray_hy2_type
+o.cfgvalue = function(self, section)
+    local val = uci:get("shadowsocksr", "@server_subscribe[0]", "xray_hy2_type")
+    if val == nil or val == "" then
+		return "__auto__"   -- 对应 Auto 选项
+    end
+    return val
+end
+o.rmempty = true
+-- 保存时更新全局配置
+o.write = function(self, section, value)
+    if value == "__auto__" then
+		-- 删除全局配置
+		uci:delete("shadowsocksr", "@server_subscribe[0]", "xray_hy2_type")
+    else
+		-- 设置具体值
+		uci:set("shadowsocksr", "@server_subscribe[0]", "xray_hy2_type", value)
+    end
 end
+
+-- 新增一个选择框,用于选择 Xray 或 Trojan 核心
+o = s:option(ListValue, "_xray_tj_type", string.format("<b><span style='color:red;'>%s</span></b>", translatef("%s Node Use Type", "Trojan")))
+o.description = translate("The configured type also applies to the core specified when manually importing nodes.")
+-- 注意:Auto 选项使用特殊字符串 "__auto__" 而不是空字符串
+o:value("__auto__", translate("Auto"))
 if has_hysteria2 then
-	o:value("hysteria2", translate("Hysteria2"))
+    o:value("trojan", translate("Trojan"))
 end
--- 读取全局 xray_hy2_type
+if has_xray then
+    o:value("v2ray", translate("Xray (Trojan)"))
+end
+-- 读取全局 xray_tj_type
 o.cfgvalue = function(self, section)
-	return self.map.uci:get("shadowsocksr", "@server_subscribe[0]", "xray_hy2_type") or "hysteria2"
+    local val = uci:get("shadowsocksr", "@server_subscribe[0]", "xray_tj_type")
+    if val == nil or val == "" then
+		return "__auto__"   -- 对应 Auto 选项
+    end
+    return val
 end
 o.rmempty = true
+-- 保存时更新全局配置
 o.write = function(self, section, value)
-	-- 更新 server_subscribe 的 xray_hy2_type
-	local old_value = self.map.uci:get("shadowsocksr", "@server_subscribe[0]", "xray_hy2_type")
-	if old_value ~= value then
-		self.map.uci:set("shadowsocksr", "@server_subscribe[0]", "xray_hy2_type", value)
-	end
+    if value == "__auto__" then
+		-- 删除全局配置
+		uci:delete("shadowsocksr", "@server_subscribe[0]", "xray_tj_type")
+    else
+		-- 设置具体值
+		uci:set("shadowsocksr", "@server_subscribe[0]", "xray_tj_type", value)
+    end
 end
 
 o = s:option(ListValue, "type", translate("Server Node Type"))
@@ -329,6 +368,29 @@ end
 if is_finded("redsocks2") then
 	o:value("tun", translate("Network Tunnel"))
 end
+local old_cfgvalue = o.cfgvalue
+o.cfgvalue = function(self, section)
+    local val = self.map.uci:get("shadowsocksr", section, "type")
+    if val == "ss-rust" or val == "ss-libev" then
+		return "ss"
+    end
+    if old_cfgvalue then
+		return old_cfgvalue(self, section)
+    end
+    return val
+end
+-- 重写 write,当用户选择 "ss" 时不写入(由 _ss_core 负责写入具体核心)
+local old_write = o.write
+o.write = function(self, section, value)
+    if value == "ss" then
+		return  -- 不做任何写入,等待 _ss_core 写入
+    end
+    if old_write then
+		old_write(self, section, value)
+    else
+		self.map.uci:set("shadowsocksr", section, "type", value)
+    end
+end
 
 o.description = translate("Using incorrect encryption mothod may causes service fail to start")
 
@@ -343,29 +405,37 @@ end
 o:depends("type", "tun")
 o.description = translate("Redirect traffic to this network interface")
 
--- 新增一个选择框,用于选择 Shadowsocks 版本
-o = s:option(ListValue, "_has_ss_type", string.format("<b><span style='color:red;'>%s</span></b>", translatef("%s Node Use Version", "ShadowSocks")))
+-- 新增一个选择框,用于选择 Shadowsocks 具体版本(仅当节点类型为 ss 或其具体子类型时显示)
+o = s:option(ListValue, "_ss_core", string.format("<b><span style='color:red;'>%s</span></b>", translatef("%s Node Use Version", "ShadowSocks")))
 o.description = translate("Selection ShadowSocks Node Use Version.")
--- 设置默认 Shadowsocks 版本
--- 动态添加选项
 if has_ss_rust then
-	o:value("ss-rust", translate("ShadowSocks-rust Version"))
+    o:value("ss-rust", translate("ShadowSocks-rust Version"))
 end
 if has_ss_libev then
-	o:value("ss-libev", translate("ShadowSocks-libev Version"))
+    o:value("ss-libev", translate("ShadowSocks-libev Version"))
 end
--- 读取全局 ss_type
 o.cfgvalue = function(self, section)
-	return self.map.uci:get("shadowsocksr", "@server_subscribe[0]", "ss_type") or "ss-rust"
+    -- 读取当前节点的 type 值,如果已经是具体核心则显示对应的选项
+    local node_type = self.map.uci:get("shadowsocksr", section, "type")
+    if node_type == "ss-rust" or node_type == "ss-libev" then
+		return node_type
+    end
+    -- 如果全局 ss_type 有值且为具体核心则返回该值
+    local ss_type = self.map.uci:get("shadowsocksr", "@server_subscribe[0]", "ss_type")
+    if ss_type == "ss-rust" or ss_type == "ss-libev" then
+		return ss_type
+    end
+    -- 如果节点 type 是旧的 "ss",则返回空,手动选择
+    return nil
 end
+-- 显示条件:当节点类型为 "ss" 或其具体核心时显示
 o:depends("type", "ss")
 o.rmempty = true
+-- 保存时,将选择的值直接写入当前节点的 type 字段
 o.write = function(self, section, value)
-	-- 更新 server_subscribe 的 ss_type
-	local old_value = self.map.uci:get("shadowsocksr", "@server_subscribe[0]", "ss_type")
-	if old_value ~= value then
-		self.map.uci:set("shadowsocksr", "@server_subscribe[0]", "ss_type", value)
-	end
+    if value and value ~= "" then
+		self.map.uci:set("shadowsocksr", section, "type", value)
+    end
 end
 
 o = s:option(ListValue, "v2ray_protocol", translate("V2Ray/XRay protocol"))

+ 0 - 1
luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua

@@ -294,4 +294,3 @@ if is_finded("chinadns-ng") then
 end
 
 return m
-

+ 77 - 25
luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua

@@ -70,9 +70,14 @@ local function set_apply_on_parse(map)
 	end
 end
 
+local has_ss_rust = is_finded("sslocal") or is_finded("ssserver")
+local has_ss_libev = is_finded("ss-redir") or is_finded("ss-local")
+local has_trojan = is_finded("trojan")
 local has_xray = is_finded("xray")
 local has_hysteria2 = is_finded("hysteria")
 
+local ss_type_list = {}
+local tj_type_list = {}
 local hy2_type_list = {}
 
 if has_hysteria2 then
@@ -82,19 +87,12 @@ if has_xray then
 	table.insert(hy2_type_list, { id = "v2ray", name = translate("Xray (Hysteria2)") })
 end
 
--- 如果用户没有手动设置,则自动选择
-if not xray_hy2_type or xray_hy2_type == "" then
-	if has_hysteria2 then
-		xray_hy2_type = "hysteria2"
-	elseif has_xray then
-		xray_hy2_type = "v2ray"
-	end
+if has_trojan then
+	table.insert(tj_type_list, { id = "trojan", name = translate("Trojan") })
+end
+if has_xray then
+	table.insert(tj_type_list, { id = "v2ray", name = translate("Xray (Trojan)") })
 end
-
-local has_ss_rust = is_finded("sslocal") or is_finded("ssserver")
-local has_ss_libev = is_finded("ss-redir") or is_finded("ss-local")
-
-local ss_type_list = {}
 
 if has_ss_rust then
 	table.insert(ss_type_list, { id = "ss-rust", name = translate("ShadowSocks-rust Version") })
@@ -106,17 +104,6 @@ if has_xray then
 	table.insert(ss_type_list, { id = "v2ray", name = translate("Xray (ShadowSocks)") })
 end
 
--- 如果用户没有手动设置,则自动选择
-if not ss_type or ss_type == "" then
-	if has_ss_rust then
-		ss_type = "ss-rust"
-	elseif has_ss_libev then
-		ss_type = "ss-libev"
-	elseif has_xray then
-		ss_type = "v2ray"
-	end
-end
-
 uci:foreach("shadowsocksr", "servers", function(s)
 	server_count = server_count + 1
 end)
@@ -162,22 +149,87 @@ o:depends("auto_update", "1")
 
 -- 确保 hy2_type_list 不为空
 if #hy2_type_list > 0 then
+	local sid = uci:get_first("shadowsocksr", "server_subscribe")
+	if not sid then
+		uci:foreach("shadowsocksr", "server_subscribe", function(section)
+			sid = section[".name"]
+			return false
+		end)
+	end
+	if sid then
+		local old_val = uci:get("shadowsocksr", sid, "xray_hy2_type")
+		if old_val and old_val ~= "" then
+			if (old_val == "hysteria2" and not has_hysteria2) or
+			   (old_val == "v2ray" and not has_xray) then
+				-- 核心不可用,设置为空(删除配置)
+				uci:set("shadowsocksr", sid, "xray_hy2_type", "")
+				uci:commit("shadowsocksr")
+			end
+		end
+	end
 	o = s:option(ListValue, "xray_hy2_type", string.format("<b><span style='color:red;'>%s</span></b>", translatef("%s Node Use Type", "Hysteria2")))
 	o.description = translate("The configured type also applies to the core specified when manually importing nodes.")
+	o:value("", translate("Auto"))
 	for _, v in ipairs(hy2_type_list) do
 		o:value(v.id, v.name) -- 存储 "Xray" / "Hysteria2",但 UI 显示完整名称
 	end
-	o.default = xray_hy2_type  -- 设置默认值
+end
+
+-- 确保 tj_type_list 不为空
+if #tj_type_list > 0 then
+	local sid = uci:get_first("shadowsocksr", "server_subscribe")
+	if not sid then
+		uci:foreach("shadowsocksr", "server_subscribe", function(section)
+			sid = section[".name"]
+			return false
+		end)
+	end
+	if sid then
+		local old_val = uci:get("shadowsocksr", sid, "xray_tj_type")
+		if old_val and old_val ~= "" then
+			if (old_val == "trojan" and not has_trojan) or
+			   (old_val == "v2ray" and not has_xray) then
+				-- 核心不可用,设置为空(删除配置)
+				uci:set("shadowsocksr", sid, "xray_tj_type", "")
+				uci:commit("shadowsocksr")
+			end
+		end
+	end
+	o = s:option(ListValue, "xray_tj_type", string.format("<b><span style='color:red;'>%s</span></b>", translatef("%s Node Use Type", "Trojan")))
+	o.description = translate("The configured type also applies to the core specified when manually importing nodes.")
+	o:value("", translate("Auto"))
+	for _, v in ipairs(tj_type_list) do
+		o:value(v.id, v.name) -- 存储 "Xray" / "Trojan",但 UI 显示完整名称
+	end
 end
 
 -- 确保 ss_type_list 不为空
 if #ss_type_list > 0 then
+	local sid = uci:get_first("shadowsocksr", "server_subscribe")
+	if not sid then
+		uci:foreach("shadowsocksr", "server_subscribe", function(section)
+			sid = section[".name"]
+			return false
+		end)
+	end
+	if sid then
+		local old_val = uci:get("shadowsocksr", sid, "ss_type")
+		if old_val and old_val ~= "" then
+			if (old_val == "ss-rust" and not has_ss_rust) or
+			   (old_val == "ss-libev" and not has_ss_libev) or
+			   (old_val == "v2ray" and not has_xray) then
+				-- 核心不可用,设置为空(删除配置)
+				uci:set("shadowsocksr", sid, "ss_type", "")
+				uci:commit("shadowsocksr")
+			end
+		end
+	end
 	o = s:option(ListValue, "ss_type", string.format("<b><span style='color:red;'>%s</span></b>", translatef("%s Node Use Version", "ShadowSocks")))
 	o.description = translate("Selection ShadowSocks Node Use Version.")
+	o:value("", translate("Auto"))
 	for _, v in ipairs(ss_type_list) do
 		o:value(v.id, v.name) -- 存储 "ss-libev" / "ss-rust",但 UI 显示完整名称
 	end
-	o.default = ss_type  -- 设置默认值
 end
 
 o = s:option(DynamicList, "subscribe_url", translate("Subscribe URL"))

+ 200 - 47
luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm

@@ -3,11 +3,24 @@
 local map = self.map
 local ss_type = map:get("@server_subscribe[0]", "ss_type")
 local xray_hy2_type = map:get("@server_subscribe[0]", "xray_hy2_type")
+local xray_tj_type = map:get("@server_subscribe[0]", "xray_tj_type")
+
+local has_ss_rust = luci.sys.exec('type -t -p sslocal 2>/dev/null || type -t -p ssserver 2>/dev/null') ~= ""
+local has_ss_libev = luci.sys.exec('type -t -p ss-redir 2>/dev/null || type -t -p ss-local 2>/dev/null') ~= ""
+local has_hysteria = luci.sys.exec('type -t -p hysteria 2>/dev/null') ~= ""
+local has_trojan = luci.sys.exec('type -t -p trojan 2>/dev/null') ~= ""
+local has_xray = luci.sys.exec('type -t -p xray 2>/dev/null') ~= ""
 -%>
 <script type="text/javascript">
 //<![CDATA[
 let ss_type = "<%=ss_type%>"
 let xray_hy2_type = "<%=xray_hy2_type%>"
+let xray_tj_type = "<%=xray_tj_type%>"
+let has_ss_rust = "<%=has_ss_rust%>"
+let has_ss_libev = "<%=has_ss_libev%>"
+let has_hysteria = "<%=has_hysteria%>"
+let has_trojan = "<%=has_trojan%>"
+let has_xray = "<%=has_xray%>"
 
 function padright(str, cnt, pad) {
 	return str + Array(cnt + 1).join(pad);
@@ -112,48 +125,105 @@ function import_ssr_url(btn, urlname, sid) {
 				return false;
 			}
 
-			if (xray_hy2_type === "hysteria2") {
+			// 普通 Hysteria2 导入函数
+			function importAsNormalHy2() {
 				document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = (ssu[0] === "hy2") ? "hysteria2" : ssu[0];
 				document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].dispatchEvent(event);
-
 				if (params.get("protocol") && params.get("protocol").trim() !== "") {
 					document.getElementsByName('cbid.shadowsocksr.' + sid + '.flag_transport')[0].checked = true; // 设置 flag_transport 为 true
 					document.getElementsByName('cbid.shadowsocksr.' + sid + '.flag_transport')[0].dispatchEvent(event); // 触发事件
 
 				document.getElementsByName('cbid.shadowsocksr.' + sid + '.transport_protocol')[0].value = params.get("protocol") || "udp";
 				}
+				if (params.get("lazy") === "1") { 
+					document.getElementsByName('cbid.shadowsocksr.' + sid + '.lazy_mode')[0].checked = true;
+					document.getElementsByName('cbid.shadowsocksr.' + sid + '.lazy_mode')[0].dispatchEvent(event);
+				}
+				if (params.get("sni") || params.get("alpn")) {
+					document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls')[0].checked = true; // 设置 tls 为 true
+					document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls')[0].dispatchEvent(event); // 触发事件
+					if (params.get("sni")) {
+						document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls_host')[0].value = params.get("sni") || "";
+					}
+					if (params.get("alpn") && params.get("alpn").trim() !== "") {
+						document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls_alpn')[0].value = params.get("alpn") || "";
+					}
+				}
 				if (params.get("pinSHA256") && params.get("pinSHA256").trim() !== "") {
 					document.getElementsByName('cbid.shadowsocksr.' + sid + '.pinsha256')[0].value = params.get("pinSHA256") || "";
 				}
+			}
+
+			// Xray Hysteria2 导入函数
+			function importAsXrayHy2() {
+				document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = "v2ray"
+				document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].dispatchEvent(event);
+				document.getElementsByName('cbid.shadowsocksr.' + sid + '.v2ray_protocol')[0].value = (ssu[0] === "hy2") ? "hysteria2" : ssu[0];
+				document.getElementsByName('cbid.shadowsocksr.' + sid + '.v2ray_protocol')[0].dispatchEvent(event);
+				if (params.get("security") === "tls" || params.get("sni") || params.get("alpn") || (params.get("pcs") || params.get("vcn"))) {
+					document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls')[0].checked = true; // 设置 tls 为 true
+					document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls')[0].dispatchEvent(event); // 触发事件
+					if (params.get("sni")) {
+						document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls_host')[0].value = params.get("sni") || "";
+					}
+					if (params.get("alpn") && params.get("alpn").trim() !== "") {
+						document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls_alpn')[0].value = params.get("alpn") || "";
+					}
+					if (params.get("pcs") && params.get("pcs").trim() !== "") {
+						document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls_CertSha')[0].value = params.get("pcs") || "";
+					}
+					if (params.get("vcn") && params.get("vcn").trim() !== "") {
+						document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls_CertByName')[0].value = params.get("vcn") || "";
+					}
+				}
 				if (params.get("fm") && params.get("fm").trim() !== "") {
 					document.getElementsByName('cbid.shadowsocksr.' + sid + '.enable_finalmask')[0].checked = true; // 设置 enable_finalmask 为 true
 					document.getElementsByName('cbid.shadowsocksr.' + sid + '.enable_finalmask')[0].dispatchEvent(event); // 触发事件
 
 				document.getElementsByName('cbid.shadowsocksr.' + sid + '.finalmask')[0].value = params.get("fm") || "";
 				}
-				document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0].value = url.hash ? decodeURIComponent(url.hash.slice(1)) : "";
-			} else {
-				document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = "v2ray"
-				document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].dispatchEvent(event);
-				document.getElementsByName('cbid.shadowsocksr.' + sid + '.v2ray_protocol')[0].value = (ssu[0] === "hy2") ? "hysteria2" : ssu[0];
-				document.getElementsByName('cbid.shadowsocksr.' + sid + '.v2ray_protocol')[0].dispatchEvent(event);
+			}
 
-				document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0].value = url.hash ? decodeURIComponent(url.hash.slice(1)) : "";
+			// 主逻辑:智能核心选择(支持回退)
+			function hasCore(core) {
+				if (core === "hysteria") return has_hysteria === "true";
+				if (core === "xray") return has_xray === "true";
+				return false;
+			}
+			let finalMode = null; // true=Xray, false=普通, null=无核心
+			if (xray_hy2_type === "v2ray") {
+				if (hasCore("xray")) finalMode = true;
+				else if (hasCore("hysteria")) finalMode = false;
+				else finalMode = null;
+			} else if (xray_hy2_type === "hysteria2") {
+				if (hasCore("hysteria")) finalMode = false;
+				else if (hasCore("xray")) finalMode = true;
+				else finalMode = null;
+			} else {
+				// auto 或空:Hysteria2 无 type 参数,优先普通 Hysteria2
+				if (hasCore("hysteria")) finalMode = false;
+				else if (hasCore("xray")) finalMode = true;
+				else finalMode = null;
+			}
+			if (finalMode === null) {
+				s.innerHTML = "<font style=\'color:red\'><%:No available core (Hysteria2 or Xray) to import this node.%></font>";
+				return false;
 			}
+			if (finalMode === true) importAsXrayHy2();
+			else importAsNormalHy2();
+
+			document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0].value = url.hash ? decodeURIComponent(url.hash.slice(1)) : "";
 			document.getElementsByName('cbid.shadowsocksr.' + sid + '.server')[0].value = url.hostname;
 			document.getElementsByName('cbid.shadowsocksr.' + sid + '.server_port')[0].value = url.port || "443";
-			if (params.get("lazy") === "1") { 
-				document.getElementsByName('cbid.shadowsocksr.' + sid + '.lazy_mode')[0].checked = true;
-				document.getElementsByName('cbid.shadowsocksr.' + sid + '.lazy_mode')[0].dispatchEvent(event);
-			}
+			document.getElementsByName('cbid.shadowsocksr.' + sid + '.hy2_auth')[0].value = decodeURIComponent(url.username);
+			document.getElementsByName('cbid.shadowsocksr.' + sid + '.hy2_auth')[0].dispatchEvent(event);
+
 			if (params.get("mport")) {
 				document.getElementsByName('cbid.shadowsocksr.' + sid + '.flag_port_hopping')[0].checked = true; // 设置 flag_port_hopping 为 true
 				document.getElementsByName('cbid.shadowsocksr.' + sid + '.flag_port_hopping')[0].dispatchEvent(event); // 触发事件
 
 			document.getElementsByName('cbid.shadowsocksr.' + sid + '.port_range')[0].value = params.get("mport") || "";
 			}
-			document.getElementsByName('cbid.shadowsocksr.' + sid + '.hy2_auth')[0].value = decodeURIComponent(url.username);
-			document.getElementsByName('cbid.shadowsocksr.' + sid + '.hy2_auth')[0].dispatchEvent(event);
 			document.getElementsByName('cbid.shadowsocksr.' + sid + '.uplink_capacity')[0].value =
 				(params.get("upmbps") && params.get("upmbps").match(/\d+/)) ? params.get("upmbps").match(/\d+/)[0] : "";
 			document.getElementsByName('cbid.shadowsocksr.' + sid + '.downlink_capacity')[0].value =
@@ -165,25 +235,6 @@ function import_ssr_url(btn, urlname, sid) {
 			document.getElementsByName('cbid.shadowsocksr.' + sid + '.obfs_type')[0].value = params.get("obfs");
 			document.getElementsByName('cbid.shadowsocksr.' + sid + '.salamander')[0].value = params.get("obfs-password") || params.get("obfs_password");
 			}
-			if (params.get("security") === "tls" || params.get("sni") || params.get("alpn") 
-					|| (xray_hy2_type !== "hysteria2" && (params.get("pcs") || params.get("vcn")))) {
-				document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls')[0].checked = true; // 设置 tls 为 true
-				document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls')[0].dispatchEvent(event); // 触发事件
-				if (params.get("sni") && params.get("protocol").trim() !== "") {
-					document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls_host')[0].value = params.get("sni") || "";
-				}
-				if (params.get("alpn") && params.get("alpn").trim() !== "") {
-					document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls_alpn')[0].value = params.get("alpn") || "";
-				}
-				if (xray_hy2_type !== "hysteria2") {
-					if (params.get("pcs") && params.get("pcs").trim() !== "") {
-						document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls_CertSha')[0].value = params.get("pcs") || "";
-					}
-					if (params.get("vcn") && params.get("vcn").trim() !== "") {
-						document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls_CertByName')[0].value = params.get("vcn") || "";
-					}
-				}
-			}
 			var allowInsecureValue = params.get("allowInsecure") || params.get("insecure");
 			if (allowInsecureValue === "1" || allowInsecureValue === "true") {
 				document.getElementsByName('cbid.shadowsocksr.' + sid + '.insecure')[0].checked = true; // 设置 insecure 为 true
@@ -218,7 +269,7 @@ function import_ssr_url(btn, urlname, sid) {
 
 			var params = Object.fromEntries(new URLSearchParams(query));
 
-			if ( ss_type !== "v2ray") {
+			function importAsNormalSS() {
 				// 普通 SS 导入逻辑
 				// 判断是否 SIP002 格式(即含 @)
 				if (url0.indexOf("@") !== -1) {
@@ -226,15 +277,28 @@ function import_ssr_url(btn, urlname, sid) {
 					var sipIndex = url0.indexOf("@");
 					// 先 URL 解码 base64 再解码
 					var userInfoB64 = decodeURIComponent(url0.substring(0, sipIndex));
+					// console.log("userInfoB64:", userInfoB64);
 					var userInfo = b64decsafe(userInfoB64);
+					if (userInfo && userInfo.indexOf(":") !== -1) {
+						var userInfo = userInfo;
+					} else {
+						var userInfo = userInfoB64;
+					}
+					// 如果没有冒号,且不是 base64 格式,我们可以尝试补齐它
+					if (userInfo.indexOf(":") === -1) {
+						userInfo = "none:" + userInfo;
+					}
+					// console.log("userInfo after decode:", userInfo);
 					var userInfoSplitIndex = userInfo.indexOf(":");
 					if(userInfoSplitIndex < 0) {
 						// 格式错误
 						s.innerHTML = "<font style='color:red'><%:Userinfo format error.%></font>";
-						break;
+						return false;
 					}
 					var method = userInfo.substring(0, userInfoSplitIndex);
+					// console.log("method:", method);
 					var password = userInfo.substring(userInfoSplitIndex + 1);
+					// console.log("password:", password);
 					var serverPart = url0.substring(sipIndex + 1);
 					var serverInfo = serverPart.split(":");
 
@@ -254,7 +318,7 @@ function import_ssr_url(btn, urlname, sid) {
 					var sstr = b64decsafe(decodedUrl0);
 					if (!sstr) {
 						s.innerHTML = "<font style='color:red'><%:Base64 sstr failed.%></font>";
-						break;
+						return false;
 					}
 
 					// 支持 SS2022 / 普通格式
@@ -276,7 +340,7 @@ function import_ssr_url(btn, urlname, sid) {
 						var port = mNormal[4];
 					} else {
 						s.innerHTML = "<font style='color:red'><%:SS URL base64 sstr format not recognized.%></font>";
-						break;
+						return false;
 					}
 
 					var plugin = "", pluginOpts = "";
@@ -314,9 +378,17 @@ function import_ssr_url(btn, urlname, sid) {
 
 				// === 填充配置项 ===
 				//var has_ss_type = (ss_type === "ss-rust") ? "ss-rust" : "ss-libev";
+				// 设置 _ss_core 的值
+				var ssCore = (ss_type === "ss-rust" || ss_type === "ss-libev") 
+							 ? ss_type 
+							 : (has_ss_rust ? "ss-rust" : (has_ss_libev ? "ss-libev" : "ss-libev"));
 
 				document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = ssu[0];
 				document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].dispatchEvent(event);
+
+				document.getElementsByName('cbid.shadowsocksr.' + sid + '._ss_core')[0].value = ssCore;
+				document.getElementsByName('cbid.shadowsocksr.' + sid + '._ss_core')[0].dispatchEvent(event);
+
 				//document.getElementsByName('cbid.shadowsocksr.' + sid + '.has_ss_type')[0].value = has_ss_type;
 				//document.getElementsByName('cbid.shadowsocksr.' + sid + '.has_ss_type')[0].dispatchEvent(event);
 				document.getElementsByName('cbid.shadowsocksr.' + sid + '.server')[0].value = server;
@@ -351,8 +423,10 @@ function import_ssr_url(btn, urlname, sid) {
 					document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0].value = decodeURIComponent(param);
 				}
 				s.innerHTML = "<font style=\'color:green\'><%:Import configuration information successfully.%></font>";
-				return false;
-			} else {			
+				return true;
+			}
+
+			function importAsXraySS() {			
 				try {
 					// Xray SS 导入逻辑
 					// 拆分 @,判断是否是 base64 userinfo 的格式
@@ -366,7 +440,14 @@ function import_ssr_url(btn, urlname, sid) {
 							password = userinfo.slice(sepIndex + 1);  //一些链接用明文uuid做密码
 						}
 					}
-					var url = new URL("http://" + url0 + (param ? "#" + encodeURIComponent(param) : ""));
+					// 已编码的别名
+					// var url = new URL("http://" + url0 + (param ? "#" + encodeURIComponent(param) : ""));
+					// 未编码的别名
+					// var url = new URL("http://" + url0 + (param ? "#" + param : ""));
+					// 兼容已编码和未编码的别名
+					var remarks = param ? decodeURIComponent(param) : "";
+					var encodedremarks = encodeURIComponent(remarks);
+					var url = new URL("http://" + url0 + (encodedremarks ? "#" + encodedremarks : ""));
 
 				} catch(e) {
 					alert(e);
@@ -411,7 +492,7 @@ function import_ssr_url(btn, urlname, sid) {
 				}
 				if (params.fm && params.fm.trim() !== "") {
 					setElementValue('cbid.shadowsocksr.' + sid + '.enable_finalmask', true); // 设置 enable_finalmask 为 true
-					setElementValue('cbid.shadowsocksr.' + sid + '.enable_finalmask', event); // 触发事件
+					dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.enable_finalmask', event); // 触发事件
 
 				setElementValue('cbid.shadowsocksr.' + sid + '.finalmask', params.fm || "");
 				}
@@ -514,8 +595,46 @@ function import_ssr_url(btn, urlname, sid) {
 					break;
 				}
 				s.innerHTML = "<font style=\'color:green\'><%:Import configuration information successfully.%></font>";
+				return true;
+			}
+
+			// 主逻辑:智能核心选择(支持回退)
+			function hasSSCore() { return has_ss_rust === "true" || has_ss_libev === "true"; }
+			function hasXrayCore() { return has_xray === "true"; }
+			let finalSSType = null; // true=Xray, false=普通SS, null=无核心
+			if (ss_type === "v2ray") {
+				if (hasXrayCore()) finalSSType = true;
+				else if (hasSSCore()) finalSSType = false;
+				else finalSSType = null;
+			} else if (ss_type === "ss-rust" || ss_type === "ss-libev") {
+				let userSSCore = (ss_type === "ss-rust" && has_ss_rust === "true") || (ss_type === "ss-libev" && has_ss_libev === "true");
+				if (userSSCore) finalSSType = false;
+				else {
+					let otherSSCore = (ss_type === "ss-rust" && has_ss_libev === "true") || (ss_type === "ss-libev" && has_ss_rust === "true");
+					if (otherSSCore) finalSSType = false;
+					else if (hasXrayCore()) finalSSType = true;
+					else finalSSType = null;
+				}
+			} else {
+				// auto 或空:根据 type 参数决定
+				let hasType = params.type && params.type !== "";
+				if (hasType) {
+					if (hasXrayCore()) finalSSType = true;
+					else if (hasSSCore()) finalSSType = false;
+					else finalSSType = null;
+				} else {
+					if (hasSSCore()) finalSSType = false;
+					else if (hasXrayCore()) finalSSType = true;
+					else finalSSType = null;
+				}
+			}
+			if (finalSSType === null) {
+				s.innerHTML = "<font style=\'color:red\'><%:No available core (Shadowsocks or Xray) to import this node.%></font>";
 				return false;
 			}
+			if (finalSSType === true) importAsXraySS();
+			else importAsNormalSS();
+			return false;
 		case "ssr":
 			var sstr = b64decsafe((ssu[1] || "").replace(/#.*/, "").trim());
 			var ploc = sstr.indexOf("/?");
@@ -561,8 +680,8 @@ function import_ssr_url(btn, urlname, sid) {
 				return false;
 			}
 
-			if (!params.get("type")) {
-				// 普通 Trojan 导入逻辑
+			// 普通 Trojan 导入逻辑
+			function importAsNormalTrojan() {
 				document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0].value = url.hash ? decodeURIComponent(url.hash.slice(1)) : "";
 				document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = "trojan";
 				document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].dispatchEvent(event);
@@ -585,9 +704,11 @@ function import_ssr_url(btn, urlname, sid) {
 				}
 
 				s.innerHTML = "<font style=\'color:green\'><%:Import configuration information successfully.%></font>";
-				return false;
-			} else {
-				// Xray Trojan 导入逻辑
+				return true;
+			}
+
+			// Xray Trojan 导入逻辑
+			function importAsXrayTrojan() {
 				document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0].value = url.hash ? decodeURIComponent(url.hash.slice(1)) : "";
 				document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = "v2ray";
 				document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].dispatchEvent(event);
@@ -690,8 +811,40 @@ function import_ssr_url(btn, urlname, sid) {
 				}
 
 				s.innerHTML = "<font style=\'color:green\'><%:Import configuration information successfully.%></font>";
+				return true;
+			}
+
+			// 主逻辑:智能核心选择(支持回退)
+			function hasTrojanCore() { return has_trojan === "true"; }
+			function hasXrayCore() { return has_xray === "true"; }
+			let finalTrojanMode = null;
+			if (xray_tj_type === "v2ray") {
+				if (hasXrayCore()) finalTrojanMode = true;
+				else if (hasTrojanCore()) finalTrojanMode = false;
+				else finalTrojanMode = null;
+			} else if (xray_tj_type === "trojan") {
+				if (hasTrojanCore()) finalTrojanMode = false;
+				else if (hasXrayCore()) finalTrojanMode = true;
+				else finalTrojanMode = null;
+			} else {
+				let hasType = params.get("type") && params.get("type") !== "";
+				if (hasType) {
+					if (hasXrayCore()) finalTrojanMode = true;
+					else if (hasTrojanCore()) finalTrojanMode = false;
+					else finalTrojanMode = null;
+				} else {
+					if (hasTrojanCore()) finalTrojanMode = false;
+					else if (hasXrayCore()) finalTrojanMode = true;
+					else finalTrojanMode = null;
+				}
+			}
+			if (finalTrojanMode === null) {
+				s.innerHTML = "<font style=\'color:red\'><%:No available core (Trojan or Xray) to import this node.%></font>";
 				return false;
 			}
+			if (finalTrojanMode === true) importAsXrayTrojan();
+			else importAsNormalTrojan();
+			return false;
 		case "vmess":
 			var sstr = b64DecodeUnicode((ssu[1] || "").replace(/#.*/, "").trim());
 			var ploc = sstr.indexOf("/?");

Diferenças do arquivo suprimidas por serem muito extensas
+ 196 - 174
luci-app-ssr-plus/po/templates/ssr-plus.pot


Diferenças do arquivo suprimidas por serem muito extensas
+ 197 - 175
luci-app-ssr-plus/po/zh_Hans/ssr-plus.po


+ 38 - 23
luci-app-ssr-plus/root/etc/init.d/shadowsocksr

@@ -611,15 +611,18 @@ gen_config_file() { #server1 type2 code3 local_port4 socks_port5 chain6 threads5
 }
 
 start_udp() {
-	local type=$(uci_get_by_name $UDP_RELAY_SERVER type)
-	local has_ss_type=$(uci_get_by_type server_subscribe ss_type)
+	local udp_relay_server_type=$(uci_get_by_name $UDP_RELAY_SERVER type)
+	local type=$udp_relay_server_type
+	if [ "$udp_relay_server_type" = "ss-rust" ] || [ "$udp_relay_server_type" = "ss-libev" ]; then
+		type="ss"
+	fi
 	redir_udp=1
 	case "$type" in
 	ss | ssr)
 		gen_config_file $UDP_RELAY_SERVER $type 2 $tmp_udp_port
-		if [ "$has_ss_type" = "ss-libev" -o "$type" = "ssr" ]; then
+		if [ "$udp_relay_server_type" = "ss-libev" ] || [ "$udp_relay_server_type" = "ssr" ]; then
 			ss_program="$(first_type ${type}-redir)"
-		elif [ "$has_ss_type" = "ss-rust" ]; then
+		elif [ "$udp_relay_server_type" = "ss-rust" ]; then
 			ss_program="$(first_type ${type}local)"
 		fi
 		echolog "$(get_name $type) program is: $ss_program"
@@ -858,14 +861,17 @@ shunt_dns_config_file_port() {
 }
 
 start_shunt() {
-	local type=$(uci_get_by_name $SHUNT_SERVER type)
-	local has_ss_type=$(uci_get_by_type server_subscribe ss_type)
+	local shunt_server_type=$(uci_get_by_name $SHUNT_SERVER type)
+	local type=$shunt_server_type
+	if [ "$shunt_server_type" = "ss-rust" ] || [ "$shunt_server_type" = "ss-libev" ]; then
+		type="ss"
+	fi
 	case "$type" in
 	ss | ssr)
 		gen_config_file $SHUNT_SERVER $type 3 $tmp_shunt_port
-		if [ "$has_ss_type" = "ss-libev" -o "$type" = "ssr" ]; then
+		if [ "$shunt_server_type" = "ss-libev" ] || [ "$shunt_server_type" = "ssr" ]; then
 			ss_program="$(first_type ${type}-redir)"
-		elif [ "$has_ss_type" = "ss-rust" ]; then
+		elif [ "$shunt_server_type" = "ss-rust" ]; then
 			ss_program="$(first_type ${type}local)"
 		fi
 		echolog "$(get_name $type) program is: $ss_program"
@@ -880,9 +886,9 @@ start_shunt() {
 			local tmp_port=$tmp_local_port
 		else
 			local tmp_port=$tmp_shunt_local_port
-			if [ "$has_ss_type" = "ss-libev" -o "$type" = "ssr" ]; then
+			if [ "$shunt_server_type" = "ss-libev" ] || [ "$shunt_server_type" = "ssr" ]; then
 				dns_ss_program="$(first_type ${type}-local)"
-			elif [ "$has_ss_type" = "ss-rust" ]; then
+			elif [ "$shunt_server_type" = "ss-rust" ]; then
 				dns_ss_program="$(first_type ${type}local)"
 			fi
 			# 获取当前软链接指向的执行文件路径
@@ -1009,14 +1015,17 @@ start_local() {
 	[ "$LOCAL_SERVER" = "nil" ] && return 1
 	local local_port=$(uci_get_by_type socks5_proxy local_port)
 	[ "$LOCAL_SERVER" == "$SHUNT_SERVER" ] && tmp_local_port=$local_port
-	local type=$(uci_get_by_name $LOCAL_SERVER type)
-	local has_ss_type=$(uci_get_by_type server_subscribe ss_type)
+	local local_server_type=$(uci_get_by_name $LOCAL_SERVER type)
+	local type=$local_server_type
+	if [ "$local_server_type" = "ss-rust" ] || [ "$local_server_type" = "ss-libev" ]; then
+		type="ss"
+	fi
 	case "$type" in
 	ss | ssr)
 		gen_config_file $LOCAL_SERVER $type 4 $local_port
-		if [ "$has_ss_type" = "ss-libev" -o "$type" = "ssr" ]; then
+		if [ "$local_server_type" = "ss-libev" ] || [ "$local_server_type" = "ssr" ]; then
 			ss_program="$(first_type ${type}-local)"
-		elif [ "$has_ss_type" = "ss-rust" ]; then
+		elif [ "$local_server_type" = "ss-rust" ]; then
 			ss_program="$(first_type ${type}local)"
 		fi
 		echolog "$(get_name $type) program is: $ss_program"
@@ -1124,14 +1133,17 @@ Start_Run() {
 		#}
 	fi
 	local tcp_port=$(uci_get_by_name $GLOBAL_SERVER local_port)
-	local type=$(uci_get_by_name $GLOBAL_SERVER type)
-	local has_ss_type=$(uci_get_by_type server_subscribe ss_type)
+	local global_server_type=$(uci_get_by_name $GLOBAL_SERVER type)
+	local type=$global_server_type
+	if [ "$global_server_type" = "ss-rust" ] || [ "$global_server_type" = "ss-libev" ]; then
+		type="ss"
+	fi
 	case "$type" in
 	ss | ssr)
 		gen_config_file $GLOBAL_SERVER $type 1 $tcp_port
-		if [ "$has_ss_type" = "ss-libev" -o "$type" = "ssr" ]; then
+		if [ "$global_server_type" = "ss-libev" ] || [ "$global_server_type" = "ssr" ]; then
 			ss_program="$(first_type ${type}-redir)"
-		elif [ "$has_ss_type" = "ss-rust" ]; then
+		elif [ "$global_server_type" = "ss-rust" ]; then
 			ss_program="$(first_type ${type}local)"
 		fi
 		echolog "$(get_name $type) program is: $ss_program"
@@ -1367,14 +1379,17 @@ start_server() {
 				fi
 			fi
 		fi
-		local type=$(uci_get_by_name $1 type)
-		local has_ss_type=$(uci_get_by_type server_subscribe ss_type)
+		local node_type=$(uci_get_by_name $1 type)
+		local type=$node_type
+		if [ "$node_type" = "ss-rust" ] || [ "$node_type" = "ss-libev" ]; then
+			type="ss"
+		fi
 		case "$type" in
 		ss | ssr)
 			gen_service_file ${type} $1 $TMP_PATH/ssr-server$server_count.json
-			if [ "$has_ss_type" = "ss-libev" -o "$type" = "ssr" ]; then
+			if [ "$node_type" = "ss-libev" ] || [ "$node_type" = "ssr" ]; then
 				ss_program="$(first_type ${type}-server)"
-			elif [ "$has_ss_type" = "ss-rust" ]; then
+			elif [ "$node_type" = "ss-rust" ]; then
 				ss_program="$(first_type ${type}server)"
 			fi
 			# 获取当前软链接指向的执行文件路径
@@ -1506,7 +1521,7 @@ start_xhttp_addr() {
 	# MD5 不同更新 download_address 地址文件
 	if [ "$md5_new" != "$md5_old" ]; then
 		mv -f "$tmp_file" "$xhttp_addr_file"
-		logger -t ssrplus-xhttp "xhttp_address.txt updated"
+		logger -t ssrplus-xhttp "download_address.txt updated"
 	else
 		rm -f "$tmp_file"
 	fi

+ 4 - 0
luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua

@@ -25,6 +25,10 @@ local remarks = server.alias or ""
 local b64decode = nixio.bin.b64decode
 local b64encode = nixio.bin.b64encode
 
+if server.type == "ss-rust" or server.type == "ss-libev" then
+    server.type = "ss"
+end
+
 -- base64 解码
 local function base64Decode(text)
 	local raw = text

+ 0 - 2
luci-app-ssr-plus/root/usr/share/shadowsocksr/shadowsocksr.config

@@ -27,10 +27,8 @@ config server_subscribe
 	option auto_update_week_time '*'
 	option auto_update_day_time '2'
 	option auto_update_min_time '0'
-	option ss_type 'ss-rust'
 	option url_test_url 'https://www.google.com/generate_204'
 	option user_agent 'v2rayN/9.99'
-	option xray_hy2_type 'hysteria2'
 	option filter_words '过期/套餐/剩余/QQ群/官网/防失联/回国'
 
 config access_control

+ 414 - 306
luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua

@@ -30,54 +30,20 @@ local subscribe_url = ucic:get_first(name, 'server_subscribe', 'subscribe_url',
 local filter_words = ucic:get_first(name, 'server_subscribe', 'filter_words', '过期时间/剩余流量')
 local save_words = ucic:get_first(name, 'server_subscribe', 'save_words', '')
 local user_agent = ucic:get_first(name, 'server_subscribe', 'user_agent', 'v2rayN/9.99')
+
 -- 读取 ss_type 设置
-local ss_type = ucic:get_first(name, 'server_subscribe', 'ss_type', 'ss-rust')
--- 根据 ss_type 选择对应的程序
-local ss_program = "sslocal"
-if ss_type == "ss-rust" then
-    ss_program = "sslocal"
-elseif ss_type == "ss-libev" then
-    ss_program = "ss-redir"
-elseif ss_type == "v2ray" then
-    ss_program = "xray"
-end
--- 从 UCI 配置读取 xray_hy2_type 设置
-local xray_hy2_type = ucic:get_first(name, 'server_subscribe', 'xray_hy2_type', 'hysteria2')
-local xray_hy2_program = "hysteria"
-if xray_hy2_type == "v2ray" then
-	xray_hy2_program = "xray"  -- Hysteria2 使用 Xray
-elseif xray_hy2_type == "hysteria2" then
-	xray_hy2_program = "hysteria"  -- Hysteria2 使用 Hysteria
-end
-local v2_ss_exists = luci.sys.exec('type -t -p ' .. ss_program .. ' 2>/dev/null') ~= ""
--- 初始化变量
-local v2_ss = nil
-local has_v2_ss_type = nil
-if v2_ss_exists then
-    if ss_type == "v2ray" then
-        -- 使用 Xray
-        v2_ss = "v2ray"
-        has_v2_ss_type = "shadowsocks"
-    else
-        -- 使用 SS (rust 或 libev)
-        v2_ss = "ss"
-    end
-end
-local v2_tj = luci.sys.exec('type -t -p trojan') ~= "" and "trojan" or "v2ray"
--- 检查程序是否存在
-local program_exists = luci.sys.exec('type -t -p ' .. xray_hy2_program .. ' 2>/dev/null') ~= ""
--- 初始化变量
-local hy2_type = nil
-local has_xray_hy2_type = nil
-if program_exists then
-	-- 设置节点类型
-	if xray_hy2_type == "hysteria2" then
-		hy2_type = "hysteria2"
-	else
-		hy2_type = "v2ray"  -- 当使用 Xray 时,节点类型是 "v2ray"
-		has_xray_hy2_type = "hysteria2"  -- 可用的协议类型是 Hysteria2
-	end
-end
+local ss_type = ucic:get_first(name, 'server_subscribe', 'ss_type')
+-- 读取 xray_hy2_type 设置
+local xray_hy2_type = ucic:get_first(name, 'server_subscribe', 'xray_hy2_type')
+-- 读取 xray_tj_type 设置
+local xray_tj_type = ucic:get_first(name, 'server_subscribe', 'xray_tj_type')
+
+local has_ss_rust = luci.sys.exec('type -t -p sslocal 2>/dev/null || type -t -p ssserver 2>/dev/null') ~= ""
+local has_ss_libev = luci.sys.exec('type -t -p ss-redir 2>/dev/null || type -t -p ss-local 2>/dev/null') ~= ""
+local has_hysteria = luci.sys.exec('type -t -p hysteria 2>/dev/null') ~= ""
+local has_trojan = luci.sys.exec('type -t -p trojan 2>/dev/null') ~= ""
+local has_xray = luci.sys.exec('type -t -p xray 2>/dev/null') ~= ""
+
 local tuic_type = luci.sys.exec('type -t -p tuic-client') ~= "" and "tuic"
 local log = function(...)
 	print(os.date("%Y-%m-%d %H:%M:%S ") .. table.concat({...}, " "))
@@ -246,12 +212,75 @@ local function processData(szType, content, cfgid)
 		--	log(k.."="..v)
 		-- end
 
-		-- 如果 hy2 或 Xray 程序未安装则跳过订阅
-		if not hy2_type then
+		-- 自动决定模式(true=Xray, false=普通)
+		local xray_hy2_mode = false  -- 默认普通模式
+		if xray_hy2_type == "v2ray" then
+			-- Xray 模式
+			if has_xray then
+				xray_hy2_mode = true
+			elseif has_hysteria then
+				xray_hy2_mode = false   -- 回退到普通 Hysteria2
+			else
+				xray_hy2_mode = nil
+			end
+		elseif xray_hy2_type == "hysteria2" then
+			-- 普通 Hysteria2 模式
+			if has_hysteria then
+				xray_hy2_mode = false
+			elseif has_xray then
+				xray_hy2_mode = true   -- 回退到 Xray
+			else
+				xray_hy2_mode = nil
+			end
+		else
+			-- auto 或空:优先普通 Hysteria2,若不存在则使用 Xray
+			if has_hysteria then
+				xray_hy2_mode = false
+			elseif has_xray then
+				xray_hy2_mode = true   -- 回退到 Xray
+			else
+				xray_hy2_mode = nil
+			end
+		end
+	
+		-- 如果无法确定模式,跳过该订阅
+		if xray_hy2_mode == nil then
 			return nil
 		end
 	
-		if xray_hy2_type == "hysteria2" then
+		if xray_hy2_mode then
+			result.type = "v2ray"
+			result.v2ray_protocol = "hysteria2"
+			if params.fm and params.fm ~= "" then
+				result.enable_finalmask = "1"
+				result.finalmask = base64Encode(params.fm)
+			end
+			if (params.security and params.security:lower() == "tls")
+					or (params.sni and params.sni ~= "")
+					or (params.alpn and params.alpn ~= "")
+					or (params.pcs or params.vcn) then
+				result.tls = "1"
+				if params.sni then
+					result.tls_host = params.sni
+				end
+				if params.alpn and params.alpn ~= "" then
+					local alpn = {}
+					for v in params.alpn:gmatch("[^,;|%s]+") do
+						table.insert(alpn, v)
+					end
+					if #alpn > 0 then
+						result.tls_alpn = table.concat(alpn, ",")  -- 确保为字符串
+					end
+				end
+				if params.pcs then
+					result.tls_CertSha = params.pcs
+				end
+				if params.vcn then
+					result.tls_CertByName = params.vcn
+				end
+			end
+		else
+			result.type = "hysteria2"
 			if params.protocol and params.protocol ~= "" then
 				result.flag_transport = "1"
 				result.transport_protocol = params.protocol
@@ -259,62 +288,47 @@ local function processData(szType, content, cfgid)
 				result.flag_transport = "1"
 				result.transport_protocol = "udp"
 			end
-			if params.fm and params.fm ~= "" then
-				result.enable_finalmask = "1"
-				result.finalmask = base64Encode(params.fm)
+			if params.lazy and params.lazy ~= "" then
+				result.lazy_mode = "1"
+			end
+			if (params.sni and params.sni ~= "") or (params.alpn and params.alpn ~= "") then
+				result.tls = "1"
+				if params.sni then
+					result.tls_host = params.sni
+				end
+				if params.alpn and params.alpn ~= "" then
+					local alpn = {}
+					for v in params.alpn:gmatch("[^,;|%s]+") do
+						table.insert(alpn, v)
+					end
+					if #alpn > 0 then
+						result.tls_alpn = table.concat(alpn, ",")  -- 确保为字符串
+					end
+				end
 			end
 			if params.pinSHA256 and params.pinSHA256 ~= "" then
 				result.pinsha256 = params.pinSHA256
 			end
-		else
-			result.v2ray_protocol = has_xray_hy2_type
 		end
 
 		local raw_alias = url.fragment and UrlDecode(url.fragment) or nil
 		result.raw_alias = raw_alias   -- 新增
 		result.alias = raw_alias       -- 临时赋值(后面会被覆盖)
-		result.type = hy2_type
 		result.server = url.host
 		result.server_port = url.port or 443
-
 		result.hy2_auth = url.user
-		result.uplink_capacity = tonumber((params.upmbps or ""):match("^(%d+)")) or nil
-		result.downlink_capacity = tonumber((params.downmbps or ""):match("^(%d+)")) or nil
+
 		if params.mport then
 			result.flag_port_hopping = "1"
 			result.port_range = params.mport
 		end
+		result.uplink_capacity = tonumber((params.upmbps or ""):match("^(%d+)")) or nil
+		result.downlink_capacity = tonumber((params.downmbps or ""):match("^(%d+)")) or nil
 		if params.obfs and params.obfs ~= "none" then
 			result.flag_obfs = "1"
 			result.obfs_type = params.obfs
 			result.salamander = params["obfs-password"] or params["obfs_password"]
 		end
-		if (params.security and params.security:lower() == "tls")
-				or (params.sni and params.sni ~= "")
-				or (params.alpn and params.alpn ~= "")
-				or (xray_hy2_type == "hysteria2" and (params.pcs or params.vcn)) then
-			result.tls = "1"
-			if params.sni then
-				result.tls_host = params.sni
-			end
-			if params.alpn and params.alpn ~= "" then
-				local alpn = {}
-				for v in params.alpn:gmatch("[^,;|%s]+") do
-					table.insert(alpn, v)
-				end
-				if #alpn > 0 then
-					result.tls_alpn = table.concat(alpn, ",")  -- 确保为字符串
-				end
-			end
-			if xray_hy2_type ~= "hysteria2" then
-				if params.pcs then
-					result.tls_CertSha = params.pcs
-				end
-				if params.vcn then
-					result.tls_CertByName = params.vcn
-				end
-			end
-		end
 		if params.allowInsecure or params.insecure then
 			local insecure = params.allowInsecure or params.insecure
 			if insecure == true or insecure == "1" or insecure == "true" then
@@ -543,153 +557,69 @@ local function processData(szType, content, cfgid)
 			result.fast_open = params.tfo
 		end
 
-		if v2_ss ~= "v2ray" then
-			local is_old_format = find_index:find("@") and not find_index:find("://.*@")
-			local old_base64, host_port, userinfo, server, port, method, password
-
-			if is_old_format then
-				-- 旧格式:base64(method:pass)@host:port
-				old_base64, host_port = find_index:match("^([^@]+)@(.-)$")
-				log("SS 节点旧格式解析:", old_base64)
-				if not old_base64 or not host_port then
-					log("SS 节点旧格式解析失败:", find_index)
-					return nil
-				end
-				local decoded = base64Decode(UrlDecode(old_base64))
-				if not decoded then
-					log("SS base64 解码失败(旧格式):", old_base64)
-					return nil
-				end
-				userinfo = decoded
+		-- 自动决定模式(true=Xray, false=普通 SS)
+		local xray_ss_mode = false
+		if ss_type == "v2ray" then
+			-- Xray 模式
+			if has_xray then
+				xray_ss_mode = true
+			elseif has_ss_rust or has_ss_libev then
+				xray_ss_mode = false   -- 回退到普通 SS
 			else
-				-- 新格式:base64(method:pass@host:port)
-				local decoded = base64Decode(UrlDecode(find_index))
-				if not decoded then
-					log("SS base64 解码失败(新格式):", find_index)
-					return nil
-				end
-				userinfo, host_port = decoded:match("^(.-)@(.-)$")
-				if not userinfo or not host_port then
-					log("SS 解码内容缺失 @ 分隔:", decoded)
-					return nil
-				end
-			end
-
-			-- 解析加密方式和密码(允许密码包含冒号)
-			local meth_pass = userinfo:find(":")
-			if not meth_pass then
-				log("SS 用户信息格式错误:", userinfo)
-				return nil
-			end
-			method = userinfo:sub(1, meth_pass - 1)
-			password = userinfo:sub(meth_pass + 1)
-
-			-- 判断密码是否经过url编码
-			local function isURLEncodedPassword(pwd)
-				if not pwd:find("%%[0-9A-Fa-f][0-9A-Fa-f]") then
-					return false
-				end
-				local ok, decoded = pcall(UrlDecode, pwd)
-				return ok and urlEncode(decoded) == pwd
-			end
-
-			local decoded = UrlDecode(password)
-			if isURLEncodedPassword(password) and decoded then
-				password = decoded
+				xray_ss_mode = nil
 			end
-
-			-- 解析服务器地址和端口(兼容 IPv6)
-			if host_port:find("^%[.*%]:%d+$") then
-				server, port = host_port:match("^%[(.*)%]:(%d+)$")
+		elseif ss_type == "ss-rust" or ss_type == "ss-libev" then
+			-- 普通 SS 模式
+			local user_core = (ss_type == "ss-rust" and has_ss_rust) or (ss_type == "ss-libev" and has_ss_libev)
+			if user_core then
+				xray_ss_mode = false  -- 否则普通 SS
 			else
-				server, port = host_port:match("^(.-):(%d+)$")
-			end
-			if not server or not port then
-				log("SS 节点服务器信息格式错误:", host_port)
-				return nil
-			end
-
-			-- 如果 SS 程序未安装则跳过订阅	
-			if not v2_ss then
-				return nil
-			end
-
-			-- 填充 result
-			result.type = v2_ss
-			result.encrypt_method_ss = method
-			result.password = password
-			result.server = server
-			result.server_port = port
-
-			-- 插件处理
-			if params.plugin then
-				local plugin_info = UrlDecode(params.plugin)
-				local idx_pn = plugin_info:find(";")
-				if idx_pn then
-					result.plugin = plugin_info:sub(1, idx_pn - 1)
-					result.plugin_opts = plugin_info:sub(idx_pn + 1, #plugin_info)
+				-- 指定的核心不存在,尝试另一个 SS 核心
+				local other_core = (ss_type == "ss-rust" and has_ss_libev) or (ss_type == "ss-libev" and has_ss_rust)
+				if other_core then
+					xray_ss_mode = false  -- 使用存在的另一个 SS 核心
+				elseif has_xray then
+					xray_ss_mode = true    -- 回退到 Xray
 				else
-					result.plugin = plugin_info
-					result.plugin_opts = ""
+					xray_ss_mode = nil
 				end
-				-- 部分机场下发的插件名为 simple-obfs,这里应该改为 obfs-local
-				if result.plugin == "simple-obfs" then
-					result.plugin = "obfs-local"
-				end
-				-- 如果插件不为 none,确保 enable_plugin 为 1
-				if result.plugin ~= "none" and result.plugin ~= "" then
-					result.enable_plugin = 1
-				end
-			elseif has_ss_type and has_ss_type ~= "ss-libev" then
-				if params["shadow-tls"] then
-					-- 特别处理 shadow-tls 作为插件
-					-- log("原始 shadow-tls 参数:", params["shadow-tls"])
-					local decoded_tls = base64Decode(UrlDecode(params["shadow-tls"]))
-					--log("SS 节点 shadow-tls 解码后:", decoded_tls or "nil")
-					if decoded_tls then
-						local ok, st = pcall(jsonParse, decoded_tls)
-						if ok and st then
-							result.plugin = "shadow-tls"
-							result.enable_plugin = 1
-							local version_flag = ""
-							if st.version and tonumber(st.version) then
-								version_flag = string.format("v%s=1;", st.version)
-							end
-					
-							-- 合成 plugin_opts 格式:v%s=1;host=xxx;password=xxx
-							result.plugin_opts = string.format("%shost=%s;passwd=%s",
-								version_flag,
-								st.host or "",
-								st.password or "")
-						else
-							log("shadow-tls JSON 解析失败")
-						end
-					end
+			end
+		else
+		    -- ss_type 为空或 auto:根据链接中是否有 type 参数决定
+			local has_type = params.type and params.type ~= ""
+			if has_type then
+				-- 有 type 参数,优先 Xray
+				if has_xray then
+					xray_ss_mode = true
+				elseif has_ss_rust or has_ss_libev then
+					xray_ss_mode = false   -- 回退到普通 SS
+				else
+					xray_ss_mode = nil
 				end
 			else
-				if params["shadow-tls"] then
-					log("错误:ShadowSocks-libev 不支持使用 shadow-tls 插件")
-					return nil, "ShadowSocks-libev 不支持使用 shadow-tls 插件"
+				-- 无 type 参数,优先普通 SS
+				if has_ss_rust or has_ss_libev then
+					-- 普通 SS 模式
+					xray_ss_mode = false
+				elseif has_xray then
+					xray_ss_mode = true    -- 回退到 Xray
+				else
+					xray_ss_mode = nil
 				end
 			end
+		end
 
-			-- 检查加密方法是否受支持
-			if not checkTabValue(encrypt_methods_ss)[method] then
-				-- 1202 年了还不支持 SS AEAD 的屑机场
-				-- log("不支持的SS加密方法:", method)
-				result.server = nil
-			end
-		else
+		-- 如果最终无可用核心,跳过该订阅
+		if xray_ss_mode == nil then
+			return nil
+		end
+
+		if xray_ss_mode then
 			local url = URL.parse("http://" .. info)
 			local params = url.query
 
-			-- 如果 Xray 程序未安装则跳过订阅	
-			if not v2_ss then
-				return nil
-			end
-
-			result.type = v2_ss
-			result.v2ray_protocol = has_v2_ss_type
+			result.type = "v2ray"
+			result.v2ray_protocol = "shadowsocks"
 			result.server = url.host
 			result.server_port = url.port
 
@@ -816,6 +746,143 @@ local function processData(szType, content, cfgid)
 					result.tcp_path = params.path and UrlDecode(params.path) or nil
 				end
 			end
+		else
+			local is_old_format = find_index:find("@") and not find_index:find("://.*@")
+			local old_base64, host_port, userinfo, server, port, method, password
+
+			if is_old_format then
+				-- 旧格式:base64(method:pass)@host:port
+				old_base64, host_port = find_index:match("^([^@]+)@(.-)$")
+				log("SS 节点旧格式解析:", old_base64)
+				if not old_base64 or not host_port then
+					log("SS 节点旧格式解析失败:", find_index)
+					return nil
+				end
+				local decoded = base64Decode(UrlDecode(old_base64))
+				if not decoded then
+					log("SS base64 解码失败(旧格式):", old_base64)
+					return nil
+				end
+				userinfo = decoded
+			else
+				-- 新格式:base64(method:pass@host:port)
+				local decoded = base64Decode(UrlDecode(find_index))
+				if not decoded then
+					log("SS base64 解码失败(新格式):", find_index)
+					return nil
+				end
+				userinfo, host_port = decoded:match("^(.-)@(.-)$")
+				if not userinfo or not host_port then
+					log("SS 解码内容缺失 @ 分隔:", decoded)
+					return nil
+				end
+			end
+
+			-- 解析加密方式和密码(允许密码包含冒号)
+			local meth_pass = userinfo:find(":")
+			if not meth_pass then
+				log("SS 用户信息格式错误:", userinfo)
+				return nil
+			end
+			method = userinfo:sub(1, meth_pass - 1)
+			password = userinfo:sub(meth_pass + 1)
+
+			-- 判断密码是否经过url编码
+			local function isURLEncodedPassword(pwd)
+				if not pwd:find("%%[0-9A-Fa-f][0-9A-Fa-f]") then
+					return false
+				end
+				local ok, decoded = pcall(UrlDecode, pwd)
+				return ok and urlEncode(decoded) == pwd
+			end
+
+			local decoded = UrlDecode(password)
+			if isURLEncodedPassword(password) and decoded then
+				password = decoded
+			end
+
+			-- 解析服务器地址和端口(兼容 IPv6)
+			if host_port:find("^%[.*%]:%d+$") then
+				server, port = host_port:match("^%[(.*)%]:(%d+)$")
+			else
+				server, port = host_port:match("^(.-):(%d+)$")
+			end
+			if not server or not port then
+				log("SS 节点服务器信息格式错误:", host_port)
+				return nil
+			end
+
+			-- 填充 result
+			local xray_ss_type
+			if ss_type == "ss-rust" or ss_type == "ss-libev" then
+				xray_ss_type = ss_type
+			else
+				xray_ss_type = has_ss_rust and "ss-rust" or "ss-libev"
+			end
+			result.type = xray_ss_type
+			result.encrypt_method_ss = method
+			result.password = password
+			result.server = server
+			result.server_port = port
+
+			-- 插件处理
+			if params.plugin then
+				local plugin_info = UrlDecode(params.plugin)
+				local idx_pn = plugin_info:find(";")
+				if idx_pn then
+					result.plugin = plugin_info:sub(1, idx_pn - 1)
+					result.plugin_opts = plugin_info:sub(idx_pn + 1, #plugin_info)
+				else
+					result.plugin = plugin_info
+					result.plugin_opts = ""
+				end
+				-- 部分机场下发的插件名为 simple-obfs,这里应该改为 obfs-local
+				if result.plugin == "simple-obfs" then
+					result.plugin = "obfs-local"
+				end
+				-- 如果插件不为 none,确保 enable_plugin 为 1
+				if result.plugin ~= "none" and result.plugin ~= "" then
+					result.enable_plugin = 1
+				end
+			elseif has_ss_type and has_ss_type ~= "ss-libev" then
+				if params["shadow-tls"] then
+					-- 特别处理 shadow-tls 作为插件
+					-- log("原始 shadow-tls 参数:", params["shadow-tls"])
+					local decoded_tls = base64Decode(UrlDecode(params["shadow-tls"]))
+					--log("SS 节点 shadow-tls 解码后:", decoded_tls or "nil")
+					if decoded_tls then
+						local ok, st = pcall(jsonParse, decoded_tls)
+						if ok and st then
+							result.plugin = "shadow-tls"
+							result.enable_plugin = 1
+							local version_flag = ""
+							if st.version and tonumber(st.version) then
+								version_flag = string.format("v%s=1;", st.version)
+							end
+					
+							-- 合成 plugin_opts 格式:v%s=1;host=xxx;password=xxx
+							result.plugin_opts = string.format("%shost=%s;passwd=%s",
+								version_flag,
+								st.host or "",
+								st.password or "")
+						else
+							log("shadow-tls JSON 解析失败")
+						end
+					end
+				end
+			else
+				if params["shadow-tls"] then
+					log("错误:ShadowSocks-libev 不支持使用 shadow-tls 插件")
+					return nil, "ShadowSocks-libev 不支持使用 shadow-tls 插件"
+				end
+			end
+
+			-- 检查加密方法是否受支持
+			if not checkTabValue(encrypt_methods_ss)[method] then
+				-- 1202 年了还不支持 SS AEAD 的屑机场
+				-- log("不支持的SS加密方法:", method)
+				result.server = nil
+			end
 		end
 	elseif szType == "sip008" then
 		result.type = v2_ss
@@ -936,102 +1003,143 @@ local function processData(szType, content, cfgid)
 			result.server_port = port
 		end
 
-		-- 如果 Tojan 程序未安装则跳过订阅	
-		if not v2_tj or v2_tj == "" then
+		-- 自动决定模式(true=Xray, false=普通 Trojan)
+		local xray_tj_mode = false
+		if xray_tj_type == "v2ray" then
+			-- Xray 模式
+			if has_xray then
+				xray_tj_mode = true
+			elseif has_trojan then
+				xray_tj_mode = false   -- 回退到普通 Trojan
+			else
+				xray_tj_mode = nil  -- 两类核心均不存在,停止订阅
+			end
+		elseif xray_tj_type == "trojan" then
+			-- 普通 Trojan 模式
+			if has_trojan then
+				xray_tj_mode = false
+			elseif has_xray then
+				xray_tj_mode = true    -- 回退到 Xray
+			else
+				xray_tj_mode = nil  -- 两类核心均不存在,停止订阅
+			end
+		else
+			-- 全局配置为空或 auto,根据链接中是否有 type 参数决定
+			local has_type = params.type and params.type ~= ""
+			-- 有 type 参数,优先 Xray
+			if has_type then
+				if has_xray then
+					xray_tj_mode = true   -- 有 type 参数使用 Xray
+				elseif has_trojan then
+					xray_tj_mode = false  -- 否则普通 Trojan
+				else
+					xray_tj_mode = nil -- 两类核心均不存在,停止订阅
+				end
+			else
+				-- 无 type 参数,优先普通 Trojan
+				if has_trojan then
+					xray_tj_mode = false  -- 普通 Trojan
+				elseif has_xray then
+					xray_tj_mode = true   -- 否则使用 Xray
+				else
+					xray_tj_mode = nil -- 两类核心均不存在,停止订阅
+				end
+			end
+		end
+
+		-- 如果最终无可用核心,跳过该订阅
+		if xray_tj_mode == nil then
 			return nil
 		end
 
-		if params.type and params.type ~= "" then
-			v2_tj = "v2ray"
-			result.type = v2_tj
+		if xray_tj_mode then
+			result.type = "v2ray"
 			result.v2ray_protocol = "trojan"
-			if v2_tj ~= "trojan" then
-				if params.fp then
-					-- 处理 fingerprint 参数
-					result.fingerprint = params.fp
-				end
-				-- 处理 ech 参数
-				if params.ech and params.ech ~= "" then
-					result.enable_ech = "1"
-					result.ech_config = params.ech
-				end
-				-- 检查 finalmaskg 参数是否存在且非空
-				if params.fm and params.fm ~= "" then
-					result.enable_finalmask = "1"
-					result.finalmaskg = base64Encode(params.fm)
-				end
-				-- 处理传输协议
-				result.transport = params.type or "raw" -- 默认传输协议为 raw
-				if result.transport == "tcp" then
-					result.transport = "raw"
-				end
-				if result.transport == "splithttp" then
-					result.transport = "xhttp"
+			if params.fp then
+				-- 处理 fingerprint 参数
+				result.fingerprint = params.fp
+			end
+			-- 处理 ech 参数
+			if params.ech and params.ech ~= "" then
+				result.enable_ech = "1"
+				result.ech_config = params.ech
+			end
+			-- 检查 finalmaskg 参数是否存在且非空
+			if params.fm and params.fm ~= "" then
+				result.enable_finalmask = "1"
+				result.finalmaskg = base64Encode(params.fm)
+			end
+			-- 处理传输协议
+			result.transport = params.type or "raw" -- 默认传输协议为 raw
+			if result.transport == "tcp" then
+				result.transport = "raw"
+			end
+			if result.transport == "splithttp" then
+				result.transport = "xhttp"
+			end
+			if params.pcs and params.pcs ~= "" then
+				result.tls_CertSha = params.pcs
+			end
+			if params.vcn and params.vcn ~= "" then
+				result.tls_CertByName = params.vcn
+			end
+			if result.transport == "ws" then
+				result.ws_host = (result.tls ~= "1") and (params.host and UrlDecode(params.host)) or nil
+				result.ws_path = params.path and UrlDecode(params.path) or "/"
+			elseif result.transport == "httpupgrade" then
+				result.httpupgrade_host = (result.tls ~= "1") and (params.host and UrlDecode(params.host)) or nil
+				result.httpupgrade_path = params.path and UrlDecode(params.path) or "/"
+			elseif result.transport == "xhttp" or result.transport == "splithttp" then
+				result.xhttp_mode = params.mode or "auto"
+				result.xhttp_host = params.host and UrlDecode(params.host) or nil
+				result.xhttp_path = params.path and UrlDecode(params.path) or "/"
+				-- 检查 extra 参数是否存在且非空
+				if params.extra and params.extra ~= "" then
+					result.enable_xhttp_extra = "1"
+					result.xhttp_extra = base64Encode(params.extra)
 				end
-				if params.pcs and params.pcs ~= "" then
-					result.tls_CertSha = params.pcs
+				-- 尝试解析 JSON 数据
+				local success, Data = pcall(jsonParse, params.extra or "")
+				if success and type(Data) == "table" then
+					local address = (Data.extra and Data.extra.downloadSettings and Data.extra.downloadSettings.address)
+						or (Data.downloadSettings and Data.downloadSettings.address)
+					result.download_address = (address and address ~= "") and address:gsub("^%[", ""):gsub("%]$", "")
+				else
+					-- 如果解析失败,清空下载地址
+					result.download_address = nil
 				end
-				if params.vcn and params.vcn ~= "" then
-					result.tls_CertByName = params.vcn
+			elseif result.transport == "http" or result.transport == "h2" then
+				result.transport = "h2"
+				result.h2_host = params.host and UrlDecode(params.host) or nil
+				result.h2_path = params.path and UrlDecode(params.path) or nil
+			elseif result.transport == "kcp" then
+				result.kcp_guise = params.headerType or "none"
+				if params.headerType and params.headerType == "dns" then
+					result.kcp_domain = params.host or ""
 				end
-				if result.transport == "ws" then
-					result.ws_host = (result.tls ~= "1") and (params.host and UrlDecode(params.host)) or nil
-					result.ws_path = params.path and UrlDecode(params.path) or "/"
-				elseif result.transport == "httpupgrade" then
-					result.httpupgrade_host = (result.tls ~= "1") and (params.host and UrlDecode(params.host)) or nil
-					result.httpupgrade_path = params.path and UrlDecode(params.path) or "/"
-				elseif result.transport == "xhttp" or result.transport == "splithttp" then
-					result.xhttp_mode = params.mode or "auto"
-					result.xhttp_host = params.host and UrlDecode(params.host) or nil
-					result.xhttp_path = params.path and UrlDecode(params.path) or "/"
-					-- 检查 extra 参数是否存在且非空
-					if params.extra and params.extra ~= "" then
-						result.enable_xhttp_extra = "1"
-						result.xhttp_extra = base64Encode(params.extra)
-					end
-					-- 尝试解析 JSON 数据
-					local success, Data = pcall(jsonParse, params.extra or "")
-					if success and type(Data) == "table" then
-						local address = (Data.extra and Data.extra.downloadSettings and Data.extra.downloadSettings.address)
-							or (Data.downloadSettings and Data.downloadSettings.address)
-						result.download_address = (address and address ~= "") and address:gsub("^%[", ""):gsub("%]$", "")
-					else
-						-- 如果解析失败,清空下载地址
-						result.download_address = nil
-					end
-				elseif result.transport == "http" or result.transport == "h2" then
-					result.transport = "h2"
-					result.h2_host = params.host and UrlDecode(params.host) or nil
-					result.h2_path = params.path and UrlDecode(params.path) or nil
-				elseif result.transport == "kcp" then
-					result.kcp_guise = params.headerType or "none"
-					if params.headerType and params.headerType == "dns" then
-						result.kcp_domain = params.host or ""
-					end
-					result.seed = params.seed
-					result.mtu = 1350
-					result.tti = 50
-					result.uplink_capacity = 5
-					result.downlink_capacity = 20
-					result.read_buffer_size = 2
-					result.write_buffer_size = 2
-				elseif result.transport == "quic" then
-					result.quic_guise = params.headerType or "none"
-					result.quic_security = params.quicSecurity or "none"
-					result.quic_key = params.key
-				elseif result.transport == "grpc" then
-					result.serviceName = params.serviceName
-					result.grpc_mode = params.mode or "gun"
-				elseif result.transport == "tcp" or result.transport == "raw" then
-					result.tcp_guise = params.headerType and params.headerType ~= "" and params.headerType or "none"
-					if result.tcp_guise == "http" then
-						result.tcp_host = params.host and UrlDecode(params.host) or nil
-						result.tcp_path = params.path and UrlDecode(params.path) or nil
-					end
+				result.seed = params.seed
+				result.mtu = 1350
+				result.tti = 50
+				result.uplink_capacity = 5
+				result.downlink_capacity = 20
+				result.read_buffer_size = 2
+				result.write_buffer_size = 2
+			elseif result.transport == "quic" then
+				result.quic_guise = params.headerType or "none"
+				result.quic_security = params.quicSecurity or "none"
+				result.quic_key = params.key
+			elseif result.transport == "grpc" then
+				result.serviceName = params.serviceName
+				result.grpc_mode = params.mode or "gun"
+			elseif result.transport == "tcp" or result.transport == "raw" then
+				result.tcp_guise = params.headerType and params.headerType ~= "" and params.headerType or "none"
+				if result.tcp_guise == "http" then
+					result.tcp_host = params.host and UrlDecode(params.host) or nil
+					result.tcp_path = params.path and UrlDecode(params.path) or nil
 				end
-			else
-				result.type = v2_tj
 			end
+		else
+			result.type = "trojan"
 		end
 	elseif szType == "vless" then
 		local url = URL.parse("http://" .. content)

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff