mirror of
https://github.com/caiwx86/small-packages.git
synced 2026-09-13 11:54:12 +08:00
update 2026-09-12 16:17:58
This commit is contained in:
@@ -61,14 +61,11 @@ function getOption(config, section, opt) {
|
||||
const id = `cbid.${config}.${section}.${opt}`;
|
||||
obj = document.getElementsByName(id)[0] || document.getElementById(id);
|
||||
if (obj) {
|
||||
//lua luci combobox
|
||||
const combobox = document.getElementById('cbi.combobox.' + id);
|
||||
if (combobox) {
|
||||
obj.combobox = combobox;
|
||||
}
|
||||
const div = document.getElementById(id);
|
||||
if (div && div.getElementsByTagName("li").length > 0) {
|
||||
obj = div;
|
||||
}
|
||||
return obj;
|
||||
} else {
|
||||
return null;
|
||||
|
||||
@@ -26,12 +26,18 @@ local config = map.config
|
||||
update_config(node_id, {
|
||||
remarks: getOption("<%=config%>", "<%=sid%>", "remarks").value,
|
||||
group: getOption("<%=config%>", "<%=sid%>", "group").value,
|
||||
type: getOption("<%=config%>", "<%=sid%>", "type").value,
|
||||
type: el.value,
|
||||
//protocol: ''
|
||||
}, node_config_url);
|
||||
}
|
||||
}
|
||||
});
|
||||
const fromUrlCache = JSON.parse(sessionStorage.getItem("fromUrl"));
|
||||
if (fromUrlCache && fromUrlCache.savetime && (Date.now() - fromUrlCache.timestamp) < fromUrlCache.savetime) {
|
||||
fromUrl(fromUrlCache.link, true)
|
||||
} else {
|
||||
sessionStorage.removeItem("fromUrl");
|
||||
}
|
||||
});
|
||||
waitForElement('select[name*="<%=config%>"][name*="protocol"]', function(el) {
|
||||
let o_val = el.value;
|
||||
@@ -56,7 +62,7 @@ local config = map.config
|
||||
update_config(node_id, {
|
||||
remarks: getOption("<%=config%>", "<%=sid%>", "remarks").value,
|
||||
group: getOption("<%=config%>", "<%=sid%>", "group").value,
|
||||
protocol: getOption("<%=config%>", "<%=sid%>", name).value,
|
||||
protocol: el.value,
|
||||
}, node_config_url);
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<%+cbi/valueheader%>
|
||||
<%
|
||||
local api = require "luci.passwall.api"
|
||||
local appname = api.appname
|
||||
local map = self.map
|
||||
local api = map.api
|
||||
local config = map.config
|
||||
|
||||
local has_ss_rust = api.is_finded("sslocal")
|
||||
local has_singbox = api.finded_com("sing-box")
|
||||
@@ -17,7 +17,7 @@ local hysteria2_type = api.get_core("hysteria2_type", {{has_hysteria2,"hysteria2
|
||||
|
||||
local current_node = map:get(section)
|
||||
-%>
|
||||
<script src="<%=resource%>/view/<%=appname%>/qrcode.min.js"></script>
|
||||
<script src="<%=resource%>/view/<%=api.appname%>/qrcode.min.js"></script>
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
let has_singbox = "<%=has_singbox%>"
|
||||
let has_xray = "<%=has_xray%>"
|
||||
@@ -112,8 +112,7 @@ local current_node = map:get(section)
|
||||
|
||||
function buildUrl(btn, urlname, sid) {
|
||||
var opt = {
|
||||
base: "cbid.<%=appname%>",
|
||||
client: true,
|
||||
base: "cbid.<%=config%>",
|
||||
get: function (opt) {
|
||||
var id = this.base + "." + opt;
|
||||
var obj = document.getElementsByName(id)[0] || document.getElementsByClassName(id)[0] || document.getElementById(id)
|
||||
@@ -158,7 +157,6 @@ local current_node = map:get(section)
|
||||
}
|
||||
}
|
||||
opt.base = "cbid." + urlname + "." + sid;
|
||||
opt.client = urlname.indexOf("server") === -1;
|
||||
var v_type = opt.get("type").value;
|
||||
var v_alias = opt.get("remarks");
|
||||
|
||||
@@ -753,34 +751,49 @@ local current_node = map:get(section)
|
||||
return server.replace(/^\[/, '').replace(/\]$/, '');
|
||||
}
|
||||
|
||||
function fromUrl(btn, urlname, sid, cacheData) {
|
||||
var opt = {
|
||||
base: 'cbid.<%=appname%>',
|
||||
client: true,
|
||||
function tofromUrl(btn) {
|
||||
let link = prompt('<%:Paste Share URL Here%>', '');
|
||||
if (link === null || link === "") {
|
||||
return false;
|
||||
}
|
||||
return fromUrl(link);
|
||||
}
|
||||
|
||||
function tofromUrl(btn) {
|
||||
let link = prompt('<%:Paste Share URL Here%>', '');
|
||||
if (link === null || link === "") {
|
||||
return false;
|
||||
}
|
||||
return fromUrl(link);
|
||||
}
|
||||
|
||||
function fromUrl(link, from_cache) {
|
||||
if (!link) {
|
||||
return false;
|
||||
}
|
||||
const s = document.getElementById("<%=self.option%>-status");
|
||||
if (!s) {
|
||||
alert("Never");
|
||||
return false;
|
||||
}
|
||||
s.innerHTML = "";
|
||||
|
||||
const current_type = '<%=current_node.type or ""%>';
|
||||
let switch_type = null;
|
||||
|
||||
const opt = {
|
||||
base: "cbid.<%=self.option%>.<%=self.value%>",
|
||||
get: function (opt) {
|
||||
var obj;
|
||||
var id = this.base + '.' + opt;
|
||||
obj = document.getElementsByName(id)[0] || document.getElementById(id);
|
||||
if (obj) {
|
||||
var combobox = document.getElementById('cbi.combobox.' + id);
|
||||
if (combobox) {
|
||||
obj.combobox = combobox;
|
||||
}
|
||||
var div = document.getElementById(id);
|
||||
if (div && div.getElementsByTagName("li").length > 0) {
|
||||
obj = div;
|
||||
}
|
||||
return obj;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return getOption("<%=config%>", "<%=self.value%>", opt);
|
||||
},
|
||||
set: function (opt, val) {
|
||||
if (!switch_type && opt == "type" && current_type != val) {
|
||||
switch_type = val;
|
||||
return;
|
||||
}
|
||||
var obj;
|
||||
obj = this.get(opt);
|
||||
if (obj) {
|
||||
var event = document.createEvent("HTMLEvents");
|
||||
event.initEvent("change", true, true);
|
||||
if (obj.type === 'checkbox') {
|
||||
obj.checked = val;
|
||||
} else {
|
||||
@@ -814,17 +827,17 @@ local current_node = map:get(section)
|
||||
}
|
||||
}
|
||||
try {
|
||||
obj.dispatchEvent(event);
|
||||
obj.dispatchEvent(new Event("change", { bubbles: true, cancelable: true }));
|
||||
} catch (err) {}
|
||||
} else {
|
||||
//alert('<%:Faltal on set option, please help in debug: %>' + opt + ' = ' + val);
|
||||
// 处理 DynamicList
|
||||
// Processing DynamicList
|
||||
var fullName = this.base + '.' + opt;
|
||||
var lists = document.querySelectorAll('.cbi-dynlist');
|
||||
for (var i = 0; i < lists.length; i++) {
|
||||
var parent = lists[i].closest('.cbi-value');
|
||||
if (!parent) continue;
|
||||
// 尝试从 label 的 for 属性中提取 fullName
|
||||
// Try to extract fullName from the label's for attribute.
|
||||
var label = parent.querySelector('label.cbi-value-title');
|
||||
var labelFor = label?.getAttribute('for');
|
||||
if (labelFor === fullName) {
|
||||
@@ -838,58 +851,20 @@ local current_node = map:get(section)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
setlist: function (opt, vlist) {
|
||||
var id = this.base + "." + opt;
|
||||
var objs = document.getElementsByName(id) || document.getElementsByClassName(id);
|
||||
if (objs) {
|
||||
var values = "";
|
||||
for (var i = 0; i < vlist.length; i++) {
|
||||
values += vlist[i] + ", ";
|
||||
}
|
||||
alert("Manually input the option:\n" + opt + "s:\n[" + values + "]");
|
||||
} else {
|
||||
//alert("<%:Faltal on set option, please help in debug: %>" + opt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var s = document.getElementById(urlname + '-status');
|
||||
if (!s) {
|
||||
alert("Never");
|
||||
return false;
|
||||
}
|
||||
opt.base = "cbid." + urlname + "." + sid;
|
||||
opt.client = urlname.indexOf("server") === -1;
|
||||
var ssrurl = null;
|
||||
if (cacheData) {
|
||||
ssrurl = cacheData.ssrurl
|
||||
} else {
|
||||
ssrurl = prompt('<%:Paste Share URL Here%>', '');
|
||||
if (ssrurl === null || ssrurl === "") {
|
||||
return false;
|
||||
}
|
||||
sessionStorage.setItem("fromUrl", JSON.stringify({
|
||||
timestamp: Date.now(),
|
||||
savetime: 60 * 1000,
|
||||
urlname: urlname,
|
||||
sid: sid,
|
||||
ssrurl: ssrurl
|
||||
}));
|
||||
}
|
||||
ssrurl = ssrurl.split(/\r\n|\r|\n/, 1)[0];
|
||||
ssrurl = ssrurl.replace(/&/gi, '&').replace(/\s*#\s*/, '#').trim(); //一些奇葩的链接用"&"当做"&","#"前后带空格
|
||||
s.innerHTML = "";
|
||||
var ssu = ssrurl.split('://');
|
||||
var event = document.createEvent("HTMLEvents");
|
||||
event.initEvent("change", true, true);
|
||||
link = link.split(/\r\n|\r|\n/, 1)[0];
|
||||
link = link.replace(/&/gi, '&').replace(/\s*#\s*/, '#').trim(); //一些奇葩的链接用"&"当做"&","#"前后带空格
|
||||
const link_split = link.split('://');
|
||||
const link_type = link_split[0];
|
||||
|
||||
var dom_prefix = null
|
||||
let dom_prefix = null;
|
||||
|
||||
if (ssu[0] === "ssr") {
|
||||
if (link_type === "ssr") {
|
||||
dom_prefix = "ssr_"
|
||||
//var b64c = ssu[1].match(/([A-Za-z0-9_-]+)/);
|
||||
var sstr = b64decsafe((ssu[1] || "").replace(/#.*/, "").trim());
|
||||
//var b64c = link_split[1].match(/([A-Za-z0-9_-]+)/);
|
||||
var sstr = b64decsafe((link_split[1] || "").replace(/#.*/, "").trim());
|
||||
var ploc = sstr.indexOf("/?");
|
||||
var url0 = "", param = "";
|
||||
if (ploc > 0) {
|
||||
@@ -924,8 +899,8 @@ local current_node = map:get(section)
|
||||
if (typeof (rem) !== 'undefined' && rem !== '' && rem.length > 0)
|
||||
opt.set('remarks', b64decutf8safe(rem));
|
||||
}
|
||||
if (ssu[0] === "ss") {
|
||||
var url0 = ssu[1] || "";
|
||||
if (link_type === "ss") {
|
||||
var url0 = link_split[1] || "";
|
||||
param = "";
|
||||
|
||||
var ploc = url0.indexOf("#");
|
||||
@@ -1000,15 +975,15 @@ local current_node = map:get(section)
|
||||
queryParam.type && queryParam.type !== "tcp" &&
|
||||
queryParam.headerType && queryParam.headerType !== "none";
|
||||
if (has_xray && (ss_type == "xray" || needUpgrade || queryParam.type === "xhttp")) {
|
||||
dom_prefix = "xray_"
|
||||
dom_prefix = "xray_";
|
||||
opt.set('type', "Xray");
|
||||
opt.set(dom_prefix + 'protocol', "shadowsocks");
|
||||
} else if (has_singbox && (ss_type == "sing-box" || needUpgrade)) {
|
||||
dom_prefix = "singbox_"
|
||||
dom_prefix = "singbox_";
|
||||
opt.set('type', "sing-box");
|
||||
opt.set(dom_prefix + 'protocol', "shadowsocks");
|
||||
} else {
|
||||
dom_prefix = "ssrust_"
|
||||
dom_prefix = "ssrust_";
|
||||
opt.set('type', "SS-Rust");
|
||||
}
|
||||
|
||||
@@ -1208,17 +1183,17 @@ local current_node = map:get(section)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ssu[0] === "trojan") {
|
||||
if (link_type === "trojan") {
|
||||
if (trojan_type == "sing-box" && has_singbox) {
|
||||
dom_prefix = "singbox_"
|
||||
dom_prefix = "singbox_";
|
||||
opt.set('type', "sing-box");
|
||||
opt.set(dom_prefix + 'protocol', "trojan");
|
||||
} else if (trojan_type == "xray" && has_xray) {
|
||||
dom_prefix = "xray_"
|
||||
dom_prefix = "xray_";
|
||||
opt.set('type', "Xray");
|
||||
opt.set(dom_prefix + 'protocol', "trojan");
|
||||
}
|
||||
var m = parseNodeUrl(ssrurl);
|
||||
var m = parseNodeUrl(link);
|
||||
var password = m.passwd;
|
||||
if (password === "") {
|
||||
s.innerHTML = "<font color='red'><%:Invalid Share URL Format%></font>";
|
||||
@@ -1346,14 +1321,14 @@ local current_node = map:get(section)
|
||||
opt.set('remarks', decodeURIComponent(m.hash.substr(1)));
|
||||
}
|
||||
}
|
||||
if (ssu[0] === "vmess") {
|
||||
var sstr = b64DecodeUnicode((ssu[1] || "").replace(/#.*/, "").trim());
|
||||
if (link_type === "vmess") {
|
||||
var sstr = b64DecodeUnicode((link_split[1] || "").replace(/#.*/, "").trim());
|
||||
var ploc = sstr.indexOf("/?");
|
||||
if (vmess_type == "sing-box" && has_singbox) {
|
||||
dom_prefix = "singbox_"
|
||||
dom_prefix = "singbox_";
|
||||
opt.set('type', "sing-box");
|
||||
} else if (has_xray) {
|
||||
dom_prefix = "xray_"
|
||||
dom_prefix = "xray_";
|
||||
opt.set('type', "Xray");
|
||||
}
|
||||
opt.set(dom_prefix + 'protocol', "vmess");
|
||||
@@ -1447,14 +1422,14 @@ local current_node = map:get(section)
|
||||
opt.set(dom_prefix + 'use_finalmask', !!ssm.fm);
|
||||
opt.set(dom_prefix + 'finalmask', ssm.fm || "");
|
||||
}
|
||||
if (ssu[0] === "vless") {
|
||||
if (link_type === "vless") {
|
||||
if (vless_type == "sing-box" && has_singbox) {
|
||||
dom_prefix = "singbox_";
|
||||
} else if (has_xray) {
|
||||
dom_prefix = "xray_";
|
||||
}
|
||||
|
||||
var m = parseNodeUrl(ssrurl);
|
||||
var m = parseNodeUrl(link);
|
||||
var password = m.passwd;
|
||||
if (password === "") {
|
||||
s.innerHTML = "<font color='red'><%:Invalid Share URL Format%></font>";
|
||||
@@ -1476,7 +1451,7 @@ local current_node = map:get(section)
|
||||
if (["xhttp", "kcp", "mkcp"].includes(queryParam.type) && vless_type !== "xray" && has_xray) {
|
||||
dom_prefix = "xray_";
|
||||
}
|
||||
opt.set("type", dom_prefix === "singbox_" ? "sing-box" : "Xray");
|
||||
opt.set('type', dom_prefix == "singbox_" ? "sing-box" : "Xray");
|
||||
|
||||
opt.set(dom_prefix + 'protocol', "vless");
|
||||
opt.set(dom_prefix + 'uuid', password);
|
||||
@@ -1606,8 +1581,8 @@ local current_node = map:get(section)
|
||||
opt.set('remarks', decodeURIComponent(m.hash.substr(1)));
|
||||
}
|
||||
}
|
||||
if (ssu[0] === "hysteria2" || ssu[0] === "hy2") {
|
||||
var m = parseNodeUrl(ssrurl);
|
||||
if (link_type === "hysteria2" || link_type === "hy2") {
|
||||
var m = parseNodeUrl(link);
|
||||
var password = m.passwd;
|
||||
if (password === "") {
|
||||
s.innerHTML = "<font color='red'><%:Invalid Share URL Format%></font>";
|
||||
@@ -1672,13 +1647,13 @@ local current_node = map:get(section)
|
||||
opt.set('remarks', decodeURIComponent(m.hash.substr(1)));
|
||||
}
|
||||
}
|
||||
if (ssu[0] === "tuic") {
|
||||
if (link_type === "tuic") {
|
||||
if (has_singbox) {
|
||||
dom_prefix = "singbox_"
|
||||
dom_prefix = "singbox_";
|
||||
opt.set('type', "sing-box");
|
||||
}
|
||||
opt.set(dom_prefix + 'protocol', "tuic");
|
||||
var _parsedUrl = new URL("http://" + ssu[1]);
|
||||
var _parsedUrl = new URL("http://" + link_split[1]);
|
||||
var username = _parsedUrl.username;
|
||||
var password = _parsedUrl.password;
|
||||
var hostname = _parsedUrl.hostname;
|
||||
@@ -1721,13 +1696,13 @@ local current_node = map:get(section)
|
||||
opt.set('remarks', decodeURIComponent(hash.substr(1)));
|
||||
}
|
||||
}
|
||||
if (ssu[0] === "anytls") {
|
||||
if (link_type === "anytls") {
|
||||
if (has_singbox) {
|
||||
dom_prefix = "singbox_"
|
||||
dom_prefix = "singbox_";
|
||||
opt.set('type', "sing-box");
|
||||
}
|
||||
opt.set(dom_prefix + 'protocol', "anytls");
|
||||
var m = parseNodeUrl(ssrurl);
|
||||
var m = parseNodeUrl(link);
|
||||
var password = m.passwd;
|
||||
if (password === "") {
|
||||
s.innerHTML = "<font color='red'><%:Invalid Share URL Format%></font>";
|
||||
@@ -1777,13 +1752,13 @@ local current_node = map:get(section)
|
||||
opt.set('remarks', decodeURIComponent(m.hash.substr(1)));
|
||||
}
|
||||
}
|
||||
if (ssu[0] === "naive+https" || ssu[0] === "naive+quic") {
|
||||
if (link_type === "naive+https" || link_type === "naive+quic") {
|
||||
if (has_singbox) {
|
||||
dom_prefix = "singbox_"
|
||||
dom_prefix = "singbox_";
|
||||
opt.set('type', "sing-box");
|
||||
}
|
||||
opt.set(dom_prefix + 'protocol', "naive");
|
||||
var _parsedUrl = new URL("http://" + ssu[1]);
|
||||
var _parsedUrl = new URL("http://" + link_split[1]);
|
||||
var username = _parsedUrl.username;
|
||||
var password = _parsedUrl.password;
|
||||
var hostname = _parsedUrl.hostname;
|
||||
@@ -1818,7 +1793,7 @@ local current_node = map:get(section)
|
||||
opt.set(dom_prefix + 'tls_serverName', queryParam.sni || '');
|
||||
opt.set(dom_prefix + 'ech', !!queryParam.ech);
|
||||
opt.set(dom_prefix + 'ech_config', queryParam.ech || '');
|
||||
if (ssu[0] === "naive+quic") {
|
||||
if (link_type === "naive+quic") {
|
||||
opt.set(dom_prefix + 'naive_quic', true);
|
||||
opt.set(dom_prefix + 'naive_congestion_control', queryParam.congestion_control || 'bbr');
|
||||
}
|
||||
@@ -1826,20 +1801,25 @@ local current_node = map:get(section)
|
||||
opt.set('remarks', decodeURIComponent(hash.substr(1)));
|
||||
}
|
||||
}
|
||||
if (dom_prefix && dom_prefix != null) {
|
||||
const port = opt.get(dom_prefix + 'port');
|
||||
if (!port) {
|
||||
return false;
|
||||
}
|
||||
if (port.value) {
|
||||
port.focus();
|
||||
port.blur();
|
||||
}
|
||||
} else {
|
||||
|
||||
if (switch_type) {
|
||||
sessionStorage.setItem("fromUrl", JSON.stringify({
|
||||
timestamp: Date.now(),
|
||||
savetime: 60 * 1000,
|
||||
link: link
|
||||
}));
|
||||
opt.set("type", switch_type);
|
||||
return
|
||||
}
|
||||
if (!dom_prefix) {
|
||||
s.innerHTML = "<font color='red'><%:Invalid Share URL Format%></font>";
|
||||
sessionStorage.removeItem("fromUrl");
|
||||
return false;
|
||||
}
|
||||
if (opt.get(dom_prefix + 'port')) {
|
||||
opt.get(dom_prefix + 'port').focus();
|
||||
opt.get(dom_prefix + 'port').blur();
|
||||
}
|
||||
s.innerHTML = "<font color='green'><%:Import Finished %></font>";
|
||||
sessionStorage.removeItem("fromUrl");
|
||||
return true;
|
||||
@@ -1849,17 +1829,6 @@ local current_node = map:get(section)
|
||||
window.open('<%=api.url("gen_client_config")%>?id=' + sid, "_blank")
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
setTimeout(function () {
|
||||
const fromUrlCache = JSON.parse(sessionStorage.getItem("fromUrl"));
|
||||
if (fromUrlCache && fromUrlCache.savetime && (Date.now() - fromUrlCache.timestamp) < fromUrlCache.savetime) {
|
||||
fromUrl(null, fromUrlCache.urlname, fromUrlCache.sid, fromUrlCache)
|
||||
} else {
|
||||
sessionStorage.removeItem("fromUrl");
|
||||
}
|
||||
}, 500);
|
||||
})
|
||||
|
||||
//]]></script>
|
||||
<style>
|
||||
.share-toolbar {
|
||||
@@ -1892,7 +1861,7 @@ local current_node = map:get(section)
|
||||
<div class="share-toolbar">
|
||||
<div class="toolbar-buttons">
|
||||
<% if not current_node.protocol or not current_node.protocol:find("^_") then -%>
|
||||
<input id="fromUrlBtn" type="button" class="btn cbi-button cbi-button-apply" value='<%:From Share URL%>' onclick="return fromUrl(this, '<%=self.option%>', '<%=self.value%>')" />
|
||||
<input id="fromUrlBtn" type="button" class="btn cbi-button cbi-button-apply" value='<%:From Share URL%>' onclick="return tofromUrl()" />
|
||||
<input id="exportUrlBtn" type="button" class="btn cbi-button cbi-button-apply" value='<%:Build Share URL%>' onclick="return exportUrl(this, '<%=self.option%>', '<%=self.value%>')" />
|
||||
<input id="genQrcodeBtn" type="button" class="btn cbi-button cbi-button-apply" value='<%:Generate QRCode%>' onclick="return genQrcode(this, '<%=self.option%>', '<%=self.value%>')" />
|
||||
<% end -%>
|
||||
|
||||
@@ -5,20 +5,21 @@ local appname = map.config
|
||||
local is_js_luci = api.is_js_luci()
|
||||
local section_tag = is_js_luci and "div" or "fieldset"
|
||||
|
||||
local default_node_type = ""
|
||||
local shunt_rule_list = {}
|
||||
local node = map:get("@global[0]", "node")
|
||||
if node then
|
||||
local node_type = map:get(node, "type")
|
||||
local node_protocol = map:get(node, "protocol")
|
||||
if (node_type == "Xray" or node_type == "sing-box") and node_protocol == "_shunt" then
|
||||
default_node_type = node_protocol
|
||||
if node_protocol == "_shunt" then
|
||||
local node_shunt_group = map:get(node, "shunt_group")
|
||||
map:foreach("shunt_rules", function(e)
|
||||
if e[".name"] and e.remarks and e.group == node_shunt_group then
|
||||
shunt_rule_list[#shunt_rule_list + 1] = e
|
||||
end
|
||||
end)
|
||||
shunt_rule_list[#shunt_rule_list + 1] = {
|
||||
[".name"] = "default_node",
|
||||
remarks = translate("Default")
|
||||
}
|
||||
end
|
||||
end
|
||||
-%>
|
||||
@@ -1671,14 +1672,13 @@ table td, .table .td {
|
||||
<input class="btn cbi-button" type="button" onclick="set_node_div.set('@global[0]', 'node')" value="<%:OK%>" />
|
||||
</div>
|
||||
</div>
|
||||
<% if default_node_type == "_shunt" then %>
|
||||
<% if #shunt_rule_list > 0 then %>
|
||||
<div id="set_node_shunt_div" style="margin: 0.5em 0; padding: 0.5em; background: #f7f7f7; border-radius: 4px;">
|
||||
<div class="cbi-section-descr" style="text-align: left;"><a style="color:#FF8C00"><%:Set as the routing rule node:%></a></div>
|
||||
<div>
|
||||
<% for i, v in ipairs(shunt_rule_list) do %>
|
||||
<input class="btn cbi-button" type="button" onclick="set_node_div.set('<%=node%>', '<%=v[".name"]%>')" value="<%=v.remarks%>" />
|
||||
<% end %>
|
||||
<input class="btn cbi-button" type="button" onclick="set_node_div.set('<%=node%>', 'default_node')" value="<%:Default%>" />
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
@@ -818,7 +818,7 @@ add_firewall_rule() {
|
||||
|
||||
# jump chains
|
||||
# Only TCP, UDP Invalid.
|
||||
nft "add rule $NFTABLE_NAME mangle_prerouting meta nfproto ipv4 meta l4proto tcp socket transparent 1 mark set ${FWMARK} counter accept"
|
||||
nft "add rule $NFTABLE_NAME mangle_prerouting meta nfproto ipv4 meta l4proto tcp socket transparent 1 mark set ${FWMARK} counter accept comment PSW2_SOCKET"
|
||||
nft "add rule $NFTABLE_NAME mangle_prerouting ip daddr != @$NFTSET_DIRECT ip protocol udp counter jump PSW2_MANGLE"
|
||||
[ -n "${is_tproxy}" ] && nft "add rule $NFTABLE_NAME mangle_prerouting ip daddr != @$NFTSET_DIRECT ip protocol tcp counter jump PSW2_MANGLE"
|
||||
|
||||
@@ -889,7 +889,7 @@ add_firewall_rule() {
|
||||
# jump chains
|
||||
[ "$PROXY_IPV6" == "1" ] && {
|
||||
# Only TCP, UDP Invalid.
|
||||
nft "add rule $NFTABLE_NAME mangle_prerouting meta nfproto ipv6 meta l4proto tcp socket transparent 1 mark set ${FWMARK} counter accept"
|
||||
nft "add rule $NFTABLE_NAME mangle_prerouting meta nfproto ipv6 meta l4proto tcp socket transparent 1 mark set ${FWMARK} counter accept comment PSW2_SOCKET"
|
||||
nft "add rule $NFTABLE_NAME mangle_prerouting ip6 daddr != @$NFTSET_DIRECT6 meta nfproto {ipv6} counter jump PSW2_MANGLE_V6"
|
||||
nft "add rule $NFTABLE_NAME mangle_output ip6 daddr != @$NFTSET_DIRECT6 meta nfproto {ipv6} counter jump PSW2_OUTPUT_MANGLE_V6 comment \"PSW2_OUTPUT_MANGLE\""
|
||||
|
||||
|
||||
Submodule luci-app-syncthing deleted from b7a197a93c
@@ -0,0 +1,22 @@
|
||||
# Copyright (C) 2020 Gyj1109
|
||||
# 适配 OpenWrt 25.12 修改版
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-syncthing
|
||||
PKG_VERSION:=1.0
|
||||
PKG_RELEASE:=3
|
||||
|
||||
LUCI_TITLE:=LuCI support for Syncthing
|
||||
LUCI_PKGARCH:=all
|
||||
# 适配 25.12:确保安装了 syncthing 后,LuCI 界面能正确拉起
|
||||
LUCI_DEPENDS:=+syncthing
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# 明确定义配置文件的归属,这对 25.12 的 apk 管理器非常重要
|
||||
define Package/$(PKG_NAME)/conffiles
|
||||
/etc/config/syncthing
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,$(PKG_NAME)))
|
||||
@@ -0,0 +1,2 @@
|
||||
# luci-app-syncthing
|
||||
在Potat0000源码基础上进行了汉化优化,官方openwrt23.05.3编译后可使用
|
||||
@@ -0,0 +1,17 @@
|
||||
module("luci.controller.syncthing", package.seeall)
|
||||
|
||||
function index()
|
||||
if not nixio.fs.access("/etc/config/syncthing") then
|
||||
return
|
||||
end
|
||||
|
||||
entry({"admin", "services", "syncthing"}, cbi("syncthing"), _("文件同步"), 10).dependent = true
|
||||
entry({"admin", "services", "syncthing", "status"}, call("act_status")).leaf = true
|
||||
end
|
||||
|
||||
function act_status()
|
||||
local e = {}
|
||||
e.running = luci.sys.call("pgrep syncthing >/dev/null") == 0
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json(e)
|
||||
end
|
||||
@@ -0,0 +1,48 @@
|
||||
require("nixio.fs")
|
||||
|
||||
m = Map("syncthing", translate("Syncthing同步工具"))
|
||||
|
||||
m:section(SimpleSection).template = "syncthing/syncthing_status"
|
||||
|
||||
s = m:section(TypedSection, "syncthing")
|
||||
|
||||
s.anonymous = true
|
||||
|
||||
o = s:option(Flag, "enabled", translate("启用"))
|
||||
o.default = 0
|
||||
o.rmempty = false
|
||||
|
||||
gui_address = s:option(Value, "gui_address", translate("GUI访问地址"))
|
||||
gui_address.description = translate("使用0.0.0.0以监控所有访问。")
|
||||
gui_address.default = "http://0.0.0.0:8384"
|
||||
gui_address.placeholder = "http://0.0.0.0:8384"
|
||||
gui_address.rmempty = false
|
||||
|
||||
home = s:option(Value, "home", translate("配置文件目录"))
|
||||
home.description = translate("只有保存在/etc/syncthing中的配置会自动备份!")
|
||||
home.default = "/etc/syncthing"
|
||||
home.placeholder = "/etc/syncthing"
|
||||
home.rmempty = false
|
||||
|
||||
user = s:option(ListValue, "user", translate("用户"))
|
||||
user.description = translate("默认是syncthing,但这可能会导致权限被拒绝。Syncthing官方不建议以root身份运行。")
|
||||
user:value("", translate("syncthing"))
|
||||
for u in luci.util.execi("cat /etc/passwd | cut -d ':' -f1") do
|
||||
user:value(u)
|
||||
end
|
||||
|
||||
macprocs = s:option(Value, "macprocs", translate("线程限制"))
|
||||
macprocs.description = translate("0表示匹配CPU数量(默认),>0表示显式指定并发数。")
|
||||
macprocs.default = "0"
|
||||
macprocs.placeholder = "0"
|
||||
macprocs.datatype = "range(0,32)"
|
||||
macprocs.rmempty = false
|
||||
|
||||
nice = s:option(Value, "nice", translate("优先级"))
|
||||
nice.description = translate("显式指定优先级值。0是最高,19是最低。(暂时不允许设置负值)")
|
||||
nice.default = "19"
|
||||
nice.placeholder = "19"
|
||||
nice.datatype = "range(0,19)"
|
||||
nice.rmempty = false
|
||||
|
||||
return m
|
||||
@@ -0,0 +1,27 @@
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
XHR.poll(1, '<%=url([[admin]], [[services]], [[syncthing]], [[status]])%>', null,
|
||||
function (x, data) {
|
||||
var tb = document.getElementById('syncthing_status');
|
||||
if (data && tb) {
|
||||
if (data.running) {
|
||||
var links = '<em><b><font color="green">Syncthing <%:运行中%></font></b></em><input class="btn cbi-button mar-10" type="button" value="<%:打开Syncthing页面%>" onclick="openwebui();" />';
|
||||
tb.innerHTML = links;
|
||||
} else {
|
||||
tb.innerHTML = '<em><b><font color="red">Syncthing <%:未运行%></font></b></em>';
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
function openwebui(){
|
||||
var url = window.location.host+":<%=luci.sys.exec("uci -q get syncthing.syncthing.gui_address"):match(":[0-9]+"):gsub(":", "")%>";
|
||||
window.open('http://'+url,'target','');
|
||||
}
|
||||
//]]>
|
||||
</script>
|
||||
<style>.mar-10 {margin-left: 50px; margin-right: 10px;}</style>
|
||||
<fieldset class="cbi-section">
|
||||
<p id="syncthing_status">
|
||||
<em><%:正在收集数据...%></em>
|
||||
</p>
|
||||
</fieldset>
|
||||
@@ -0,0 +1,12 @@
|
||||
#!/bin/sh
|
||||
touch /etc/config/syncthing
|
||||
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete ucitrack.@syncthing[-1]
|
||||
add ucitrack syncthing
|
||||
set ucitrack.@syncthing[-1].exec='/etc/init.d/syncthing stop && /etc/init.d/syncthing start'
|
||||
commit ucitrack
|
||||
EOF
|
||||
# remove LuCI cache
|
||||
rm -f /tmp/luci*
|
||||
exit 0
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"luci-app-syncthing": {
|
||||
"description": "Grant UCI access for luci-app-syncthing",
|
||||
"read": {
|
||||
"uci": [ "syncthing" ]
|
||||
},
|
||||
"write": {
|
||||
"uci": [ "syncthing" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user