mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-03 19:23:56 +08:00
🎉 Sync 2026-10-13 02:34:41
This commit is contained in:
1 parent
b537a62e59
commit
72c44a6325
38 files changed
+3510
-1734
No files matched your search
@@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-passwall
|
||||
PKG_VERSION:=26.10.4
|
||||
PKG_RELEASE:=331
|
||||
PKG_RELEASE:=332
|
||||
PKG_PO_VERSION:=$(PKG_VERSION)
|
||||
|
||||
PKG_CONFIG_DEPENDS:= \
|
||||
|
||||
@@ -133,10 +133,10 @@ sources.validate = function(self, value, t)
|
||||
flag = true
|
||||
end
|
||||
end
|
||||
if flag == false and datatypes.macaddr(v) then
|
||||
if flag == false and api.datatypes.macaddr(v) then
|
||||
flag = true
|
||||
end
|
||||
if flag == false and datatypes.ip4addr(v) then
|
||||
if flag == false and api.datatypes.ip4addr(v) then
|
||||
flag = true
|
||||
end
|
||||
if flag == false and api.iprange(v) then
|
||||
|
||||
@@ -3,6 +3,7 @@ datatypes = api.datatypes
|
||||
local fs = api.fs
|
||||
has_singbox = api.finded_com("sing-box")
|
||||
has_xray = api.finded_com("xray")
|
||||
local has_smartdns = api.is_finded("smartdns")
|
||||
local has_gfwlist = fs.access("/usr/share/passwall/rules/gfwlist")
|
||||
local has_chnlist = fs.access("/usr/share/passwall/rules/chnlist")
|
||||
local has_chnroute = fs.access("/usr/share/passwall/rules/chnroute")
|
||||
@@ -180,7 +181,7 @@ o.write = function(self, section, value)
|
||||
end
|
||||
return ListValue.write(self, section, value)
|
||||
end
|
||||
if api.is_finded("smartdns") then
|
||||
if has_smartdns then
|
||||
o:value("smartdns", "SmartDNS")
|
||||
|
||||
o = s:taboption("DNS", Value, "group_domestic", translate("Domestic group name"))
|
||||
@@ -284,7 +285,7 @@ o.remove = function(self, section)
|
||||
end
|
||||
|
||||
---- SmartDNS Forward Mode
|
||||
if api.is_finded("smartdns") then
|
||||
if has_smartdns then
|
||||
o = s:taboption("DNS", ListValue, "smartdns_dns_mode", translate("Filter Mode"))
|
||||
o:value("socks", "Socks")
|
||||
if has_singbox then
|
||||
@@ -487,14 +488,14 @@ o:value("remote", translate("Remote DNS"))
|
||||
o:value("direct", translate("Direct DNS"))
|
||||
o.description = desc .. "</ul>"
|
||||
o:depends({dns_shunt = "dnsmasq", tcp_proxy_mode = "proxy", chn_list = "direct"})
|
||||
if api.is_finded("smartdns") then
|
||||
if has_smartdns then
|
||||
o:depends({dns_shunt = "smartdns", tcp_proxy_mode = "proxy", chn_list = "direct"})
|
||||
end
|
||||
|
||||
o = s:taboption("DNS", Flag, "force_https_soa", translate("Force HTTPS SOA"), translate("Force queries with qtype 65 to respond with an SOA record."))
|
||||
o.default = "0"
|
||||
o:depends({dns_shunt = "chinadns-ng"})
|
||||
if api.is_finded("smartdns") then
|
||||
if has_smartdns then
|
||||
o:depends({dns_shunt = "smartdns"})
|
||||
end
|
||||
|
||||
|
||||
@@ -871,19 +871,26 @@ function clone(org)
|
||||
end
|
||||
|
||||
function get_bin_version_cache(file, cmd)
|
||||
sys.call("mkdir -p " .. CACHE_PATH)
|
||||
if fs.access(file) then
|
||||
if file and file ~= "" and fs.access(file) then
|
||||
chmod_755(file)
|
||||
local md5 = md5_file(file)
|
||||
if fs.access(CACHE_PATH .. "/" .. md5) then
|
||||
return sys.exec("echo -n $(cat %s)" % { CACHE_PATH .. "/" .. md5 })
|
||||
else
|
||||
local version = sys.exec(string.format("echo -n $(%s %s)", file, cmd))
|
||||
if version and version ~= "" then
|
||||
sys.call("echo '%s' > %s" % { version, CACHE_PATH .. "/" .. md5})
|
||||
return version
|
||||
local stat = fs.stat(file)
|
||||
local cache_file
|
||||
if stat and stat.dev and stat.ino and stat.size and stat.mtime and stat.ctime then
|
||||
-- Use metadata to avoid hashing the entire binary on every lookup.
|
||||
cache_file = CACHE_PATH .. "/binver_" .. table.concat({stat.dev, stat.ino, stat.size, stat.mtime, stat.ctime}, "_")
|
||||
local cached = fs.readfile(cache_file)
|
||||
if cached and trim(cached) ~= "" then
|
||||
return trim(cached)
|
||||
end
|
||||
end
|
||||
local version = sys.exec(string.format("echo -n $(%s %s)", util.shellquote(file), cmd))
|
||||
if version and version ~= "" then
|
||||
if cache_file then
|
||||
fs.mkdirr(CACHE_PATH)
|
||||
fs.writefile(cache_file, version)
|
||||
end
|
||||
return version
|
||||
end
|
||||
end
|
||||
return ""
|
||||
end
|
||||
@@ -904,7 +911,7 @@ end
|
||||
|
||||
local function is_file(path)
|
||||
if path and #path > 1 then
|
||||
if sys.exec('[ -f "%s" ] && echo -n 1' % path) == "1" then
|
||||
if fs.stat(path, "type") == "reg" then
|
||||
return true
|
||||
end
|
||||
end
|
||||
@@ -913,7 +920,7 @@ end
|
||||
|
||||
local function is_dir(path)
|
||||
if path and #path > 1 then
|
||||
if sys.exec('[ -d "%s" ] && echo -n 1' % path) == "1" then
|
||||
if fs.stat(path, "type") == "dir" then
|
||||
return true
|
||||
end
|
||||
end
|
||||
@@ -1554,7 +1561,7 @@ function to_install_self(id, force)
|
||||
remove(dir)
|
||||
return {code = 1}
|
||||
end
|
||||
fs.chmod(script, 755)
|
||||
chmod_755(script)
|
||||
fs.writefile(status, '{"installing":true}')
|
||||
sys.call("nohup " .. script .. " " .. dir .. " " .. status .. " " .. manager .. " " ..
|
||||
(force == "1" and "1" or "0") .. " >/dev/null 2>&1 </dev/null &")
|
||||
@@ -1562,7 +1569,7 @@ function to_install_self(id, force)
|
||||
end
|
||||
|
||||
function is_js_luci()
|
||||
return sys.call('[ -f "/www/luci-static/resources/uci.js" ]') == 0
|
||||
return fs.stat("/www/luci-static/resources/uci.js", "type") == "reg"
|
||||
end
|
||||
|
||||
function set_default_cbi()
|
||||
@@ -1614,6 +1621,16 @@ function set_default_cbi()
|
||||
return obj
|
||||
end
|
||||
end
|
||||
if true then
|
||||
--Table
|
||||
local Table = cbi.Table
|
||||
local default_init = Table.__init__
|
||||
function Table.__init__(self, form, ...)
|
||||
default_init(self, form, ...)
|
||||
-- Table 的 map 是独立数据源,需要从所属表单传递 API
|
||||
self.map.api = form.api
|
||||
end
|
||||
end
|
||||
if true then
|
||||
--TextValue
|
||||
local TextValue = cbi.TextValue
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
-- Description: Passwall(2) UI template
|
||||
|
||||
local json = require "luci.jsonc"
|
||||
local api = self.map.api
|
||||
|
||||
-- 读取值(keylist/vallist/group)
|
||||
local values = {}
|
||||
@@ -48,6 +49,30 @@ for _, item in ipairs(values) do
|
||||
end
|
||||
end
|
||||
|
||||
-- 仅共享组名、节点 key/label 及顺序完全相同的分组,保留各控件的候选限制
|
||||
local group_cache = self.map._lv_group_cache
|
||||
if not group_cache then
|
||||
group_cache = {}
|
||||
self.map._lv_group_cache = group_cache
|
||||
end
|
||||
local group_refs = {}
|
||||
local new_groups = {}
|
||||
for i, g in ipairs(group_order) do
|
||||
-- 使用有序数组生成完整签名,不依赖 JSON 对象的字段顺序或哈希值
|
||||
local signature = {g}
|
||||
for _, item in ipairs(groups[g]) do
|
||||
signature[#signature + 1] = {item.key, item.label}
|
||||
end
|
||||
local cache_key = json.stringify(signature)
|
||||
local ref = group_cache[cache_key]
|
||||
if not ref then
|
||||
ref = cbid .. ".group." .. i
|
||||
group_cache[cache_key] = ref
|
||||
new_groups[ref] = groups[g]
|
||||
end
|
||||
group_refs[i] = ref
|
||||
end
|
||||
|
||||
-- 如果没有配置值,默认取第一个(优先无组第一项,否则第一组第一项)
|
||||
if not current_key then
|
||||
if #ungrouped > 0 then
|
||||
@@ -73,19 +98,28 @@ local function find_label_by_key(k)
|
||||
end
|
||||
local current_label = find_label_by_key(current_key) or ""
|
||||
|
||||
-- 打包数据给 JS
|
||||
-- 控件只携带分组引用,重复的候选数据在页面中仅输出一次
|
||||
local dropdown_data = {
|
||||
appname = api.appname,
|
||||
current_key = current_key,
|
||||
current_label = current_label,
|
||||
ungrouped = ungrouped,
|
||||
groups = groups,
|
||||
group_refs = group_refs,
|
||||
group_order = group_order,
|
||||
cbid = cbid,
|
||||
}
|
||||
%>
|
||||
<script>
|
||||
window.lv_dropdown_data = window.lv_dropdown_data || {};
|
||||
window.lv_dropdown_data["<%=cbid%>"] = <%=json.stringify(dropdown_data)%>;
|
||||
(function() {
|
||||
const appname = <%=json.stringify(api.appname)%>;
|
||||
window.lv_groups_pool = window.lv_groups_pool || Object.create(null);
|
||||
const pool = window.lv_groups_pool[appname] || (window.lv_groups_pool[appname] = Object.create(null));
|
||||
<% if next(new_groups) then %>
|
||||
Object.assign(pool, <%=json.stringify(new_groups)%>);
|
||||
<% end %>
|
||||
window.lv_dropdown_data = window.lv_dropdown_data || {};
|
||||
window.lv_dropdown_data[<%=json.stringify(cbid)%>] = <%=json.stringify(dropdown_data)%>;
|
||||
})();
|
||||
</script>
|
||||
|
||||
<div id="<%=cbid%>.main" class="lv-dropdown-container">
|
||||
|
||||
@@ -577,8 +577,10 @@
|
||||
}
|
||||
|
||||
// 分组项
|
||||
data.group_order.forEach(gname => {
|
||||
const items = data.groups[gname];
|
||||
const groupPool = window.lv_groups_pool && window.lv_groups_pool[data.appname];
|
||||
data.group_order.forEach((gname, index) => {
|
||||
const items = data.groups ? data.groups[gname] : groupPool && groupPool[data.group_refs[index]];
|
||||
if (!Array.isArray(items)) return;
|
||||
|
||||
html += `
|
||||
<div class="lv-group" data-group="${lv_idSafe(gname)}" style="margin-bottom:8px;">
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
-- Description: Passwall(2) UI template
|
||||
|
||||
local json = require "luci.jsonc"
|
||||
local api = self.map.api
|
||||
|
||||
-- 读取值(keylist/vallist/group)
|
||||
local values = {{key = "", label = translate("-- Please choose --")}}
|
||||
@@ -56,6 +57,30 @@ if not current_key_added and current_key and current_key ~= "" then
|
||||
table.insert(ungrouped, {key = current_key, label = current_key})
|
||||
end
|
||||
|
||||
-- 仅共享候选分组,各控件的自定义地址仍保留在自己的 ungrouped 中
|
||||
local group_cache = self.map._v_group_cache
|
||||
if not group_cache then
|
||||
group_cache = {}
|
||||
self.map._v_group_cache = group_cache
|
||||
end
|
||||
local group_refs = {}
|
||||
local new_groups = {}
|
||||
for i, g in ipairs(group_order) do
|
||||
-- 组名、节点 key/label 及顺序完全相同才复用,不与 ListValue 缓存混用
|
||||
local signature = {g}
|
||||
for _, item in ipairs(groups[g]) do
|
||||
signature[#signature + 1] = {item.key, item.label}
|
||||
end
|
||||
local cache_key = json.stringify(signature)
|
||||
local ref = group_cache[cache_key]
|
||||
if not ref then
|
||||
ref = cbid .. ".v-group." .. i
|
||||
group_cache[cache_key] = ref
|
||||
new_groups[ref] = groups[g]
|
||||
end
|
||||
group_refs[i] = ref
|
||||
end
|
||||
|
||||
-- 如果没有配置值,默认取第一个(优先无组第一项,否则第一组第一项)
|
||||
if not current_key then
|
||||
if #ungrouped > 0 then
|
||||
@@ -81,19 +106,28 @@ local function find_label_by_key(k)
|
||||
end
|
||||
local current_label = find_label_by_key(current_key) or ""
|
||||
|
||||
-- 打包数据给 JS
|
||||
-- 控件只携带分组引用,重复的候选数据在页面中仅输出一次
|
||||
local dropdown_data = {
|
||||
appname = api.appname,
|
||||
current_key = current_key,
|
||||
current_label = current_label,
|
||||
ungrouped = ungrouped,
|
||||
groups = groups,
|
||||
group_refs = group_refs,
|
||||
group_order = group_order,
|
||||
cbid = cbid,
|
||||
}
|
||||
%>
|
||||
<script>
|
||||
window.v_dropdown_data = window.v_dropdown_data || {};
|
||||
window.v_dropdown_data["<%=cbid%>"] = <%=json.stringify(dropdown_data)%>;
|
||||
(function() {
|
||||
const appname = <%=json.stringify(api.appname)%>;
|
||||
window.v_groups_pool = window.v_groups_pool || Object.create(null);
|
||||
const pool = window.v_groups_pool[appname] || (window.v_groups_pool[appname] = Object.create(null));
|
||||
<% if next(new_groups) then %>
|
||||
Object.assign(pool, <%=json.stringify(new_groups)%>);
|
||||
<% end %>
|
||||
window.v_dropdown_data = window.v_dropdown_data || {};
|
||||
window.v_dropdown_data[<%=json.stringify(cbid)%>] = <%=json.stringify(dropdown_data)%>;
|
||||
})();
|
||||
</script>
|
||||
|
||||
<div id="<%=cbid%>.v-main" class="v-dropdown-container">
|
||||
|
||||
@@ -603,8 +603,10 @@
|
||||
}
|
||||
|
||||
// 分组项
|
||||
data.group_order.forEach(gname => {
|
||||
const items = data.groups[gname];
|
||||
const groupPool = window.v_groups_pool && window.v_groups_pool[data.appname];
|
||||
data.group_order.forEach((gname, index) => {
|
||||
const items = data.groups ? data.groups[gname] : groupPool && groupPool[data.group_refs[index]];
|
||||
if (!Array.isArray(items)) return;
|
||||
|
||||
html += `
|
||||
<div class="v-group" data-group="${v_idSafe(gname)}" style="margin-bottom:8px;">
|
||||
|
||||
@@ -139,7 +139,7 @@ https://github.com/pure-css/pure/blob/master/LICENSE.md
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pure-u-1-4 check" onclick="check_connect('aliyun', 'https://www.aliyun.com')" title="<%:HTTP request latency, for reference only%>">
|
||||
<div class="pure-u-1-4 check" onclick="check_connect('aliyun', 'https://www.aliyun.com/favicon.ico')" title="<%:HTTP request latency, for reference only%>">
|
||||
<div class="block pure-g">
|
||||
<div class="pure-u-1-3">
|
||||
<div class="img-con">
|
||||
@@ -163,7 +163,7 @@ https://github.com/pure-css/pure/blob/master/LICENSE.md
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pure-u-1-4 check" onclick="check_connect('github', 'https://github.com')" title="<%:HTTP request latency, for reference only%>">
|
||||
<div class="pure-u-1-4 check" onclick="check_connect('github', 'https://github.com/favicon.ico')" title="<%:HTTP request latency, for reference only%>">
|
||||
<div class="block pure-g">
|
||||
<div class="pure-u-1-3">
|
||||
<div class="img-con">
|
||||
|
||||
Reference in new issue
Block a user