<%+header%> <% local http = require("luci.http") local core = require("substore.core") -- meta.error / human_duration 返回的都是语言中立的 msgid(可能是组合消息), -- 翻译在视图侧做 —— 后端模块不能 require("luci.i18n"),见 msg.lua 的文件头。 local msg = require("substore.msg") local function tmsg(s) return msg.translate(s, luci.i18n.translate) end local id = http.formvalue("id") or "" local it = id ~= "" and core.get(id) or nil local is_edit = it ~= nil local cron_enabled = it and (it.cron_enable == true or it.cron_enable == "1") or false local cron = (it and it.cron_time and it.cron_time ~= "") and it.cron_time or "0 3 * * *" local cm, ch, cdom, cmon, cdow = cron:match("^(%S+) (%S+) (%S+) (%S+) (%S+)$") cm = cm or "0"; ch = ch or "3"; cdom = cdom or "*"; cmon = cmon or "*"; cdow = cdow or "*" local rules_enabled = it and (it.rules_enable == true or it.rules_enable == "1") or false local ki = (it and it.keyword_include) or "" local ke = (it and it.keyword_exclude) or "" local dedup = it and (it.dedup == "1" or it.dedup == true) -- 协议筛选 / 重命名:控制器一直在读这两项(read_rules_fields),但此前三个表单 -- 都没有提交它们的控件 —— 字段永远写空,且每次保存会把 UCI 里已有的值重置为 ""。 local proto_sel = {} for p in ((it and it.proto_filter) or ""):gmatch("[^,]+") do proto_sel[p:match("^%s*(.-)%s*$")] = true end local rm = (it and it.rename_map) or "" local proxy_enabled = it and (it.proxy_enable == true or it.proxy_enable == "1") or false -- 订阅客户端类型(User-Agent)。部分机场按 UA 决定返回真实节点还是占位内容: -- 同一个订单链接只有用绑定的客户端 UA 才拿得到真节点。预设见 core.UA_PRESETS。 local ua_preset = core.ua_preset_of(it and it.user_agent) local ua_custom = (ua_preset == "custom") and (it and it.user_agent or "") or "" local util = require("substore.util") -- 剩余流量 / 剩余时长(仅编辑页且有 subscription-userinfo 数据时显示,首页不显示) local traffic_str = nil local time_str = nil if is_edit and it then if it.total then local rem = (tonumber(it.total) or 0) - (tonumber(it.upload) or 0) - (tonumber(it.download) or 0) if rem < 0 then rem = 0 end traffic_str = util.human_bytes(rem) end if it.expire then time_str = tmsg(util.human_duration((tonumber(it.expire) or 0) - os.time())) end end %>

<%=is_edit and luci.i18n.translate("Edit subscription") or luci.i18n.translate("Add subscription")%>

<% if is_edit then %><% end %>
"/>
" style="width:60%"/>
onchange="var r=document.getElementById('proxy_row');if(r)r.style.display=this.checked?'block':'none';"/>
"> " style="width:60%"/>
<%:Download the subscription through a proxy (leave empty to disable); http:// and socks5:// addresses are supported, e.g. socks5://192.168.5.1:1080%>
<%:Some airports hand out nodes based on the client type: on the same link, only the right type parses into real nodes — the wrong one yields a placeholder node saying your client is incompatible. Keep “Default” if unsure.%>
<%:“Custom” is for clients the presets do not cover: enter the User-Agent header to send verbatim, in the same shape as the preset values, i.e. client-name/version — for example clash-verge/v2.5.0, v2rayN/7.22.0, mihomo.party/v2.0.0 (clash.meta).%>
<%:Visible characters such as spaces, parentheses, semicolons and underscores are allowed (the whole string is sent verbatim — not parsed or rewritten); control characters such as newlines are not. Maximum length is 256 characters. Set the version to the minimum version the airport accepts; check the airport or client documentation for the exact value.%> <%:Selecting “Custom” but leaving it empty sends no User-Agent (same as “Default”).%>
">
onchange="var r=document.getElementById('cron_time_row');if(r)r.style.display=this.checked?'block':'none';"/>
"> <%:Minute%> <%:Hour%> <%:Day%> <%:Month%> <%:Week%>
onchange="var r=document.getElementById('rules_row');if(r)r.style.display=this.checked?'block':'none';"/> <%:When enabled, apply keyword include/exclude and dedup rules to nodes%>
">
/>
<% for _, p in ipairs(core.RULE_PROTOS) do %> /> <% end %>
<%:Separate multiple keywords with commas (e.g. HK,US,JP); include = keep if any matches, exclude = drop if any matches.%>
<%:Protocol filter: with none ticked no filtering is applied.%>
<%:Rename: one rule per line (# starts a comment); rules apply top to bottom and are chained. The three forms differ in scope:%>
<%:OLD=NEW — exact match: renames only nodes named exactly OLD.%>
<%:PATTERN -> REPLACEMENT — regex: replaces matches in the name of every node (Lua patterns, not PCRE; $1 for captures).%>
<%:{server}_{port}_{proto} — placeholder template: renames every node unconditionally.%>
<%:Placeholders: {server} {port} {proto} {name} {uuid} {password} {group}.%>
<% if is_edit and it.last_update then %>
<%:Nodes:%> <%=it.node_count or 0%> <% if traffic_str then %> | <%:Remaining traffic:%> <%=traffic_str%><% end %> <% if time_str then %> | <%:Remaining time:%> <%=time_str%><% end %> | <%:Last updated:%> <%=os.date("%Y-%m-%d %H:%M", it.last_update)%> <% if it.error and it.error ~= "" then %> | <%=luci.util.pcdata(tmsg(it.error))%><% end %>
<% end %>
<%+footer%>