diff --git a/luci-app-fchomo/htdocs/luci-static/resources/fchomo/listeners.js b/luci-app-fchomo/htdocs/luci-static/resources/fchomo/listeners.js index c591e585..eef85e9f 100644 --- a/luci-app-fchomo/htdocs/luci-static/resources/fchomo/listeners.js +++ b/luci-app-fchomo/htdocs/luci-static/resources/fchomo/listeners.js @@ -967,18 +967,18 @@ function renderListeners(s, uciconfig, isClient) { o = s.taboption('field_transport', form.ListValue, 'transport_type', _('Transport type')); o.value('grpc', _('gRPC')); o.value('ws', _('WebSocket')); + o.value('xhttp', _('XHTTP')); o.validate = function(section_id, value) { const type = this.section.getOption('type').formvalue(section_id); switch (type) { - case 'vmess': case 'vless': - if (!['http', 'h2', 'grpc', 'ws'].includes(value)) - return _('Expecting: only support %s.').format(_('HTTP') + - ' / ' + _('HTTPUpgrade') + - ' / ' + _('gRPC') + - ' / ' + _('WebSocket')); + if (!['grpc', 'ws', 'xhttp'].includes(value)) + return _('Expecting: only support %s.').format(_('gRPC') + + ' / ' + _('WebSocket') + + ' / ' + _('XHTTP')); break; + case 'vmess': case 'trojan': if (!['grpc', 'ws'].includes(value)) return _('Expecting: only support %s.').format(_('gRPC') + @@ -993,11 +993,17 @@ function renderListeners(s, uciconfig, isClient) { o.depends('transport_enabled', '1'); o.modalonly = true; + o = s.taboption('field_transport', form.Value, 'transport_host', _('Server hostname')); + o.datatype = 'hostname'; + o.placeholder = 'example.com'; + o.depends({transport_enabled: '1', transport_type: 'xhttp'}); + o.modalonly = true; + o = s.taboption('field_transport', form.Value, 'transport_path', _('Request path')); o.placeholder = '/'; o.default = '/'; o.rmempty = false; - o.depends({transport_enabled: '1', transport_type: 'ws'}); + o.depends({transport_enabled: '1', transport_type: /^(ws|xhttp)$/}); o.modalonly = true; o = s.taboption('field_transport', form.Value, 'transport_grpc_servicename', _('gRPC service name')); @@ -1005,6 +1011,30 @@ function renderListeners(s, uciconfig, isClient) { o.rmempty = false; o.depends({transport_enabled: '1', transport_type: 'grpc'}); o.modalonly = true; + + o = s.taboption('field_transport', form.ListValue, 'transport_xhttp_mode', _('XHTTP mode')); + o.value('auto', _('Auto')); + o.value('stream-one', _('stream-one')); + o.value('stream-up', _('stream-up')); + o.value('packet-up', _('packet-up')); + o.depends({transport_enabled: '1', transport_type: 'xhttp'}); + o.modalonly = true; + + o = s.taboption('field_transport', form.Flag, 'transport_xhttp_no_sse_header', _('No SSE header')); + o.default = o.disabled; + o.depends({transport_enabled: '1', transport_type: 'xhttp'}); + o.modalonly = true; + + o = s.taboption('field_transport', form.Value, 'transport_xhttp_sc_stream_up_server_secs', _('stream-up server seconds')); + o.placeholder = '20-80'; + o.depends({transport_enabled: '1', transport_type: 'xhttp'}); + o.modalonly = true; + + o = s.taboption('field_transport', form.Value, 'transport_xhttp_sc_max_each_post_bytes', _('Max each POST bytes')); + o.datatype = 'uinteger'; + o.placeholder = '1000000'; + o.depends({transport_enabled: '1', transport_type: 'xhttp'}); + o.modalonly = true; } return baseclass.extend({ diff --git a/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/node.js b/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/node.js index 8554a0f6..849ac297 100644 --- a/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/node.js +++ b/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/node.js @@ -1170,7 +1170,7 @@ return view.extend({ so.depends({transport_enabled: '1', transport_type: 'h2'}); so.modalonly = true; - so = ss.taboption('field_transport', form.DynamicList, 'transport_host', _('Server hostname')); + so = ss.taboption('field_transport', form.Value, 'transport_host', _('Server hostname')); so.datatype = 'hostname'; so.placeholder = 'example.com'; so.depends({transport_enabled: '1', transport_type: 'xhttp'}); @@ -1261,6 +1261,42 @@ return view.extend({ so.depends({transport_enabled: '1', transport_type: 'xhttp'}); so.modalonly = true; + so = ss.taboption('field_transport', form.Value, 'transport_xhttp_sc_max_each_post_bytes', _('Max each POST bytes')); + so.datatype = 'uinteger'; + so.placeholder = '1000000'; + so.depends({transport_enabled: '1', transport_type: 'xhttp'}); + so.modalonly = true; + + so = ss.taboption('field_transport', form.Flag, 'transport_xhttp_xmux', _('XMUX')); + so.default = so.disabled; + so.depends({transport_enabled: '1', transport_type: 'xhttp'}); + so.modalonly = true; + + so = ss.taboption('field_transport', form.Value, 'transport_xhttp_xmux_max_connections', _('XMUX: ') + _('Max connections')); + so.placeholder = '16-32'; + so.depends('transport_xhttp_xmux', '1'); + so.modalonly = true; + + so = ss.taboption('field_transport', form.Value, 'transport_xhttp_xmux_max_concurrency', _('XMUX: ') + _('Max concurrency')); + so.placeholder = '0'; + so.depends({transport_xhttp_xmux: '1', transport_xhttp_xmux_max_connections: ''}); + so.modalonly = true; + + so = ss.taboption('field_transport', form.Value, 'transport_xhttp_xmux_max_reuse_times', _('XMUX: ') + _('Max reuse times')); + so.placeholder = '0'; + so.depends('transport_xhttp_xmux', '1'); + so.modalonly = true; + + so = ss.taboption('field_transport', form.Value, 'transport_xhttp_xmux_max_request_times', _('XMUX: ') + _('Max request times')); + so.placeholder = '600-900'; + so.depends('transport_xhttp_xmux', '1'); + so.modalonly = true; + + so = ss.taboption('field_transport', form.Value, 'transport_xhttp_xmux_max_reusable_secs', _('XMUX: ') + _('Max reusable seconds')); + so.placeholder = '1800-3000'; + so.depends('transport_xhttp_xmux', '1'); + so.modalonly = true; + /* Multiplex fields */ // TCP protocol only so = ss.taboption('field_general', form.Flag, 'smux_enabled', _('Multiplex')); so.default = so.disabled; @@ -1280,6 +1316,8 @@ return view.extend({ so.datatype = 'uinteger'; so.placeholder = '4'; so.depends('smux_enabled', '1'); + so.depends({transport_enabled: '1', transport_type: 'grpc'}); + so.depends('type', 'trusttunnel'); so.modalonly = true; so = ss.taboption('field_multiplex', form.Value, 'smux_min_streams', _('Minimum streams'), @@ -1287,6 +1325,8 @@ return view.extend({ so.datatype = 'uinteger'; so.placeholder = '4'; so.depends('smux_enabled', '1'); + so.depends({transport_enabled: '1', transport_type: 'grpc'}); + so.depends('type', 'trusttunnel'); so.modalonly = true; so = ss.taboption('field_multiplex', form.Value, 'smux_max_streams', _('Maximum streams'), @@ -1296,6 +1336,8 @@ return view.extend({ so.datatype = 'uinteger'; so.placeholder = '0'; so.depends({smux_enabled: '1', smux_max_connections: '', smux_min_streams: ''}); + so.depends({transport_enabled: '1', transport_type: 'grpc', smux_max_connections: '', smux_min_streams: ''}); + so.depends({type: 'trusttunnel', smux_max_connections: '', smux_min_streams: ''}); so.modalonly = true; so = ss.taboption('field_multiplex', form.Flag, 'smux_padding', _('Enable padding')); diff --git a/luci-app-fchomo/po/templates/fchomo.pot b/luci-app-fchomo/po/templates/fchomo.pot index c00e0b3a..ddffe1fa 100644 --- a/luci-app-fchomo/po/templates/fchomo.pot +++ b/luci-app-fchomo/po/templates/fchomo.pot @@ -25,10 +25,10 @@ msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:861 #: htdocs/luci-static/resources/view/fchomo/global.js:543 #: htdocs/luci-static/resources/view/fchomo/global.js:549 -#: htdocs/luci-static/resources/view/fchomo/node.js:1045 -#: htdocs/luci-static/resources/view/fchomo/node.js:1051 -#: htdocs/luci-static/resources/view/fchomo/node.js:1059 #: htdocs/luci-static/resources/view/fchomo/node.js:1065 +#: htdocs/luci-static/resources/view/fchomo/node.js:1071 +#: htdocs/luci-static/resources/view/fchomo/node.js:1079 +#: htdocs/luci-static/resources/view/fchomo/node.js:1085 msgid "(mTLS)" msgstr "" @@ -39,10 +39,10 @@ msgstr "" #: htdocs/luci-static/resources/view/fchomo/client.js:1056 #: htdocs/luci-static/resources/view/fchomo/client.js:1057 #: htdocs/luci-static/resources/view/fchomo/client.js:1278 -#: htdocs/luci-static/resources/view/fchomo/node.js:1788 -#: htdocs/luci-static/resources/view/fchomo/node.js:1794 -#: htdocs/luci-static/resources/view/fchomo/node.js:1808 -#: htdocs/luci-static/resources/view/fchomo/node.js:1814 +#: htdocs/luci-static/resources/view/fchomo/node.js:1846 +#: htdocs/luci-static/resources/view/fchomo/node.js:1852 +#: htdocs/luci-static/resources/view/fchomo/node.js:1866 +#: htdocs/luci-static/resources/view/fchomo/node.js:1872 msgid "-- Please choose --" msgstr "" @@ -78,8 +78,8 @@ msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:822 #: htdocs/luci-static/resources/fchomo/listeners.js:837 #: htdocs/luci-static/resources/fchomo/listeners.js:862 -#: htdocs/luci-static/resources/view/fchomo/node.js:1052 -#: htdocs/luci-static/resources/view/fchomo/node.js:1066 +#: htdocs/luci-static/resources/view/fchomo/node.js:1072 +#: htdocs/luci-static/resources/view/fchomo/node.js:1086 msgid "Save your configuration before uploading files!" msgstr "" @@ -173,11 +173,11 @@ msgstr "" msgid "Add a inbound" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1379 +#: htdocs/luci-static/resources/view/fchomo/node.js:1437 msgid "Add a provider" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1764 +#: htdocs/luci-static/resources/view/fchomo/node.js:1822 msgid "Add a proxy chain" msgstr "" @@ -201,11 +201,11 @@ msgstr "" msgid "Add a sub rule" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1589 +#: htdocs/luci-static/resources/view/fchomo/node.js:1647 msgid "Add prefix" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1593 +#: htdocs/luci-static/resources/view/fchomo/node.js:1651 msgid "Add suffix" msgstr "" @@ -240,7 +240,7 @@ msgid "" "network from a public website, it must be enabled." msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:768 +#: htdocs/luci-static/resources/view/fchomo/node.js:788 msgid "Allowed IPs" msgstr "" @@ -284,9 +284,11 @@ msgid "Authenticated length" msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:392 +#: htdocs/luci-static/resources/fchomo/listeners.js:1016 #: htdocs/luci-static/resources/view/fchomo/global.js:402 #: htdocs/luci-static/resources/view/fchomo/node.js:459 #: htdocs/luci-static/resources/view/fchomo/node.js:483 +#: htdocs/luci-static/resources/view/fchomo/node.js:1267 msgid "Auto" msgstr "" @@ -332,13 +334,13 @@ msgid "Binary mrs" msgstr "" #: htdocs/luci-static/resources/view/fchomo/global.js:734 -#: htdocs/luci-static/resources/view/fchomo/node.js:1349 -#: htdocs/luci-static/resources/view/fchomo/node.js:1662 +#: htdocs/luci-static/resources/view/fchomo/node.js:1407 +#: htdocs/luci-static/resources/view/fchomo/node.js:1720 msgid "Bind interface" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1350 -#: htdocs/luci-static/resources/view/fchomo/node.js:1663 +#: htdocs/luci-static/resources/view/fchomo/node.js:1408 +#: htdocs/luci-static/resources/view/fchomo/node.js:1721 msgid "Bind outbound interface.
" msgstr "" @@ -403,17 +405,17 @@ msgstr "" msgid "Cancel" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1024 +#: htdocs/luci-static/resources/view/fchomo/node.js:1044 msgid "Cert fingerprint" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1025 +#: htdocs/luci-static/resources/view/fchomo/node.js:1045 msgid "" "Certificate fingerprint. Used to implement SSL Pinning and prevent MitM." msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:814 -#: htdocs/luci-static/resources/view/fchomo/node.js:1045 +#: htdocs/luci-static/resources/view/fchomo/node.js:1065 msgid "Certificate path" msgstr "" @@ -468,9 +470,9 @@ msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:637 #: htdocs/luci-static/resources/fchomo/listeners.js:853 #: htdocs/luci-static/resources/view/fchomo/global.js:550 -#: htdocs/luci-static/resources/view/fchomo/node.js:919 -#: htdocs/luci-static/resources/view/fchomo/node.js:1046 -#: htdocs/luci-static/resources/view/fchomo/node.js:1060 +#: htdocs/luci-static/resources/view/fchomo/node.js:939 +#: htdocs/luci-static/resources/view/fchomo/node.js:1066 +#: htdocs/luci-static/resources/view/fchomo/node.js:1080 #: root/usr/share/luci/menu.d/luci-app-fchomo.json:22 msgid "Client" msgstr "" @@ -483,7 +485,7 @@ msgstr "" msgid "Client Auth type" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1091 +#: htdocs/luci-static/resources/view/fchomo/node.js:1111 msgid "Client fingerprint" msgstr "" @@ -508,12 +510,12 @@ msgstr "" msgid "Complete" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1609 +#: htdocs/luci-static/resources/view/fchomo/node.js:1667 msgid "Configuration Items" msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:540 -#: htdocs/luci-static/resources/view/fchomo/node.js:857 +#: htdocs/luci-static/resources/view/fchomo/node.js:877 msgid "Congestion controller" msgstr "" @@ -526,14 +528,14 @@ msgid "Content copied to clipboard!" msgstr "" #: htdocs/luci-static/resources/view/fchomo/client.js:670 -#: htdocs/luci-static/resources/view/fchomo/node.js:1519 -#: htdocs/luci-static/resources/view/fchomo/node.js:1545 +#: htdocs/luci-static/resources/view/fchomo/node.js:1577 +#: htdocs/luci-static/resources/view/fchomo/node.js:1603 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:339 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:365 msgid "Content will not be verified, Please make sure you enter it correctly." msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1518 +#: htdocs/luci-static/resources/view/fchomo/node.js:1576 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:338 msgid "Contents" msgstr "" @@ -558,7 +560,7 @@ msgstr "" msgid "Custom Direct List" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1580 +#: htdocs/luci-static/resources/view/fchomo/node.js:1638 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:400 msgid "Custom HTTP header." msgstr "" @@ -594,7 +596,7 @@ msgstr "" #: htdocs/luci-static/resources/view/fchomo/client.js:1428 #: htdocs/luci-static/resources/view/fchomo/client.js:1437 #: htdocs/luci-static/resources/view/fchomo/node.js:715 -#: htdocs/luci-static/resources/view/fchomo/node.js:798 +#: htdocs/luci-static/resources/view/fchomo/node.js:818 msgid "DNS server" msgstr "" @@ -622,15 +624,15 @@ msgstr "" msgid "Default DNS server" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:769 +#: htdocs/luci-static/resources/view/fchomo/node.js:789 msgid "Destination addresses allowed to be forwarded via Wireguard." msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1787 +#: htdocs/luci-static/resources/view/fchomo/node.js:1845 msgid "Destination provider" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1793 +#: htdocs/luci-static/resources/view/fchomo/node.js:1851 msgid "Destination proxy node" msgstr "" @@ -638,8 +640,8 @@ msgstr "" msgid "Dial fields" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1800 -#: htdocs/luci-static/resources/view/fchomo/node.js:1820 +#: htdocs/luci-static/resources/view/fchomo/node.js:1858 +#: htdocs/luci-static/resources/view/fchomo/node.js:1878 msgid "Different chain head/tail" msgstr "" @@ -677,7 +679,7 @@ msgstr "" msgid "Disable ICMP Forwarding" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:970 +#: htdocs/luci-static/resources/view/fchomo/node.js:990 msgid "Disable SNI" msgstr "" @@ -703,21 +705,21 @@ msgstr "" msgid "Domain" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:971 +#: htdocs/luci-static/resources/view/fchomo/node.js:991 msgid "Donot send server name in ClientHello." msgstr "" #: htdocs/luci-static/resources/view/fchomo/client.js:1577 -#: htdocs/luci-static/resources/view/fchomo/node.js:1038 -#: htdocs/luci-static/resources/view/fchomo/node.js:1649 +#: htdocs/luci-static/resources/view/fchomo/node.js:1058 +#: htdocs/luci-static/resources/view/fchomo/node.js:1707 msgid "Donot verifying server certificate." msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1328 +#: htdocs/luci-static/resources/view/fchomo/node.js:1386 msgid "Download bandwidth" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1329 +#: htdocs/luci-static/resources/view/fchomo/node.js:1387 msgid "Download bandwidth in Mbps." msgstr "" @@ -733,12 +735,12 @@ msgstr "" msgid "Dual stack" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1085 +#: htdocs/luci-static/resources/view/fchomo/node.js:1105 msgid "ECH HTTPS record query servername" msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:910 -#: htdocs/luci-static/resources/view/fchomo/node.js:1079 +#: htdocs/luci-static/resources/view/fchomo/node.js:1099 msgid "ECH config" msgstr "" @@ -758,11 +760,11 @@ msgstr "" msgid "ETag support" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1225 +#: htdocs/luci-static/resources/view/fchomo/node.js:1245 msgid "Early Data first packet length limit." msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1231 +#: htdocs/luci-static/resources/view/fchomo/node.js:1251 msgid "Early Data header name" msgstr "" @@ -778,7 +780,7 @@ msgstr "" msgid "Edit ruleset" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1516 +#: htdocs/luci-static/resources/view/fchomo/node.js:1574 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:336 msgid "Editer" msgstr "" @@ -798,9 +800,9 @@ msgstr "" #: htdocs/luci-static/resources/view/fchomo/global.js:401 #: htdocs/luci-static/resources/view/fchomo/global.js:680 #: htdocs/luci-static/resources/view/fchomo/node.js:234 -#: htdocs/luci-static/resources/view/fchomo/node.js:1489 -#: htdocs/luci-static/resources/view/fchomo/node.js:1685 -#: htdocs/luci-static/resources/view/fchomo/node.js:1774 +#: htdocs/luci-static/resources/view/fchomo/node.js:1547 +#: htdocs/luci-static/resources/view/fchomo/node.js:1743 +#: htdocs/luci-static/resources/view/fchomo/node.js:1832 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:264 #: htdocs/luci-static/resources/view/fchomo/server.js:49 msgid "Enable" @@ -823,19 +825,19 @@ msgid "" "conversion for outbound connections" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1073 +#: htdocs/luci-static/resources/view/fchomo/node.js:1093 msgid "Enable ECH" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1316 +#: htdocs/luci-static/resources/view/fchomo/node.js:1374 msgid "Enable TCP Brutal" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1317 +#: htdocs/luci-static/resources/view/fchomo/node.js:1375 msgid "Enable TCP Brutal congestion control algorithm" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1305 +#: htdocs/luci-static/resources/view/fchomo/node.js:1363 msgid "Enable multiplexing only for TCP." msgstr "" @@ -844,16 +846,16 @@ msgstr "" msgid "Enable obfuscate for downlink" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1299 +#: htdocs/luci-static/resources/view/fchomo/node.js:1357 msgid "Enable padding" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1310 +#: htdocs/luci-static/resources/view/fchomo/node.js:1368 msgid "Enable statistic" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:871 -#: htdocs/luci-static/resources/view/fchomo/node.js:1631 +#: htdocs/luci-static/resources/view/fchomo/node.js:891 +#: htdocs/luci-static/resources/view/fchomo/node.js:1689 msgid "" "Enable the SUoT protocol, requires server support. Conflict with Multiplex." msgstr "" @@ -892,7 +894,7 @@ msgid "" "if empty." msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1743 +#: htdocs/luci-static/resources/view/fchomo/node.js:1801 msgid "Exclude matched node types." msgstr "" @@ -903,7 +905,7 @@ msgid "" msgstr "" #: htdocs/luci-static/resources/view/fchomo/client.js:1161 -#: htdocs/luci-static/resources/view/fchomo/node.js:1736 +#: htdocs/luci-static/resources/view/fchomo/node.js:1794 msgid "Exclude nodes that meet keywords or regexps." msgstr "" @@ -912,12 +914,12 @@ msgid "Expand/Collapse result" msgstr "" #: htdocs/luci-static/resources/view/fchomo/client.js:1121 -#: htdocs/luci-static/resources/view/fchomo/node.js:1721 +#: htdocs/luci-static/resources/view/fchomo/node.js:1779 msgid "Expected HTTP code. 204 will be used if empty." msgstr "" #: htdocs/luci-static/resources/view/fchomo/client.js:1123 -#: htdocs/luci-static/resources/view/fchomo/node.js:1723 +#: htdocs/luci-static/resources/view/fchomo/node.js:1781 msgid "Expected status" msgstr "" @@ -958,10 +960,10 @@ msgstr "" #: htdocs/luci-static/resources/view/fchomo/node.js:436 #: htdocs/luci-static/resources/view/fchomo/node.js:489 #: htdocs/luci-static/resources/view/fchomo/node.js:491 -#: htdocs/luci-static/resources/view/fchomo/node.js:942 -#: htdocs/luci-static/resources/view/fchomo/node.js:1030 -#: htdocs/luci-static/resources/view/fchomo/node.js:1800 -#: htdocs/luci-static/resources/view/fchomo/node.js:1820 +#: htdocs/luci-static/resources/view/fchomo/node.js:962 +#: htdocs/luci-static/resources/view/fchomo/node.js:1050 +#: htdocs/luci-static/resources/view/fchomo/node.js:1858 +#: htdocs/luci-static/resources/view/fchomo/node.js:1878 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:291 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:305 msgid "Expecting: %s" @@ -969,9 +971,9 @@ msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:977 #: htdocs/luci-static/resources/fchomo/listeners.js:984 -#: htdocs/luci-static/resources/view/fchomo/node.js:1140 -#: htdocs/luci-static/resources/view/fchomo/node.js:1147 -#: htdocs/luci-static/resources/view/fchomo/node.js:1155 +#: htdocs/luci-static/resources/view/fchomo/node.js:1160 +#: htdocs/luci-static/resources/view/fchomo/node.js:1167 +#: htdocs/luci-static/resources/view/fchomo/node.js:1175 msgid "Expecting: only support %s." msgstr "" @@ -1021,7 +1023,7 @@ msgid "Fallback filter" msgstr "" #: htdocs/luci-static/resources/view/fchomo/client.js:1156 -#: htdocs/luci-static/resources/view/fchomo/node.js:1730 +#: htdocs/luci-static/resources/view/fchomo/node.js:1788 msgid "Filter nodes that meet keywords or regexps." msgstr "" @@ -1062,15 +1064,15 @@ msgid "" msgstr "" #: htdocs/luci-static/resources/view/fchomo/client.js:1122 -#: htdocs/luci-static/resources/view/fchomo/node.js:1599 -#: htdocs/luci-static/resources/view/fchomo/node.js:1722 +#: htdocs/luci-static/resources/view/fchomo/node.js:1657 +#: htdocs/luci-static/resources/view/fchomo/node.js:1780 msgid "" "For format see %s." msgstr "" #: htdocs/luci-static/resources/view/fchomo/node.js:710 -#: htdocs/luci-static/resources/view/fchomo/node.js:793 +#: htdocs/luci-static/resources/view/fchomo/node.js:813 msgid "Force DNS remote resolution." msgstr "" @@ -1089,7 +1091,7 @@ msgstr "" msgid "FullCombo Shark!" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1180 +#: htdocs/luci-static/resources/view/fchomo/node.js:1200 msgid "GET" msgstr "" @@ -1104,7 +1106,7 @@ msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:119 #: htdocs/luci-static/resources/view/fchomo/client.js:1009 #: htdocs/luci-static/resources/view/fchomo/node.js:222 -#: htdocs/luci-static/resources/view/fchomo/node.js:1479 +#: htdocs/luci-static/resources/view/fchomo/node.js:1537 msgid "General fields" msgstr "" @@ -1186,17 +1188,16 @@ msgstr "" #: htdocs/luci-static/resources/fchomo.js:146 #: htdocs/luci-static/resources/fchomo.js:179 -#: htdocs/luci-static/resources/fchomo/listeners.js:977 -#: htdocs/luci-static/resources/view/fchomo/node.js:816 -#: htdocs/luci-static/resources/view/fchomo/node.js:1129 -#: htdocs/luci-static/resources/view/fchomo/node.js:1140 -#: htdocs/luci-static/resources/view/fchomo/node.js:1147 +#: htdocs/luci-static/resources/view/fchomo/node.js:836 +#: htdocs/luci-static/resources/view/fchomo/node.js:1149 +#: htdocs/luci-static/resources/view/fchomo/node.js:1160 +#: htdocs/luci-static/resources/view/fchomo/node.js:1167 msgid "HTTP" msgstr "" #: htdocs/luci-static/resources/view/fchomo/node.js:267 -#: htdocs/luci-static/resources/view/fchomo/node.js:1202 -#: htdocs/luci-static/resources/view/fchomo/node.js:1579 +#: htdocs/luci-static/resources/view/fchomo/node.js:1222 +#: htdocs/luci-static/resources/view/fchomo/node.js:1637 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:399 msgid "HTTP header" msgstr "" @@ -1222,7 +1223,7 @@ msgstr "" msgid "HTTP mask: %s" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1179 +#: htdocs/luci-static/resources/view/fchomo/node.js:1199 msgid "HTTP request method" msgstr "" @@ -1241,10 +1242,9 @@ msgid "" "returned if empty." msgstr "" -#: htdocs/luci-static/resources/fchomo/listeners.js:978 -#: htdocs/luci-static/resources/view/fchomo/node.js:1130 -#: htdocs/luci-static/resources/view/fchomo/node.js:1141 -#: htdocs/luci-static/resources/view/fchomo/node.js:1148 +#: htdocs/luci-static/resources/view/fchomo/node.js:1150 +#: htdocs/luci-static/resources/view/fchomo/node.js:1161 +#: htdocs/luci-static/resources/view/fchomo/node.js:1168 msgid "HTTPUpgrade" msgstr "" @@ -1269,27 +1269,27 @@ msgid "Health check" msgstr "" #: htdocs/luci-static/resources/view/fchomo/client.js:1091 -#: htdocs/luci-static/resources/view/fchomo/node.js:1690 +#: htdocs/luci-static/resources/view/fchomo/node.js:1748 msgid "Health check URL" msgstr "" #: htdocs/luci-static/resources/view/fchomo/client.js:1120 -#: htdocs/luci-static/resources/view/fchomo/node.js:1720 +#: htdocs/luci-static/resources/view/fchomo/node.js:1778 msgid "Health check expected status" msgstr "" #: htdocs/luci-static/resources/view/fchomo/client.js:1100 -#: htdocs/luci-static/resources/view/fchomo/node.js:1700 +#: htdocs/luci-static/resources/view/fchomo/node.js:1758 msgid "Health check interval" msgstr "" #: htdocs/luci-static/resources/view/fchomo/client.js:1107 -#: htdocs/luci-static/resources/view/fchomo/node.js:1707 +#: htdocs/luci-static/resources/view/fchomo/node.js:1765 msgid "Health check timeout" msgstr "" #: htdocs/luci-static/resources/view/fchomo/client.js:1011 -#: htdocs/luci-static/resources/view/fchomo/node.js:1481 +#: htdocs/luci-static/resources/view/fchomo/node.js:1539 msgid "Health fields" msgstr "" @@ -1301,7 +1301,7 @@ msgstr "" msgid "Hidden" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:822 +#: htdocs/luci-static/resources/view/fchomo/node.js:842 msgid "Host that supports TLS 1.3" msgstr "" @@ -1340,8 +1340,8 @@ msgstr "" msgid "IP override" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1361 -#: htdocs/luci-static/resources/view/fchomo/node.js:1676 +#: htdocs/luci-static/resources/view/fchomo/node.js:1419 +#: htdocs/luci-static/resources/view/fchomo/node.js:1734 msgid "IP version" msgstr "" @@ -1402,8 +1402,8 @@ msgstr "" #: htdocs/luci-static/resources/view/fchomo/client.js:1713 #: htdocs/luci-static/resources/view/fchomo/client.js:1748 #: htdocs/luci-static/resources/view/fchomo/client.js:1769 -#: htdocs/luci-static/resources/view/fchomo/node.js:1386 -#: htdocs/luci-static/resources/view/fchomo/node.js:1467 +#: htdocs/luci-static/resources/view/fchomo/node.js:1444 +#: htdocs/luci-static/resources/view/fchomo/node.js:1525 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:153 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:241 msgid "Import mihomo config" @@ -1419,12 +1419,12 @@ msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:181 #: htdocs/luci-static/resources/view/fchomo/node.js:286 #: htdocs/luci-static/resources/view/fchomo/node.js:292 -#: htdocs/luci-static/resources/view/fchomo/node.js:1637 -#: htdocs/luci-static/resources/view/fchomo/node.js:1643 +#: htdocs/luci-static/resources/view/fchomo/node.js:1695 +#: htdocs/luci-static/resources/view/fchomo/node.js:1701 msgid "In Mbps." msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1557 +#: htdocs/luci-static/resources/view/fchomo/node.js:1615 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:377 msgid "In bytes. %s will be used if empty." msgstr "" @@ -1436,7 +1436,7 @@ msgstr "" #: htdocs/luci-static/resources/view/fchomo/client.js:1108 #: htdocs/luci-static/resources/view/fchomo/client.js:1137 -#: htdocs/luci-static/resources/view/fchomo/node.js:1708 +#: htdocs/luci-static/resources/view/fchomo/node.js:1766 msgid "In millisecond. %s will be used if empty." msgstr "" @@ -1445,7 +1445,7 @@ msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:428 #: htdocs/luci-static/resources/view/fchomo/node.js:604 #: htdocs/luci-static/resources/view/fchomo/node.js:611 -#: htdocs/luci-static/resources/view/fchomo/node.js:1218 +#: htdocs/luci-static/resources/view/fchomo/node.js:1238 msgid "In seconds." msgstr "" @@ -1454,14 +1454,14 @@ msgstr "" #: htdocs/luci-static/resources/view/fchomo/global.js:430 #: htdocs/luci-static/resources/view/fchomo/global.js:515 #: htdocs/luci-static/resources/view/fchomo/node.js:280 -#: htdocs/luci-static/resources/view/fchomo/node.js:1563 -#: htdocs/luci-static/resources/view/fchomo/node.js:1701 +#: htdocs/luci-static/resources/view/fchomo/node.js:1621 +#: htdocs/luci-static/resources/view/fchomo/node.js:1759 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:383 msgid "In seconds. %s will be used if empty." msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:649 -#: htdocs/luci-static/resources/view/fchomo/node.js:931 +#: htdocs/luci-static/resources/view/fchomo/node.js:951 msgid "" "In the order of one Padding-Length and one Padding-" "Interval, infinite concatenation." @@ -1501,7 +1501,7 @@ msgstr "" msgid "Info" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1496 +#: htdocs/luci-static/resources/view/fchomo/node.js:1554 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:279 msgid "Inline" msgstr "" @@ -1522,7 +1522,7 @@ msgid "Key" msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:829 -#: htdocs/luci-static/resources/view/fchomo/node.js:1059 +#: htdocs/luci-static/resources/view/fchomo/node.js:1079 msgid "Key path" msgstr "" @@ -1538,14 +1538,14 @@ msgstr "" #: htdocs/luci-static/resources/view/fchomo/client.js:1719 #: htdocs/luci-static/resources/view/fchomo/client.js:1775 #: htdocs/luci-static/resources/view/fchomo/node.js:229 -#: htdocs/luci-static/resources/view/fchomo/node.js:1484 -#: htdocs/luci-static/resources/view/fchomo/node.js:1769 +#: htdocs/luci-static/resources/view/fchomo/node.js:1542 +#: htdocs/luci-static/resources/view/fchomo/node.js:1827 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:259 msgid "Label" msgstr "" #: htdocs/luci-static/resources/view/fchomo/client.js:1114 -#: htdocs/luci-static/resources/view/fchomo/node.js:1714 +#: htdocs/luci-static/resources/view/fchomo/node.js:1772 msgid "Lazy" msgstr "" @@ -1565,7 +1565,7 @@ msgid "Less compatibility and sometimes better performance." msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:810 -#: htdocs/luci-static/resources/view/fchomo/node.js:983 +#: htdocs/luci-static/resources/view/fchomo/node.js:1003 msgid "List of supported application level protocols, in order of preference." msgstr "" @@ -1594,18 +1594,18 @@ msgstr "" msgid "Load balance" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1494 +#: htdocs/luci-static/resources/view/fchomo/node.js:1552 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:277 msgid "Local" msgstr "" #: htdocs/luci-static/resources/view/fchomo/node.js:697 -#: htdocs/luci-static/resources/view/fchomo/node.js:740 +#: htdocs/luci-static/resources/view/fchomo/node.js:760 msgid "Local IPv6 address" msgstr "" #: htdocs/luci-static/resources/view/fchomo/node.js:689 -#: htdocs/luci-static/resources/view/fchomo/node.js:732 +#: htdocs/luci-static/resources/view/fchomo/node.js:752 msgid "Local address" msgstr "" @@ -1642,7 +1642,7 @@ msgstr "" #: htdocs/luci-static/resources/view/fchomo/global.js:502 #: htdocs/luci-static/resources/view/fchomo/node.js:703 -#: htdocs/luci-static/resources/view/fchomo/node.js:786 +#: htdocs/luci-static/resources/view/fchomo/node.js:806 msgid "MTU" msgstr "" @@ -1682,7 +1682,7 @@ msgstr "" msgid "Match rule set." msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1224 +#: htdocs/luci-static/resources/view/fchomo/node.js:1244 msgid "Max Early Data" msgstr "" @@ -1691,6 +1691,15 @@ msgstr "" msgid "Max UDP relay packet size" msgstr "" +#: htdocs/luci-static/resources/view/fchomo/node.js:1300 +msgid "Max concurrency" +msgstr "" + +#: htdocs/luci-static/resources/view/fchomo/node.js:731 +#: htdocs/luci-static/resources/view/fchomo/node.js:1295 +msgid "Max connections" +msgstr "" + #: htdocs/luci-static/resources/view/fchomo/client.js:1128 msgid "Max count of failures" msgstr "" @@ -1700,21 +1709,47 @@ msgstr "" msgid "Max download speed" msgstr "" +#: htdocs/luci-static/resources/fchomo/listeners.js:1033 +#: htdocs/luci-static/resources/view/fchomo/node.js:1284 +msgid "Max each POST bytes" +msgstr "" + #: htdocs/luci-static/resources/view/fchomo/node.js:573 msgid "Max open streams" msgstr "" +#: htdocs/luci-static/resources/view/fchomo/node.js:1310 +msgid "Max request times" +msgstr "" + +#: htdocs/luci-static/resources/view/fchomo/node.js:1315 +msgid "Max reusable seconds" +msgstr "" + +#: htdocs/luci-static/resources/view/fchomo/node.js:1305 +msgid "Max reuse times" +msgstr "" + +#: htdocs/luci-static/resources/view/fchomo/node.js:744 +msgid "Max streams" +msgstr "" + #: htdocs/luci-static/resources/fchomo/listeners.js:174 #: htdocs/luci-static/resources/view/fchomo/node.js:285 msgid "Max upload speed" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1277 -#: htdocs/luci-static/resources/view/fchomo/node.js:1293 +#: htdocs/luci-static/resources/view/fchomo/node.js:1335 +#: htdocs/luci-static/resources/view/fchomo/node.js:1351 msgid "Maximum connections" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1291 +#: htdocs/luci-static/resources/view/fchomo/node.js:745 +msgid "" +"Maximum multiplexed streams in a connection before opening a new connection." +msgstr "" + +#: htdocs/luci-static/resources/view/fchomo/node.js:1349 msgid "" "Maximum multiplexed streams in a connection before opening a new connection." "
Conflict with %s and %s." @@ -1732,7 +1767,7 @@ msgid "" "rate." msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1290 +#: htdocs/luci-static/resources/view/fchomo/node.js:1348 msgid "Maximum streams" msgstr "" @@ -1757,7 +1792,12 @@ msgstr "" msgid "Min of idle sessions to keep" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1284 +#: htdocs/luci-static/resources/view/fchomo/node.js:737 +msgid "Min streams" +msgstr "" + +#: htdocs/luci-static/resources/view/fchomo/node.js:738 +#: htdocs/luci-static/resources/view/fchomo/node.js:1342 msgid "" "Minimum multiplexed streams in a connection before opening a new connection." msgstr "" @@ -1767,8 +1807,8 @@ msgstr "" msgid "Minimum padding rate" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1283 -#: htdocs/luci-static/resources/view/fchomo/node.js:1293 +#: htdocs/luci-static/resources/view/fchomo/node.js:1341 +#: htdocs/luci-static/resources/view/fchomo/node.js:1351 msgid "Minimum streams" msgstr "" @@ -1785,7 +1825,7 @@ msgstr "" msgid "Mixed port" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1263 +#: htdocs/luci-static/resources/view/fchomo/node.js:1321 msgid "Multiplex" msgstr "" @@ -1807,7 +1847,7 @@ msgstr "" msgid "Name of the Proxy group as outbound." msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1569 +#: htdocs/luci-static/resources/view/fchomo/node.js:1627 msgid "Name of the Proxy group to download provider." msgstr "" @@ -1835,16 +1875,20 @@ msgstr "" msgid "No Authentication IP ranges" msgstr "" +#: htdocs/luci-static/resources/fchomo/listeners.js:1023 +msgid "No SSE header" +msgstr "" + #: htdocs/luci-static/resources/view/fchomo/client.js:1508 msgid "No add'l params" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1252 +#: htdocs/luci-static/resources/view/fchomo/node.js:1274 msgid "No gRPC header" msgstr "" #: htdocs/luci-static/resources/view/fchomo/client.js:1115 -#: htdocs/luci-static/resources/view/fchomo/node.js:1715 +#: htdocs/luci-static/resources/view/fchomo/node.js:1773 msgid "No testing is performed when this provider node is not in use." msgstr "" @@ -1863,17 +1907,17 @@ msgid "Node" msgstr "" #: htdocs/luci-static/resources/view/fchomo/client.js:1160 -#: htdocs/luci-static/resources/view/fchomo/node.js:1735 +#: htdocs/luci-static/resources/view/fchomo/node.js:1793 msgid "Node exclude filter" msgstr "" #: htdocs/luci-static/resources/view/fchomo/client.js:1165 -#: htdocs/luci-static/resources/view/fchomo/node.js:1742 +#: htdocs/luci-static/resources/view/fchomo/node.js:1800 msgid "Node exclude type" msgstr "" #: htdocs/luci-static/resources/view/fchomo/client.js:1155 -#: htdocs/luci-static/resources/view/fchomo/node.js:1729 +#: htdocs/luci-static/resources/view/fchomo/node.js:1787 msgid "Node filter" msgstr "" @@ -1901,7 +1945,7 @@ msgstr "" msgid "ON" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:815 +#: htdocs/luci-static/resources/view/fchomo/node.js:835 msgid "Obfs Mode" msgstr "" @@ -1951,7 +1995,7 @@ msgid "Override destination" msgstr "" #: htdocs/luci-static/resources/view/fchomo/client.js:1010 -#: htdocs/luci-static/resources/view/fchomo/node.js:1480 +#: htdocs/luci-static/resources/view/fchomo/node.js:1538 msgid "Override fields" msgstr "" @@ -1971,7 +2015,7 @@ msgstr "" msgid "Override the existing ECS in original request." msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1086 +#: htdocs/luci-static/resources/view/fchomo/node.js:1106 msgid "Overrides the domain name used for HTTPS record queries." msgstr "" @@ -1979,11 +2023,11 @@ msgstr "" msgid "Overview" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1181 +#: htdocs/luci-static/resources/view/fchomo/node.js:1201 msgid "POST" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1182 +#: htdocs/luci-static/resources/view/fchomo/node.js:1202 msgid "PUT" msgstr "" @@ -1991,7 +2035,7 @@ msgstr "" msgid "Packet encoding" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1257 +#: htdocs/luci-static/resources/view/fchomo/node.js:1279 msgid "Padding bytes" msgstr "" @@ -2000,7 +2044,7 @@ msgid "Padding scheme" msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:647 -#: htdocs/luci-static/resources/view/fchomo/node.js:929 +#: htdocs/luci-static/resources/view/fchomo/node.js:949 msgid "Paddings" msgstr "" @@ -2009,17 +2053,17 @@ msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:508 #: htdocs/luci-static/resources/view/fchomo/node.js:261 #: htdocs/luci-static/resources/view/fchomo/node.js:340 -#: htdocs/luci-static/resources/view/fchomo/node.js:830 +#: htdocs/luci-static/resources/view/fchomo/node.js:850 msgid "Password" msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:587 -#: htdocs/luci-static/resources/view/fchomo/node.js:1544 +#: htdocs/luci-static/resources/view/fchomo/node.js:1602 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:364 msgid "Payload" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:754 +#: htdocs/luci-static/resources/view/fchomo/node.js:774 msgid "Peer pubkic key" msgstr "" @@ -2029,11 +2073,11 @@ msgid "" "it is not needed." msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:781 +#: htdocs/luci-static/resources/view/fchomo/node.js:801 msgid "Periodically sends data packets to maintain connection persistence." msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:780 +#: htdocs/luci-static/resources/view/fchomo/node.js:800 msgid "Persistent keepalive" msgstr "" @@ -2054,8 +2098,8 @@ msgid "" "standards." msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1517 -#: htdocs/luci-static/resources/view/fchomo/node.js:1543 +#: htdocs/luci-static/resources/view/fchomo/node.js:1575 +#: htdocs/luci-static/resources/view/fchomo/node.js:1601 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:337 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:363 msgid "" @@ -2069,25 +2113,25 @@ msgstr "" #: htdocs/luci-static/resources/view/fchomo/client.js:1445 #: htdocs/luci-static/resources/view/fchomo/client.js:1697 #: htdocs/luci-static/resources/view/fchomo/client.js:1749 -#: htdocs/luci-static/resources/view/fchomo/node.js:1387 +#: htdocs/luci-static/resources/view/fchomo/node.js:1445 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:154 msgid "Please type %s fields of mihomo config.
" msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:494 -#: htdocs/luci-static/resources/view/fchomo/node.js:804 +#: htdocs/luci-static/resources/view/fchomo/node.js:824 msgid "Plugin" msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:501 #: htdocs/luci-static/resources/fchomo/listeners.js:508 #: htdocs/luci-static/resources/fchomo/listeners.js:514 -#: htdocs/luci-static/resources/view/fchomo/node.js:815 -#: htdocs/luci-static/resources/view/fchomo/node.js:822 -#: htdocs/luci-static/resources/view/fchomo/node.js:830 -#: htdocs/luci-static/resources/view/fchomo/node.js:836 -#: htdocs/luci-static/resources/view/fchomo/node.js:844 +#: htdocs/luci-static/resources/view/fchomo/node.js:835 +#: htdocs/luci-static/resources/view/fchomo/node.js:842 #: htdocs/luci-static/resources/view/fchomo/node.js:850 +#: htdocs/luci-static/resources/view/fchomo/node.js:856 +#: htdocs/luci-static/resources/view/fchomo/node.js:864 +#: htdocs/luci-static/resources/view/fchomo/node.js:870 msgid "Plugin:" msgstr "" @@ -2117,7 +2161,7 @@ msgid "Ports pool" msgstr "" #: htdocs/luci-static/resources/view/fchomo/node.js:499 -#: htdocs/luci-static/resources/view/fchomo/node.js:761 +#: htdocs/luci-static/resources/view/fchomo/node.js:781 msgid "Pre-shared key" msgstr "" @@ -2136,10 +2180,10 @@ msgstr "" #: htdocs/luci-static/resources/view/fchomo/global.js:736 #: htdocs/luci-static/resources/view/fchomo/global.js:753 -#: htdocs/luci-static/resources/view/fchomo/node.js:1351 -#: htdocs/luci-static/resources/view/fchomo/node.js:1357 -#: htdocs/luci-static/resources/view/fchomo/node.js:1664 -#: htdocs/luci-static/resources/view/fchomo/node.js:1671 +#: htdocs/luci-static/resources/view/fchomo/node.js:1409 +#: htdocs/luci-static/resources/view/fchomo/node.js:1415 +#: htdocs/luci-static/resources/view/fchomo/node.js:1722 +#: htdocs/luci-static/resources/view/fchomo/node.js:1729 msgid "Priority: Proxy Node > Global." msgstr "" @@ -2152,7 +2196,7 @@ msgid "Priv-key passphrase" msgstr "" #: htdocs/luci-static/resources/view/fchomo/node.js:674 -#: htdocs/luci-static/resources/view/fchomo/node.js:746 +#: htdocs/luci-static/resources/view/fchomo/node.js:766 msgid "Private key" msgstr "" @@ -2161,7 +2205,7 @@ msgid "Process matching mode" msgstr "" #: htdocs/luci-static/resources/view/fchomo/global.js:684 -#: htdocs/luci-static/resources/view/fchomo/node.js:1269 +#: htdocs/luci-static/resources/view/fchomo/node.js:1327 msgid "Protocol" msgstr "" @@ -2176,13 +2220,13 @@ msgid "" msgstr "" #: htdocs/luci-static/resources/view/fchomo/client.js:1055 -#: htdocs/luci-static/resources/view/fchomo/node.js:1370 -#: htdocs/luci-static/resources/view/fchomo/node.js:1379 -#: htdocs/luci-static/resources/view/fchomo/node.js:1780 +#: htdocs/luci-static/resources/view/fchomo/node.js:1428 +#: htdocs/luci-static/resources/view/fchomo/node.js:1437 +#: htdocs/luci-static/resources/view/fchomo/node.js:1838 msgid "Provider" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1550 +#: htdocs/luci-static/resources/view/fchomo/node.js:1608 msgid "Provider URL" msgstr "" @@ -2205,19 +2249,19 @@ msgid "Proxy MAC-s" msgstr "" #: htdocs/luci-static/resources/view/fchomo/node.js:208 -#: htdocs/luci-static/resources/view/fchomo/node.js:1779 +#: htdocs/luci-static/resources/view/fchomo/node.js:1837 msgid "Proxy Node" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1755 -#: htdocs/luci-static/resources/view/fchomo/node.js:1764 +#: htdocs/luci-static/resources/view/fchomo/node.js:1813 +#: htdocs/luci-static/resources/view/fchomo/node.js:1822 msgid "Proxy chain" msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:530 #: htdocs/luci-static/resources/view/fchomo/client.js:783 #: htdocs/luci-static/resources/view/fchomo/client.js:1543 -#: htdocs/luci-static/resources/view/fchomo/node.js:1568 +#: htdocs/luci-static/resources/view/fchomo/node.js:1626 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:388 msgid "Proxy group" msgstr "" @@ -2245,11 +2289,11 @@ msgid "Quick Reload" msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:917 -#: htdocs/luci-static/resources/view/fchomo/node.js:1100 +#: htdocs/luci-static/resources/view/fchomo/node.js:1120 msgid "REALITY" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1115 +#: htdocs/luci-static/resources/view/fchomo/node.js:1135 msgid "REALITY X25519MLKEM768 PQC support" msgstr "" @@ -2266,18 +2310,18 @@ msgid "REALITY private key" msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:944 -#: htdocs/luci-static/resources/view/fchomo/node.js:1105 +#: htdocs/luci-static/resources/view/fchomo/node.js:1125 msgid "REALITY public key" msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:948 -#: htdocs/luci-static/resources/view/fchomo/node.js:1110 +#: htdocs/luci-static/resources/view/fchomo/node.js:1130 msgid "REALITY short ID" msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:618 #: htdocs/luci-static/resources/fchomo/listeners.js:637 -#: htdocs/luci-static/resources/view/fchomo/node.js:919 +#: htdocs/luci-static/resources/view/fchomo/node.js:939 msgid "RTT" msgstr "" @@ -2324,13 +2368,13 @@ msgstr "" msgid "Reload All" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1495 +#: htdocs/luci-static/resources/view/fchomo/node.js:1553 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:278 msgid "Remote" msgstr "" #: htdocs/luci-static/resources/view/fchomo/node.js:709 -#: htdocs/luci-static/resources/view/fchomo/node.js:792 +#: htdocs/luci-static/resources/view/fchomo/node.js:812 msgid "Remote DNS resolve" msgstr "" @@ -2339,18 +2383,18 @@ msgid "Remove" msgstr "" #: htdocs/luci-static/resources/fchomo.js:1354 -#: htdocs/luci-static/resources/view/fchomo/node.js:1471 -#: htdocs/luci-static/resources/view/fchomo/node.js:1473 +#: htdocs/luci-static/resources/view/fchomo/node.js:1529 +#: htdocs/luci-static/resources/view/fchomo/node.js:1531 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:251 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:253 msgid "Remove idles" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1597 +#: htdocs/luci-static/resources/view/fchomo/node.js:1655 msgid "Replace name" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1598 +#: htdocs/luci-static/resources/view/fchomo/node.js:1656 msgid "Replace node name." msgstr "" @@ -2358,9 +2402,9 @@ msgstr "" msgid "Request" msgstr "" -#: htdocs/luci-static/resources/fchomo/listeners.js:996 -#: htdocs/luci-static/resources/view/fchomo/node.js:1188 -#: htdocs/luci-static/resources/view/fchomo/node.js:1195 +#: htdocs/luci-static/resources/fchomo/listeners.js:1002 +#: htdocs/luci-static/resources/view/fchomo/node.js:1208 +#: htdocs/luci-static/resources/view/fchomo/node.js:1215 msgid "Request path" msgstr "" @@ -2377,11 +2421,11 @@ msgid "Require any" msgstr "" #: htdocs/luci-static/resources/fchomo.js:384 -#: htdocs/luci-static/resources/view/fchomo/node.js:1116 +#: htdocs/luci-static/resources/view/fchomo/node.js:1136 msgid "Requires server support." msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:775 +#: htdocs/luci-static/resources/view/fchomo/node.js:795 msgid "Reserved field bytes" msgstr "" @@ -2389,7 +2433,7 @@ msgstr "" msgid "Resources management" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:850 +#: htdocs/luci-static/resources/view/fchomo/node.js:870 msgid "Restls script" msgstr "" @@ -2425,8 +2469,8 @@ msgstr "" msgid "Routing GFW" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1356 -#: htdocs/luci-static/resources/view/fchomo/node.js:1670 +#: htdocs/luci-static/resources/view/fchomo/node.js:1414 +#: htdocs/luci-static/resources/view/fchomo/node.js:1728 msgid "Routing mark" msgstr "" @@ -2514,7 +2558,7 @@ msgstr "" msgid "SUB-RULE" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:876 +#: htdocs/luci-static/resources/view/fchomo/node.js:896 msgid "SUoT version" msgstr "" @@ -2564,8 +2608,9 @@ msgstr "" msgid "Server address" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1167 -#: htdocs/luci-static/resources/view/fchomo/node.js:1173 +#: htdocs/luci-static/resources/fchomo/listeners.js:996 +#: htdocs/luci-static/resources/view/fchomo/node.js:1187 +#: htdocs/luci-static/resources/view/fchomo/node.js:1193 msgid "Server hostname" msgstr "" @@ -2597,7 +2642,7 @@ msgstr "" msgid "Shadowsocks password" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1311 +#: htdocs/luci-static/resources/view/fchomo/node.js:1369 msgid "Show connections in the dashboard for breaking connections easier." msgstr "" @@ -2609,14 +2654,14 @@ msgstr "" msgid "Simple round-robin all nodes" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1556 +#: htdocs/luci-static/resources/view/fchomo/node.js:1614 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:376 msgid "Size limit" msgstr "" #: htdocs/luci-static/resources/view/fchomo/client.js:1576 -#: htdocs/luci-static/resources/view/fchomo/node.js:1037 -#: htdocs/luci-static/resources/view/fchomo/node.js:1648 +#: htdocs/luci-static/resources/view/fchomo/node.js:1057 +#: htdocs/luci-static/resources/view/fchomo/node.js:1706 msgid "Skip cert verify" msgstr "" @@ -2742,7 +2787,7 @@ msgstr "" msgid "TCP concurrency" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1304 +#: htdocs/luci-static/resources/view/fchomo/node.js:1362 msgid "TCP only" msgstr "" @@ -2768,25 +2813,25 @@ msgstr "" msgid "TCP/UDP" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1335 -#: htdocs/luci-static/resources/view/fchomo/node.js:1615 +#: htdocs/luci-static/resources/view/fchomo/node.js:1393 +#: htdocs/luci-static/resources/view/fchomo/node.js:1673 msgid "TFO" msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:772 #: htdocs/luci-static/resources/view/fchomo/global.js:529 #: htdocs/luci-static/resources/view/fchomo/node.js:464 -#: htdocs/luci-static/resources/view/fchomo/node.js:817 -#: htdocs/luci-static/resources/view/fchomo/node.js:951 +#: htdocs/luci-static/resources/view/fchomo/node.js:837 +#: htdocs/luci-static/resources/view/fchomo/node.js:971 msgid "TLS" msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:809 -#: htdocs/luci-static/resources/view/fchomo/node.js:982 +#: htdocs/luci-static/resources/view/fchomo/node.js:1002 msgid "TLS ALPN" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:976 +#: htdocs/luci-static/resources/view/fchomo/node.js:996 msgid "TLS SNI" msgstr "" @@ -2818,24 +2863,24 @@ msgstr "" msgid "The %s address used by local machine in the Cloudflare WARP network." msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:733 -#: htdocs/luci-static/resources/view/fchomo/node.js:741 +#: htdocs/luci-static/resources/view/fchomo/node.js:753 +#: htdocs/luci-static/resources/view/fchomo/node.js:761 msgid "The %s address used by local machine in the Wireguard network." msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:830 -#: htdocs/luci-static/resources/view/fchomo/node.js:1060 +#: htdocs/luci-static/resources/view/fchomo/node.js:1080 msgid "The %s private key, in PEM format." msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:815 #: htdocs/luci-static/resources/fchomo/listeners.js:853 #: htdocs/luci-static/resources/view/fchomo/global.js:550 -#: htdocs/luci-static/resources/view/fchomo/node.js:1046 +#: htdocs/luci-static/resources/view/fchomo/node.js:1066 msgid "The %s public key, in PEM format." msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1080 +#: htdocs/luci-static/resources/view/fchomo/node.js:1100 msgid "" "The ECH parameter of the HTTPS record for the domain. Leave empty to resolve " "via DNS." @@ -2854,7 +2899,7 @@ msgid "The default value is 2:00 every day." msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:650 -#: htdocs/luci-static/resources/view/fchomo/node.js:932 +#: htdocs/luci-static/resources/view/fchomo/node.js:952 msgid "" "The first padding must have a probability of 100% and at least 35 bytes." msgstr "" @@ -2870,7 +2915,7 @@ msgid "The matching %s will be deemed as poisoned." msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:648 -#: htdocs/luci-static/resources/view/fchomo/node.js:930 +#: htdocs/luci-static/resources/view/fchomo/node.js:950 msgid "The server and client can set different padding parameters." msgstr "" @@ -2880,8 +2925,8 @@ msgid "This ECH parameter needs to be added to the HTTPS record of the domain." msgstr "" #: htdocs/luci-static/resources/view/fchomo/client.js:1579 -#: htdocs/luci-static/resources/view/fchomo/node.js:1040 -#: htdocs/luci-static/resources/view/fchomo/node.js:1651 +#: htdocs/luci-static/resources/view/fchomo/node.js:1060 +#: htdocs/luci-static/resources/view/fchomo/node.js:1709 msgid "" "This is DANGEROUS, your traffic is almost like " "PLAIN TEXT! Use at your own risk!" @@ -2921,18 +2966,18 @@ msgstr "" msgid "Traffic pattern" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1807 +#: htdocs/luci-static/resources/view/fchomo/node.js:1865 msgid "Transit proxy group" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1813 +#: htdocs/luci-static/resources/view/fchomo/node.js:1871 msgid "Transit proxy node" msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:231 #: htdocs/luci-static/resources/fchomo/listeners.js:962 #: htdocs/luci-static/resources/view/fchomo/node.js:355 -#: htdocs/luci-static/resources/view/fchomo/node.js:1122 +#: htdocs/luci-static/resources/view/fchomo/node.js:1142 msgid "Transport" msgstr "" @@ -2942,7 +2987,7 @@ msgid "Transport fields" msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:967 -#: htdocs/luci-static/resources/view/fchomo/node.js:1127 +#: htdocs/luci-static/resources/view/fchomo/node.js:1147 msgid "Transport type" msgstr "" @@ -2987,8 +3032,8 @@ msgstr "" #: htdocs/luci-static/resources/view/fchomo/client.js:842 #: htdocs/luci-static/resources/view/fchomo/client.js:1028 #: htdocs/luci-static/resources/view/fchomo/node.js:238 -#: htdocs/luci-static/resources/view/fchomo/node.js:1493 -#: htdocs/luci-static/resources/view/fchomo/node.js:1778 +#: htdocs/luci-static/resources/view/fchomo/node.js:1551 +#: htdocs/luci-static/resources/view/fchomo/node.js:1836 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:276 msgid "Type" msgstr "" @@ -3003,8 +3048,8 @@ msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:555 #: htdocs/luci-static/resources/view/fchomo/client.js:588 #: htdocs/luci-static/resources/view/fchomo/client.js:678 -#: htdocs/luci-static/resources/view/fchomo/node.js:865 -#: htdocs/luci-static/resources/view/fchomo/node.js:1625 +#: htdocs/luci-static/resources/view/fchomo/node.js:885 +#: htdocs/luci-static/resources/view/fchomo/node.js:1683 msgid "UDP" msgstr "" @@ -3072,8 +3117,8 @@ msgstr "" msgid "Unknown error: %s" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:870 -#: htdocs/luci-static/resources/view/fchomo/node.js:1630 +#: htdocs/luci-static/resources/view/fchomo/node.js:890 +#: htdocs/luci-static/resources/view/fchomo/node.js:1688 msgid "UoT" msgstr "" @@ -3081,22 +3126,22 @@ msgstr "" msgid "Update failed." msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1562 +#: htdocs/luci-static/resources/view/fchomo/node.js:1620 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:382 msgid "Update interval" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1322 +#: htdocs/luci-static/resources/view/fchomo/node.js:1380 msgid "Upload bandwidth" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1323 +#: htdocs/luci-static/resources/view/fchomo/node.js:1381 msgid "Upload bandwidth in Mbps." msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:821 #: htdocs/luci-static/resources/fchomo/listeners.js:861 -#: htdocs/luci-static/resources/view/fchomo/node.js:1051 +#: htdocs/luci-static/resources/view/fchomo/node.js:1071 msgid "Upload certificate" msgstr "" @@ -3105,7 +3150,7 @@ msgid "Upload initial package" msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:836 -#: htdocs/luci-static/resources/view/fchomo/node.js:1065 +#: htdocs/luci-static/resources/view/fchomo/node.js:1085 msgid "Upload key" msgstr "" @@ -3113,8 +3158,8 @@ msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:839 #: htdocs/luci-static/resources/fchomo/listeners.js:864 #: htdocs/luci-static/resources/view/fchomo/global.js:306 -#: htdocs/luci-static/resources/view/fchomo/node.js:1054 -#: htdocs/luci-static/resources/view/fchomo/node.js:1068 +#: htdocs/luci-static/resources/view/fchomo/node.js:1074 +#: htdocs/luci-static/resources/view/fchomo/node.js:1088 msgid "Upload..." msgstr "" @@ -3138,7 +3183,7 @@ msgstr "" msgid "Used to resolve the domain of the Proxy node." msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:977 +#: htdocs/luci-static/resources/view/fchomo/node.js:997 msgid "Used to verify the hostname on the returned certificates." msgstr "" @@ -3155,11 +3200,11 @@ msgstr "" msgid "Users filter mode" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1236 +#: htdocs/luci-static/resources/view/fchomo/node.js:1256 msgid "V2ray HTTPUpgrade" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1241 +#: htdocs/luci-static/resources/view/fchomo/node.js:1261 msgid "V2ray HTTPUpgrade fast open" msgstr "" @@ -3173,8 +3218,8 @@ msgstr "" msgid "VMess" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1499 -#: htdocs/luci-static/resources/view/fchomo/node.js:1784 +#: htdocs/luci-static/resources/view/fchomo/node.js:1557 +#: htdocs/luci-static/resources/view/fchomo/node.js:1842 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:319 msgid "Value" msgstr "" @@ -3185,11 +3230,11 @@ msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:514 #: htdocs/luci-static/resources/view/fchomo/node.js:506 -#: htdocs/luci-static/resources/view/fchomo/node.js:836 +#: htdocs/luci-static/resources/view/fchomo/node.js:856 msgid "Version" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:844 +#: htdocs/luci-static/resources/view/fchomo/node.js:864 msgid "Version hint" msgstr "" @@ -3208,14 +3253,14 @@ msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:393 #: htdocs/luci-static/resources/fchomo/listeners.js:969 -#: htdocs/luci-static/resources/fchomo/listeners.js:980 +#: htdocs/luci-static/resources/fchomo/listeners.js:978 #: htdocs/luci-static/resources/fchomo/listeners.js:985 #: htdocs/luci-static/resources/view/fchomo/node.js:460 #: htdocs/luci-static/resources/view/fchomo/node.js:489 -#: htdocs/luci-static/resources/view/fchomo/node.js:1132 -#: htdocs/luci-static/resources/view/fchomo/node.js:1143 -#: htdocs/luci-static/resources/view/fchomo/node.js:1150 -#: htdocs/luci-static/resources/view/fchomo/node.js:1156 +#: htdocs/luci-static/resources/view/fchomo/node.js:1152 +#: htdocs/luci-static/resources/view/fchomo/node.js:1163 +#: htdocs/luci-static/resources/view/fchomo/node.js:1170 +#: htdocs/luci-static/resources/view/fchomo/node.js:1176 msgid "WebSocket" msgstr "" @@ -3231,27 +3276,42 @@ msgstr "" msgid "WireGuard" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:755 +#: htdocs/luci-static/resources/view/fchomo/node.js:775 msgid "WireGuard peer public key." msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:762 +#: htdocs/luci-static/resources/view/fchomo/node.js:782 msgid "WireGuard pre-shared key." msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:747 +#: htdocs/luci-static/resources/view/fchomo/node.js:767 msgid "WireGuard requires base64-encoded private keys." msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1133 -#: htdocs/luci-static/resources/view/fchomo/node.js:1151 +#: htdocs/luci-static/resources/fchomo/listeners.js:970 +#: htdocs/luci-static/resources/fchomo/listeners.js:979 +#: htdocs/luci-static/resources/view/fchomo/node.js:1153 +#: htdocs/luci-static/resources/view/fchomo/node.js:1171 msgid "XHTTP" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1246 +#: htdocs/luci-static/resources/fchomo/listeners.js:1015 +#: htdocs/luci-static/resources/view/fchomo/node.js:1266 msgid "XHTTP mode" msgstr "" +#: htdocs/luci-static/resources/view/fchomo/node.js:1290 +msgid "XMUX" +msgstr "" + +#: htdocs/luci-static/resources/view/fchomo/node.js:1295 +#: htdocs/luci-static/resources/view/fchomo/node.js:1300 +#: htdocs/luci-static/resources/view/fchomo/node.js:1305 +#: htdocs/luci-static/resources/view/fchomo/node.js:1310 +#: htdocs/luci-static/resources/view/fchomo/node.js:1315 +msgid "XMUX:" +msgstr "" + #: htdocs/luci-static/resources/fchomo/listeners.js:609 msgid "XOR mode" msgstr "" @@ -3298,7 +3358,7 @@ msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:826 #: htdocs/luci-static/resources/fchomo/listeners.js:866 -#: htdocs/luci-static/resources/view/fchomo/node.js:1056 +#: htdocs/luci-static/resources/view/fchomo/node.js:1076 msgid "certificate" msgstr "" @@ -3325,13 +3385,13 @@ msgstr "" msgid "dnsmasq selects upstream on its own. (may affect CDN accuracy)" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1642 +#: htdocs/luci-static/resources/view/fchomo/node.js:1700 msgid "down" msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:596 -#: htdocs/luci-static/resources/view/fchomo/node.js:884 -#: htdocs/luci-static/resources/view/fchomo/node.js:907 +#: htdocs/luci-static/resources/view/fchomo/node.js:904 +#: htdocs/luci-static/resources/view/fchomo/node.js:927 msgid "encryption" msgstr "" @@ -3341,25 +3401,25 @@ msgid "false = bandwidth optimized downlink; true = pure Sudoku downlink." msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:968 -#: htdocs/luci-static/resources/fchomo/listeners.js:979 +#: htdocs/luci-static/resources/fchomo/listeners.js:977 #: htdocs/luci-static/resources/fchomo/listeners.js:984 -#: htdocs/luci-static/resources/view/fchomo/node.js:1131 -#: htdocs/luci-static/resources/view/fchomo/node.js:1142 -#: htdocs/luci-static/resources/view/fchomo/node.js:1149 -#: htdocs/luci-static/resources/view/fchomo/node.js:1155 +#: htdocs/luci-static/resources/view/fchomo/node.js:1151 +#: htdocs/luci-static/resources/view/fchomo/node.js:1162 +#: htdocs/luci-static/resources/view/fchomo/node.js:1169 +#: htdocs/luci-static/resources/view/fchomo/node.js:1175 msgid "gRPC" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1212 +#: htdocs/luci-static/resources/view/fchomo/node.js:1232 msgid "gRPC User-Agent" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1217 +#: htdocs/luci-static/resources/view/fchomo/node.js:1237 msgid "gRPC ping interval" msgstr "" -#: htdocs/luci-static/resources/fchomo/listeners.js:1003 -#: htdocs/luci-static/resources/view/fchomo/node.js:1208 +#: htdocs/luci-static/resources/fchomo/listeners.js:1009 +#: htdocs/luci-static/resources/view/fchomo/node.js:1228 msgid "gRPC service name" msgstr "" @@ -3367,7 +3427,7 @@ msgstr "" msgid "gVisor" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1273 +#: htdocs/luci-static/resources/view/fchomo/node.js:1331 msgid "h2mux" msgstr "" @@ -3385,7 +3445,7 @@ msgstr "" #: htdocs/luci-static/resources/view/fchomo/client.js:1480 #: htdocs/luci-static/resources/view/fchomo/client.js:1711 #: htdocs/luci-static/resources/view/fchomo/client.js:1767 -#: htdocs/luci-static/resources/view/fchomo/node.js:1465 +#: htdocs/luci-static/resources/view/fchomo/node.js:1523 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:239 msgid "mihomo config" msgstr "" @@ -3394,8 +3454,8 @@ msgstr "" msgid "mlkem768x25519plus" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1339 -#: htdocs/luci-static/resources/view/fchomo/node.js:1620 +#: htdocs/luci-static/resources/view/fchomo/node.js:1397 +#: htdocs/luci-static/resources/view/fchomo/node.js:1678 msgid "mpTCP" msgstr "" @@ -3420,7 +3480,7 @@ msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:495 #: htdocs/luci-static/resources/view/fchomo/node.js:647 #: htdocs/luci-static/resources/view/fchomo/node.js:667 -#: htdocs/luci-static/resources/view/fchomo/node.js:805 +#: htdocs/luci-static/resources/view/fchomo/node.js:825 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:315 msgid "none" msgstr "" @@ -3439,7 +3499,7 @@ msgstr "" msgid "null" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:806 +#: htdocs/luci-static/resources/view/fchomo/node.js:826 msgid "obfs-simple" msgstr "" @@ -3451,7 +3511,7 @@ msgstr "" msgid "only applies when %s is not %s." msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1600 +#: htdocs/luci-static/resources/view/fchomo/node.js:1658 msgid "override.proxy-name" msgstr "" @@ -3459,7 +3519,8 @@ msgstr "" msgid "packet addr (v2ray-core v5+)" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1248 +#: htdocs/luci-static/resources/fchomo/listeners.js:1019 +#: htdocs/luci-static/resources/view/fchomo/node.js:1270 msgid "packet-up" msgstr "" @@ -3469,7 +3530,7 @@ msgid "poll" msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:841 -#: htdocs/luci-static/resources/view/fchomo/node.js:1070 +#: htdocs/luci-static/resources/view/fchomo/node.js:1090 msgid "private key" msgstr "" @@ -3482,7 +3543,7 @@ msgstr "" msgid "requires front-end adaptation using the API." msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:810 +#: htdocs/luci-static/resources/view/fchomo/node.js:830 msgid "restls" msgstr "" @@ -3491,11 +3552,11 @@ msgid "rule-set" msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:496 -#: htdocs/luci-static/resources/view/fchomo/node.js:809 +#: htdocs/luci-static/resources/view/fchomo/node.js:829 msgid "shadow-tls" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1271 +#: htdocs/luci-static/resources/view/fchomo/node.js:1329 msgid "smux" msgstr "" @@ -3508,10 +3569,20 @@ msgstr "" msgid "src" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1247 +#: htdocs/luci-static/resources/fchomo/listeners.js:1017 +#: htdocs/luci-static/resources/view/fchomo/node.js:1268 msgid "stream-one" msgstr "" +#: htdocs/luci-static/resources/fchomo/listeners.js:1018 +#: htdocs/luci-static/resources/view/fchomo/node.js:1269 +msgid "stream-up" +msgstr "" + +#: htdocs/luci-static/resources/fchomo/listeners.js:1028 +msgid "stream-up server seconds" +msgstr "" + #: htdocs/luci-static/resources/view/fchomo/node.js:491 msgid "stream/poll/auto" msgstr "" @@ -3536,28 +3607,28 @@ msgstr "" msgid "unique value" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1636 +#: htdocs/luci-static/resources/view/fchomo/node.js:1694 msgid "up" msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:515 #: htdocs/luci-static/resources/view/fchomo/node.js:507 #: htdocs/luci-static/resources/view/fchomo/node.js:542 -#: htdocs/luci-static/resources/view/fchomo/node.js:837 -#: htdocs/luci-static/resources/view/fchomo/node.js:877 +#: htdocs/luci-static/resources/view/fchomo/node.js:857 +#: htdocs/luci-static/resources/view/fchomo/node.js:897 msgid "v1" msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:516 #: htdocs/luci-static/resources/view/fchomo/node.js:508 -#: htdocs/luci-static/resources/view/fchomo/node.js:838 -#: htdocs/luci-static/resources/view/fchomo/node.js:878 +#: htdocs/luci-static/resources/view/fchomo/node.js:858 +#: htdocs/luci-static/resources/view/fchomo/node.js:898 msgid "v2" msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:517 #: htdocs/luci-static/resources/view/fchomo/node.js:509 -#: htdocs/luci-static/resources/view/fchomo/node.js:839 +#: htdocs/luci-static/resources/view/fchomo/node.js:859 msgid "v3" msgstr "" @@ -3566,7 +3637,7 @@ msgstr "" msgid "valid JSON format" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1030 +#: htdocs/luci-static/resources/view/fchomo/node.js:1050 msgid "valid SHA256 string with %d characters" msgstr "" @@ -3612,7 +3683,7 @@ msgstr "" msgid "yacd-meta" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1272 +#: htdocs/luci-static/resources/view/fchomo/node.js:1330 msgid "yamux" msgstr "" diff --git a/luci-app-fchomo/po/zh_Hans/fchomo.po b/luci-app-fchomo/po/zh_Hans/fchomo.po index 359a8051..44275e42 100644 --- a/luci-app-fchomo/po/zh_Hans/fchomo.po +++ b/luci-app-fchomo/po/zh_Hans/fchomo.po @@ -32,10 +32,10 @@ msgstr "(已导入)" #: htdocs/luci-static/resources/fchomo/listeners.js:861 #: htdocs/luci-static/resources/view/fchomo/global.js:543 #: htdocs/luci-static/resources/view/fchomo/global.js:549 -#: htdocs/luci-static/resources/view/fchomo/node.js:1045 -#: htdocs/luci-static/resources/view/fchomo/node.js:1051 -#: htdocs/luci-static/resources/view/fchomo/node.js:1059 #: htdocs/luci-static/resources/view/fchomo/node.js:1065 +#: htdocs/luci-static/resources/view/fchomo/node.js:1071 +#: htdocs/luci-static/resources/view/fchomo/node.js:1079 +#: htdocs/luci-static/resources/view/fchomo/node.js:1085 msgid "(mTLS)" msgstr "" @@ -46,10 +46,10 @@ msgstr "" #: htdocs/luci-static/resources/view/fchomo/client.js:1056 #: htdocs/luci-static/resources/view/fchomo/client.js:1057 #: htdocs/luci-static/resources/view/fchomo/client.js:1278 -#: htdocs/luci-static/resources/view/fchomo/node.js:1788 -#: htdocs/luci-static/resources/view/fchomo/node.js:1794 -#: htdocs/luci-static/resources/view/fchomo/node.js:1808 -#: htdocs/luci-static/resources/view/fchomo/node.js:1814 +#: htdocs/luci-static/resources/view/fchomo/node.js:1846 +#: htdocs/luci-static/resources/view/fchomo/node.js:1852 +#: htdocs/luci-static/resources/view/fchomo/node.js:1866 +#: htdocs/luci-static/resources/view/fchomo/node.js:1872 msgid "-- Please choose --" msgstr "-- 请选择 --" @@ -85,8 +85,8 @@ msgstr "仅限 01。" #: htdocs/luci-static/resources/fchomo/listeners.js:822 #: htdocs/luci-static/resources/fchomo/listeners.js:837 #: htdocs/luci-static/resources/fchomo/listeners.js:862 -#: htdocs/luci-static/resources/view/fchomo/node.js:1052 -#: htdocs/luci-static/resources/view/fchomo/node.js:1066 +#: htdocs/luci-static/resources/view/fchomo/node.js:1072 +#: htdocs/luci-static/resources/view/fchomo/node.js:1086 msgid "Save your configuration before uploading files!" msgstr "上传文件前请先保存配置!" @@ -182,11 +182,11 @@ msgstr "新增 节点" msgid "Add a inbound" msgstr "新增 入站" -#: htdocs/luci-static/resources/view/fchomo/node.js:1379 +#: htdocs/luci-static/resources/view/fchomo/node.js:1437 msgid "Add a provider" msgstr "新增 供应商" -#: htdocs/luci-static/resources/view/fchomo/node.js:1764 +#: htdocs/luci-static/resources/view/fchomo/node.js:1822 msgid "Add a proxy chain" msgstr "新增 代理链" @@ -210,11 +210,11 @@ msgstr "新增 服务器" msgid "Add a sub rule" msgstr "新增 子规则" -#: htdocs/luci-static/resources/view/fchomo/node.js:1589 +#: htdocs/luci-static/resources/view/fchomo/node.js:1647 msgid "Add prefix" msgstr "添加前缀" -#: htdocs/luci-static/resources/view/fchomo/node.js:1593 +#: htdocs/luci-static/resources/view/fchomo/node.js:1651 msgid "Add suffix" msgstr "添加后缀" @@ -251,7 +251,7 @@ msgid "" msgstr "" "允许从私有网络访问。
要从公共网站访问私有网络上的 API,则必须启用。" -#: htdocs/luci-static/resources/view/fchomo/node.js:768 +#: htdocs/luci-static/resources/view/fchomo/node.js:788 msgid "Allowed IPs" msgstr "允许的 IP" @@ -295,9 +295,11 @@ msgid "Authenticated length" msgstr "认证长度" #: htdocs/luci-static/resources/fchomo/listeners.js:392 +#: htdocs/luci-static/resources/fchomo/listeners.js:1016 #: htdocs/luci-static/resources/view/fchomo/global.js:402 #: htdocs/luci-static/resources/view/fchomo/node.js:459 #: htdocs/luci-static/resources/view/fchomo/node.js:483 +#: htdocs/luci-static/resources/view/fchomo/node.js:1267 msgid "Auto" msgstr "自动" @@ -343,13 +345,13 @@ msgid "Binary mrs" msgstr "二进制 mrs" #: htdocs/luci-static/resources/view/fchomo/global.js:734 -#: htdocs/luci-static/resources/view/fchomo/node.js:1349 -#: htdocs/luci-static/resources/view/fchomo/node.js:1662 +#: htdocs/luci-static/resources/view/fchomo/node.js:1407 +#: htdocs/luci-static/resources/view/fchomo/node.js:1720 msgid "Bind interface" msgstr "绑定接口" -#: htdocs/luci-static/resources/view/fchomo/node.js:1350 -#: htdocs/luci-static/resources/view/fchomo/node.js:1663 +#: htdocs/luci-static/resources/view/fchomo/node.js:1408 +#: htdocs/luci-static/resources/view/fchomo/node.js:1721 msgid "Bind outbound interface.
" msgstr "绑定出站接口。
" @@ -414,17 +416,17 @@ msgstr "CORS 允许的来源,留空则使用 *。" msgid "Cancel" msgstr "取消" -#: htdocs/luci-static/resources/view/fchomo/node.js:1024 +#: htdocs/luci-static/resources/view/fchomo/node.js:1044 msgid "Cert fingerprint" msgstr "证书指纹" -#: htdocs/luci-static/resources/view/fchomo/node.js:1025 +#: htdocs/luci-static/resources/view/fchomo/node.js:1045 msgid "" "Certificate fingerprint. Used to implement SSL Pinning and prevent MitM." msgstr "证书指纹。用于实现 SSL证书固定 并防止 MitM。" #: htdocs/luci-static/resources/fchomo/listeners.js:814 -#: htdocs/luci-static/resources/view/fchomo/node.js:1045 +#: htdocs/luci-static/resources/view/fchomo/node.js:1065 msgid "Certificate path" msgstr "证书路径" @@ -481,9 +483,9 @@ msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:637 #: htdocs/luci-static/resources/fchomo/listeners.js:853 #: htdocs/luci-static/resources/view/fchomo/global.js:550 -#: htdocs/luci-static/resources/view/fchomo/node.js:919 -#: htdocs/luci-static/resources/view/fchomo/node.js:1046 -#: htdocs/luci-static/resources/view/fchomo/node.js:1060 +#: htdocs/luci-static/resources/view/fchomo/node.js:939 +#: htdocs/luci-static/resources/view/fchomo/node.js:1066 +#: htdocs/luci-static/resources/view/fchomo/node.js:1080 #: root/usr/share/luci/menu.d/luci-app-fchomo.json:22 msgid "Client" msgstr "客户端" @@ -496,7 +498,7 @@ msgstr "客户端认证证书路径" msgid "Client Auth type" msgstr "客户端认证类型" -#: htdocs/luci-static/resources/view/fchomo/node.js:1091 +#: htdocs/luci-static/resources/view/fchomo/node.js:1111 msgid "Client fingerprint" msgstr "客户端指纹" @@ -521,12 +523,12 @@ msgstr "常用端口(绕过 P2P 流量)" msgid "Complete" msgstr "完成" -#: htdocs/luci-static/resources/view/fchomo/node.js:1609 +#: htdocs/luci-static/resources/view/fchomo/node.js:1667 msgid "Configuration Items" msgstr "配置项" #: htdocs/luci-static/resources/fchomo/listeners.js:540 -#: htdocs/luci-static/resources/view/fchomo/node.js:857 +#: htdocs/luci-static/resources/view/fchomo/node.js:877 msgid "Congestion controller" msgstr "拥塞控制器" @@ -539,14 +541,14 @@ msgid "Content copied to clipboard!" msgstr "内容已复制到剪贴板!" #: htdocs/luci-static/resources/view/fchomo/client.js:670 -#: htdocs/luci-static/resources/view/fchomo/node.js:1519 -#: htdocs/luci-static/resources/view/fchomo/node.js:1545 +#: htdocs/luci-static/resources/view/fchomo/node.js:1577 +#: htdocs/luci-static/resources/view/fchomo/node.js:1603 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:339 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:365 msgid "Content will not be verified, Please make sure you enter it correctly." msgstr "内容将不会被验证,请确保输入正确。" -#: htdocs/luci-static/resources/view/fchomo/node.js:1518 +#: htdocs/luci-static/resources/view/fchomo/node.js:1576 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:338 msgid "Contents" msgstr "内容" @@ -571,7 +573,7 @@ msgstr "Cron 表达式" msgid "Custom Direct List" msgstr "自定义直连列表" -#: htdocs/luci-static/resources/view/fchomo/node.js:1580 +#: htdocs/luci-static/resources/view/fchomo/node.js:1638 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:400 msgid "Custom HTTP header." msgstr "自定义 HTTP header。" @@ -607,7 +609,7 @@ msgstr " DNS 端口" #: htdocs/luci-static/resources/view/fchomo/client.js:1428 #: htdocs/luci-static/resources/view/fchomo/client.js:1437 #: htdocs/luci-static/resources/view/fchomo/node.js:715 -#: htdocs/luci-static/resources/view/fchomo/node.js:798 +#: htdocs/luci-static/resources/view/fchomo/node.js:818 msgid "DNS server" msgstr "DNS 服务器" @@ -635,15 +637,15 @@ msgstr "默认 DNS(由 WAN 下发)" msgid "Default DNS server" msgstr "默认 DNS 服务器" -#: htdocs/luci-static/resources/view/fchomo/node.js:769 +#: htdocs/luci-static/resources/view/fchomo/node.js:789 msgid "Destination addresses allowed to be forwarded via Wireguard." msgstr "允许通过 WireGuard 转发的目的地址" -#: htdocs/luci-static/resources/view/fchomo/node.js:1787 +#: htdocs/luci-static/resources/view/fchomo/node.js:1845 msgid "Destination provider" msgstr "落地供应商" -#: htdocs/luci-static/resources/view/fchomo/node.js:1793 +#: htdocs/luci-static/resources/view/fchomo/node.js:1851 msgid "Destination proxy node" msgstr "落地代理节点" @@ -651,8 +653,8 @@ msgstr "落地代理节点" msgid "Dial fields" msgstr "拨号字段" -#: htdocs/luci-static/resources/view/fchomo/node.js:1800 -#: htdocs/luci-static/resources/view/fchomo/node.js:1820 +#: htdocs/luci-static/resources/view/fchomo/node.js:1858 +#: htdocs/luci-static/resources/view/fchomo/node.js:1878 msgid "Different chain head/tail" msgstr "不同的链头/链尾" @@ -690,7 +692,7 @@ msgstr "禁用 quic-go 的 通用分段卸载(GSO)" msgid "Disable ICMP Forwarding" msgstr "禁用 ICMP 转发" -#: htdocs/luci-static/resources/view/fchomo/node.js:970 +#: htdocs/luci-static/resources/view/fchomo/node.js:990 msgid "Disable SNI" msgstr "禁用 SNI" @@ -718,21 +720,21 @@ msgstr "" msgid "Domain" msgstr "域名" -#: htdocs/luci-static/resources/view/fchomo/node.js:971 +#: htdocs/luci-static/resources/view/fchomo/node.js:991 msgid "Donot send server name in ClientHello." msgstr "不要在 ClientHello 中发送服务器名称。" #: htdocs/luci-static/resources/view/fchomo/client.js:1577 -#: htdocs/luci-static/resources/view/fchomo/node.js:1038 -#: htdocs/luci-static/resources/view/fchomo/node.js:1649 +#: htdocs/luci-static/resources/view/fchomo/node.js:1058 +#: htdocs/luci-static/resources/view/fchomo/node.js:1707 msgid "Donot verifying server certificate." msgstr "不验证服务器证书。" -#: htdocs/luci-static/resources/view/fchomo/node.js:1328 +#: htdocs/luci-static/resources/view/fchomo/node.js:1386 msgid "Download bandwidth" msgstr "下载带宽" -#: htdocs/luci-static/resources/view/fchomo/node.js:1329 +#: htdocs/luci-static/resources/view/fchomo/node.js:1387 msgid "Download bandwidth in Mbps." msgstr "下载带宽(单位:Mbps)。" @@ -748,12 +750,12 @@ msgstr "下载成功。" msgid "Dual stack" msgstr "双栈" -#: htdocs/luci-static/resources/view/fchomo/node.js:1085 +#: htdocs/luci-static/resources/view/fchomo/node.js:1105 msgid "ECH HTTPS record query servername" msgstr "ECH HTTPS 记录查询域名" #: htdocs/luci-static/resources/fchomo/listeners.js:910 -#: htdocs/luci-static/resources/view/fchomo/node.js:1079 +#: htdocs/luci-static/resources/view/fchomo/node.js:1099 msgid "ECH config" msgstr "ECH 配置" @@ -773,11 +775,11 @@ msgstr "" msgid "ETag support" msgstr "ETag 支持" -#: htdocs/luci-static/resources/view/fchomo/node.js:1225 +#: htdocs/luci-static/resources/view/fchomo/node.js:1245 msgid "Early Data first packet length limit." msgstr "前置数据长度阈值" -#: htdocs/luci-static/resources/view/fchomo/node.js:1231 +#: htdocs/luci-static/resources/view/fchomo/node.js:1251 msgid "Early Data header name" msgstr "前置数据标头" @@ -793,7 +795,7 @@ msgstr "编辑节点" msgid "Edit ruleset" msgstr "编辑规则集" -#: htdocs/luci-static/resources/view/fchomo/node.js:1516 +#: htdocs/luci-static/resources/view/fchomo/node.js:1574 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:336 msgid "Editer" msgstr "编辑器" @@ -813,9 +815,9 @@ msgstr "消除加密头特征" #: htdocs/luci-static/resources/view/fchomo/global.js:401 #: htdocs/luci-static/resources/view/fchomo/global.js:680 #: htdocs/luci-static/resources/view/fchomo/node.js:234 -#: htdocs/luci-static/resources/view/fchomo/node.js:1489 -#: htdocs/luci-static/resources/view/fchomo/node.js:1685 -#: htdocs/luci-static/resources/view/fchomo/node.js:1774 +#: htdocs/luci-static/resources/view/fchomo/node.js:1547 +#: htdocs/luci-static/resources/view/fchomo/node.js:1743 +#: htdocs/luci-static/resources/view/fchomo/node.js:1832 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:264 #: htdocs/luci-static/resources/view/fchomo/server.js:49 msgid "Enable" @@ -842,19 +844,19 @@ msgstr "" "为出站连接启用 IP4P 转换" -#: htdocs/luci-static/resources/view/fchomo/node.js:1073 +#: htdocs/luci-static/resources/view/fchomo/node.js:1093 msgid "Enable ECH" msgstr "启用 ECH" -#: htdocs/luci-static/resources/view/fchomo/node.js:1316 +#: htdocs/luci-static/resources/view/fchomo/node.js:1374 msgid "Enable TCP Brutal" msgstr "启用 TCP Brutal" -#: htdocs/luci-static/resources/view/fchomo/node.js:1317 +#: htdocs/luci-static/resources/view/fchomo/node.js:1375 msgid "Enable TCP Brutal congestion control algorithm" msgstr "启用 TCP Brutal 拥塞控制算法。" -#: htdocs/luci-static/resources/view/fchomo/node.js:1305 +#: htdocs/luci-static/resources/view/fchomo/node.js:1363 msgid "Enable multiplexing only for TCP." msgstr "仅为 TCP 启用多路复用。" @@ -863,16 +865,16 @@ msgstr "仅为 TCP 启用多路复用。" msgid "Enable obfuscate for downlink" msgstr "启用下行链路混淆" -#: htdocs/luci-static/resources/view/fchomo/node.js:1299 +#: htdocs/luci-static/resources/view/fchomo/node.js:1357 msgid "Enable padding" msgstr "启用填充" -#: htdocs/luci-static/resources/view/fchomo/node.js:1310 +#: htdocs/luci-static/resources/view/fchomo/node.js:1368 msgid "Enable statistic" msgstr "启用统计" -#: htdocs/luci-static/resources/view/fchomo/node.js:871 -#: htdocs/luci-static/resources/view/fchomo/node.js:1631 +#: htdocs/luci-static/resources/view/fchomo/node.js:891 +#: htdocs/luci-static/resources/view/fchomo/node.js:1689 msgid "" "Enable the SUoT protocol, requires server support. Conflict with Multiplex." msgstr "启用 SUoT 协议,需要服务端支持。与多路复用冲突。" @@ -911,7 +913,7 @@ msgid "" "if empty." msgstr "超过此限制将会触发强制健康检查。留空则使用 5。" -#: htdocs/luci-static/resources/view/fchomo/node.js:1743 +#: htdocs/luci-static/resources/view/fchomo/node.js:1801 msgid "Exclude matched node types." msgstr "排除匹配的节点类型。" @@ -924,7 +926,7 @@ msgstr "" "rel=\"noreferrer noopener\">此处。" #: htdocs/luci-static/resources/view/fchomo/client.js:1161 -#: htdocs/luci-static/resources/view/fchomo/node.js:1736 +#: htdocs/luci-static/resources/view/fchomo/node.js:1794 msgid "Exclude nodes that meet keywords or regexps." msgstr "排除匹配关键词或表达式的节点。" @@ -933,12 +935,12 @@ msgid "Expand/Collapse result" msgstr "展开/收起 结果" #: htdocs/luci-static/resources/view/fchomo/client.js:1121 -#: htdocs/luci-static/resources/view/fchomo/node.js:1721 +#: htdocs/luci-static/resources/view/fchomo/node.js:1779 msgid "Expected HTTP code. 204 will be used if empty." msgstr "预期的 HTTP code。留空则使用 204。" #: htdocs/luci-static/resources/view/fchomo/client.js:1123 -#: htdocs/luci-static/resources/view/fchomo/node.js:1723 +#: htdocs/luci-static/resources/view/fchomo/node.js:1781 msgid "Expected status" msgstr "预期状态" @@ -979,10 +981,10 @@ msgstr "预期状态" #: htdocs/luci-static/resources/view/fchomo/node.js:436 #: htdocs/luci-static/resources/view/fchomo/node.js:489 #: htdocs/luci-static/resources/view/fchomo/node.js:491 -#: htdocs/luci-static/resources/view/fchomo/node.js:942 -#: htdocs/luci-static/resources/view/fchomo/node.js:1030 -#: htdocs/luci-static/resources/view/fchomo/node.js:1800 -#: htdocs/luci-static/resources/view/fchomo/node.js:1820 +#: htdocs/luci-static/resources/view/fchomo/node.js:962 +#: htdocs/luci-static/resources/view/fchomo/node.js:1050 +#: htdocs/luci-static/resources/view/fchomo/node.js:1858 +#: htdocs/luci-static/resources/view/fchomo/node.js:1878 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:291 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:305 msgid "Expecting: %s" @@ -990,9 +992,9 @@ msgstr "请输入:%s" #: htdocs/luci-static/resources/fchomo/listeners.js:977 #: htdocs/luci-static/resources/fchomo/listeners.js:984 -#: htdocs/luci-static/resources/view/fchomo/node.js:1140 -#: htdocs/luci-static/resources/view/fchomo/node.js:1147 -#: htdocs/luci-static/resources/view/fchomo/node.js:1155 +#: htdocs/luci-static/resources/view/fchomo/node.js:1160 +#: htdocs/luci-static/resources/view/fchomo/node.js:1167 +#: htdocs/luci-static/resources/view/fchomo/node.js:1175 msgid "Expecting: only support %s." msgstr "请输入:仅支援 %s." @@ -1042,7 +1044,7 @@ msgid "Fallback filter" msgstr "後備过滤器" #: htdocs/luci-static/resources/view/fchomo/client.js:1156 -#: htdocs/luci-static/resources/view/fchomo/node.js:1730 +#: htdocs/luci-static/resources/view/fchomo/node.js:1788 msgid "Filter nodes that meet keywords or regexps." msgstr "过滤匹配关键字或表达式的节点。" @@ -1085,8 +1087,8 @@ msgstr "" "noopener\">%s." #: htdocs/luci-static/resources/view/fchomo/client.js:1122 -#: htdocs/luci-static/resources/view/fchomo/node.js:1599 -#: htdocs/luci-static/resources/view/fchomo/node.js:1722 +#: htdocs/luci-static/resources/view/fchomo/node.js:1657 +#: htdocs/luci-static/resources/view/fchomo/node.js:1780 msgid "" "For format see %s." @@ -1095,7 +1097,7 @@ msgstr "" "a>." #: htdocs/luci-static/resources/view/fchomo/node.js:710 -#: htdocs/luci-static/resources/view/fchomo/node.js:793 +#: htdocs/luci-static/resources/view/fchomo/node.js:813 msgid "Force DNS remote resolution." msgstr "强制 DNS 远程解析。" @@ -1114,7 +1116,7 @@ msgstr "格式" msgid "FullCombo Shark!" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1180 +#: htdocs/luci-static/resources/view/fchomo/node.js:1200 msgid "GET" msgstr "" @@ -1129,7 +1131,7 @@ msgstr "常规" #: htdocs/luci-static/resources/fchomo/listeners.js:119 #: htdocs/luci-static/resources/view/fchomo/client.js:1009 #: htdocs/luci-static/resources/view/fchomo/node.js:222 -#: htdocs/luci-static/resources/view/fchomo/node.js:1479 +#: htdocs/luci-static/resources/view/fchomo/node.js:1537 msgid "General fields" msgstr "常规字段" @@ -1211,17 +1213,16 @@ msgstr "组" #: htdocs/luci-static/resources/fchomo.js:146 #: htdocs/luci-static/resources/fchomo.js:179 -#: htdocs/luci-static/resources/fchomo/listeners.js:977 -#: htdocs/luci-static/resources/view/fchomo/node.js:816 -#: htdocs/luci-static/resources/view/fchomo/node.js:1129 -#: htdocs/luci-static/resources/view/fchomo/node.js:1140 -#: htdocs/luci-static/resources/view/fchomo/node.js:1147 +#: htdocs/luci-static/resources/view/fchomo/node.js:836 +#: htdocs/luci-static/resources/view/fchomo/node.js:1149 +#: htdocs/luci-static/resources/view/fchomo/node.js:1160 +#: htdocs/luci-static/resources/view/fchomo/node.js:1167 msgid "HTTP" msgstr "" #: htdocs/luci-static/resources/view/fchomo/node.js:267 -#: htdocs/luci-static/resources/view/fchomo/node.js:1202 -#: htdocs/luci-static/resources/view/fchomo/node.js:1579 +#: htdocs/luci-static/resources/view/fchomo/node.js:1222 +#: htdocs/luci-static/resources/view/fchomo/node.js:1637 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:399 msgid "HTTP header" msgstr "HTTP header" @@ -1247,7 +1248,7 @@ msgstr "HTTP 伪装多路复用" msgid "HTTP mask: %s" msgstr "HTTP 伪装: %s" -#: htdocs/luci-static/resources/view/fchomo/node.js:1179 +#: htdocs/luci-static/resources/view/fchomo/node.js:1199 msgid "HTTP request method" msgstr "HTTP 请求方法" @@ -1266,10 +1267,9 @@ msgid "" "returned if empty." msgstr "身份验证失败时的 HTTP3 服务器响应。默认返回 404 页面。" -#: htdocs/luci-static/resources/fchomo/listeners.js:978 -#: htdocs/luci-static/resources/view/fchomo/node.js:1130 -#: htdocs/luci-static/resources/view/fchomo/node.js:1141 -#: htdocs/luci-static/resources/view/fchomo/node.js:1148 +#: htdocs/luci-static/resources/view/fchomo/node.js:1150 +#: htdocs/luci-static/resources/view/fchomo/node.js:1161 +#: htdocs/luci-static/resources/view/fchomo/node.js:1168 msgid "HTTPUpgrade" msgstr "" @@ -1294,27 +1294,27 @@ msgid "Health check" msgstr "健康检查" #: htdocs/luci-static/resources/view/fchomo/client.js:1091 -#: htdocs/luci-static/resources/view/fchomo/node.js:1690 +#: htdocs/luci-static/resources/view/fchomo/node.js:1748 msgid "Health check URL" msgstr "健康检查 URL" #: htdocs/luci-static/resources/view/fchomo/client.js:1120 -#: htdocs/luci-static/resources/view/fchomo/node.js:1720 +#: htdocs/luci-static/resources/view/fchomo/node.js:1778 msgid "Health check expected status" msgstr "健康检查预期状态" #: htdocs/luci-static/resources/view/fchomo/client.js:1100 -#: htdocs/luci-static/resources/view/fchomo/node.js:1700 +#: htdocs/luci-static/resources/view/fchomo/node.js:1758 msgid "Health check interval" msgstr "健康检查间隔" #: htdocs/luci-static/resources/view/fchomo/client.js:1107 -#: htdocs/luci-static/resources/view/fchomo/node.js:1707 +#: htdocs/luci-static/resources/view/fchomo/node.js:1765 msgid "Health check timeout" msgstr "健康检查超时" #: htdocs/luci-static/resources/view/fchomo/client.js:1011 -#: htdocs/luci-static/resources/view/fchomo/node.js:1481 +#: htdocs/luci-static/resources/view/fchomo/node.js:1539 msgid "Health fields" msgstr "健康字段" @@ -1326,7 +1326,7 @@ msgstr "心跳间隔" msgid "Hidden" msgstr "隐藏" -#: htdocs/luci-static/resources/view/fchomo/node.js:822 +#: htdocs/luci-static/resources/view/fchomo/node.js:842 msgid "Host that supports TLS 1.3" msgstr "主机名称 (支援 TLS 1.3)" @@ -1365,8 +1365,8 @@ msgstr "" msgid "IP override" msgstr "IP 覆写" -#: htdocs/luci-static/resources/view/fchomo/node.js:1361 -#: htdocs/luci-static/resources/view/fchomo/node.js:1676 +#: htdocs/luci-static/resources/view/fchomo/node.js:1419 +#: htdocs/luci-static/resources/view/fchomo/node.js:1734 msgid "IP version" msgstr "IP 版本" @@ -1427,8 +1427,8 @@ msgstr "导入" #: htdocs/luci-static/resources/view/fchomo/client.js:1713 #: htdocs/luci-static/resources/view/fchomo/client.js:1748 #: htdocs/luci-static/resources/view/fchomo/client.js:1769 -#: htdocs/luci-static/resources/view/fchomo/node.js:1386 -#: htdocs/luci-static/resources/view/fchomo/node.js:1467 +#: htdocs/luci-static/resources/view/fchomo/node.js:1444 +#: htdocs/luci-static/resources/view/fchomo/node.js:1525 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:153 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:241 msgid "Import mihomo config" @@ -1444,12 +1444,12 @@ msgstr "导入规则集链接" #: htdocs/luci-static/resources/fchomo/listeners.js:181 #: htdocs/luci-static/resources/view/fchomo/node.js:286 #: htdocs/luci-static/resources/view/fchomo/node.js:292 -#: htdocs/luci-static/resources/view/fchomo/node.js:1637 -#: htdocs/luci-static/resources/view/fchomo/node.js:1643 +#: htdocs/luci-static/resources/view/fchomo/node.js:1695 +#: htdocs/luci-static/resources/view/fchomo/node.js:1701 msgid "In Mbps." msgstr "单位为 Mbps。" -#: htdocs/luci-static/resources/view/fchomo/node.js:1557 +#: htdocs/luci-static/resources/view/fchomo/node.js:1615 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:377 msgid "In bytes. %s will be used if empty." msgstr "单位为字节。留空则使用 %s。" @@ -1461,7 +1461,7 @@ msgstr "单位为毫秒。" #: htdocs/luci-static/resources/view/fchomo/client.js:1108 #: htdocs/luci-static/resources/view/fchomo/client.js:1137 -#: htdocs/luci-static/resources/view/fchomo/node.js:1708 +#: htdocs/luci-static/resources/view/fchomo/node.js:1766 msgid "In millisecond. %s will be used if empty." msgstr "单位为毫秒。留空则使用 %s。" @@ -1470,7 +1470,7 @@ msgstr "单位为毫秒。留空则使用 %s。" #: htdocs/luci-static/resources/fchomo/listeners.js:428 #: htdocs/luci-static/resources/view/fchomo/node.js:604 #: htdocs/luci-static/resources/view/fchomo/node.js:611 -#: htdocs/luci-static/resources/view/fchomo/node.js:1218 +#: htdocs/luci-static/resources/view/fchomo/node.js:1238 msgid "In seconds." msgstr "单位为秒。" @@ -1479,14 +1479,14 @@ msgstr "单位为秒。" #: htdocs/luci-static/resources/view/fchomo/global.js:430 #: htdocs/luci-static/resources/view/fchomo/global.js:515 #: htdocs/luci-static/resources/view/fchomo/node.js:280 -#: htdocs/luci-static/resources/view/fchomo/node.js:1563 -#: htdocs/luci-static/resources/view/fchomo/node.js:1701 +#: htdocs/luci-static/resources/view/fchomo/node.js:1621 +#: htdocs/luci-static/resources/view/fchomo/node.js:1759 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:383 msgid "In seconds. %s will be used if empty." msgstr "单位为秒。留空则使用 %s。" #: htdocs/luci-static/resources/fchomo/listeners.js:649 -#: htdocs/luci-static/resources/view/fchomo/node.js:931 +#: htdocs/luci-static/resources/view/fchomo/node.js:951 msgid "" "In the order of one Padding-Length and one Padding-" "Interval, infinite concatenation." @@ -1528,7 +1528,7 @@ msgstr "引入所有代理节点。" msgid "Info" msgstr "信息" -#: htdocs/luci-static/resources/view/fchomo/node.js:1496 +#: htdocs/luci-static/resources/view/fchomo/node.js:1554 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:279 msgid "Inline" msgstr "内嵌" @@ -1549,7 +1549,7 @@ msgid "Key" msgstr "密钥" #: htdocs/luci-static/resources/fchomo/listeners.js:829 -#: htdocs/luci-static/resources/view/fchomo/node.js:1059 +#: htdocs/luci-static/resources/view/fchomo/node.js:1079 msgid "Key path" msgstr "证书路径" @@ -1565,14 +1565,14 @@ msgstr "密钥对" #: htdocs/luci-static/resources/view/fchomo/client.js:1719 #: htdocs/luci-static/resources/view/fchomo/client.js:1775 #: htdocs/luci-static/resources/view/fchomo/node.js:229 -#: htdocs/luci-static/resources/view/fchomo/node.js:1484 -#: htdocs/luci-static/resources/view/fchomo/node.js:1769 +#: htdocs/luci-static/resources/view/fchomo/node.js:1542 +#: htdocs/luci-static/resources/view/fchomo/node.js:1827 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:259 msgid "Label" msgstr "标签" #: htdocs/luci-static/resources/view/fchomo/client.js:1114 -#: htdocs/luci-static/resources/view/fchomo/node.js:1714 +#: htdocs/luci-static/resources/view/fchomo/node.js:1772 msgid "Lazy" msgstr "懒惰状态" @@ -1594,7 +1594,7 @@ msgid "Less compatibility and sometimes better performance." msgstr "有时性能更好。" #: htdocs/luci-static/resources/fchomo/listeners.js:810 -#: htdocs/luci-static/resources/view/fchomo/node.js:983 +#: htdocs/luci-static/resources/view/fchomo/node.js:1003 msgid "List of supported application level protocols, in order of preference." msgstr "支持的应用层协议协商列表,按顺序排列。" @@ -1623,18 +1623,18 @@ msgstr "监听端口" msgid "Load balance" msgstr "负载均衡" -#: htdocs/luci-static/resources/view/fchomo/node.js:1494 +#: htdocs/luci-static/resources/view/fchomo/node.js:1552 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:277 msgid "Local" msgstr "本地" #: htdocs/luci-static/resources/view/fchomo/node.js:697 -#: htdocs/luci-static/resources/view/fchomo/node.js:740 +#: htdocs/luci-static/resources/view/fchomo/node.js:760 msgid "Local IPv6 address" msgstr "本地 IPv6 地址" #: htdocs/luci-static/resources/view/fchomo/node.js:689 -#: htdocs/luci-static/resources/view/fchomo/node.js:732 +#: htdocs/luci-static/resources/view/fchomo/node.js:752 msgid "Local address" msgstr "本地地址" @@ -1671,7 +1671,7 @@ msgstr "仅限小写" #: htdocs/luci-static/resources/view/fchomo/global.js:502 #: htdocs/luci-static/resources/view/fchomo/node.js:703 -#: htdocs/luci-static/resources/view/fchomo/node.js:786 +#: htdocs/luci-static/resources/view/fchomo/node.js:806 msgid "MTU" msgstr "" @@ -1711,7 +1711,7 @@ msgstr "匹配响应通过 ipcidr
" msgid "Match rule set." msgstr "匹配规则集。" -#: htdocs/luci-static/resources/view/fchomo/node.js:1224 +#: htdocs/luci-static/resources/view/fchomo/node.js:1244 msgid "Max Early Data" msgstr "前置数据最大值" @@ -1720,6 +1720,15 @@ msgstr "前置数据最大值" msgid "Max UDP relay packet size" msgstr "UDP 中继数据包最大尺寸" +#: htdocs/luci-static/resources/view/fchomo/node.js:1300 +msgid "Max concurrency" +msgstr "最大并发" + +#: htdocs/luci-static/resources/view/fchomo/node.js:731 +#: htdocs/luci-static/resources/view/fchomo/node.js:1295 +msgid "Max connections" +msgstr "最大连接数" + #: htdocs/luci-static/resources/view/fchomo/client.js:1128 msgid "Max count of failures" msgstr "最大失败次数" @@ -1729,21 +1738,47 @@ msgstr "最大失败次数" msgid "Max download speed" msgstr "最大下载速度" +#: htdocs/luci-static/resources/fchomo/listeners.js:1033 +#: htdocs/luci-static/resources/view/fchomo/node.js:1284 +msgid "Max each POST bytes" +msgstr "POST 最大字节数" + #: htdocs/luci-static/resources/view/fchomo/node.js:573 msgid "Max open streams" msgstr "限制打开流的数量" +#: htdocs/luci-static/resources/view/fchomo/node.js:1310 +msgid "Max request times" +msgstr "最大请求次数" + +#: htdocs/luci-static/resources/view/fchomo/node.js:1315 +msgid "Max reusable seconds" +msgstr "最大可复用秒数" + +#: htdocs/luci-static/resources/view/fchomo/node.js:1305 +msgid "Max reuse times" +msgstr "最大复用次数" + +#: htdocs/luci-static/resources/view/fchomo/node.js:744 +msgid "Max streams" +msgstr "" + #: htdocs/luci-static/resources/fchomo/listeners.js:174 #: htdocs/luci-static/resources/view/fchomo/node.js:285 msgid "Max upload speed" msgstr "最大上传速度" -#: htdocs/luci-static/resources/view/fchomo/node.js:1277 -#: htdocs/luci-static/resources/view/fchomo/node.js:1293 +#: htdocs/luci-static/resources/view/fchomo/node.js:1335 +#: htdocs/luci-static/resources/view/fchomo/node.js:1351 msgid "Maximum connections" msgstr "最大连接数" -#: htdocs/luci-static/resources/view/fchomo/node.js:1291 +#: htdocs/luci-static/resources/view/fchomo/node.js:745 +msgid "" +"Maximum multiplexed streams in a connection before opening a new connection." +msgstr "" + +#: htdocs/luci-static/resources/view/fchomo/node.js:1349 msgid "" "Maximum multiplexed streams in a connection before opening a new connection." "
Conflict with %s and %s." @@ -1763,7 +1798,7 @@ msgid "" "rate." msgstr "最大填充率必须大于等于最小填充率。" -#: htdocs/luci-static/resources/view/fchomo/node.js:1290 +#: htdocs/luci-static/resources/view/fchomo/node.js:1348 msgid "Maximum streams" msgstr "最大流数量" @@ -1788,7 +1823,12 @@ msgstr "Mihomo 服务端" msgid "Min of idle sessions to keep" msgstr "要保留的最少闲置会话数" -#: htdocs/luci-static/resources/view/fchomo/node.js:1284 +#: htdocs/luci-static/resources/view/fchomo/node.js:737 +msgid "Min streams" +msgstr "" + +#: htdocs/luci-static/resources/view/fchomo/node.js:738 +#: htdocs/luci-static/resources/view/fchomo/node.js:1342 msgid "" "Minimum multiplexed streams in a connection before opening a new connection." msgstr "在打开新连接之前,连接中的最小多路复用流数量。" @@ -1798,8 +1838,8 @@ msgstr "在打开新连接之前,连接中的最小多路复用流数量。" msgid "Minimum padding rate" msgstr "最小填充率" -#: htdocs/luci-static/resources/view/fchomo/node.js:1283 -#: htdocs/luci-static/resources/view/fchomo/node.js:1293 +#: htdocs/luci-static/resources/view/fchomo/node.js:1341 +#: htdocs/luci-static/resources/view/fchomo/node.js:1351 msgid "Minimum streams" msgstr "最小流数量" @@ -1816,7 +1856,7 @@ msgstr "混合 系统 TCP 栈和 gVisor UDP 栈。" msgid "Mixed port" msgstr "混合端口" -#: htdocs/luci-static/resources/view/fchomo/node.js:1263 +#: htdocs/luci-static/resources/view/fchomo/node.js:1321 msgid "Multiplex" msgstr "多路复用" @@ -1838,7 +1878,7 @@ msgstr "NOT" msgid "Name of the Proxy group as outbound." msgstr "出站代理组的名称。" -#: htdocs/luci-static/resources/view/fchomo/node.js:1569 +#: htdocs/luci-static/resources/view/fchomo/node.js:1627 msgid "Name of the Proxy group to download provider." msgstr "用于下载供应商订阅的代理组名称。" @@ -1866,16 +1906,20 @@ msgstr "网络类型" msgid "No Authentication IP ranges" msgstr "无需认证的 IP 范围" +#: htdocs/luci-static/resources/fchomo/listeners.js:1023 +msgid "No SSE header" +msgstr "无 SSE header" + #: htdocs/luci-static/resources/view/fchomo/client.js:1508 msgid "No add'l params" msgstr "无附加参数" -#: htdocs/luci-static/resources/view/fchomo/node.js:1252 +#: htdocs/luci-static/resources/view/fchomo/node.js:1274 msgid "No gRPC header" msgstr "无 gRPC header" #: htdocs/luci-static/resources/view/fchomo/client.js:1115 -#: htdocs/luci-static/resources/view/fchomo/node.js:1715 +#: htdocs/luci-static/resources/view/fchomo/node.js:1773 msgid "No testing is performed when this provider node is not in use." msgstr "当此供应商的节点未使用时,不执行任何测试。" @@ -1894,17 +1938,17 @@ msgid "Node" msgstr "节点" #: htdocs/luci-static/resources/view/fchomo/client.js:1160 -#: htdocs/luci-static/resources/view/fchomo/node.js:1735 +#: htdocs/luci-static/resources/view/fchomo/node.js:1793 msgid "Node exclude filter" msgstr "排除节点" #: htdocs/luci-static/resources/view/fchomo/client.js:1165 -#: htdocs/luci-static/resources/view/fchomo/node.js:1742 +#: htdocs/luci-static/resources/view/fchomo/node.js:1800 msgid "Node exclude type" msgstr "排除节点类型" #: htdocs/luci-static/resources/view/fchomo/client.js:1155 -#: htdocs/luci-static/resources/view/fchomo/node.js:1729 +#: htdocs/luci-static/resources/view/fchomo/node.js:1787 msgid "Node filter" msgstr "过滤节点" @@ -1932,7 +1976,7 @@ msgstr "" msgid "ON" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:815 +#: htdocs/luci-static/resources/view/fchomo/node.js:835 msgid "Obfs Mode" msgstr "Obfs 模式" @@ -1982,7 +2026,7 @@ msgid "Override destination" msgstr "覆盖目标地址" #: htdocs/luci-static/resources/view/fchomo/client.js:1010 -#: htdocs/luci-static/resources/view/fchomo/node.js:1480 +#: htdocs/luci-static/resources/view/fchomo/node.js:1538 msgid "Override fields" msgstr "覆盖字段" @@ -2002,7 +2046,7 @@ msgstr "使用嗅探到的域名覆盖连接目标。" msgid "Override the existing ECS in original request." msgstr "覆盖原始请求中已有的 ECS。" -#: htdocs/luci-static/resources/view/fchomo/node.js:1086 +#: htdocs/luci-static/resources/view/fchomo/node.js:1106 msgid "Overrides the domain name used for HTTPS record queries." msgstr "覆盖用于 HTTPS 记录查询的域名。" @@ -2010,11 +2054,11 @@ msgstr "覆盖用于 HTTPS 记录查询的域名。" msgid "Overview" msgstr "概览" -#: htdocs/luci-static/resources/view/fchomo/node.js:1181 +#: htdocs/luci-static/resources/view/fchomo/node.js:1201 msgid "POST" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1182 +#: htdocs/luci-static/resources/view/fchomo/node.js:1202 msgid "PUT" msgstr "" @@ -2022,7 +2066,7 @@ msgstr "" msgid "Packet encoding" msgstr "数据包编码" -#: htdocs/luci-static/resources/view/fchomo/node.js:1257 +#: htdocs/luci-static/resources/view/fchomo/node.js:1279 msgid "Padding bytes" msgstr "填充字节" @@ -2031,7 +2075,7 @@ msgid "Padding scheme" msgstr "填充方案" #: htdocs/luci-static/resources/fchomo/listeners.js:647 -#: htdocs/luci-static/resources/view/fchomo/node.js:929 +#: htdocs/luci-static/resources/view/fchomo/node.js:949 msgid "Paddings" msgstr "填充 (Paddings)" @@ -2040,17 +2084,17 @@ msgstr "填充 (Paddings)" #: htdocs/luci-static/resources/fchomo/listeners.js:508 #: htdocs/luci-static/resources/view/fchomo/node.js:261 #: htdocs/luci-static/resources/view/fchomo/node.js:340 -#: htdocs/luci-static/resources/view/fchomo/node.js:830 +#: htdocs/luci-static/resources/view/fchomo/node.js:850 msgid "Password" msgstr "密码" #: htdocs/luci-static/resources/fchomo/listeners.js:587 -#: htdocs/luci-static/resources/view/fchomo/node.js:1544 +#: htdocs/luci-static/resources/view/fchomo/node.js:1602 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:364 msgid "Payload" msgstr "Payload" -#: htdocs/luci-static/resources/view/fchomo/node.js:754 +#: htdocs/luci-static/resources/view/fchomo/node.js:774 msgid "Peer pubkic key" msgstr "对端公钥" @@ -2060,11 +2104,11 @@ msgid "" "it is not needed." msgstr "性能可能会略有下降,建议仅在需要时开启。" -#: htdocs/luci-static/resources/view/fchomo/node.js:781 +#: htdocs/luci-static/resources/view/fchomo/node.js:801 msgid "Periodically sends data packets to maintain connection persistence." msgstr "定期发送数据包以维持连接持久性。" -#: htdocs/luci-static/resources/view/fchomo/node.js:780 +#: htdocs/luci-static/resources/view/fchomo/node.js:800 msgid "Persistent keepalive" msgstr "持久连接" @@ -2087,8 +2131,8 @@ msgid "" "standards." msgstr "链接格式标准请参考 %s。" -#: htdocs/luci-static/resources/view/fchomo/node.js:1517 -#: htdocs/luci-static/resources/view/fchomo/node.js:1543 +#: htdocs/luci-static/resources/view/fchomo/node.js:1575 +#: htdocs/luci-static/resources/view/fchomo/node.js:1601 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:337 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:363 msgid "" @@ -2103,25 +2147,25 @@ msgstr "" #: htdocs/luci-static/resources/view/fchomo/client.js:1445 #: htdocs/luci-static/resources/view/fchomo/client.js:1697 #: htdocs/luci-static/resources/view/fchomo/client.js:1749 -#: htdocs/luci-static/resources/view/fchomo/node.js:1387 +#: htdocs/luci-static/resources/view/fchomo/node.js:1445 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:154 msgid "Please type %s fields of mihomo config.
" msgstr "请输入 mihomo 配置的 %s 字段。
" #: htdocs/luci-static/resources/fchomo/listeners.js:494 -#: htdocs/luci-static/resources/view/fchomo/node.js:804 +#: htdocs/luci-static/resources/view/fchomo/node.js:824 msgid "Plugin" msgstr "插件" #: htdocs/luci-static/resources/fchomo/listeners.js:501 #: htdocs/luci-static/resources/fchomo/listeners.js:508 #: htdocs/luci-static/resources/fchomo/listeners.js:514 -#: htdocs/luci-static/resources/view/fchomo/node.js:815 -#: htdocs/luci-static/resources/view/fchomo/node.js:822 -#: htdocs/luci-static/resources/view/fchomo/node.js:830 -#: htdocs/luci-static/resources/view/fchomo/node.js:836 -#: htdocs/luci-static/resources/view/fchomo/node.js:844 +#: htdocs/luci-static/resources/view/fchomo/node.js:835 +#: htdocs/luci-static/resources/view/fchomo/node.js:842 #: htdocs/luci-static/resources/view/fchomo/node.js:850 +#: htdocs/luci-static/resources/view/fchomo/node.js:856 +#: htdocs/luci-static/resources/view/fchomo/node.js:864 +#: htdocs/luci-static/resources/view/fchomo/node.js:870 msgid "Plugin:" msgstr "插件:" @@ -2151,7 +2195,7 @@ msgid "Ports pool" msgstr "端口池" #: htdocs/luci-static/resources/view/fchomo/node.js:499 -#: htdocs/luci-static/resources/view/fchomo/node.js:761 +#: htdocs/luci-static/resources/view/fchomo/node.js:781 msgid "Pre-shared key" msgstr "预共享密钥" @@ -2170,10 +2214,10 @@ msgstr "防止某些情况下的 ICMP 环回问题。Ping 不会显示实际延 #: htdocs/luci-static/resources/view/fchomo/global.js:736 #: htdocs/luci-static/resources/view/fchomo/global.js:753 -#: htdocs/luci-static/resources/view/fchomo/node.js:1351 -#: htdocs/luci-static/resources/view/fchomo/node.js:1357 -#: htdocs/luci-static/resources/view/fchomo/node.js:1664 -#: htdocs/luci-static/resources/view/fchomo/node.js:1671 +#: htdocs/luci-static/resources/view/fchomo/node.js:1409 +#: htdocs/luci-static/resources/view/fchomo/node.js:1415 +#: htdocs/luci-static/resources/view/fchomo/node.js:1722 +#: htdocs/luci-static/resources/view/fchomo/node.js:1729 msgid "Priority: Proxy Node > Global." msgstr "优先级: 代理节点 > 全局。" @@ -2186,7 +2230,7 @@ msgid "Priv-key passphrase" msgstr "密钥密码" #: htdocs/luci-static/resources/view/fchomo/node.js:674 -#: htdocs/luci-static/resources/view/fchomo/node.js:746 +#: htdocs/luci-static/resources/view/fchomo/node.js:766 msgid "Private key" msgstr "私钥" @@ -2195,7 +2239,7 @@ msgid "Process matching mode" msgstr "进程匹配模式" #: htdocs/luci-static/resources/view/fchomo/global.js:684 -#: htdocs/luci-static/resources/view/fchomo/node.js:1269 +#: htdocs/luci-static/resources/view/fchomo/node.js:1327 msgid "Protocol" msgstr "协议" @@ -2210,13 +2254,13 @@ msgid "" msgstr "协议参数。 如启用会随机浪费流量(在 v2ray 中默认启用并且无法禁用)。" #: htdocs/luci-static/resources/view/fchomo/client.js:1055 -#: htdocs/luci-static/resources/view/fchomo/node.js:1370 -#: htdocs/luci-static/resources/view/fchomo/node.js:1379 -#: htdocs/luci-static/resources/view/fchomo/node.js:1780 +#: htdocs/luci-static/resources/view/fchomo/node.js:1428 +#: htdocs/luci-static/resources/view/fchomo/node.js:1437 +#: htdocs/luci-static/resources/view/fchomo/node.js:1838 msgid "Provider" msgstr "供应商" -#: htdocs/luci-static/resources/view/fchomo/node.js:1550 +#: htdocs/luci-static/resources/view/fchomo/node.js:1608 msgid "Provider URL" msgstr "供应商订阅 URL" @@ -2239,19 +2283,19 @@ msgid "Proxy MAC-s" msgstr "代理 MAC 地址" #: htdocs/luci-static/resources/view/fchomo/node.js:208 -#: htdocs/luci-static/resources/view/fchomo/node.js:1779 +#: htdocs/luci-static/resources/view/fchomo/node.js:1837 msgid "Proxy Node" msgstr "代理节点" -#: htdocs/luci-static/resources/view/fchomo/node.js:1755 -#: htdocs/luci-static/resources/view/fchomo/node.js:1764 +#: htdocs/luci-static/resources/view/fchomo/node.js:1813 +#: htdocs/luci-static/resources/view/fchomo/node.js:1822 msgid "Proxy chain" msgstr "代理链" #: htdocs/luci-static/resources/fchomo/listeners.js:530 #: htdocs/luci-static/resources/view/fchomo/client.js:783 #: htdocs/luci-static/resources/view/fchomo/client.js:1543 -#: htdocs/luci-static/resources/view/fchomo/node.js:1568 +#: htdocs/luci-static/resources/view/fchomo/node.js:1626 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:388 msgid "Proxy group" msgstr "代理组" @@ -2279,11 +2323,11 @@ msgid "Quick Reload" msgstr "快速重载" #: htdocs/luci-static/resources/fchomo/listeners.js:917 -#: htdocs/luci-static/resources/view/fchomo/node.js:1100 +#: htdocs/luci-static/resources/view/fchomo/node.js:1120 msgid "REALITY" msgstr "REALITY" -#: htdocs/luci-static/resources/view/fchomo/node.js:1115 +#: htdocs/luci-static/resources/view/fchomo/node.js:1135 msgid "REALITY X25519MLKEM768 PQC support" msgstr "REALITY X25519MLKEM768 后量子加密支持" @@ -2300,18 +2344,18 @@ msgid "REALITY private key" msgstr "REALITY 私钥" #: htdocs/luci-static/resources/fchomo/listeners.js:944 -#: htdocs/luci-static/resources/view/fchomo/node.js:1105 +#: htdocs/luci-static/resources/view/fchomo/node.js:1125 msgid "REALITY public key" msgstr "REALITY 公钥" #: htdocs/luci-static/resources/fchomo/listeners.js:948 -#: htdocs/luci-static/resources/view/fchomo/node.js:1110 +#: htdocs/luci-static/resources/view/fchomo/node.js:1130 msgid "REALITY short ID" msgstr "REALITY 标识符" #: htdocs/luci-static/resources/fchomo/listeners.js:618 #: htdocs/luci-static/resources/fchomo/listeners.js:637 -#: htdocs/luci-static/resources/view/fchomo/node.js:919 +#: htdocs/luci-static/resources/view/fchomo/node.js:939 msgid "RTT" msgstr "" @@ -2358,13 +2402,13 @@ msgstr "重载" msgid "Reload All" msgstr "重载所有" -#: htdocs/luci-static/resources/view/fchomo/node.js:1495 +#: htdocs/luci-static/resources/view/fchomo/node.js:1553 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:278 msgid "Remote" msgstr "远程" #: htdocs/luci-static/resources/view/fchomo/node.js:709 -#: htdocs/luci-static/resources/view/fchomo/node.js:792 +#: htdocs/luci-static/resources/view/fchomo/node.js:812 msgid "Remote DNS resolve" msgstr "远程 DNS 解析" @@ -2373,18 +2417,18 @@ msgid "Remove" msgstr "移除" #: htdocs/luci-static/resources/fchomo.js:1354 -#: htdocs/luci-static/resources/view/fchomo/node.js:1471 -#: htdocs/luci-static/resources/view/fchomo/node.js:1473 +#: htdocs/luci-static/resources/view/fchomo/node.js:1529 +#: htdocs/luci-static/resources/view/fchomo/node.js:1531 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:251 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:253 msgid "Remove idles" msgstr "移除闲置" -#: htdocs/luci-static/resources/view/fchomo/node.js:1597 +#: htdocs/luci-static/resources/view/fchomo/node.js:1655 msgid "Replace name" msgstr "名称替换" -#: htdocs/luci-static/resources/view/fchomo/node.js:1598 +#: htdocs/luci-static/resources/view/fchomo/node.js:1656 msgid "Replace node name." msgstr "替换节点名称" @@ -2392,9 +2436,9 @@ msgstr "替换节点名称" msgid "Request" msgstr "" -#: htdocs/luci-static/resources/fchomo/listeners.js:996 -#: htdocs/luci-static/resources/view/fchomo/node.js:1188 -#: htdocs/luci-static/resources/view/fchomo/node.js:1195 +#: htdocs/luci-static/resources/fchomo/listeners.js:1002 +#: htdocs/luci-static/resources/view/fchomo/node.js:1208 +#: htdocs/luci-static/resources/view/fchomo/node.js:1215 msgid "Request path" msgstr "请求路径" @@ -2411,11 +2455,11 @@ msgid "Require any" msgstr "" #: htdocs/luci-static/resources/fchomo.js:384 -#: htdocs/luci-static/resources/view/fchomo/node.js:1116 +#: htdocs/luci-static/resources/view/fchomo/node.js:1136 msgid "Requires server support." msgstr "需要服务器支持。" -#: htdocs/luci-static/resources/view/fchomo/node.js:775 +#: htdocs/luci-static/resources/view/fchomo/node.js:795 msgid "Reserved field bytes" msgstr "保留字段字节" @@ -2423,7 +2467,7 @@ msgstr "保留字段字节" msgid "Resources management" msgstr "资源管理" -#: htdocs/luci-static/resources/view/fchomo/node.js:850 +#: htdocs/luci-static/resources/view/fchomo/node.js:870 msgid "Restls script" msgstr "Restls 剧本" @@ -2459,8 +2503,8 @@ msgstr "路由 DSCP" msgid "Routing GFW" msgstr "路由 GFW 流量" -#: htdocs/luci-static/resources/view/fchomo/node.js:1356 -#: htdocs/luci-static/resources/view/fchomo/node.js:1670 +#: htdocs/luci-static/resources/view/fchomo/node.js:1414 +#: htdocs/luci-static/resources/view/fchomo/node.js:1728 msgid "Routing mark" msgstr "路由标记" @@ -2548,7 +2592,7 @@ msgstr "" msgid "SUB-RULE" msgstr "SUB-RULE" -#: htdocs/luci-static/resources/view/fchomo/node.js:876 +#: htdocs/luci-static/resources/view/fchomo/node.js:896 msgid "SUoT version" msgstr "SUoT 版本" @@ -2598,8 +2642,9 @@ msgstr "服务端" msgid "Server address" msgstr "服务器地址" -#: htdocs/luci-static/resources/view/fchomo/node.js:1167 -#: htdocs/luci-static/resources/view/fchomo/node.js:1173 +#: htdocs/luci-static/resources/fchomo/listeners.js:996 +#: htdocs/luci-static/resources/view/fchomo/node.js:1187 +#: htdocs/luci-static/resources/view/fchomo/node.js:1193 msgid "Server hostname" msgstr "服务器主机名称" @@ -2631,7 +2676,7 @@ msgstr "Shadowsocks 加密" msgid "Shadowsocks password" msgstr "Shadowsocks 密码" -#: htdocs/luci-static/resources/view/fchomo/node.js:1311 +#: htdocs/luci-static/resources/view/fchomo/node.js:1369 msgid "Show connections in the dashboard for breaking connections easier." msgstr "在面板中显示连接以便于打断连接。" @@ -2643,14 +2688,14 @@ msgstr "静音" msgid "Simple round-robin all nodes" msgstr "简单轮替所有节点" -#: htdocs/luci-static/resources/view/fchomo/node.js:1556 +#: htdocs/luci-static/resources/view/fchomo/node.js:1614 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:376 msgid "Size limit" msgstr "大小限制" #: htdocs/luci-static/resources/view/fchomo/client.js:1576 -#: htdocs/luci-static/resources/view/fchomo/node.js:1037 -#: htdocs/luci-static/resources/view/fchomo/node.js:1648 +#: htdocs/luci-static/resources/view/fchomo/node.js:1057 +#: htdocs/luci-static/resources/view/fchomo/node.js:1706 msgid "Skip cert verify" msgstr "跳过证书验证" @@ -2778,7 +2823,7 @@ msgstr "TCP" msgid "TCP concurrency" msgstr "TCP 并发" -#: htdocs/luci-static/resources/view/fchomo/node.js:1304 +#: htdocs/luci-static/resources/view/fchomo/node.js:1362 msgid "TCP only" msgstr "仅 TCP" @@ -2804,25 +2849,25 @@ msgstr "TCP-Keep-Alive 间隔" msgid "TCP/UDP" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1335 -#: htdocs/luci-static/resources/view/fchomo/node.js:1615 +#: htdocs/luci-static/resources/view/fchomo/node.js:1393 +#: htdocs/luci-static/resources/view/fchomo/node.js:1673 msgid "TFO" msgstr "TCP 快速打开 (TFO)" #: htdocs/luci-static/resources/fchomo/listeners.js:772 #: htdocs/luci-static/resources/view/fchomo/global.js:529 #: htdocs/luci-static/resources/view/fchomo/node.js:464 -#: htdocs/luci-static/resources/view/fchomo/node.js:817 -#: htdocs/luci-static/resources/view/fchomo/node.js:951 +#: htdocs/luci-static/resources/view/fchomo/node.js:837 +#: htdocs/luci-static/resources/view/fchomo/node.js:971 msgid "TLS" msgstr "TLS" #: htdocs/luci-static/resources/fchomo/listeners.js:809 -#: htdocs/luci-static/resources/view/fchomo/node.js:982 +#: htdocs/luci-static/resources/view/fchomo/node.js:1002 msgid "TLS ALPN" msgstr "TLS ALPN" -#: htdocs/luci-static/resources/view/fchomo/node.js:976 +#: htdocs/luci-static/resources/view/fchomo/node.js:996 msgid "TLS SNI" msgstr "" @@ -2854,24 +2899,24 @@ msgstr "让客户端使用 BBR 流控算法。" msgid "The %s address used by local machine in the Cloudflare WARP network." msgstr "Cloudflare WARP 网络中使用的本机 %s 地址。" -#: htdocs/luci-static/resources/view/fchomo/node.js:733 -#: htdocs/luci-static/resources/view/fchomo/node.js:741 +#: htdocs/luci-static/resources/view/fchomo/node.js:753 +#: htdocs/luci-static/resources/view/fchomo/node.js:761 msgid "The %s address used by local machine in the Wireguard network." msgstr "WireGuard 网络中使用的本机 %s 地址。" #: htdocs/luci-static/resources/fchomo/listeners.js:830 -#: htdocs/luci-static/resources/view/fchomo/node.js:1060 +#: htdocs/luci-static/resources/view/fchomo/node.js:1080 msgid "The %s private key, in PEM format." msgstr "%s私钥,需要 PEM 格式。" #: htdocs/luci-static/resources/fchomo/listeners.js:815 #: htdocs/luci-static/resources/fchomo/listeners.js:853 #: htdocs/luci-static/resources/view/fchomo/global.js:550 -#: htdocs/luci-static/resources/view/fchomo/node.js:1046 +#: htdocs/luci-static/resources/view/fchomo/node.js:1066 msgid "The %s public key, in PEM format." msgstr "%s公钥,需要 PEM 格式。" -#: htdocs/luci-static/resources/view/fchomo/node.js:1080 +#: htdocs/luci-static/resources/view/fchomo/node.js:1100 msgid "" "The ECH parameter of the HTTPS record for the domain. Leave empty to resolve " "via DNS." @@ -2890,7 +2935,7 @@ msgid "The default value is 2:00 every day." msgstr "默认值为每天 2:00。" #: htdocs/luci-static/resources/fchomo/listeners.js:650 -#: htdocs/luci-static/resources/view/fchomo/node.js:932 +#: htdocs/luci-static/resources/view/fchomo/node.js:952 msgid "" "The first padding must have a probability of 100% and at least 35 bytes." msgstr "首个填充必须为 100% 的概率并且至少 35 字节。" @@ -2906,7 +2951,7 @@ msgid "The matching %s will be deemed as poisoned." msgstr "匹配 %s 的将被视为已被投毒污染。" #: htdocs/luci-static/resources/fchomo/listeners.js:648 -#: htdocs/luci-static/resources/view/fchomo/node.js:930 +#: htdocs/luci-static/resources/view/fchomo/node.js:950 msgid "The server and client can set different padding parameters." msgstr "服务器和客户端可以设置不同的填充参数。" @@ -2916,8 +2961,8 @@ msgid "This ECH parameter needs to be added to the HTTPS record of the domain." msgstr "此 ECH 参数需要添加到域名的 HTTPS 记录中。" #: htdocs/luci-static/resources/view/fchomo/client.js:1579 -#: htdocs/luci-static/resources/view/fchomo/node.js:1040 -#: htdocs/luci-static/resources/view/fchomo/node.js:1651 +#: htdocs/luci-static/resources/view/fchomo/node.js:1060 +#: htdocs/luci-static/resources/view/fchomo/node.js:1709 msgid "" "This is DANGEROUS, your traffic is almost like " "PLAIN TEXT! Use at your own risk!" @@ -2961,18 +3006,18 @@ msgstr "Tproxy 端口" msgid "Traffic pattern" msgstr "流量模式" -#: htdocs/luci-static/resources/view/fchomo/node.js:1807 +#: htdocs/luci-static/resources/view/fchomo/node.js:1865 msgid "Transit proxy group" msgstr "中转代理组" -#: htdocs/luci-static/resources/view/fchomo/node.js:1813 +#: htdocs/luci-static/resources/view/fchomo/node.js:1871 msgid "Transit proxy node" msgstr "中转代理节点" #: htdocs/luci-static/resources/fchomo/listeners.js:231 #: htdocs/luci-static/resources/fchomo/listeners.js:962 #: htdocs/luci-static/resources/view/fchomo/node.js:355 -#: htdocs/luci-static/resources/view/fchomo/node.js:1122 +#: htdocs/luci-static/resources/view/fchomo/node.js:1142 msgid "Transport" msgstr "传输层" @@ -2982,7 +3027,7 @@ msgid "Transport fields" msgstr "传输层字段" #: htdocs/luci-static/resources/fchomo/listeners.js:967 -#: htdocs/luci-static/resources/view/fchomo/node.js:1127 +#: htdocs/luci-static/resources/view/fchomo/node.js:1147 msgid "Transport type" msgstr "传输层类型" @@ -3027,8 +3072,8 @@ msgstr "" #: htdocs/luci-static/resources/view/fchomo/client.js:842 #: htdocs/luci-static/resources/view/fchomo/client.js:1028 #: htdocs/luci-static/resources/view/fchomo/node.js:238 -#: htdocs/luci-static/resources/view/fchomo/node.js:1493 -#: htdocs/luci-static/resources/view/fchomo/node.js:1778 +#: htdocs/luci-static/resources/view/fchomo/node.js:1551 +#: htdocs/luci-static/resources/view/fchomo/node.js:1836 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:276 msgid "Type" msgstr "类型" @@ -3043,8 +3088,8 @@ msgstr "类型" #: htdocs/luci-static/resources/fchomo/listeners.js:555 #: htdocs/luci-static/resources/view/fchomo/client.js:588 #: htdocs/luci-static/resources/view/fchomo/client.js:678 -#: htdocs/luci-static/resources/view/fchomo/node.js:865 -#: htdocs/luci-static/resources/view/fchomo/node.js:1625 +#: htdocs/luci-static/resources/view/fchomo/node.js:885 +#: htdocs/luci-static/resources/view/fchomo/node.js:1683 msgid "UDP" msgstr "UDP" @@ -3112,8 +3157,8 @@ msgstr "未知错误。" msgid "Unknown error: %s" msgstr "未知错误:%s" -#: htdocs/luci-static/resources/view/fchomo/node.js:870 -#: htdocs/luci-static/resources/view/fchomo/node.js:1630 +#: htdocs/luci-static/resources/view/fchomo/node.js:890 +#: htdocs/luci-static/resources/view/fchomo/node.js:1688 msgid "UoT" msgstr "UDP over TCP (UoT)" @@ -3121,22 +3166,22 @@ msgstr "UDP over TCP (UoT)" msgid "Update failed." msgstr "更新失败。" -#: htdocs/luci-static/resources/view/fchomo/node.js:1562 +#: htdocs/luci-static/resources/view/fchomo/node.js:1620 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:382 msgid "Update interval" msgstr "更新间隔" -#: htdocs/luci-static/resources/view/fchomo/node.js:1322 +#: htdocs/luci-static/resources/view/fchomo/node.js:1380 msgid "Upload bandwidth" msgstr "上传带宽" -#: htdocs/luci-static/resources/view/fchomo/node.js:1323 +#: htdocs/luci-static/resources/view/fchomo/node.js:1381 msgid "Upload bandwidth in Mbps." msgstr "上传带宽(单位:Mbps)。" #: htdocs/luci-static/resources/fchomo/listeners.js:821 #: htdocs/luci-static/resources/fchomo/listeners.js:861 -#: htdocs/luci-static/resources/view/fchomo/node.js:1051 +#: htdocs/luci-static/resources/view/fchomo/node.js:1071 msgid "Upload certificate" msgstr "上传证书" @@ -3145,7 +3190,7 @@ msgid "Upload initial package" msgstr "上传初始资源包" #: htdocs/luci-static/resources/fchomo/listeners.js:836 -#: htdocs/luci-static/resources/view/fchomo/node.js:1065 +#: htdocs/luci-static/resources/view/fchomo/node.js:1085 msgid "Upload key" msgstr "上传密钥" @@ -3153,8 +3198,8 @@ msgstr "上传密钥" #: htdocs/luci-static/resources/fchomo/listeners.js:839 #: htdocs/luci-static/resources/fchomo/listeners.js:864 #: htdocs/luci-static/resources/view/fchomo/global.js:306 -#: htdocs/luci-static/resources/view/fchomo/node.js:1054 -#: htdocs/luci-static/resources/view/fchomo/node.js:1068 +#: htdocs/luci-static/resources/view/fchomo/node.js:1074 +#: htdocs/luci-static/resources/view/fchomo/node.js:1088 msgid "Upload..." msgstr "上传..." @@ -3178,7 +3223,7 @@ msgstr "用于解析 DNS 服务器的域名。必须是 IP。" msgid "Used to resolve the domain of the Proxy node." msgstr "用于解析代理节点的域名。" -#: htdocs/luci-static/resources/view/fchomo/node.js:977 +#: htdocs/luci-static/resources/view/fchomo/node.js:997 msgid "Used to verify the hostname on the returned certificates." msgstr "用于验证返回的证书上的主机名。" @@ -3195,11 +3240,11 @@ msgstr "用户名" msgid "Users filter mode" msgstr "使用者过滤模式" -#: htdocs/luci-static/resources/view/fchomo/node.js:1236 +#: htdocs/luci-static/resources/view/fchomo/node.js:1256 msgid "V2ray HTTPUpgrade" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1241 +#: htdocs/luci-static/resources/view/fchomo/node.js:1261 msgid "V2ray HTTPUpgrade fast open" msgstr "" @@ -3213,8 +3258,8 @@ msgstr "" msgid "VMess" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1499 -#: htdocs/luci-static/resources/view/fchomo/node.js:1784 +#: htdocs/luci-static/resources/view/fchomo/node.js:1557 +#: htdocs/luci-static/resources/view/fchomo/node.js:1842 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:319 msgid "Value" msgstr "可视化值" @@ -3225,11 +3270,11 @@ msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:514 #: htdocs/luci-static/resources/view/fchomo/node.js:506 -#: htdocs/luci-static/resources/view/fchomo/node.js:836 +#: htdocs/luci-static/resources/view/fchomo/node.js:856 msgid "Version" msgstr "版本" -#: htdocs/luci-static/resources/view/fchomo/node.js:844 +#: htdocs/luci-static/resources/view/fchomo/node.js:864 msgid "Version hint" msgstr "" @@ -3248,14 +3293,14 @@ msgstr "警告" #: htdocs/luci-static/resources/fchomo/listeners.js:393 #: htdocs/luci-static/resources/fchomo/listeners.js:969 -#: htdocs/luci-static/resources/fchomo/listeners.js:980 +#: htdocs/luci-static/resources/fchomo/listeners.js:978 #: htdocs/luci-static/resources/fchomo/listeners.js:985 #: htdocs/luci-static/resources/view/fchomo/node.js:460 #: htdocs/luci-static/resources/view/fchomo/node.js:489 -#: htdocs/luci-static/resources/view/fchomo/node.js:1132 -#: htdocs/luci-static/resources/view/fchomo/node.js:1143 -#: htdocs/luci-static/resources/view/fchomo/node.js:1150 -#: htdocs/luci-static/resources/view/fchomo/node.js:1156 +#: htdocs/luci-static/resources/view/fchomo/node.js:1152 +#: htdocs/luci-static/resources/view/fchomo/node.js:1163 +#: htdocs/luci-static/resources/view/fchomo/node.js:1170 +#: htdocs/luci-static/resources/view/fchomo/node.js:1176 msgid "WebSocket" msgstr "" @@ -3271,27 +3316,42 @@ msgstr "白名单" msgid "WireGuard" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:755 +#: htdocs/luci-static/resources/view/fchomo/node.js:775 msgid "WireGuard peer public key." msgstr "WireGuard 对端公钥。" -#: htdocs/luci-static/resources/view/fchomo/node.js:762 +#: htdocs/luci-static/resources/view/fchomo/node.js:782 msgid "WireGuard pre-shared key." msgstr "WireGuard 预共享密钥。" -#: htdocs/luci-static/resources/view/fchomo/node.js:747 +#: htdocs/luci-static/resources/view/fchomo/node.js:767 msgid "WireGuard requires base64-encoded private keys." msgstr "WireGuard 要求 base64 编码的私钥。" -#: htdocs/luci-static/resources/view/fchomo/node.js:1133 -#: htdocs/luci-static/resources/view/fchomo/node.js:1151 +#: htdocs/luci-static/resources/fchomo/listeners.js:970 +#: htdocs/luci-static/resources/fchomo/listeners.js:979 +#: htdocs/luci-static/resources/view/fchomo/node.js:1153 +#: htdocs/luci-static/resources/view/fchomo/node.js:1171 msgid "XHTTP" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1246 +#: htdocs/luci-static/resources/fchomo/listeners.js:1015 +#: htdocs/luci-static/resources/view/fchomo/node.js:1266 msgid "XHTTP mode" msgstr "XHTTP 模式" +#: htdocs/luci-static/resources/view/fchomo/node.js:1290 +msgid "XMUX" +msgstr "" + +#: htdocs/luci-static/resources/view/fchomo/node.js:1295 +#: htdocs/luci-static/resources/view/fchomo/node.js:1300 +#: htdocs/luci-static/resources/view/fchomo/node.js:1305 +#: htdocs/luci-static/resources/view/fchomo/node.js:1310 +#: htdocs/luci-static/resources/view/fchomo/node.js:1315 +msgid "XMUX:" +msgstr "" + #: htdocs/luci-static/resources/fchomo/listeners.js:609 msgid "XOR mode" msgstr "XOR 模式" @@ -3338,7 +3398,7 @@ msgstr "bbr" #: htdocs/luci-static/resources/fchomo/listeners.js:826 #: htdocs/luci-static/resources/fchomo/listeners.js:866 -#: htdocs/luci-static/resources/view/fchomo/node.js:1056 +#: htdocs/luci-static/resources/view/fchomo/node.js:1076 msgid "certificate" msgstr "证书" @@ -3365,13 +3425,13 @@ msgstr "decryption" msgid "dnsmasq selects upstream on its own. (may affect CDN accuracy)" msgstr "dnsmasq 自行选择上游服务器。 (可能影响 CDN 准确性)" -#: htdocs/luci-static/resources/view/fchomo/node.js:1642 +#: htdocs/luci-static/resources/view/fchomo/node.js:1700 msgid "down" msgstr "Hysteria 下载速率" #: htdocs/luci-static/resources/fchomo/listeners.js:596 -#: htdocs/luci-static/resources/view/fchomo/node.js:884 -#: htdocs/luci-static/resources/view/fchomo/node.js:907 +#: htdocs/luci-static/resources/view/fchomo/node.js:904 +#: htdocs/luci-static/resources/view/fchomo/node.js:927 msgid "encryption" msgstr "encryption" @@ -3381,25 +3441,25 @@ msgid "false = bandwidth optimized downlink; true = pure Sudoku downlink." msgstr "false = 带宽优化下行 true = 纯 Sudoku 下行。" #: htdocs/luci-static/resources/fchomo/listeners.js:968 -#: htdocs/luci-static/resources/fchomo/listeners.js:979 +#: htdocs/luci-static/resources/fchomo/listeners.js:977 #: htdocs/luci-static/resources/fchomo/listeners.js:984 -#: htdocs/luci-static/resources/view/fchomo/node.js:1131 -#: htdocs/luci-static/resources/view/fchomo/node.js:1142 -#: htdocs/luci-static/resources/view/fchomo/node.js:1149 -#: htdocs/luci-static/resources/view/fchomo/node.js:1155 +#: htdocs/luci-static/resources/view/fchomo/node.js:1151 +#: htdocs/luci-static/resources/view/fchomo/node.js:1162 +#: htdocs/luci-static/resources/view/fchomo/node.js:1169 +#: htdocs/luci-static/resources/view/fchomo/node.js:1175 msgid "gRPC" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1212 +#: htdocs/luci-static/resources/view/fchomo/node.js:1232 msgid "gRPC User-Agent" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1217 +#: htdocs/luci-static/resources/view/fchomo/node.js:1237 msgid "gRPC ping interval" msgstr "gRPC ping 间隔" -#: htdocs/luci-static/resources/fchomo/listeners.js:1003 -#: htdocs/luci-static/resources/view/fchomo/node.js:1208 +#: htdocs/luci-static/resources/fchomo/listeners.js:1009 +#: htdocs/luci-static/resources/view/fchomo/node.js:1228 msgid "gRPC service name" msgstr "gRPC 服务名称" @@ -3407,7 +3467,7 @@ msgstr "gRPC 服务名称" msgid "gVisor" msgstr "gVisor" -#: htdocs/luci-static/resources/view/fchomo/node.js:1273 +#: htdocs/luci-static/resources/view/fchomo/node.js:1331 msgid "h2mux" msgstr "" @@ -3425,7 +3485,7 @@ msgstr "metacubexd" #: htdocs/luci-static/resources/view/fchomo/client.js:1480 #: htdocs/luci-static/resources/view/fchomo/client.js:1711 #: htdocs/luci-static/resources/view/fchomo/client.js:1767 -#: htdocs/luci-static/resources/view/fchomo/node.js:1465 +#: htdocs/luci-static/resources/view/fchomo/node.js:1523 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:239 msgid "mihomo config" msgstr "mihomo 配置" @@ -3434,8 +3494,8 @@ msgstr "mihomo 配置" msgid "mlkem768x25519plus" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1339 -#: htdocs/luci-static/resources/view/fchomo/node.js:1620 +#: htdocs/luci-static/resources/view/fchomo/node.js:1397 +#: htdocs/luci-static/resources/view/fchomo/node.js:1678 msgid "mpTCP" msgstr "多路径 TCP (mpTCP)" @@ -3460,7 +3520,7 @@ msgstr "非空值" #: htdocs/luci-static/resources/fchomo/listeners.js:495 #: htdocs/luci-static/resources/view/fchomo/node.js:647 #: htdocs/luci-static/resources/view/fchomo/node.js:667 -#: htdocs/luci-static/resources/view/fchomo/node.js:805 +#: htdocs/luci-static/resources/view/fchomo/node.js:825 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:315 msgid "none" msgstr "无" @@ -3479,7 +3539,7 @@ msgstr "不包含 \",\"" msgid "null" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:806 +#: htdocs/luci-static/resources/view/fchomo/node.js:826 msgid "obfs-simple" msgstr "" @@ -3491,7 +3551,7 @@ msgstr "仅当 %s 为 %s 时适用。" msgid "only applies when %s is not %s." msgstr "仅当 %s 不为 %s 时适用。" -#: htdocs/luci-static/resources/view/fchomo/node.js:1600 +#: htdocs/luci-static/resources/view/fchomo/node.js:1658 msgid "override.proxy-name" msgstr "" @@ -3499,7 +3559,8 @@ msgstr "" msgid "packet addr (v2ray-core v5+)" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1248 +#: htdocs/luci-static/resources/fchomo/listeners.js:1019 +#: htdocs/luci-static/resources/view/fchomo/node.js:1270 msgid "packet-up" msgstr "" @@ -3509,7 +3570,7 @@ msgid "poll" msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:841 -#: htdocs/luci-static/resources/view/fchomo/node.js:1070 +#: htdocs/luci-static/resources/view/fchomo/node.js:1090 msgid "private key" msgstr "私钥" @@ -3522,7 +3583,7 @@ msgstr "razord-meta" msgid "requires front-end adaptation using the API." msgstr "需要使用 API 的前端适配。" -#: htdocs/luci-static/resources/view/fchomo/node.js:810 +#: htdocs/luci-static/resources/view/fchomo/node.js:830 msgid "restls" msgstr "" @@ -3531,11 +3592,11 @@ msgid "rule-set" msgstr "规则集" #: htdocs/luci-static/resources/fchomo/listeners.js:496 -#: htdocs/luci-static/resources/view/fchomo/node.js:809 +#: htdocs/luci-static/resources/view/fchomo/node.js:829 msgid "shadow-tls" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1271 +#: htdocs/luci-static/resources/view/fchomo/node.js:1329 msgid "smux" msgstr "" @@ -3548,10 +3609,20 @@ msgstr "" msgid "src" msgstr "src" -#: htdocs/luci-static/resources/view/fchomo/node.js:1247 +#: htdocs/luci-static/resources/fchomo/listeners.js:1017 +#: htdocs/luci-static/resources/view/fchomo/node.js:1268 msgid "stream-one" msgstr "" +#: htdocs/luci-static/resources/fchomo/listeners.js:1018 +#: htdocs/luci-static/resources/view/fchomo/node.js:1269 +msgid "stream-up" +msgstr "" + +#: htdocs/luci-static/resources/fchomo/listeners.js:1028 +msgid "stream-up server seconds" +msgstr "" + #: htdocs/luci-static/resources/view/fchomo/node.js:491 msgid "stream/poll/auto" msgstr "" @@ -3576,28 +3647,28 @@ msgstr "独立标识" msgid "unique value" msgstr "独立值" -#: htdocs/luci-static/resources/view/fchomo/node.js:1636 +#: htdocs/luci-static/resources/view/fchomo/node.js:1694 msgid "up" msgstr "Hysteria 上传速率" #: htdocs/luci-static/resources/fchomo/listeners.js:515 #: htdocs/luci-static/resources/view/fchomo/node.js:507 #: htdocs/luci-static/resources/view/fchomo/node.js:542 -#: htdocs/luci-static/resources/view/fchomo/node.js:837 -#: htdocs/luci-static/resources/view/fchomo/node.js:877 +#: htdocs/luci-static/resources/view/fchomo/node.js:857 +#: htdocs/luci-static/resources/view/fchomo/node.js:897 msgid "v1" msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:516 #: htdocs/luci-static/resources/view/fchomo/node.js:508 -#: htdocs/luci-static/resources/view/fchomo/node.js:838 -#: htdocs/luci-static/resources/view/fchomo/node.js:878 +#: htdocs/luci-static/resources/view/fchomo/node.js:858 +#: htdocs/luci-static/resources/view/fchomo/node.js:898 msgid "v2" msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:517 #: htdocs/luci-static/resources/view/fchomo/node.js:509 -#: htdocs/luci-static/resources/view/fchomo/node.js:839 +#: htdocs/luci-static/resources/view/fchomo/node.js:859 msgid "v3" msgstr "" @@ -3606,7 +3677,7 @@ msgstr "" msgid "valid JSON format" msgstr "有效的 JSON 格式" -#: htdocs/luci-static/resources/view/fchomo/node.js:1030 +#: htdocs/luci-static/resources/view/fchomo/node.js:1050 msgid "valid SHA256 string with %d characters" msgstr "包含 %d 个字符的有效 SHA256 字符串" @@ -3652,7 +3723,7 @@ msgstr "" msgid "yacd-meta" msgstr "yacd-meta" -#: htdocs/luci-static/resources/view/fchomo/node.js:1272 +#: htdocs/luci-static/resources/view/fchomo/node.js:1330 msgid "yamux" msgstr "" diff --git a/luci-app-fchomo/po/zh_Hant/fchomo.po b/luci-app-fchomo/po/zh_Hant/fchomo.po index 7426cc83..21dd1701 100644 --- a/luci-app-fchomo/po/zh_Hant/fchomo.po +++ b/luci-app-fchomo/po/zh_Hant/fchomo.po @@ -32,10 +32,10 @@ msgstr "(已導入)" #: htdocs/luci-static/resources/fchomo/listeners.js:861 #: htdocs/luci-static/resources/view/fchomo/global.js:543 #: htdocs/luci-static/resources/view/fchomo/global.js:549 -#: htdocs/luci-static/resources/view/fchomo/node.js:1045 -#: htdocs/luci-static/resources/view/fchomo/node.js:1051 -#: htdocs/luci-static/resources/view/fchomo/node.js:1059 #: htdocs/luci-static/resources/view/fchomo/node.js:1065 +#: htdocs/luci-static/resources/view/fchomo/node.js:1071 +#: htdocs/luci-static/resources/view/fchomo/node.js:1079 +#: htdocs/luci-static/resources/view/fchomo/node.js:1085 msgid "(mTLS)" msgstr "" @@ -46,10 +46,10 @@ msgstr "" #: htdocs/luci-static/resources/view/fchomo/client.js:1056 #: htdocs/luci-static/resources/view/fchomo/client.js:1057 #: htdocs/luci-static/resources/view/fchomo/client.js:1278 -#: htdocs/luci-static/resources/view/fchomo/node.js:1788 -#: htdocs/luci-static/resources/view/fchomo/node.js:1794 -#: htdocs/luci-static/resources/view/fchomo/node.js:1808 -#: htdocs/luci-static/resources/view/fchomo/node.js:1814 +#: htdocs/luci-static/resources/view/fchomo/node.js:1846 +#: htdocs/luci-static/resources/view/fchomo/node.js:1852 +#: htdocs/luci-static/resources/view/fchomo/node.js:1866 +#: htdocs/luci-static/resources/view/fchomo/node.js:1872 msgid "-- Please choose --" msgstr "-- 請選擇 --" @@ -85,8 +85,8 @@ msgstr "僅限 01。" #: htdocs/luci-static/resources/fchomo/listeners.js:822 #: htdocs/luci-static/resources/fchomo/listeners.js:837 #: htdocs/luci-static/resources/fchomo/listeners.js:862 -#: htdocs/luci-static/resources/view/fchomo/node.js:1052 -#: htdocs/luci-static/resources/view/fchomo/node.js:1066 +#: htdocs/luci-static/resources/view/fchomo/node.js:1072 +#: htdocs/luci-static/resources/view/fchomo/node.js:1086 msgid "Save your configuration before uploading files!" msgstr "上傳文件前請先保存配置!" @@ -182,11 +182,11 @@ msgstr "新增 節點" msgid "Add a inbound" msgstr "新增 入站" -#: htdocs/luci-static/resources/view/fchomo/node.js:1379 +#: htdocs/luci-static/resources/view/fchomo/node.js:1437 msgid "Add a provider" msgstr "新增 供應商" -#: htdocs/luci-static/resources/view/fchomo/node.js:1764 +#: htdocs/luci-static/resources/view/fchomo/node.js:1822 msgid "Add a proxy chain" msgstr "新增 代理鏈" @@ -210,11 +210,11 @@ msgstr "新增 伺服器" msgid "Add a sub rule" msgstr "新增 子規則" -#: htdocs/luci-static/resources/view/fchomo/node.js:1589 +#: htdocs/luci-static/resources/view/fchomo/node.js:1647 msgid "Add prefix" msgstr "添加前綴" -#: htdocs/luci-static/resources/view/fchomo/node.js:1593 +#: htdocs/luci-static/resources/view/fchomo/node.js:1651 msgid "Add suffix" msgstr "添加後綴" @@ -251,7 +251,7 @@ msgid "" msgstr "" "允許從私有網路訪問。
要從公共網站訪問私有網路上的 API,則必須啟用。" -#: htdocs/luci-static/resources/view/fchomo/node.js:768 +#: htdocs/luci-static/resources/view/fchomo/node.js:788 msgid "Allowed IPs" msgstr "允許的 IP" @@ -295,9 +295,11 @@ msgid "Authenticated length" msgstr "認證長度" #: htdocs/luci-static/resources/fchomo/listeners.js:392 +#: htdocs/luci-static/resources/fchomo/listeners.js:1016 #: htdocs/luci-static/resources/view/fchomo/global.js:402 #: htdocs/luci-static/resources/view/fchomo/node.js:459 #: htdocs/luci-static/resources/view/fchomo/node.js:483 +#: htdocs/luci-static/resources/view/fchomo/node.js:1267 msgid "Auto" msgstr "自動" @@ -343,13 +345,13 @@ msgid "Binary mrs" msgstr "二進位 mrs" #: htdocs/luci-static/resources/view/fchomo/global.js:734 -#: htdocs/luci-static/resources/view/fchomo/node.js:1349 -#: htdocs/luci-static/resources/view/fchomo/node.js:1662 +#: htdocs/luci-static/resources/view/fchomo/node.js:1407 +#: htdocs/luci-static/resources/view/fchomo/node.js:1720 msgid "Bind interface" msgstr "綁定介面" -#: htdocs/luci-static/resources/view/fchomo/node.js:1350 -#: htdocs/luci-static/resources/view/fchomo/node.js:1663 +#: htdocs/luci-static/resources/view/fchomo/node.js:1408 +#: htdocs/luci-static/resources/view/fchomo/node.js:1721 msgid "Bind outbound interface.
" msgstr "綁定出站介面。
" @@ -414,17 +416,17 @@ msgstr "CORS 允許的來源,留空則使用 *。" msgid "Cancel" msgstr "取消" -#: htdocs/luci-static/resources/view/fchomo/node.js:1024 +#: htdocs/luci-static/resources/view/fchomo/node.js:1044 msgid "Cert fingerprint" msgstr "憑證指紋" -#: htdocs/luci-static/resources/view/fchomo/node.js:1025 +#: htdocs/luci-static/resources/view/fchomo/node.js:1045 msgid "" "Certificate fingerprint. Used to implement SSL Pinning and prevent MitM." msgstr "憑證指紋。用於實現 SSL憑證固定 並防止 MitM。" #: htdocs/luci-static/resources/fchomo/listeners.js:814 -#: htdocs/luci-static/resources/view/fchomo/node.js:1045 +#: htdocs/luci-static/resources/view/fchomo/node.js:1065 msgid "Certificate path" msgstr "憑證路徑" @@ -481,9 +483,9 @@ msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:637 #: htdocs/luci-static/resources/fchomo/listeners.js:853 #: htdocs/luci-static/resources/view/fchomo/global.js:550 -#: htdocs/luci-static/resources/view/fchomo/node.js:919 -#: htdocs/luci-static/resources/view/fchomo/node.js:1046 -#: htdocs/luci-static/resources/view/fchomo/node.js:1060 +#: htdocs/luci-static/resources/view/fchomo/node.js:939 +#: htdocs/luci-static/resources/view/fchomo/node.js:1066 +#: htdocs/luci-static/resources/view/fchomo/node.js:1080 #: root/usr/share/luci/menu.d/luci-app-fchomo.json:22 msgid "Client" msgstr "客戶端" @@ -496,7 +498,7 @@ msgstr "客戶端認證憑證路徑" msgid "Client Auth type" msgstr "客戶端認證類型" -#: htdocs/luci-static/resources/view/fchomo/node.js:1091 +#: htdocs/luci-static/resources/view/fchomo/node.js:1111 msgid "Client fingerprint" msgstr "客戶端指紋" @@ -521,12 +523,12 @@ msgstr "常用連接埠(繞過 P2P 流量)" msgid "Complete" msgstr "完成" -#: htdocs/luci-static/resources/view/fchomo/node.js:1609 +#: htdocs/luci-static/resources/view/fchomo/node.js:1667 msgid "Configuration Items" msgstr "配置項" #: htdocs/luci-static/resources/fchomo/listeners.js:540 -#: htdocs/luci-static/resources/view/fchomo/node.js:857 +#: htdocs/luci-static/resources/view/fchomo/node.js:877 msgid "Congestion controller" msgstr "擁塞控制器" @@ -539,14 +541,14 @@ msgid "Content copied to clipboard!" msgstr "內容已複製到剪貼簿!" #: htdocs/luci-static/resources/view/fchomo/client.js:670 -#: htdocs/luci-static/resources/view/fchomo/node.js:1519 -#: htdocs/luci-static/resources/view/fchomo/node.js:1545 +#: htdocs/luci-static/resources/view/fchomo/node.js:1577 +#: htdocs/luci-static/resources/view/fchomo/node.js:1603 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:339 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:365 msgid "Content will not be verified, Please make sure you enter it correctly." msgstr "內容將不會被驗證,請確保輸入正確。" -#: htdocs/luci-static/resources/view/fchomo/node.js:1518 +#: htdocs/luci-static/resources/view/fchomo/node.js:1576 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:338 msgid "Contents" msgstr "內容" @@ -571,7 +573,7 @@ msgstr "Cron 表達式" msgid "Custom Direct List" msgstr "自訂直連清單" -#: htdocs/luci-static/resources/view/fchomo/node.js:1580 +#: htdocs/luci-static/resources/view/fchomo/node.js:1638 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:400 msgid "Custom HTTP header." msgstr "自訂 HTTP header。" @@ -607,7 +609,7 @@ msgstr " DNS 連接埠" #: htdocs/luci-static/resources/view/fchomo/client.js:1428 #: htdocs/luci-static/resources/view/fchomo/client.js:1437 #: htdocs/luci-static/resources/view/fchomo/node.js:715 -#: htdocs/luci-static/resources/view/fchomo/node.js:798 +#: htdocs/luci-static/resources/view/fchomo/node.js:818 msgid "DNS server" msgstr "DNS 伺服器" @@ -635,15 +637,15 @@ msgstr "預設 DNS(由 WAN 下發)" msgid "Default DNS server" msgstr "預設 DNS 伺服器" -#: htdocs/luci-static/resources/view/fchomo/node.js:769 +#: htdocs/luci-static/resources/view/fchomo/node.js:789 msgid "Destination addresses allowed to be forwarded via Wireguard." msgstr "允許通過 WireGuard 轉發的目的位址" -#: htdocs/luci-static/resources/view/fchomo/node.js:1787 +#: htdocs/luci-static/resources/view/fchomo/node.js:1845 msgid "Destination provider" msgstr "落地供應商" -#: htdocs/luci-static/resources/view/fchomo/node.js:1793 +#: htdocs/luci-static/resources/view/fchomo/node.js:1851 msgid "Destination proxy node" msgstr "落地代理節點" @@ -651,8 +653,8 @@ msgstr "落地代理節點" msgid "Dial fields" msgstr "撥號欄位" -#: htdocs/luci-static/resources/view/fchomo/node.js:1800 -#: htdocs/luci-static/resources/view/fchomo/node.js:1820 +#: htdocs/luci-static/resources/view/fchomo/node.js:1858 +#: htdocs/luci-static/resources/view/fchomo/node.js:1878 msgid "Different chain head/tail" msgstr "不同的鏈頭/鏈尾" @@ -690,7 +692,7 @@ msgstr "停用 quic-go 的 通用分段卸載(GSO)" msgid "Disable ICMP Forwarding" msgstr "禁用 ICMP 轉發" -#: htdocs/luci-static/resources/view/fchomo/node.js:970 +#: htdocs/luci-static/resources/view/fchomo/node.js:990 msgid "Disable SNI" msgstr "停用 SNI" @@ -718,21 +720,21 @@ msgstr "" msgid "Domain" msgstr "網域" -#: htdocs/luci-static/resources/view/fchomo/node.js:971 +#: htdocs/luci-static/resources/view/fchomo/node.js:991 msgid "Donot send server name in ClientHello." msgstr "不要在 ClientHello 中傳送伺服器名稱。" #: htdocs/luci-static/resources/view/fchomo/client.js:1577 -#: htdocs/luci-static/resources/view/fchomo/node.js:1038 -#: htdocs/luci-static/resources/view/fchomo/node.js:1649 +#: htdocs/luci-static/resources/view/fchomo/node.js:1058 +#: htdocs/luci-static/resources/view/fchomo/node.js:1707 msgid "Donot verifying server certificate." msgstr "不驗證伺服器憑證。" -#: htdocs/luci-static/resources/view/fchomo/node.js:1328 +#: htdocs/luci-static/resources/view/fchomo/node.js:1386 msgid "Download bandwidth" msgstr "下載頻寬" -#: htdocs/luci-static/resources/view/fchomo/node.js:1329 +#: htdocs/luci-static/resources/view/fchomo/node.js:1387 msgid "Download bandwidth in Mbps." msgstr "下載頻寬(單位:Mbps)。" @@ -748,12 +750,12 @@ msgstr "下載成功。" msgid "Dual stack" msgstr "雙棧" -#: htdocs/luci-static/resources/view/fchomo/node.js:1085 +#: htdocs/luci-static/resources/view/fchomo/node.js:1105 msgid "ECH HTTPS record query servername" msgstr "ECH HTTPS 記錄查詢網域" #: htdocs/luci-static/resources/fchomo/listeners.js:910 -#: htdocs/luci-static/resources/view/fchomo/node.js:1079 +#: htdocs/luci-static/resources/view/fchomo/node.js:1099 msgid "ECH config" msgstr "ECH 配置" @@ -773,11 +775,11 @@ msgstr "" msgid "ETag support" msgstr "ETag 支援" -#: htdocs/luci-static/resources/view/fchomo/node.js:1225 +#: htdocs/luci-static/resources/view/fchomo/node.js:1245 msgid "Early Data first packet length limit." msgstr "前置數據長度閾值" -#: htdocs/luci-static/resources/view/fchomo/node.js:1231 +#: htdocs/luci-static/resources/view/fchomo/node.js:1251 msgid "Early Data header name" msgstr "前置數據標頭" @@ -793,7 +795,7 @@ msgstr "編輯節點" msgid "Edit ruleset" msgstr "編輯規則集" -#: htdocs/luci-static/resources/view/fchomo/node.js:1516 +#: htdocs/luci-static/resources/view/fchomo/node.js:1574 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:336 msgid "Editer" msgstr "編輯器" @@ -813,9 +815,9 @@ msgstr "消除加密頭特徵" #: htdocs/luci-static/resources/view/fchomo/global.js:401 #: htdocs/luci-static/resources/view/fchomo/global.js:680 #: htdocs/luci-static/resources/view/fchomo/node.js:234 -#: htdocs/luci-static/resources/view/fchomo/node.js:1489 -#: htdocs/luci-static/resources/view/fchomo/node.js:1685 -#: htdocs/luci-static/resources/view/fchomo/node.js:1774 +#: htdocs/luci-static/resources/view/fchomo/node.js:1547 +#: htdocs/luci-static/resources/view/fchomo/node.js:1743 +#: htdocs/luci-static/resources/view/fchomo/node.js:1832 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:264 #: htdocs/luci-static/resources/view/fchomo/server.js:49 msgid "Enable" @@ -842,19 +844,19 @@ msgstr "" "為出站連線啟用 IP4P 轉換" -#: htdocs/luci-static/resources/view/fchomo/node.js:1073 +#: htdocs/luci-static/resources/view/fchomo/node.js:1093 msgid "Enable ECH" msgstr "啟用 ECH" -#: htdocs/luci-static/resources/view/fchomo/node.js:1316 +#: htdocs/luci-static/resources/view/fchomo/node.js:1374 msgid "Enable TCP Brutal" msgstr "啟用 TCP Brutal" -#: htdocs/luci-static/resources/view/fchomo/node.js:1317 +#: htdocs/luci-static/resources/view/fchomo/node.js:1375 msgid "Enable TCP Brutal congestion control algorithm" msgstr "啟用 TCP Brutal 擁塞控制演算法。" -#: htdocs/luci-static/resources/view/fchomo/node.js:1305 +#: htdocs/luci-static/resources/view/fchomo/node.js:1363 msgid "Enable multiplexing only for TCP." msgstr "僅為 TCP 啟用多路復用。" @@ -863,16 +865,16 @@ msgstr "僅為 TCP 啟用多路復用。" msgid "Enable obfuscate for downlink" msgstr "啟用下行鏈路混淆" -#: htdocs/luci-static/resources/view/fchomo/node.js:1299 +#: htdocs/luci-static/resources/view/fchomo/node.js:1357 msgid "Enable padding" msgstr "啟用填充" -#: htdocs/luci-static/resources/view/fchomo/node.js:1310 +#: htdocs/luci-static/resources/view/fchomo/node.js:1368 msgid "Enable statistic" msgstr "啟用統計" -#: htdocs/luci-static/resources/view/fchomo/node.js:871 -#: htdocs/luci-static/resources/view/fchomo/node.js:1631 +#: htdocs/luci-static/resources/view/fchomo/node.js:891 +#: htdocs/luci-static/resources/view/fchomo/node.js:1689 msgid "" "Enable the SUoT protocol, requires server support. Conflict with Multiplex." msgstr "啟用 SUoT 協議,需要服務端支援。與多路復用衝突。" @@ -911,7 +913,7 @@ msgid "" "if empty." msgstr "超過此限制將會觸發強制健康檢查。留空則使用 5。" -#: htdocs/luci-static/resources/view/fchomo/node.js:1743 +#: htdocs/luci-static/resources/view/fchomo/node.js:1801 msgid "Exclude matched node types." msgstr "排除匹配的節點類型。" @@ -924,7 +926,7 @@ msgstr "" "rel=\"noreferrer noopener\">此處。" #: htdocs/luci-static/resources/view/fchomo/client.js:1161 -#: htdocs/luci-static/resources/view/fchomo/node.js:1736 +#: htdocs/luci-static/resources/view/fchomo/node.js:1794 msgid "Exclude nodes that meet keywords or regexps." msgstr "排除匹配關鍵字或表達式的節點。" @@ -933,12 +935,12 @@ msgid "Expand/Collapse result" msgstr "展開/收起 結果" #: htdocs/luci-static/resources/view/fchomo/client.js:1121 -#: htdocs/luci-static/resources/view/fchomo/node.js:1721 +#: htdocs/luci-static/resources/view/fchomo/node.js:1779 msgid "Expected HTTP code. 204 will be used if empty." msgstr "預期的 HTTP code。留空則使用 204。" #: htdocs/luci-static/resources/view/fchomo/client.js:1123 -#: htdocs/luci-static/resources/view/fchomo/node.js:1723 +#: htdocs/luci-static/resources/view/fchomo/node.js:1781 msgid "Expected status" msgstr "預期狀態" @@ -979,10 +981,10 @@ msgstr "預期狀態" #: htdocs/luci-static/resources/view/fchomo/node.js:436 #: htdocs/luci-static/resources/view/fchomo/node.js:489 #: htdocs/luci-static/resources/view/fchomo/node.js:491 -#: htdocs/luci-static/resources/view/fchomo/node.js:942 -#: htdocs/luci-static/resources/view/fchomo/node.js:1030 -#: htdocs/luci-static/resources/view/fchomo/node.js:1800 -#: htdocs/luci-static/resources/view/fchomo/node.js:1820 +#: htdocs/luci-static/resources/view/fchomo/node.js:962 +#: htdocs/luci-static/resources/view/fchomo/node.js:1050 +#: htdocs/luci-static/resources/view/fchomo/node.js:1858 +#: htdocs/luci-static/resources/view/fchomo/node.js:1878 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:291 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:305 msgid "Expecting: %s" @@ -990,9 +992,9 @@ msgstr "請輸入:%s" #: htdocs/luci-static/resources/fchomo/listeners.js:977 #: htdocs/luci-static/resources/fchomo/listeners.js:984 -#: htdocs/luci-static/resources/view/fchomo/node.js:1140 -#: htdocs/luci-static/resources/view/fchomo/node.js:1147 -#: htdocs/luci-static/resources/view/fchomo/node.js:1155 +#: htdocs/luci-static/resources/view/fchomo/node.js:1160 +#: htdocs/luci-static/resources/view/fchomo/node.js:1167 +#: htdocs/luci-static/resources/view/fchomo/node.js:1175 msgid "Expecting: only support %s." msgstr "請輸入:僅支援 %s." @@ -1042,7 +1044,7 @@ msgid "Fallback filter" msgstr "後備過濾器" #: htdocs/luci-static/resources/view/fchomo/client.js:1156 -#: htdocs/luci-static/resources/view/fchomo/node.js:1730 +#: htdocs/luci-static/resources/view/fchomo/node.js:1788 msgid "Filter nodes that meet keywords or regexps." msgstr "過濾匹配關鍵字或表達式的節點。" @@ -1085,8 +1087,8 @@ msgstr "" "noopener\">%s." #: htdocs/luci-static/resources/view/fchomo/client.js:1122 -#: htdocs/luci-static/resources/view/fchomo/node.js:1599 -#: htdocs/luci-static/resources/view/fchomo/node.js:1722 +#: htdocs/luci-static/resources/view/fchomo/node.js:1657 +#: htdocs/luci-static/resources/view/fchomo/node.js:1780 msgid "" "For format see %s." @@ -1095,7 +1097,7 @@ msgstr "" "a>." #: htdocs/luci-static/resources/view/fchomo/node.js:710 -#: htdocs/luci-static/resources/view/fchomo/node.js:793 +#: htdocs/luci-static/resources/view/fchomo/node.js:813 msgid "Force DNS remote resolution." msgstr "強制 DNS 遠端解析。" @@ -1114,7 +1116,7 @@ msgstr "格式" msgid "FullCombo Shark!" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1180 +#: htdocs/luci-static/resources/view/fchomo/node.js:1200 msgid "GET" msgstr "" @@ -1129,7 +1131,7 @@ msgstr "常規" #: htdocs/luci-static/resources/fchomo/listeners.js:119 #: htdocs/luci-static/resources/view/fchomo/client.js:1009 #: htdocs/luci-static/resources/view/fchomo/node.js:222 -#: htdocs/luci-static/resources/view/fchomo/node.js:1479 +#: htdocs/luci-static/resources/view/fchomo/node.js:1537 msgid "General fields" msgstr "常規欄位" @@ -1211,17 +1213,16 @@ msgstr "組" #: htdocs/luci-static/resources/fchomo.js:146 #: htdocs/luci-static/resources/fchomo.js:179 -#: htdocs/luci-static/resources/fchomo/listeners.js:977 -#: htdocs/luci-static/resources/view/fchomo/node.js:816 -#: htdocs/luci-static/resources/view/fchomo/node.js:1129 -#: htdocs/luci-static/resources/view/fchomo/node.js:1140 -#: htdocs/luci-static/resources/view/fchomo/node.js:1147 +#: htdocs/luci-static/resources/view/fchomo/node.js:836 +#: htdocs/luci-static/resources/view/fchomo/node.js:1149 +#: htdocs/luci-static/resources/view/fchomo/node.js:1160 +#: htdocs/luci-static/resources/view/fchomo/node.js:1167 msgid "HTTP" msgstr "" #: htdocs/luci-static/resources/view/fchomo/node.js:267 -#: htdocs/luci-static/resources/view/fchomo/node.js:1202 -#: htdocs/luci-static/resources/view/fchomo/node.js:1579 +#: htdocs/luci-static/resources/view/fchomo/node.js:1222 +#: htdocs/luci-static/resources/view/fchomo/node.js:1637 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:399 msgid "HTTP header" msgstr "HTTP header" @@ -1247,7 +1248,7 @@ msgstr "HTTP 偽裝多路復用" msgid "HTTP mask: %s" msgstr "HTTP 偽裝: %s" -#: htdocs/luci-static/resources/view/fchomo/node.js:1179 +#: htdocs/luci-static/resources/view/fchomo/node.js:1199 msgid "HTTP request method" msgstr "HTTP 請求方法" @@ -1266,10 +1267,9 @@ msgid "" "returned if empty." msgstr "身份驗證失敗時的 HTTP3 伺服器回應。預設回傳 404 頁面。" -#: htdocs/luci-static/resources/fchomo/listeners.js:978 -#: htdocs/luci-static/resources/view/fchomo/node.js:1130 -#: htdocs/luci-static/resources/view/fchomo/node.js:1141 -#: htdocs/luci-static/resources/view/fchomo/node.js:1148 +#: htdocs/luci-static/resources/view/fchomo/node.js:1150 +#: htdocs/luci-static/resources/view/fchomo/node.js:1161 +#: htdocs/luci-static/resources/view/fchomo/node.js:1168 msgid "HTTPUpgrade" msgstr "" @@ -1294,27 +1294,27 @@ msgid "Health check" msgstr "健康檢查" #: htdocs/luci-static/resources/view/fchomo/client.js:1091 -#: htdocs/luci-static/resources/view/fchomo/node.js:1690 +#: htdocs/luci-static/resources/view/fchomo/node.js:1748 msgid "Health check URL" msgstr "健康檢查 URL" #: htdocs/luci-static/resources/view/fchomo/client.js:1120 -#: htdocs/luci-static/resources/view/fchomo/node.js:1720 +#: htdocs/luci-static/resources/view/fchomo/node.js:1778 msgid "Health check expected status" msgstr "健康檢查预期状态" #: htdocs/luci-static/resources/view/fchomo/client.js:1100 -#: htdocs/luci-static/resources/view/fchomo/node.js:1700 +#: htdocs/luci-static/resources/view/fchomo/node.js:1758 msgid "Health check interval" msgstr "健康檢查間隔" #: htdocs/luci-static/resources/view/fchomo/client.js:1107 -#: htdocs/luci-static/resources/view/fchomo/node.js:1707 +#: htdocs/luci-static/resources/view/fchomo/node.js:1765 msgid "Health check timeout" msgstr "健康檢查超时" #: htdocs/luci-static/resources/view/fchomo/client.js:1011 -#: htdocs/luci-static/resources/view/fchomo/node.js:1481 +#: htdocs/luci-static/resources/view/fchomo/node.js:1539 msgid "Health fields" msgstr "健康欄位" @@ -1326,7 +1326,7 @@ msgstr "心跳間隔" msgid "Hidden" msgstr "隱藏" -#: htdocs/luci-static/resources/view/fchomo/node.js:822 +#: htdocs/luci-static/resources/view/fchomo/node.js:842 msgid "Host that supports TLS 1.3" msgstr "主機名稱 (支援 TLS 1.3)" @@ -1365,8 +1365,8 @@ msgstr "" msgid "IP override" msgstr "IP 覆寫" -#: htdocs/luci-static/resources/view/fchomo/node.js:1361 -#: htdocs/luci-static/resources/view/fchomo/node.js:1676 +#: htdocs/luci-static/resources/view/fchomo/node.js:1419 +#: htdocs/luci-static/resources/view/fchomo/node.js:1734 msgid "IP version" msgstr "IP 版本" @@ -1427,8 +1427,8 @@ msgstr "導入" #: htdocs/luci-static/resources/view/fchomo/client.js:1713 #: htdocs/luci-static/resources/view/fchomo/client.js:1748 #: htdocs/luci-static/resources/view/fchomo/client.js:1769 -#: htdocs/luci-static/resources/view/fchomo/node.js:1386 -#: htdocs/luci-static/resources/view/fchomo/node.js:1467 +#: htdocs/luci-static/resources/view/fchomo/node.js:1444 +#: htdocs/luci-static/resources/view/fchomo/node.js:1525 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:153 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:241 msgid "Import mihomo config" @@ -1444,12 +1444,12 @@ msgstr "導入規則集連結" #: htdocs/luci-static/resources/fchomo/listeners.js:181 #: htdocs/luci-static/resources/view/fchomo/node.js:286 #: htdocs/luci-static/resources/view/fchomo/node.js:292 -#: htdocs/luci-static/resources/view/fchomo/node.js:1637 -#: htdocs/luci-static/resources/view/fchomo/node.js:1643 +#: htdocs/luci-static/resources/view/fchomo/node.js:1695 +#: htdocs/luci-static/resources/view/fchomo/node.js:1701 msgid "In Mbps." msgstr "單位為 Mbps。" -#: htdocs/luci-static/resources/view/fchomo/node.js:1557 +#: htdocs/luci-static/resources/view/fchomo/node.js:1615 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:377 msgid "In bytes. %s will be used if empty." msgstr "單位為位元組。留空則使用 %s。" @@ -1461,7 +1461,7 @@ msgstr "單位為毫秒。" #: htdocs/luci-static/resources/view/fchomo/client.js:1108 #: htdocs/luci-static/resources/view/fchomo/client.js:1137 -#: htdocs/luci-static/resources/view/fchomo/node.js:1708 +#: htdocs/luci-static/resources/view/fchomo/node.js:1766 msgid "In millisecond. %s will be used if empty." msgstr "單位為毫秒。留空則使用 %s。" @@ -1470,7 +1470,7 @@ msgstr "單位為毫秒。留空則使用 %s。" #: htdocs/luci-static/resources/fchomo/listeners.js:428 #: htdocs/luci-static/resources/view/fchomo/node.js:604 #: htdocs/luci-static/resources/view/fchomo/node.js:611 -#: htdocs/luci-static/resources/view/fchomo/node.js:1218 +#: htdocs/luci-static/resources/view/fchomo/node.js:1238 msgid "In seconds." msgstr "單位為秒。" @@ -1479,14 +1479,14 @@ msgstr "單位為秒。" #: htdocs/luci-static/resources/view/fchomo/global.js:430 #: htdocs/luci-static/resources/view/fchomo/global.js:515 #: htdocs/luci-static/resources/view/fchomo/node.js:280 -#: htdocs/luci-static/resources/view/fchomo/node.js:1563 -#: htdocs/luci-static/resources/view/fchomo/node.js:1701 +#: htdocs/luci-static/resources/view/fchomo/node.js:1621 +#: htdocs/luci-static/resources/view/fchomo/node.js:1759 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:383 msgid "In seconds. %s will be used if empty." msgstr "單位為秒。留空則使用 %s。" #: htdocs/luci-static/resources/fchomo/listeners.js:649 -#: htdocs/luci-static/resources/view/fchomo/node.js:931 +#: htdocs/luci-static/resources/view/fchomo/node.js:951 msgid "" "In the order of one Padding-Length and one Padding-" "Interval, infinite concatenation." @@ -1528,7 +1528,7 @@ msgstr "引入所有代理節點。" msgid "Info" msgstr "訊息" -#: htdocs/luci-static/resources/view/fchomo/node.js:1496 +#: htdocs/luci-static/resources/view/fchomo/node.js:1554 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:279 msgid "Inline" msgstr "內嵌" @@ -1549,7 +1549,7 @@ msgid "Key" msgstr "密鑰" #: htdocs/luci-static/resources/fchomo/listeners.js:829 -#: htdocs/luci-static/resources/view/fchomo/node.js:1059 +#: htdocs/luci-static/resources/view/fchomo/node.js:1079 msgid "Key path" msgstr "憑證路徑" @@ -1565,14 +1565,14 @@ msgstr "密鑰對" #: htdocs/luci-static/resources/view/fchomo/client.js:1719 #: htdocs/luci-static/resources/view/fchomo/client.js:1775 #: htdocs/luci-static/resources/view/fchomo/node.js:229 -#: htdocs/luci-static/resources/view/fchomo/node.js:1484 -#: htdocs/luci-static/resources/view/fchomo/node.js:1769 +#: htdocs/luci-static/resources/view/fchomo/node.js:1542 +#: htdocs/luci-static/resources/view/fchomo/node.js:1827 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:259 msgid "Label" msgstr "標籤" #: htdocs/luci-static/resources/view/fchomo/client.js:1114 -#: htdocs/luci-static/resources/view/fchomo/node.js:1714 +#: htdocs/luci-static/resources/view/fchomo/node.js:1772 msgid "Lazy" msgstr "懶惰狀態" @@ -1594,7 +1594,7 @@ msgid "Less compatibility and sometimes better performance." msgstr "有時效能較好。" #: htdocs/luci-static/resources/fchomo/listeners.js:810 -#: htdocs/luci-static/resources/view/fchomo/node.js:983 +#: htdocs/luci-static/resources/view/fchomo/node.js:1003 msgid "List of supported application level protocols, in order of preference." msgstr "支援的應用層協議協商清單,依序排列。" @@ -1623,18 +1623,18 @@ msgstr "監聽埠" msgid "Load balance" msgstr "負載均衡" -#: htdocs/luci-static/resources/view/fchomo/node.js:1494 +#: htdocs/luci-static/resources/view/fchomo/node.js:1552 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:277 msgid "Local" msgstr "本地" #: htdocs/luci-static/resources/view/fchomo/node.js:697 -#: htdocs/luci-static/resources/view/fchomo/node.js:740 +#: htdocs/luci-static/resources/view/fchomo/node.js:760 msgid "Local IPv6 address" msgstr "本地 IPv6 位址" #: htdocs/luci-static/resources/view/fchomo/node.js:689 -#: htdocs/luci-static/resources/view/fchomo/node.js:732 +#: htdocs/luci-static/resources/view/fchomo/node.js:752 msgid "Local address" msgstr "本地位址" @@ -1671,7 +1671,7 @@ msgstr "僅限小寫" #: htdocs/luci-static/resources/view/fchomo/global.js:502 #: htdocs/luci-static/resources/view/fchomo/node.js:703 -#: htdocs/luci-static/resources/view/fchomo/node.js:786 +#: htdocs/luci-static/resources/view/fchomo/node.js:806 msgid "MTU" msgstr "" @@ -1711,7 +1711,7 @@ msgstr "匹配回應通過 ipcidr
" msgid "Match rule set." msgstr "匹配規則集。" -#: htdocs/luci-static/resources/view/fchomo/node.js:1224 +#: htdocs/luci-static/resources/view/fchomo/node.js:1244 msgid "Max Early Data" msgstr "前置數據最大值" @@ -1720,6 +1720,15 @@ msgstr "前置數據最大值" msgid "Max UDP relay packet size" msgstr "UDP 中繼數據包最大尺寸" +#: htdocs/luci-static/resources/view/fchomo/node.js:1300 +msgid "Max concurrency" +msgstr "最大並發" + +#: htdocs/luci-static/resources/view/fchomo/node.js:731 +#: htdocs/luci-static/resources/view/fchomo/node.js:1295 +msgid "Max connections" +msgstr "最大連線數" + #: htdocs/luci-static/resources/view/fchomo/client.js:1128 msgid "Max count of failures" msgstr "最大失敗次數" @@ -1729,21 +1738,47 @@ msgstr "最大失敗次數" msgid "Max download speed" msgstr "最大下載速度" +#: htdocs/luci-static/resources/fchomo/listeners.js:1033 +#: htdocs/luci-static/resources/view/fchomo/node.js:1284 +msgid "Max each POST bytes" +msgstr "POST 最大位元組數" + #: htdocs/luci-static/resources/view/fchomo/node.js:573 msgid "Max open streams" msgstr "限制打開流的數量" +#: htdocs/luci-static/resources/view/fchomo/node.js:1310 +msgid "Max request times" +msgstr "最大請求次數" + +#: htdocs/luci-static/resources/view/fchomo/node.js:1315 +msgid "Max reusable seconds" +msgstr "最大可重用秒數" + +#: htdocs/luci-static/resources/view/fchomo/node.js:1305 +msgid "Max reuse times" +msgstr "最大重用次數" + +#: htdocs/luci-static/resources/view/fchomo/node.js:744 +msgid "Max streams" +msgstr "" + #: htdocs/luci-static/resources/fchomo/listeners.js:174 #: htdocs/luci-static/resources/view/fchomo/node.js:285 msgid "Max upload speed" msgstr "最大上傳速度" -#: htdocs/luci-static/resources/view/fchomo/node.js:1277 -#: htdocs/luci-static/resources/view/fchomo/node.js:1293 +#: htdocs/luci-static/resources/view/fchomo/node.js:1335 +#: htdocs/luci-static/resources/view/fchomo/node.js:1351 msgid "Maximum connections" msgstr "最大連線數" -#: htdocs/luci-static/resources/view/fchomo/node.js:1291 +#: htdocs/luci-static/resources/view/fchomo/node.js:745 +msgid "" +"Maximum multiplexed streams in a connection before opening a new connection." +msgstr "" + +#: htdocs/luci-static/resources/view/fchomo/node.js:1349 msgid "" "Maximum multiplexed streams in a connection before opening a new connection." "
Conflict with %s and %s." @@ -1763,7 +1798,7 @@ msgid "" "rate." msgstr "最大填充率必須大於等于最小填充率。" -#: htdocs/luci-static/resources/view/fchomo/node.js:1290 +#: htdocs/luci-static/resources/view/fchomo/node.js:1348 msgid "Maximum streams" msgstr "最大流數量" @@ -1788,7 +1823,12 @@ msgstr "Mihomo 服務端" msgid "Min of idle sessions to keep" msgstr "要保留的最少閒置會話數" -#: htdocs/luci-static/resources/view/fchomo/node.js:1284 +#: htdocs/luci-static/resources/view/fchomo/node.js:737 +msgid "Min streams" +msgstr "" + +#: htdocs/luci-static/resources/view/fchomo/node.js:738 +#: htdocs/luci-static/resources/view/fchomo/node.js:1342 msgid "" "Minimum multiplexed streams in a connection before opening a new connection." msgstr "在開啟新連線之前,連線中的最小多路復用流數量。" @@ -1798,8 +1838,8 @@ msgstr "在開啟新連線之前,連線中的最小多路復用流數量。" msgid "Minimum padding rate" msgstr "最小填充率" -#: htdocs/luci-static/resources/view/fchomo/node.js:1283 -#: htdocs/luci-static/resources/view/fchomo/node.js:1293 +#: htdocs/luci-static/resources/view/fchomo/node.js:1341 +#: htdocs/luci-static/resources/view/fchomo/node.js:1351 msgid "Minimum streams" msgstr "最小流數量" @@ -1816,7 +1856,7 @@ msgstr "混合 系統 TCP 堆栈和 gVisor UDP 堆栈 msgid "Mixed port" msgstr "混合連接埠" -#: htdocs/luci-static/resources/view/fchomo/node.js:1263 +#: htdocs/luci-static/resources/view/fchomo/node.js:1321 msgid "Multiplex" msgstr "多路復用" @@ -1838,7 +1878,7 @@ msgstr "NOT" msgid "Name of the Proxy group as outbound." msgstr "出站代理組的名稱。" -#: htdocs/luci-static/resources/view/fchomo/node.js:1569 +#: htdocs/luci-static/resources/view/fchomo/node.js:1627 msgid "Name of the Proxy group to download provider." msgstr "用於下載供應商訂閱的代理組名稱。" @@ -1866,16 +1906,20 @@ msgstr "網路類型" msgid "No Authentication IP ranges" msgstr "無需認證的 IP 範圍" +#: htdocs/luci-static/resources/fchomo/listeners.js:1023 +msgid "No SSE header" +msgstr "無 SSE header" + #: htdocs/luci-static/resources/view/fchomo/client.js:1508 msgid "No add'l params" msgstr "無附加參數" -#: htdocs/luci-static/resources/view/fchomo/node.js:1252 +#: htdocs/luci-static/resources/view/fchomo/node.js:1274 msgid "No gRPC header" msgstr "無 gRPC header" #: htdocs/luci-static/resources/view/fchomo/client.js:1115 -#: htdocs/luci-static/resources/view/fchomo/node.js:1715 +#: htdocs/luci-static/resources/view/fchomo/node.js:1773 msgid "No testing is performed when this provider node is not in use." msgstr "當此供應商的節點未使用時,不執行任何測試。" @@ -1894,17 +1938,17 @@ msgid "Node" msgstr "節點" #: htdocs/luci-static/resources/view/fchomo/client.js:1160 -#: htdocs/luci-static/resources/view/fchomo/node.js:1735 +#: htdocs/luci-static/resources/view/fchomo/node.js:1793 msgid "Node exclude filter" msgstr "排除節點" #: htdocs/luci-static/resources/view/fchomo/client.js:1165 -#: htdocs/luci-static/resources/view/fchomo/node.js:1742 +#: htdocs/luci-static/resources/view/fchomo/node.js:1800 msgid "Node exclude type" msgstr "排除節點類型" #: htdocs/luci-static/resources/view/fchomo/client.js:1155 -#: htdocs/luci-static/resources/view/fchomo/node.js:1729 +#: htdocs/luci-static/resources/view/fchomo/node.js:1787 msgid "Node filter" msgstr "過濾節點" @@ -1932,7 +1976,7 @@ msgstr "" msgid "ON" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:815 +#: htdocs/luci-static/resources/view/fchomo/node.js:835 msgid "Obfs Mode" msgstr "Obfs 模式" @@ -1982,7 +2026,7 @@ msgid "Override destination" msgstr "覆蓋目標位址" #: htdocs/luci-static/resources/view/fchomo/client.js:1010 -#: htdocs/luci-static/resources/view/fchomo/node.js:1480 +#: htdocs/luci-static/resources/view/fchomo/node.js:1538 msgid "Override fields" msgstr "覆蓋欄位" @@ -2002,7 +2046,7 @@ msgstr "使用嗅探到的網域覆寫連線目標。" msgid "Override the existing ECS in original request." msgstr "覆蓋原始請求中已有的 ECS。" -#: htdocs/luci-static/resources/view/fchomo/node.js:1086 +#: htdocs/luci-static/resources/view/fchomo/node.js:1106 msgid "Overrides the domain name used for HTTPS record queries." msgstr "覆蓋用於 HTTPS 記錄查詢的網域。" @@ -2010,11 +2054,11 @@ msgstr "覆蓋用於 HTTPS 記錄查詢的網域。" msgid "Overview" msgstr "概覽" -#: htdocs/luci-static/resources/view/fchomo/node.js:1181 +#: htdocs/luci-static/resources/view/fchomo/node.js:1201 msgid "POST" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1182 +#: htdocs/luci-static/resources/view/fchomo/node.js:1202 msgid "PUT" msgstr "" @@ -2022,7 +2066,7 @@ msgstr "" msgid "Packet encoding" msgstr "數據包編碼" -#: htdocs/luci-static/resources/view/fchomo/node.js:1257 +#: htdocs/luci-static/resources/view/fchomo/node.js:1279 msgid "Padding bytes" msgstr "填充位元組" @@ -2031,7 +2075,7 @@ msgid "Padding scheme" msgstr "填充方案" #: htdocs/luci-static/resources/fchomo/listeners.js:647 -#: htdocs/luci-static/resources/view/fchomo/node.js:929 +#: htdocs/luci-static/resources/view/fchomo/node.js:949 msgid "Paddings" msgstr "填充 (Paddings)" @@ -2040,17 +2084,17 @@ msgstr "填充 (Paddings)" #: htdocs/luci-static/resources/fchomo/listeners.js:508 #: htdocs/luci-static/resources/view/fchomo/node.js:261 #: htdocs/luci-static/resources/view/fchomo/node.js:340 -#: htdocs/luci-static/resources/view/fchomo/node.js:830 +#: htdocs/luci-static/resources/view/fchomo/node.js:850 msgid "Password" msgstr "密碼" #: htdocs/luci-static/resources/fchomo/listeners.js:587 -#: htdocs/luci-static/resources/view/fchomo/node.js:1544 +#: htdocs/luci-static/resources/view/fchomo/node.js:1602 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:364 msgid "Payload" msgstr "Payload" -#: htdocs/luci-static/resources/view/fchomo/node.js:754 +#: htdocs/luci-static/resources/view/fchomo/node.js:774 msgid "Peer pubkic key" msgstr "對端公鑰" @@ -2060,11 +2104,11 @@ msgid "" "it is not needed." msgstr "效能可能會略有下降,建議僅在需要時開啟。" -#: htdocs/luci-static/resources/view/fchomo/node.js:781 +#: htdocs/luci-static/resources/view/fchomo/node.js:801 msgid "Periodically sends data packets to maintain connection persistence." msgstr "定期發送資料包以維持連線持久性。" -#: htdocs/luci-static/resources/view/fchomo/node.js:780 +#: htdocs/luci-static/resources/view/fchomo/node.js:800 msgid "Persistent keepalive" msgstr "持久連接" @@ -2087,8 +2131,8 @@ msgid "" "standards." msgstr "連結格式標準請參考 %s。" -#: htdocs/luci-static/resources/view/fchomo/node.js:1517 -#: htdocs/luci-static/resources/view/fchomo/node.js:1543 +#: htdocs/luci-static/resources/view/fchomo/node.js:1575 +#: htdocs/luci-static/resources/view/fchomo/node.js:1601 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:337 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:363 msgid "" @@ -2103,25 +2147,25 @@ msgstr "" #: htdocs/luci-static/resources/view/fchomo/client.js:1445 #: htdocs/luci-static/resources/view/fchomo/client.js:1697 #: htdocs/luci-static/resources/view/fchomo/client.js:1749 -#: htdocs/luci-static/resources/view/fchomo/node.js:1387 +#: htdocs/luci-static/resources/view/fchomo/node.js:1445 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:154 msgid "Please type %s fields of mihomo config.
" msgstr "請輸入 mihomo 配置的 %s 欄位。
" #: htdocs/luci-static/resources/fchomo/listeners.js:494 -#: htdocs/luci-static/resources/view/fchomo/node.js:804 +#: htdocs/luci-static/resources/view/fchomo/node.js:824 msgid "Plugin" msgstr "插件" #: htdocs/luci-static/resources/fchomo/listeners.js:501 #: htdocs/luci-static/resources/fchomo/listeners.js:508 #: htdocs/luci-static/resources/fchomo/listeners.js:514 -#: htdocs/luci-static/resources/view/fchomo/node.js:815 -#: htdocs/luci-static/resources/view/fchomo/node.js:822 -#: htdocs/luci-static/resources/view/fchomo/node.js:830 -#: htdocs/luci-static/resources/view/fchomo/node.js:836 -#: htdocs/luci-static/resources/view/fchomo/node.js:844 +#: htdocs/luci-static/resources/view/fchomo/node.js:835 +#: htdocs/luci-static/resources/view/fchomo/node.js:842 #: htdocs/luci-static/resources/view/fchomo/node.js:850 +#: htdocs/luci-static/resources/view/fchomo/node.js:856 +#: htdocs/luci-static/resources/view/fchomo/node.js:864 +#: htdocs/luci-static/resources/view/fchomo/node.js:870 msgid "Plugin:" msgstr "插件:" @@ -2151,7 +2195,7 @@ msgid "Ports pool" msgstr "連接埠池" #: htdocs/luci-static/resources/view/fchomo/node.js:499 -#: htdocs/luci-static/resources/view/fchomo/node.js:761 +#: htdocs/luci-static/resources/view/fchomo/node.js:781 msgid "Pre-shared key" msgstr "預先共用金鑰" @@ -2170,10 +2214,10 @@ msgstr "防止某些情況下的 ICMP 環回問題。 Ping 不會顯示實際延 #: htdocs/luci-static/resources/view/fchomo/global.js:736 #: htdocs/luci-static/resources/view/fchomo/global.js:753 -#: htdocs/luci-static/resources/view/fchomo/node.js:1351 -#: htdocs/luci-static/resources/view/fchomo/node.js:1357 -#: htdocs/luci-static/resources/view/fchomo/node.js:1664 -#: htdocs/luci-static/resources/view/fchomo/node.js:1671 +#: htdocs/luci-static/resources/view/fchomo/node.js:1409 +#: htdocs/luci-static/resources/view/fchomo/node.js:1415 +#: htdocs/luci-static/resources/view/fchomo/node.js:1722 +#: htdocs/luci-static/resources/view/fchomo/node.js:1729 msgid "Priority: Proxy Node > Global." msgstr "優先權: 代理節點 > 全域。" @@ -2186,7 +2230,7 @@ msgid "Priv-key passphrase" msgstr "金鑰密碼" #: htdocs/luci-static/resources/view/fchomo/node.js:674 -#: htdocs/luci-static/resources/view/fchomo/node.js:746 +#: htdocs/luci-static/resources/view/fchomo/node.js:766 msgid "Private key" msgstr "私鑰" @@ -2195,7 +2239,7 @@ msgid "Process matching mode" msgstr "進程匹配模式" #: htdocs/luci-static/resources/view/fchomo/global.js:684 -#: htdocs/luci-static/resources/view/fchomo/node.js:1269 +#: htdocs/luci-static/resources/view/fchomo/node.js:1327 msgid "Protocol" msgstr "協議" @@ -2210,13 +2254,13 @@ msgid "" msgstr "協議參數。 如啟用會隨機浪費流量(在 v2ray 中預設為啟用且無法停用)。" #: htdocs/luci-static/resources/view/fchomo/client.js:1055 -#: htdocs/luci-static/resources/view/fchomo/node.js:1370 -#: htdocs/luci-static/resources/view/fchomo/node.js:1379 -#: htdocs/luci-static/resources/view/fchomo/node.js:1780 +#: htdocs/luci-static/resources/view/fchomo/node.js:1428 +#: htdocs/luci-static/resources/view/fchomo/node.js:1437 +#: htdocs/luci-static/resources/view/fchomo/node.js:1838 msgid "Provider" msgstr "供應商" -#: htdocs/luci-static/resources/view/fchomo/node.js:1550 +#: htdocs/luci-static/resources/view/fchomo/node.js:1608 msgid "Provider URL" msgstr "供應商訂閱 URL" @@ -2239,19 +2283,19 @@ msgid "Proxy MAC-s" msgstr "代理 MAC 位址" #: htdocs/luci-static/resources/view/fchomo/node.js:208 -#: htdocs/luci-static/resources/view/fchomo/node.js:1779 +#: htdocs/luci-static/resources/view/fchomo/node.js:1837 msgid "Proxy Node" msgstr "代理節點" -#: htdocs/luci-static/resources/view/fchomo/node.js:1755 -#: htdocs/luci-static/resources/view/fchomo/node.js:1764 +#: htdocs/luci-static/resources/view/fchomo/node.js:1813 +#: htdocs/luci-static/resources/view/fchomo/node.js:1822 msgid "Proxy chain" msgstr "代理鏈" #: htdocs/luci-static/resources/fchomo/listeners.js:530 #: htdocs/luci-static/resources/view/fchomo/client.js:783 #: htdocs/luci-static/resources/view/fchomo/client.js:1543 -#: htdocs/luci-static/resources/view/fchomo/node.js:1568 +#: htdocs/luci-static/resources/view/fchomo/node.js:1626 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:388 msgid "Proxy group" msgstr "代理組" @@ -2279,11 +2323,11 @@ msgid "Quick Reload" msgstr "快速重載" #: htdocs/luci-static/resources/fchomo/listeners.js:917 -#: htdocs/luci-static/resources/view/fchomo/node.js:1100 +#: htdocs/luci-static/resources/view/fchomo/node.js:1120 msgid "REALITY" msgstr "REALITY" -#: htdocs/luci-static/resources/view/fchomo/node.js:1115 +#: htdocs/luci-static/resources/view/fchomo/node.js:1135 msgid "REALITY X25519MLKEM768 PQC support" msgstr "REALITY X25519MLKEM768 後量子加密支援" @@ -2300,18 +2344,18 @@ msgid "REALITY private key" msgstr "REALITY 私鑰" #: htdocs/luci-static/resources/fchomo/listeners.js:944 -#: htdocs/luci-static/resources/view/fchomo/node.js:1105 +#: htdocs/luci-static/resources/view/fchomo/node.js:1125 msgid "REALITY public key" msgstr "REALITY 公鑰" #: htdocs/luci-static/resources/fchomo/listeners.js:948 -#: htdocs/luci-static/resources/view/fchomo/node.js:1110 +#: htdocs/luci-static/resources/view/fchomo/node.js:1130 msgid "REALITY short ID" msgstr "REALITY 標識符" #: htdocs/luci-static/resources/fchomo/listeners.js:618 #: htdocs/luci-static/resources/fchomo/listeners.js:637 -#: htdocs/luci-static/resources/view/fchomo/node.js:919 +#: htdocs/luci-static/resources/view/fchomo/node.js:939 msgid "RTT" msgstr "" @@ -2358,13 +2402,13 @@ msgstr "重載" msgid "Reload All" msgstr "重載所有" -#: htdocs/luci-static/resources/view/fchomo/node.js:1495 +#: htdocs/luci-static/resources/view/fchomo/node.js:1553 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:278 msgid "Remote" msgstr "遠端" #: htdocs/luci-static/resources/view/fchomo/node.js:709 -#: htdocs/luci-static/resources/view/fchomo/node.js:792 +#: htdocs/luci-static/resources/view/fchomo/node.js:812 msgid "Remote DNS resolve" msgstr "遠端 DNS 解析" @@ -2373,18 +2417,18 @@ msgid "Remove" msgstr "移除" #: htdocs/luci-static/resources/fchomo.js:1354 -#: htdocs/luci-static/resources/view/fchomo/node.js:1471 -#: htdocs/luci-static/resources/view/fchomo/node.js:1473 +#: htdocs/luci-static/resources/view/fchomo/node.js:1529 +#: htdocs/luci-static/resources/view/fchomo/node.js:1531 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:251 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:253 msgid "Remove idles" msgstr "移除閒置" -#: htdocs/luci-static/resources/view/fchomo/node.js:1597 +#: htdocs/luci-static/resources/view/fchomo/node.js:1655 msgid "Replace name" msgstr "名稱替換" -#: htdocs/luci-static/resources/view/fchomo/node.js:1598 +#: htdocs/luci-static/resources/view/fchomo/node.js:1656 msgid "Replace node name." msgstr "替換節點名稱" @@ -2392,9 +2436,9 @@ msgstr "替換節點名稱" msgid "Request" msgstr "" -#: htdocs/luci-static/resources/fchomo/listeners.js:996 -#: htdocs/luci-static/resources/view/fchomo/node.js:1188 -#: htdocs/luci-static/resources/view/fchomo/node.js:1195 +#: htdocs/luci-static/resources/fchomo/listeners.js:1002 +#: htdocs/luci-static/resources/view/fchomo/node.js:1208 +#: htdocs/luci-static/resources/view/fchomo/node.js:1215 msgid "Request path" msgstr "請求路徑" @@ -2411,11 +2455,11 @@ msgid "Require any" msgstr "" #: htdocs/luci-static/resources/fchomo.js:384 -#: htdocs/luci-static/resources/view/fchomo/node.js:1116 +#: htdocs/luci-static/resources/view/fchomo/node.js:1136 msgid "Requires server support." msgstr "需要伺服器支援。" -#: htdocs/luci-static/resources/view/fchomo/node.js:775 +#: htdocs/luci-static/resources/view/fchomo/node.js:795 msgid "Reserved field bytes" msgstr "保留字段位元組" @@ -2423,7 +2467,7 @@ msgstr "保留字段位元組" msgid "Resources management" msgstr "資源管理" -#: htdocs/luci-static/resources/view/fchomo/node.js:850 +#: htdocs/luci-static/resources/view/fchomo/node.js:870 msgid "Restls script" msgstr "Restls 劇本" @@ -2459,8 +2503,8 @@ msgstr "路由 DSCP" msgid "Routing GFW" msgstr "路由 GFW 流量" -#: htdocs/luci-static/resources/view/fchomo/node.js:1356 -#: htdocs/luci-static/resources/view/fchomo/node.js:1670 +#: htdocs/luci-static/resources/view/fchomo/node.js:1414 +#: htdocs/luci-static/resources/view/fchomo/node.js:1728 msgid "Routing mark" msgstr "路由標記" @@ -2548,7 +2592,7 @@ msgstr "" msgid "SUB-RULE" msgstr "SUB-RULE" -#: htdocs/luci-static/resources/view/fchomo/node.js:876 +#: htdocs/luci-static/resources/view/fchomo/node.js:896 msgid "SUoT version" msgstr "SUoT 版本" @@ -2598,8 +2642,9 @@ msgstr "服務端" msgid "Server address" msgstr "伺服器位址" -#: htdocs/luci-static/resources/view/fchomo/node.js:1167 -#: htdocs/luci-static/resources/view/fchomo/node.js:1173 +#: htdocs/luci-static/resources/fchomo/listeners.js:996 +#: htdocs/luci-static/resources/view/fchomo/node.js:1187 +#: htdocs/luci-static/resources/view/fchomo/node.js:1193 msgid "Server hostname" msgstr "伺服器主機名稱" @@ -2631,7 +2676,7 @@ msgstr "Shadowsocks 加密" msgid "Shadowsocks password" msgstr "Shadowsocks 密碼" -#: htdocs/luci-static/resources/view/fchomo/node.js:1311 +#: htdocs/luci-static/resources/view/fchomo/node.js:1369 msgid "Show connections in the dashboard for breaking connections easier." msgstr "在面板中顯示連線以便於打斷連線。" @@ -2643,14 +2688,14 @@ msgstr "靜音" msgid "Simple round-robin all nodes" msgstr "簡單輪替所有節點" -#: htdocs/luci-static/resources/view/fchomo/node.js:1556 +#: htdocs/luci-static/resources/view/fchomo/node.js:1614 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:376 msgid "Size limit" msgstr "大小限制" #: htdocs/luci-static/resources/view/fchomo/client.js:1576 -#: htdocs/luci-static/resources/view/fchomo/node.js:1037 -#: htdocs/luci-static/resources/view/fchomo/node.js:1648 +#: htdocs/luci-static/resources/view/fchomo/node.js:1057 +#: htdocs/luci-static/resources/view/fchomo/node.js:1706 msgid "Skip cert verify" msgstr "跳過憑證驗證" @@ -2778,7 +2823,7 @@ msgstr "TCP" msgid "TCP concurrency" msgstr "TCP 併發" -#: htdocs/luci-static/resources/view/fchomo/node.js:1304 +#: htdocs/luci-static/resources/view/fchomo/node.js:1362 msgid "TCP only" msgstr "僅 TCP" @@ -2804,25 +2849,25 @@ msgstr "TCP-Keep-Alive 間隔" msgid "TCP/UDP" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1335 -#: htdocs/luci-static/resources/view/fchomo/node.js:1615 +#: htdocs/luci-static/resources/view/fchomo/node.js:1393 +#: htdocs/luci-static/resources/view/fchomo/node.js:1673 msgid "TFO" msgstr "TCP 快速開啟 (TFO)" #: htdocs/luci-static/resources/fchomo/listeners.js:772 #: htdocs/luci-static/resources/view/fchomo/global.js:529 #: htdocs/luci-static/resources/view/fchomo/node.js:464 -#: htdocs/luci-static/resources/view/fchomo/node.js:817 -#: htdocs/luci-static/resources/view/fchomo/node.js:951 +#: htdocs/luci-static/resources/view/fchomo/node.js:837 +#: htdocs/luci-static/resources/view/fchomo/node.js:971 msgid "TLS" msgstr "TLS" #: htdocs/luci-static/resources/fchomo/listeners.js:809 -#: htdocs/luci-static/resources/view/fchomo/node.js:982 +#: htdocs/luci-static/resources/view/fchomo/node.js:1002 msgid "TLS ALPN" msgstr "TLS ALPN" -#: htdocs/luci-static/resources/view/fchomo/node.js:976 +#: htdocs/luci-static/resources/view/fchomo/node.js:996 msgid "TLS SNI" msgstr "" @@ -2854,24 +2899,24 @@ msgstr "讓客戶端使用 BBR 流控演算法。" msgid "The %s address used by local machine in the Cloudflare WARP network." msgstr "Cloudflare WARP 網路中使用的本機 %s 位址。" -#: htdocs/luci-static/resources/view/fchomo/node.js:733 -#: htdocs/luci-static/resources/view/fchomo/node.js:741 +#: htdocs/luci-static/resources/view/fchomo/node.js:753 +#: htdocs/luci-static/resources/view/fchomo/node.js:761 msgid "The %s address used by local machine in the Wireguard network." msgstr "WireGuard 網路中使用的本機 %s 位址。" #: htdocs/luci-static/resources/fchomo/listeners.js:830 -#: htdocs/luci-static/resources/view/fchomo/node.js:1060 +#: htdocs/luci-static/resources/view/fchomo/node.js:1080 msgid "The %s private key, in PEM format." msgstr "%s私鑰,需要 PEM 格式。" #: htdocs/luci-static/resources/fchomo/listeners.js:815 #: htdocs/luci-static/resources/fchomo/listeners.js:853 #: htdocs/luci-static/resources/view/fchomo/global.js:550 -#: htdocs/luci-static/resources/view/fchomo/node.js:1046 +#: htdocs/luci-static/resources/view/fchomo/node.js:1066 msgid "The %s public key, in PEM format." msgstr "%s公鑰,需要 PEM 格式。" -#: htdocs/luci-static/resources/view/fchomo/node.js:1080 +#: htdocs/luci-static/resources/view/fchomo/node.js:1100 msgid "" "The ECH parameter of the HTTPS record for the domain. Leave empty to resolve " "via DNS." @@ -2890,7 +2935,7 @@ msgid "The default value is 2:00 every day." msgstr "預設值為每天 2:00。" #: htdocs/luci-static/resources/fchomo/listeners.js:650 -#: htdocs/luci-static/resources/view/fchomo/node.js:932 +#: htdocs/luci-static/resources/view/fchomo/node.js:952 msgid "" "The first padding must have a probability of 100% and at least 35 bytes." msgstr "首個填充必須為 100% 的機率並且至少 35 位元組。" @@ -2906,7 +2951,7 @@ msgid "The matching %s will be deemed as poisoned." msgstr "匹配 %s 的將被視為已被投毒汙染。" #: htdocs/luci-static/resources/fchomo/listeners.js:648 -#: htdocs/luci-static/resources/view/fchomo/node.js:930 +#: htdocs/luci-static/resources/view/fchomo/node.js:950 msgid "The server and client can set different padding parameters." msgstr "伺服器和客戶端可以設定不同的填充參數。" @@ -2916,8 +2961,8 @@ msgid "This ECH parameter needs to be added to the HTTPS record of the domain." msgstr "此 ECH 參數需要加入到網域的 HTTPS 記錄中。" #: htdocs/luci-static/resources/view/fchomo/client.js:1579 -#: htdocs/luci-static/resources/view/fchomo/node.js:1040 -#: htdocs/luci-static/resources/view/fchomo/node.js:1651 +#: htdocs/luci-static/resources/view/fchomo/node.js:1060 +#: htdocs/luci-static/resources/view/fchomo/node.js:1709 msgid "" "This is DANGEROUS, your traffic is almost like " "PLAIN TEXT! Use at your own risk!" @@ -2961,18 +3006,18 @@ msgstr "Tproxy 連接埠" msgid "Traffic pattern" msgstr "流量模式" -#: htdocs/luci-static/resources/view/fchomo/node.js:1807 +#: htdocs/luci-static/resources/view/fchomo/node.js:1865 msgid "Transit proxy group" msgstr "中轉代理組" -#: htdocs/luci-static/resources/view/fchomo/node.js:1813 +#: htdocs/luci-static/resources/view/fchomo/node.js:1871 msgid "Transit proxy node" msgstr "中轉代理節點" #: htdocs/luci-static/resources/fchomo/listeners.js:231 #: htdocs/luci-static/resources/fchomo/listeners.js:962 #: htdocs/luci-static/resources/view/fchomo/node.js:355 -#: htdocs/luci-static/resources/view/fchomo/node.js:1122 +#: htdocs/luci-static/resources/view/fchomo/node.js:1142 msgid "Transport" msgstr "傳輸層" @@ -2982,7 +3027,7 @@ msgid "Transport fields" msgstr "傳輸層欄位" #: htdocs/luci-static/resources/fchomo/listeners.js:967 -#: htdocs/luci-static/resources/view/fchomo/node.js:1127 +#: htdocs/luci-static/resources/view/fchomo/node.js:1147 msgid "Transport type" msgstr "傳輸層類型" @@ -3027,8 +3072,8 @@ msgstr "" #: htdocs/luci-static/resources/view/fchomo/client.js:842 #: htdocs/luci-static/resources/view/fchomo/client.js:1028 #: htdocs/luci-static/resources/view/fchomo/node.js:238 -#: htdocs/luci-static/resources/view/fchomo/node.js:1493 -#: htdocs/luci-static/resources/view/fchomo/node.js:1778 +#: htdocs/luci-static/resources/view/fchomo/node.js:1551 +#: htdocs/luci-static/resources/view/fchomo/node.js:1836 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:276 msgid "Type" msgstr "類型" @@ -3043,8 +3088,8 @@ msgstr "類型" #: htdocs/luci-static/resources/fchomo/listeners.js:555 #: htdocs/luci-static/resources/view/fchomo/client.js:588 #: htdocs/luci-static/resources/view/fchomo/client.js:678 -#: htdocs/luci-static/resources/view/fchomo/node.js:865 -#: htdocs/luci-static/resources/view/fchomo/node.js:1625 +#: htdocs/luci-static/resources/view/fchomo/node.js:885 +#: htdocs/luci-static/resources/view/fchomo/node.js:1683 msgid "UDP" msgstr "UDP" @@ -3112,8 +3157,8 @@ msgstr "未知錯誤。" msgid "Unknown error: %s" msgstr "未知錯誤:%s" -#: htdocs/luci-static/resources/view/fchomo/node.js:870 -#: htdocs/luci-static/resources/view/fchomo/node.js:1630 +#: htdocs/luci-static/resources/view/fchomo/node.js:890 +#: htdocs/luci-static/resources/view/fchomo/node.js:1688 msgid "UoT" msgstr "UDP over TCP (UoT)" @@ -3121,22 +3166,22 @@ msgstr "UDP over TCP (UoT)" msgid "Update failed." msgstr "更新失敗。" -#: htdocs/luci-static/resources/view/fchomo/node.js:1562 +#: htdocs/luci-static/resources/view/fchomo/node.js:1620 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:382 msgid "Update interval" msgstr "更新間隔" -#: htdocs/luci-static/resources/view/fchomo/node.js:1322 +#: htdocs/luci-static/resources/view/fchomo/node.js:1380 msgid "Upload bandwidth" msgstr "上傳頻寬" -#: htdocs/luci-static/resources/view/fchomo/node.js:1323 +#: htdocs/luci-static/resources/view/fchomo/node.js:1381 msgid "Upload bandwidth in Mbps." msgstr "上傳頻寬(單位:Mbps)。" #: htdocs/luci-static/resources/fchomo/listeners.js:821 #: htdocs/luci-static/resources/fchomo/listeners.js:861 -#: htdocs/luci-static/resources/view/fchomo/node.js:1051 +#: htdocs/luci-static/resources/view/fchomo/node.js:1071 msgid "Upload certificate" msgstr "上傳憑證" @@ -3145,7 +3190,7 @@ msgid "Upload initial package" msgstr "上傳初始資源包" #: htdocs/luci-static/resources/fchomo/listeners.js:836 -#: htdocs/luci-static/resources/view/fchomo/node.js:1065 +#: htdocs/luci-static/resources/view/fchomo/node.js:1085 msgid "Upload key" msgstr "上傳金鑰" @@ -3153,8 +3198,8 @@ msgstr "上傳金鑰" #: htdocs/luci-static/resources/fchomo/listeners.js:839 #: htdocs/luci-static/resources/fchomo/listeners.js:864 #: htdocs/luci-static/resources/view/fchomo/global.js:306 -#: htdocs/luci-static/resources/view/fchomo/node.js:1054 -#: htdocs/luci-static/resources/view/fchomo/node.js:1068 +#: htdocs/luci-static/resources/view/fchomo/node.js:1074 +#: htdocs/luci-static/resources/view/fchomo/node.js:1088 msgid "Upload..." msgstr "上傳..." @@ -3178,7 +3223,7 @@ msgstr "用於解析 DNS 伺服器的網域。必須是 IP。" msgid "Used to resolve the domain of the Proxy node." msgstr "用於解析代理節點的網域。" -#: htdocs/luci-static/resources/view/fchomo/node.js:977 +#: htdocs/luci-static/resources/view/fchomo/node.js:997 msgid "Used to verify the hostname on the returned certificates." msgstr "用於驗證傳回的憑證上的主機名稱。" @@ -3195,11 +3240,11 @@ msgstr "使用者名稱" msgid "Users filter mode" msgstr "使用者過濾模式" -#: htdocs/luci-static/resources/view/fchomo/node.js:1236 +#: htdocs/luci-static/resources/view/fchomo/node.js:1256 msgid "V2ray HTTPUpgrade" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1241 +#: htdocs/luci-static/resources/view/fchomo/node.js:1261 msgid "V2ray HTTPUpgrade fast open" msgstr "" @@ -3213,8 +3258,8 @@ msgstr "" msgid "VMess" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1499 -#: htdocs/luci-static/resources/view/fchomo/node.js:1784 +#: htdocs/luci-static/resources/view/fchomo/node.js:1557 +#: htdocs/luci-static/resources/view/fchomo/node.js:1842 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:319 msgid "Value" msgstr "可視化值" @@ -3225,11 +3270,11 @@ msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:514 #: htdocs/luci-static/resources/view/fchomo/node.js:506 -#: htdocs/luci-static/resources/view/fchomo/node.js:836 +#: htdocs/luci-static/resources/view/fchomo/node.js:856 msgid "Version" msgstr "版本" -#: htdocs/luci-static/resources/view/fchomo/node.js:844 +#: htdocs/luci-static/resources/view/fchomo/node.js:864 msgid "Version hint" msgstr "" @@ -3248,14 +3293,14 @@ msgstr "警告" #: htdocs/luci-static/resources/fchomo/listeners.js:393 #: htdocs/luci-static/resources/fchomo/listeners.js:969 -#: htdocs/luci-static/resources/fchomo/listeners.js:980 +#: htdocs/luci-static/resources/fchomo/listeners.js:978 #: htdocs/luci-static/resources/fchomo/listeners.js:985 #: htdocs/luci-static/resources/view/fchomo/node.js:460 #: htdocs/luci-static/resources/view/fchomo/node.js:489 -#: htdocs/luci-static/resources/view/fchomo/node.js:1132 -#: htdocs/luci-static/resources/view/fchomo/node.js:1143 -#: htdocs/luci-static/resources/view/fchomo/node.js:1150 -#: htdocs/luci-static/resources/view/fchomo/node.js:1156 +#: htdocs/luci-static/resources/view/fchomo/node.js:1152 +#: htdocs/luci-static/resources/view/fchomo/node.js:1163 +#: htdocs/luci-static/resources/view/fchomo/node.js:1170 +#: htdocs/luci-static/resources/view/fchomo/node.js:1176 msgid "WebSocket" msgstr "" @@ -3271,27 +3316,42 @@ msgstr "白名單" msgid "WireGuard" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:755 +#: htdocs/luci-static/resources/view/fchomo/node.js:775 msgid "WireGuard peer public key." msgstr "WireGuard 對端公鑰。" -#: htdocs/luci-static/resources/view/fchomo/node.js:762 +#: htdocs/luci-static/resources/view/fchomo/node.js:782 msgid "WireGuard pre-shared key." msgstr "WireGuard 預先共用金鑰。" -#: htdocs/luci-static/resources/view/fchomo/node.js:747 +#: htdocs/luci-static/resources/view/fchomo/node.js:767 msgid "WireGuard requires base64-encoded private keys." msgstr "WireGuard 要求 base64 編碼的私鑰。" -#: htdocs/luci-static/resources/view/fchomo/node.js:1133 -#: htdocs/luci-static/resources/view/fchomo/node.js:1151 +#: htdocs/luci-static/resources/fchomo/listeners.js:970 +#: htdocs/luci-static/resources/fchomo/listeners.js:979 +#: htdocs/luci-static/resources/view/fchomo/node.js:1153 +#: htdocs/luci-static/resources/view/fchomo/node.js:1171 msgid "XHTTP" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1246 +#: htdocs/luci-static/resources/fchomo/listeners.js:1015 +#: htdocs/luci-static/resources/view/fchomo/node.js:1266 msgid "XHTTP mode" msgstr "XHTTP 模式" +#: htdocs/luci-static/resources/view/fchomo/node.js:1290 +msgid "XMUX" +msgstr "" + +#: htdocs/luci-static/resources/view/fchomo/node.js:1295 +#: htdocs/luci-static/resources/view/fchomo/node.js:1300 +#: htdocs/luci-static/resources/view/fchomo/node.js:1305 +#: htdocs/luci-static/resources/view/fchomo/node.js:1310 +#: htdocs/luci-static/resources/view/fchomo/node.js:1315 +msgid "XMUX:" +msgstr "" + #: htdocs/luci-static/resources/fchomo/listeners.js:609 msgid "XOR mode" msgstr "XOR 模式" @@ -3338,7 +3398,7 @@ msgstr "bbr" #: htdocs/luci-static/resources/fchomo/listeners.js:826 #: htdocs/luci-static/resources/fchomo/listeners.js:866 -#: htdocs/luci-static/resources/view/fchomo/node.js:1056 +#: htdocs/luci-static/resources/view/fchomo/node.js:1076 msgid "certificate" msgstr "憑證" @@ -3365,13 +3425,13 @@ msgstr "decryption" msgid "dnsmasq selects upstream on its own. (may affect CDN accuracy)" msgstr "dnsmasq 自行選擇上游服務器。 (可能影響 CDN 準確性)" -#: htdocs/luci-static/resources/view/fchomo/node.js:1642 +#: htdocs/luci-static/resources/view/fchomo/node.js:1700 msgid "down" msgstr "Hysteria 下載速率" #: htdocs/luci-static/resources/fchomo/listeners.js:596 -#: htdocs/luci-static/resources/view/fchomo/node.js:884 -#: htdocs/luci-static/resources/view/fchomo/node.js:907 +#: htdocs/luci-static/resources/view/fchomo/node.js:904 +#: htdocs/luci-static/resources/view/fchomo/node.js:927 msgid "encryption" msgstr "encryption" @@ -3381,25 +3441,25 @@ msgid "false = bandwidth optimized downlink; true = pure Sudoku downlink." msgstr "false = 頻寬最佳化下行 true = 純 Sudoku 下行。" #: htdocs/luci-static/resources/fchomo/listeners.js:968 -#: htdocs/luci-static/resources/fchomo/listeners.js:979 +#: htdocs/luci-static/resources/fchomo/listeners.js:977 #: htdocs/luci-static/resources/fchomo/listeners.js:984 -#: htdocs/luci-static/resources/view/fchomo/node.js:1131 -#: htdocs/luci-static/resources/view/fchomo/node.js:1142 -#: htdocs/luci-static/resources/view/fchomo/node.js:1149 -#: htdocs/luci-static/resources/view/fchomo/node.js:1155 +#: htdocs/luci-static/resources/view/fchomo/node.js:1151 +#: htdocs/luci-static/resources/view/fchomo/node.js:1162 +#: htdocs/luci-static/resources/view/fchomo/node.js:1169 +#: htdocs/luci-static/resources/view/fchomo/node.js:1175 msgid "gRPC" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1212 +#: htdocs/luci-static/resources/view/fchomo/node.js:1232 msgid "gRPC User-Agent" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1217 +#: htdocs/luci-static/resources/view/fchomo/node.js:1237 msgid "gRPC ping interval" msgstr "gRPC ping 間隔" -#: htdocs/luci-static/resources/fchomo/listeners.js:1003 -#: htdocs/luci-static/resources/view/fchomo/node.js:1208 +#: htdocs/luci-static/resources/fchomo/listeners.js:1009 +#: htdocs/luci-static/resources/view/fchomo/node.js:1228 msgid "gRPC service name" msgstr "gRPC 服務名稱" @@ -3407,7 +3467,7 @@ msgstr "gRPC 服務名稱" msgid "gVisor" msgstr "gVisor" -#: htdocs/luci-static/resources/view/fchomo/node.js:1273 +#: htdocs/luci-static/resources/view/fchomo/node.js:1331 msgid "h2mux" msgstr "" @@ -3425,7 +3485,7 @@ msgstr "metacubexd" #: htdocs/luci-static/resources/view/fchomo/client.js:1480 #: htdocs/luci-static/resources/view/fchomo/client.js:1711 #: htdocs/luci-static/resources/view/fchomo/client.js:1767 -#: htdocs/luci-static/resources/view/fchomo/node.js:1465 +#: htdocs/luci-static/resources/view/fchomo/node.js:1523 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:239 msgid "mihomo config" msgstr "mihomo 配置" @@ -3434,8 +3494,8 @@ msgstr "mihomo 配置" msgid "mlkem768x25519plus" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1339 -#: htdocs/luci-static/resources/view/fchomo/node.js:1620 +#: htdocs/luci-static/resources/view/fchomo/node.js:1397 +#: htdocs/luci-static/resources/view/fchomo/node.js:1678 msgid "mpTCP" msgstr "多路徑 TCP (mpTCP)" @@ -3460,7 +3520,7 @@ msgstr "非空值" #: htdocs/luci-static/resources/fchomo/listeners.js:495 #: htdocs/luci-static/resources/view/fchomo/node.js:647 #: htdocs/luci-static/resources/view/fchomo/node.js:667 -#: htdocs/luci-static/resources/view/fchomo/node.js:805 +#: htdocs/luci-static/resources/view/fchomo/node.js:825 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:315 msgid "none" msgstr "無" @@ -3479,7 +3539,7 @@ msgstr "不包含 \",\"" msgid "null" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:806 +#: htdocs/luci-static/resources/view/fchomo/node.js:826 msgid "obfs-simple" msgstr "" @@ -3491,7 +3551,7 @@ msgstr "僅當 %s 為 %s 時適用。" msgid "only applies when %s is not %s." msgstr "僅當 %s 不為 %s 時適用。" -#: htdocs/luci-static/resources/view/fchomo/node.js:1600 +#: htdocs/luci-static/resources/view/fchomo/node.js:1658 msgid "override.proxy-name" msgstr "" @@ -3499,7 +3559,8 @@ msgstr "" msgid "packet addr (v2ray-core v5+)" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1248 +#: htdocs/luci-static/resources/fchomo/listeners.js:1019 +#: htdocs/luci-static/resources/view/fchomo/node.js:1270 msgid "packet-up" msgstr "" @@ -3509,7 +3570,7 @@ msgid "poll" msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:841 -#: htdocs/luci-static/resources/view/fchomo/node.js:1070 +#: htdocs/luci-static/resources/view/fchomo/node.js:1090 msgid "private key" msgstr "私鑰" @@ -3522,7 +3583,7 @@ msgstr "razord-meta" msgid "requires front-end adaptation using the API." msgstr "需要使用 API 的前端適配。" -#: htdocs/luci-static/resources/view/fchomo/node.js:810 +#: htdocs/luci-static/resources/view/fchomo/node.js:830 msgid "restls" msgstr "" @@ -3531,11 +3592,11 @@ msgid "rule-set" msgstr "規則集" #: htdocs/luci-static/resources/fchomo/listeners.js:496 -#: htdocs/luci-static/resources/view/fchomo/node.js:809 +#: htdocs/luci-static/resources/view/fchomo/node.js:829 msgid "shadow-tls" msgstr "" -#: htdocs/luci-static/resources/view/fchomo/node.js:1271 +#: htdocs/luci-static/resources/view/fchomo/node.js:1329 msgid "smux" msgstr "" @@ -3548,10 +3609,20 @@ msgstr "" msgid "src" msgstr "src" -#: htdocs/luci-static/resources/view/fchomo/node.js:1247 +#: htdocs/luci-static/resources/fchomo/listeners.js:1017 +#: htdocs/luci-static/resources/view/fchomo/node.js:1268 msgid "stream-one" msgstr "" +#: htdocs/luci-static/resources/fchomo/listeners.js:1018 +#: htdocs/luci-static/resources/view/fchomo/node.js:1269 +msgid "stream-up" +msgstr "" + +#: htdocs/luci-static/resources/fchomo/listeners.js:1028 +msgid "stream-up server seconds" +msgstr "" + #: htdocs/luci-static/resources/view/fchomo/node.js:491 msgid "stream/poll/auto" msgstr "" @@ -3576,28 +3647,28 @@ msgstr "獨立標識" msgid "unique value" msgstr "獨立值" -#: htdocs/luci-static/resources/view/fchomo/node.js:1636 +#: htdocs/luci-static/resources/view/fchomo/node.js:1694 msgid "up" msgstr "Hysteria 上傳速率" #: htdocs/luci-static/resources/fchomo/listeners.js:515 #: htdocs/luci-static/resources/view/fchomo/node.js:507 #: htdocs/luci-static/resources/view/fchomo/node.js:542 -#: htdocs/luci-static/resources/view/fchomo/node.js:837 -#: htdocs/luci-static/resources/view/fchomo/node.js:877 +#: htdocs/luci-static/resources/view/fchomo/node.js:857 +#: htdocs/luci-static/resources/view/fchomo/node.js:897 msgid "v1" msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:516 #: htdocs/luci-static/resources/view/fchomo/node.js:508 -#: htdocs/luci-static/resources/view/fchomo/node.js:838 -#: htdocs/luci-static/resources/view/fchomo/node.js:878 +#: htdocs/luci-static/resources/view/fchomo/node.js:858 +#: htdocs/luci-static/resources/view/fchomo/node.js:898 msgid "v2" msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:517 #: htdocs/luci-static/resources/view/fchomo/node.js:509 -#: htdocs/luci-static/resources/view/fchomo/node.js:839 +#: htdocs/luci-static/resources/view/fchomo/node.js:859 msgid "v3" msgstr "" @@ -3606,7 +3677,7 @@ msgstr "" msgid "valid JSON format" msgstr "有效的 JSON 格式" -#: htdocs/luci-static/resources/view/fchomo/node.js:1030 +#: htdocs/luci-static/resources/view/fchomo/node.js:1050 msgid "valid SHA256 string with %d characters" msgstr "包含 %d 個字元的有效 SHA256 字串" @@ -3652,7 +3723,7 @@ msgstr "" msgid "yacd-meta" msgstr "yacd-meta" -#: htdocs/luci-static/resources/view/fchomo/node.js:1272 +#: htdocs/luci-static/resources/view/fchomo/node.js:1330 msgid "yamux" msgstr "" diff --git a/luci-app-fchomo/root/usr/share/fchomo/generate_client.uc b/luci-app-fchomo/root/usr/share/fchomo/generate_client.uc index a2ae2ccb..4926e297 100644 --- a/luci-app-fchomo/root/usr/share/fchomo/generate_client.uc +++ b/luci-app-fchomo/root/usr/share/fchomo/generate_client.uc @@ -649,7 +649,10 @@ uci.foreach(uciconf, ucinode, (cfg) => { "grpc-opts": cfg.transport_type === 'grpc' ? { "grpc-service-name": cfg.transport_grpc_servicename, "grpc-user-agent": cfg.transport_grpc_user_agent, - "ping-interval": strToInt(cfg.transport_grpc_ping_interval) || null + "ping-interval": strToInt(cfg.transport_grpc_ping_interval) || null, + "max-connections": strToInt(cfg.smux_max_connections) || null, + "min-streams": strToInt(cfg.smux_min_streams) || null, + "max-streams": strToInt(cfg.smux_max_streams) || null, } : null, "ws-opts": cfg.transport_type === 'ws' ? { path: cfg.transport_path || '/', @@ -665,11 +668,24 @@ uci.foreach(uciconf, ucinode, (cfg) => { headers: cfg.transport_http_headers ? json(cfg.transport_http_headers) : null, mode: cfg.transport_xhttp_mode, "no-grpc-header": strToBool(cfg.transport_xhttp_no_grpc_header), - "x-padding-bytes": cfg.transport_xhttp_x_padding_bytes + "x-padding-bytes": cfg.transport_xhttp_x_padding_bytes, + "sc-max-each-post-bytes": strToInt(cfg.transport_xhttp_sc_max_each_post_bytes) || null, + "reuse-settings": cfg.transport_xhttp_xmux ? { + "max-connections": cfg.transport_xhttp_xmux_max_connections, + "max-concurrency": cfg.transport_xhttp_xmux_max_concurrency, + "c-max-reuse-times": cfg.transport_xhttp_xmux_max_reuse_times, + "h-max-request-times": cfg.transport_xhttp_xmux_max_request_times, + "h-max-reusable-secs": cfg.transport_xhttp_xmux_max_reusable_secs + } : null } : null } : {}), /* Multiplex fields */ + ...(cfg.type in ['trusttunnel'] ? { + "max-connections": strToInt(cfg.smux_max_connections) || null, + "min-streams": strToInt(cfg.smux_min_streams) || null, + "max-streams": strToInt(cfg.smux_max_streams) || null + } : {}), smux: cfg.smux_enabled === '1' ? { enabled: true, protocol: cfg.smux_protocol, diff --git a/luci-app-fchomo/root/usr/share/ucode/fchomo.uc b/luci-app-fchomo/root/usr/share/ucode/fchomo.uc index 3d05cced..8bbf9d4e 100644 --- a/luci-app-fchomo/root/usr/share/ucode/fchomo.uc +++ b/luci-app-fchomo/root/usr/share/ucode/fchomo.uc @@ -345,8 +345,16 @@ export function parseListener(cfg, isClient, label) { /* Transport fields */ ...(cfg.transport_enabled === '1' ? { - "grpc-service-name": cfg.transport_grpc_servicename, - "ws-path": cfg.transport_path + "grpc-service-name": cfg.transport_type === 'grpc' ? cfg.transport_grpc_servicename : null, + "ws-path": cfg.transport_type === 'ws' ? cfg.transport_path : null, + "xhttp-config": cfg.transport_type === 'xhttp' ? { + path: cfg.transport_path, + host: cfg.transport_host, + mode: cfg.transport_xhttp_mode, + "no-sse-header": strToBool(cfg.transport_xhttp_no_sse_header), + "sc-stream-up-server-secs": cfg.transport_xhttp_sc_stream_up_server_secs, + "sc-max-each-post-bytes": strToInt(cfg.transport_xhttp_sc_max_each_post_bytes) || null, + } : null } : {}) } }; diff --git a/luci-app-openclawmgr/Makefile b/luci-app-openclawmgr/Makefile index e5ce4791..80fb9328 100644 --- a/luci-app-openclawmgr/Makefile +++ b/luci-app-openclawmgr/Makefile @@ -1,8 +1,8 @@ include $(TOPDIR)/rules.mk -PKG_VERSION:=0.1.9 -PKG_RELEASE:=11 +PKG_VERSION:=0.1.10 +PKG_RELEASE:=12 LUCI_TITLE:=LuCI support for OpenClaw Launcher LUCI_PKGARCH:=all diff --git a/luci-app-openclawmgr/htdocs/luci-static/resources/openclawmgr/app.css b/luci-app-openclawmgr/htdocs/luci-static/resources/openclawmgr/app.css index 4b3a9c57..ebb8c6ab 100644 --- a/luci-app-openclawmgr/htdocs/luci-static/resources/openclawmgr/app.css +++ b/luci-app-openclawmgr/htdocs/luci-static/resources/openclawmgr/app.css @@ -327,6 +327,73 @@ color: var(--oclm-primary); } +.oclm-button-ghost { + background: transparent; + border-color: transparent; + color: var(--oclm-subtle); + box-shadow: none; +} + +.oclm-button-ghost:hover { + background: rgba(47, 103, 246, 0.08); + border-color: transparent; + color: var(--oclm-primary); +} + +.oclm-button-ghost-danger { + background: transparent; + border-color: transparent; + color: var(--oclm-danger); + box-shadow: none; +} + +.oclm-button-ghost-danger:hover { + background: rgba(239, 68, 68, 0.08); + border-color: transparent; + color: #dc2626; +} + +.oclm-icon-ghost-button { + appearance: none; + display: inline-flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + padding: 0; + border: 0; + border-radius: 8px; + background: transparent; + color: var(--oclm-subtle); + cursor: pointer; +} + +.oclm-icon-ghost-button:hover { + background: rgba(47, 103, 246, 0.08); + color: var(--oclm-primary); +} + +.oclm-icon-ghost-button:disabled { + opacity: 0.55; + cursor: default; +} + +.oclm-icon-ghost-danger { + color: var(--oclm-danger); +} + +.oclm-icon-ghost-danger:hover { + background: rgba(239, 68, 68, 0.08); + color: #dc2626; +} + +.oclm-row-icon { + width: 16px; + height: 16px; + stroke: currentColor; + fill: none; +} + .oclm-form-grid { display: grid; gap: 14px; @@ -564,6 +631,295 @@ font-size: 12px; } +.oclm-security-hero { + margin-bottom: 16px; +} + +.oclm-security-hero-title { + margin: 0 0 6px; + font-size: 18px; + font-weight: 700; +} + +.oclm-security-stack { + display: grid; + gap: 16px; +} + +.oclm-security-card, +.oclm-security-info-card { + border: 1px solid var(--oclm-border); + border-radius: 16px; + background: var(--oclm-card); + padding: 16px; +} + +.oclm-security-title-row { + margin-bottom: 12px; +} + +.oclm-security-title-row .oclm-hint { + margin-top: 4px; +} + +.oclm-security-title-row h3, +.oclm-security-info-card h3, +.oclm-dialog-card h3 { + margin: 0 0 6px; + font-size: 15px; +} + +.oclm-security-input-row { + display: flex; + gap: 8px; + align-items: flex-start; +} + +.oclm-security-input-wrap { + min-width: 0; + flex: 1; +} + +#oclm-security-add { + flex: 0 0 auto; + white-space: nowrap; +} + +.oclm-control-danger { + border-color: rgba(239, 68, 68, 0.7); + box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.08); +} + +.oclm-security-error { + margin-top: 6px; + color: var(--oclm-danger); + font-size: 12px; +} + +.oclm-security-list-box { + margin-top: 16px; + border: 1px solid var(--oclm-border); + border-radius: 12px; + overflow: hidden; + background: var(--oclm-card); +} + +.oclm-security-list { + display: grid; + gap: 0; +} + +.oclm-security-row { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 12px; + padding: 16px; +} + +.oclm-security-row + .oclm-security-row { + border-top: 1px solid var(--oclm-border); +} + +.oclm-security-row-main { + display: flex; + min-width: 0; + flex: 1; + flex-direction: column; +} + +.oclm-security-item-path { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 8px; + margin-bottom: 10px; +} + +.oclm-security-item-path code, +.oclm-dialog-code { + display: inline-block; + max-width: 100%; + padding: 6px 8px; + border-radius: 8px; + background: rgba(148, 163, 184, 0.14); + font: 12px/1.5 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; + word-break: break-all; +} + +.oclm-security-badge { + display: inline-flex; + align-items: center; + min-height: 24px; + padding: 0 10px; + border-radius: 999px; + font-size: 12px; + font-weight: 700; +} + +.oclm-security-badge.is-active { + background: rgba(18, 185, 129, 0.12); + color: var(--oclm-success); +} + +.oclm-security-badge.is-danger { + background: rgba(239, 68, 68, 0.12); + color: var(--oclm-danger); +} + +.oclm-security-badge.is-muted { + background: rgba(148, 163, 184, 0.16); + color: var(--oclm-subtle); +} + +.oclm-security-item-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 10px 16px; + color: var(--oclm-subtle); + font-size: 13px; +} + +.oclm-security-key { + color: var(--oclm-text); + font-weight: 600; +} + +.oclm-security-row-actions { + display: flex; + gap: 4px; + flex-wrap: wrap; + flex: 0 0 auto; +} + +.oclm-security-empty { + margin-top: 16px; + border: 1px dashed var(--oclm-border); + border-radius: 14px; + padding: 28px 16px; + text-align: center; + color: var(--oclm-subtle); +} + +.oclm-security-empty-icon { + font-size: 28px; + margin-bottom: 6px; +} + +.oclm-security-info-card { + background: rgba(47, 103, 246, 0.06); + border-color: rgba(96, 165, 250, 0.32); +} + +.oclm-security-info-card h3 { + margin-bottom: 10px; +} + +.oclm-security-info-card ul { + margin: 0; + padding-left: 18px; + color: var(--oclm-subtle); +} + +.oclm-security-info-card li + li { + margin-top: 8px; +} + +.oclm-dialog { + position: fixed; + inset: 0; + z-index: 9998; + display: flex; + align-items: center; + justify-content: center; + padding: 20px; + background: rgba(15, 23, 42, 0.42); +} + +.oclm-dialog-card { + width: min(560px, 100%); + border-radius: 18px; + border: 1px solid var(--oclm-border); + background: var(--oclm-card); + box-shadow: var(--oclm-shadow); + padding: 20px; +} + +.oclm-dialog-text { + color: var(--oclm-subtle); + margin-bottom: 10px; +} + +.oclm-dialog-code { + display: block; + margin-bottom: 14px; +} + +.oclm-dialog-warning { + margin-top: 4px; + margin-bottom: 14px; + padding: 12px 14px; + border: 1px solid rgba(245, 158, 11, 0.24); + border-radius: 12px; + background: rgba(245, 158, 11, 0.08); +} + +.oclm-dialog-warning-title { + margin-bottom: 8px; + color: var(--oclm-text); + font-size: 13px; + font-weight: 700; +} + +.oclm-dialog-warning ul { + margin: 0; + padding-left: 18px; + color: var(--oclm-subtle); +} + +.oclm-dialog-warning li + li { + margin-top: 6px; +} + +.oclm-dialog-actions { + display: grid; + gap: 10px; +} + +.oclm-dialog-option { + justify-content: flex-start; + align-items: flex-start; + flex-direction: column; + min-height: 58px; + height: auto; + padding: 12px 14px; +} + +.oclm-dialog-option-title { + color: var(--oclm-text); + font-weight: 700; + text-align: left; +} + +.oclm-dialog-option-note { + margin-top: 4px; + color: var(--oclm-subtle); + font-size: 12px; + font-weight: 500; + text-align: left; +} + +.oclm-dialog-footer { + display: flex; + justify-content: flex-end; + gap: 14px; + margin-top: 12px; +} + +.oclm-dialog-footer .oclm-button { + min-width: 96px; +} + .oclm-banner { color: var(--oclm-danger); margin-bottom: 12px; @@ -646,6 +1002,27 @@ gap: 8px; } + .oclm-security-item-grid { + grid-template-columns: 1fr; + } + + .oclm-security-input-row, + .oclm-security-row { + flex-direction: column; + } + + .oclm-security-row-actions { + justify-content: flex-start; + } + + .oclm-dialog-footer { + justify-content: stretch; + } + + .oclm-dialog-footer .oclm-button { + width: 100%; + } + .oclm-log-modal { padding: 12px; } diff --git a/luci-app-openclawmgr/htdocs/luci-static/resources/openclawmgr/app.js b/luci-app-openclawmgr/htdocs/luci-static/resources/openclawmgr/app.js index 543f3776..01efa96c 100644 --- a/luci-app-openclawmgr/htdocs/luci-static/resources/openclawmgr/app.js +++ b/luci-app-openclawmgr/htdocs/luci-static/resources/openclawmgr/app.js @@ -26,11 +26,25 @@ } var root = container.attachShadow ? (container.shadowRoot || container.attachShadow({ mode: "open" })) : container; + + function defaultProtectedDirectories() { + return []; + } + var state = { status: null, form: null, options: null, newOrigin: "", + security: { + runningUser: "openclawmgr", + newDirectoryPath: "", + directoryError: "", + pendingAddPath: "", + deleteTargetId: null, + deleteTargetPath: "", + protectedDirectories: defaultProtectedDirectories() + }, activeTab: "basic", savingSection: "", lastAppliedAt: "", @@ -102,60 +116,32 @@ .replace(/"/g, """); } - function modelForAgent(agent) { + function defaultModelForAgent(agent) { return { - openai: "openai/gpt-5.2", - anthropic: "anthropic/claude-sonnet-4-6", - "minimax-cn": "minimax-cn/MiniMax-M2.5", - moonshot: "moonshot/kimi-k2.5", - "custom-provider": "custom-provider/custom-model" - }[agent] || "anthropic/claude-sonnet-4-6"; + openai: "gpt-5.2", + anthropic: "claude-sonnet-4-6", + "minimax-cn": "MiniMax-M2.5", + moonshot: "kimi-k2.5", + "custom-provider": "custom-model" + }[agent] || "claude-sonnet-4-6"; } - function modelPrefixForAgent(agent) { - return { - openai: "openai", - anthropic: "anthropic", - "minimax-cn": "minimax-cn", - moonshot: "moonshot", - "custom-provider": "custom-provider" - }[agent] || "anthropic"; - } - - function normalizeModelValue(agent, value) { - var prefix = modelPrefixForAgent(agent); + function normalizeModelValue(value, fallback) { value = String(value || "").replace(/^\s+|\s+$/g, ""); if (!value) { - return modelForAgent(agent); + return String(fallback || ""); } - if (value.indexOf(prefix + "/") === 0) { - return value; - } - if (/^[^/]+\/.+/.test(value)) { - return prefix + "/" + value.replace(/^[^/]+\//, ""); - } - return prefix + "/" + value; - } - - function modelMatchesAgent(agent, model) { - model = String(model || ""); - return model.indexOf(modelPrefixForAgent(agent) + "/") === 0; + return value.replace(/^[^/]+\//, ""); } function resolveModelValue(form) { var agent = form && form.default_agent ? form.default_agent : "anthropic"; var value = form && form.default_model ? String(form.default_model) : ""; - if (!value || !modelMatchesAgent(agent, value)) { - return normalizeModelValue(agent, value); - } - return value; + return normalizeModelValue(value, defaultModelForAgent(agent)); } - function modelPlaceholder(agent) { - if (agent === "custom-provider") { - return "例如 gpt-5.1 或 custom-provider/gpt-5.1"; - } - return "请按照/格式填写"; + function modelPlaceholder() { + return "这里只填写模型名;例如 gpt-5.1"; } function statusText(status) { @@ -181,6 +167,101 @@ return escapeHtml(value).replace(/'/g, "'"); } + function getSecurityState() { + if (!state.security) { + state.security = { + runningUser: "openclawmgr", + newDirectoryPath: "", + directoryError: "", + pendingAddPath: "", + deleteTargetId: null, + deleteTargetPath: "", + protectedDirectories: defaultProtectedDirectories() + }; + } + if (!Array.isArray(state.security.protectedDirectories)) { + state.security.protectedDirectories = defaultProtectedDirectories(); + } + if (state.security.newDirectoryPath == null) { + state.security.newDirectoryPath = ""; + } + if (state.security.directoryError == null) { + state.security.directoryError = ""; + } + if (state.security.pendingAddPath == null) { + state.security.pendingAddPath = ""; + } + if (state.security.deleteTargetPath == null) { + state.security.deleteTargetPath = ""; + } + return state.security; + } + + function securityDataDirectory() { + var formBaseDir = state.form && state.form.base_dir ? String(state.form.base_dir) : ""; + var statusBaseDir = state.status && state.status.base_dir ? String(state.status.base_dir) : ""; + var suggestedBaseDir = state.options && state.options.suggested_base_dir ? String(state.options.suggested_base_dir) : ""; + return formBaseDir || statusBaseDir || suggestedBaseDir || ""; + } + + function validateProtectedDirectory(path) { + var security = getSecurityState(); + var value = String(path || "").replace(/^\s+|\s+$/g, ""); + var dataDirectory = securityDataDirectory(); + if (!value) { + return "请输入目录路径"; + } + if (value.charAt(0) !== "/") { + return "请输入绝对路径"; + } + if (value === "/") { + return "不能添加根目录 /"; + } + if (dataDirectory && (value === dataDirectory || value.indexOf(dataDirectory + "/") === 0)) { + return "不能添加 OpenClaw 的运行目录"; + } + if (dataDirectory && dataDirectory.indexOf(value + "/") === 0) { + return "不能添加 OpenClaw 运行目录的父目录"; + } + if (security.protectedDirectories.some(function(item) { return item.path === value; })) { + return "该目录已在列表中"; + } + return ""; + } + + function securityProtectionMode(level) { + return level === "strict" ? "仅允许 root 访问" : "仅允许 root 和 root 组访问"; + } + + function securityStatusBadge(status) { + var map = { + active: ["已生效", "is-active"], + inactive: ["未生效", "is-danger"], + "not-found": ["目录不存在", "is-muted"], + denied: ["已拒绝", "is-active"], + "check-failed": ["检测失败", "is-danger"] + }; + var item = map[status] || [status || "未知", "is-muted"]; + return '' + escapeHtml(item[0]) + ''; + } + + function loadSecurityData(done) { + if (!config.securityDataUrl) { + if (typeof done === "function") done(); + return; + } + request(config.securityDataUrl).then(function(rv) { + var security = getSecurityState(); + security.protectedDirectories = rv && rv.ok && Array.isArray(rv.items) ? rv.items : []; + render(); + if (typeof done === "function") done(rv); + }).catch(function() { + getSecurityState().protectedDirectories = []; + render(); + if (typeof done === "function") done(null); + }); + } + function maskedTokenUrl(url) { var value = String(url || ""); if (!value) { @@ -335,6 +416,26 @@ ''; } + function refreshIcon(className) { + return '' + + ''; + } + + function trashIcon(className) { + return '' + + ''; + } + function taskWindowAvailable() { return !!(window.taskd && window.taskd.show_log); } @@ -448,6 +549,7 @@ var status = state.status || {}; var form = state.form || {}; var options = state.options || { base_dir_choices: [] }; + var security = getSecurityState(); var allowedOrigins = Array.isArray(form.allowed_origins) ? form.allowed_origins : []; var baseDirOptions = (options.base_dir_choices || []).map(function(path) { return ''; @@ -472,6 +574,24 @@ var savingAi = state.savingSection === "ai"; var savingAccess = state.savingSection === "access"; var noteText = statusNoteText(status); + var securityList = security.protectedDirectories.map(function(item) { + return '' + + '
' + + '
' + + '
' + escapeHtml(item.path) + '' + securityStatusBadge(item.status) + '
' + + '
' + + '
保护方式:' + escapeHtml(item.protectionMode) + '
' + + '
检测结果:' + escapeHtml(item.checkResult) + '
' + + '
' + + '
' + + '
' + + '' + + '' + + '
' + + '
'; + }).join(""); + var addDialogOpen = !!security.pendingAddPath; + var deleteDialogOpen = security.deleteTargetId != null; var canStartService = !status.running && !status.reachable; var canStopService = !!status.running; @@ -515,6 +635,7 @@ '' + '' + '' + + '' + '' + '' + '' + @@ -553,7 +674,7 @@ : "如果你的供应商兼容 OpenAI 协议,可选择“自定义供应商”并在下方填写地址与模型。") + '') + fieldInput("API 密钥", passwordHtml("oclm-api-key", form.provider_api_key || "", "sk-...")) + fieldInput(form.default_agent === "custom-provider" ? "服务地址" : "中转地址(可选)", '') + - fieldInput("默认模型", '
将按照“供应商名称/模型名称”的格式保存
') + + fieldInput("默认模型", '
这里只填写模型名;例如 gpt-5.1
') + '
' + (state.lastAppliedAt ? '已于 ' + escapeHtml(state.lastAppliedAt) + ' 更新配置' : '') + '
' + '' + @@ -569,6 +690,37 @@ '
' + (state.lastAppliedAt ? '已于 ' + escapeHtml(state.lastAppliedAt) + ' 更新配置' : '') + '
' + '' + + '
' + + '
' + + '

🔒 禁止访问目录

' + + '
在 OpenClaw 以 ' + escapeHtml(security.runningUser) + ' 用户运行时禁止读取本地敏感目录。可能导致影响其他程序访问,请谨慎使用。
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '' + + '
' + escapeHtml(security.directoryError || "") + '
' + + '
请输入绝对路径。不建议添加整个磁盘根目录或 OpenClaw 自身工作目录。
' + + '
' + + '' + + '
' + + (security.protectedDirectories.length + ? '
' + securityList + '
' + : '
🔒
暂无受保护的目录
添加目录以限制 OpenClaw 访问
') + + '
' + + '
' + + '

ℹ 使用说明

' + + '
    ' + + '
  • 本功能通过 Linux 文件权限限制 openclawmgr 用户访问目录。
  • ' + + '
  • 本功能不是容器或沙箱隔离。
  • ' + + '
  • 修改目录权限后,可能影响其他服务或用户访问这些目录。
  • ' + + '
  • 请勿将 OpenClaw 的数据目录、程序目录加入禁止访问列表。
  • ' + + '
' + + '
' + + '
' + + '
' + + '
' + '

版本管理

openclaw 官方正在快速迭代,最新版本可能不兼容旧版本配置导致无法启动。请加入交流群了解最新稳定版本号
' + '
' + @@ -594,6 +746,41 @@ '' + '
' + '
' + + '
' + + '
' + + '

删除禁止访问目录

' + + '
确定要从保护列表中移除以下目录吗?
' + + '' + escapeHtml(security.deleteTargetPath || "") + '' + + '
请选择删除方式:
' + + '
' + + '' + + '' + + '
' + + '' + + '
' + + '
' + + '
' + + '
' + + '

确认添加禁止访问目录

' + + '
添加后将尝试修改该目录权限,限制 OpenClaw 对其访问:
' + + '' + escapeHtml(security.pendingAddPath || "") + '' + + '
' + + '
请确认你已知晓以下风险:
' + + '
    ' + + '
  • 该目录的 Linux 权限会被修改为仅允许 root 和 root 组访问。
  • ' + + '
  • 这可能影响其他服务、用户或脚本对该目录的正常访问。
  • ' + + '
  • 本功能不是容器或沙箱隔离,只是基于系统文件权限限制。
  • ' + + '
  • 请勿将 OpenClaw 自身的数据目录、程序目录加入禁止访问列表。
  • ' + + '
' + + '
' + + '' + + '
' + + '
' + '' + ''; @@ -821,6 +1008,10 @@ var newOriginEl = getEl("oclm-new-origin"); if (newOriginEl) state.newOrigin = newOriginEl.value; + + var securityPathEl = getEl("oclm-security-path"); + if (securityPathEl) getSecurityState().newDirectoryPath = securityPathEl.value; + } function bindEvents() { @@ -1060,11 +1251,11 @@ if (agent) { agent.onchange = function() { syncDraftFromDom(); - state.form.default_agent = agent.value; - state.form.default_model = modelForAgent(agent.value); - render(); - }; - } + state.form.default_agent = agent.value; + state.form.default_model = defaultModelForAgent(agent.value); + render(); + }; + } var apiKey = root.getElementById("oclm-api-key"); if (apiKey) { @@ -1125,6 +1316,158 @@ }; }); + var securityPath = root.getElementById("oclm-security-path"); + if (securityPath) { + securityPath.oninput = function() { + var security = getSecurityState(); + security.newDirectoryPath = securityPath.value; + if (security.directoryError) { + security.directoryError = ""; + securityPath.classList.remove("oclm-control-danger"); + var errorEl = root.getElementById("oclm-security-error"); + if (errorEl) { + errorEl.textContent = ""; + errorEl.classList.add("oclm-hidden"); + } + } + }; + } + + var securityAdd = root.getElementById("oclm-security-add"); + if (securityAdd) { + securityAdd.onclick = function() { + var security = getSecurityState(); + var path = securityPath && securityPath.value ? securityPath.value.replace(/^\s+|\s+$/g, "") : ""; + var error = validateProtectedDirectory(path); + if (error) { + security.directoryError = error; + render(); + return; + } + security.pendingAddPath = path; + render(); + }; + } + + var securityAddCancel = root.getElementById("oclm-security-add-cancel"); + if (securityAddCancel) { + securityAddCancel.onclick = function() { + var security = getSecurityState(); + security.pendingAddPath = ""; + render(); + }; + } + + var securityAddConfirm = root.getElementById("oclm-security-add-confirm"); + if (securityAddConfirm) { + securityAddConfirm.onclick = function() { + var security = getSecurityState(); + var path = security.pendingAddPath || ""; + if (!path) { + render(); + return; + } + postJson(config.securityAddUrl, { path: path }).then(function(rv) { + if (!rv || !rv.ok) { + security.pendingAddPath = ""; + security.directoryError = (rv && rv.error) || "添加目录失败"; + render(); + return; + } + security.pendingAddPath = ""; + security.newDirectoryPath = ""; + security.directoryError = ""; + loadSecurityData(); + }).catch(function() { + security.pendingAddPath = ""; + security.directoryError = "添加目录失败"; + render(); + }); + }; + } + + Array.prototype.forEach.call(root.querySelectorAll("[data-security-recheck]"), function(el) { + el.onclick = function() { + var id = el.getAttribute("data-security-recheck"); + if (!id) return; + postJson(config.securityRecheckUrl, { id: id }).then(function(rv) { + if (!rv || !rv.ok) { + window.alert((rv && rv.error) || "重新检测失败"); + return; + } + loadSecurityData(); + }).catch(function() { + window.alert("重新检测失败"); + }); + }; + }); + + Array.prototype.forEach.call(root.querySelectorAll("[data-security-delete]"), function(el) { + el.onclick = function() { + var id = el.getAttribute("data-security-delete"); + if (!id) return; + var security = getSecurityState(); + var target = null; + security.protectedDirectories.forEach(function(item) { + if (item.id === id) { + target = item; + } + }); + if (!target) return; + security.deleteTargetId = id; + security.deleteTargetPath = target.path; + render(); + }; + }); + + var securityDeleteDirect = root.getElementById("oclm-security-delete-direct"); + if (securityDeleteDirect) { + securityDeleteDirect.onclick = function() { + var security = getSecurityState(); + if (security.deleteTargetId == null) return; + postJson(config.securityRemoveUrl, { id: security.deleteTargetId, mode: "direct" }).then(function(rv) { + if (!rv || !rv.ok) { + window.alert((rv && rv.error) || "删除失败"); + return; + } + security.deleteTargetId = null; + security.deleteTargetPath = ""; + loadSecurityData(); + }).catch(function() { + window.alert("删除失败"); + }); + }; + } + + var securityDeleteRestore = root.getElementById("oclm-security-delete-restore"); + if (securityDeleteRestore) { + securityDeleteRestore.onclick = function() { + var security = getSecurityState(); + if (security.deleteTargetId == null) return; + postJson(config.securityRemoveUrl, { id: security.deleteTargetId, mode: "restore" }).then(function(rv) { + if (!rv || !rv.ok) { + window.alert((rv && rv.error) || "恢复并删除失败"); + return; + } + security.deleteTargetId = null; + security.deleteTargetPath = ""; + loadSecurityData(); + }).catch(function() { + window.alert("恢复并删除失败"); + }); + }; + } + + var securityDeleteCancel = root.getElementById("oclm-security-delete-cancel"); + if (securityDeleteCancel) { + securityDeleteCancel.onclick = function() { + var security = getSecurityState(); + security.deleteTargetId = null; + security.deleteTargetPath = ""; + render(); + }; + } + var saveBasic = root.getElementById("oclm-save-basic"); if (saveBasic) { saveBasic.onclick = function() { @@ -1148,7 +1491,7 @@ if (saveAi) { saveAi.onclick = function() { var agentValue = root.getElementById("oclm-agent").value; - var modelValue = normalizeModelValue(agentValue, root.getElementById("oclm-model").value); + var modelValue = normalizeModelValue(root.getElementById("oclm-model").value, defaultModelForAgent(agentValue)); var baseUrlValue = root.getElementById("oclm-base-url").value; if (agentValue === "custom-provider" && !String(baseUrlValue || "").replace(/^\s+|\s+$/g, "")) { window.alert("自定义供应商必须填写服务地址"); @@ -1282,11 +1625,13 @@ } } render(); + loadSecurityData(); refreshStatus(); }).catch(function() { state.form = state.form || {}; state.options = state.options || { base_dir_choices: [] }; render(); + loadSecurityData(); }); } diff --git a/luci-app-openclawmgr/luasrc/controller/openclawmgr.lua b/luci-app-openclawmgr/luasrc/controller/openclawmgr.lua index 9be8a14e..fd713802 100644 --- a/luci-app-openclawmgr/luasrc/controller/openclawmgr.lua +++ b/luci-app-openclawmgr/luasrc/controller/openclawmgr.lua @@ -19,6 +19,10 @@ function index() entry({"admin", "services", "openclawmgr", "check_update"}, call("action_check_update")).leaf = true entry({"admin", "services", "openclawmgr", "config_data"}, call("action_config_data")).leaf = true entry({"admin", "services", "openclawmgr", "apply_config"}, call("action_apply_config")).leaf = true + entry({"admin", "services", "openclawmgr", "security_data"}, call("action_security_data")).leaf = true + entry({"admin", "services", "openclawmgr", "security_add"}, call("action_security_add")).leaf = true + entry({"admin", "services", "openclawmgr", "security_remove"}, call("action_security_remove")).leaf = true + entry({"admin", "services", "openclawmgr", "security_recheck"}, call("action_security_recheck")).leaf = true entry({"admin", "services", "openclawmgr", "logs_api"}, call("action_logs")).leaf = true @@ -68,6 +72,51 @@ local function write_json(obj) http.write_json(obj) end +local function read_json_file(path) + local jsonc = require "luci.jsonc" + local f = io.open(path, "r") + if not f then return nil end + local raw = f:read("*a") + f:close() + if not raw or raw == "" then return nil end + return jsonc.parse(raw) +end + +local function openclaw_config_path(base_dir) + base_dir = tostring(base_dir or ""):gsub("^%s+", ""):gsub("%s+$", "") + if base_dir == "" then + return "" + end + return base_dir .. "/data/.openclaw/openclaw.json" +end + +local function get_runtime_gateway_config(base_dir, fallback) + fallback = fallback or {} + local cfg = read_json_file(openclaw_config_path(base_dir)) or {} + local gateway = cfg.gateway or {} + local auth = gateway.auth or {} + local port = tostring(gateway.port or fallback.port or "18789") + if not port:match("^%d+$") then + port = tostring(fallback.port or "18789") + end + if not port:match("^%d+$") then + port = "18789" + end + local bind = tostring(gateway.bind or fallback.bind or "lan") + if bind ~= "loopback" and bind ~= "lan" and bind ~= "auto" and bind ~= "tailnet" and bind ~= "custom" then + bind = tostring(fallback.bind or "lan") + if bind ~= "loopback" and bind ~= "lan" and bind ~= "auto" and bind ~= "tailnet" and bind ~= "custom" then + bind = "lan" + end + end + local token = tostring(auth.token or fallback.token or "") + return { + port = port, + bind = bind, + token = token, + } +end + local function read_json_body() local http = require "luci.http" local jsonc = require "luci.jsonc" @@ -273,6 +322,213 @@ local function get_host() return host end +local function security_config_path(base_dir) + base_dir = trim(base_dir) + if base_dir == "" then + return "" + end + return base_dir .. "/data/.openclawmgr/openclawmgr-security.json" +end + +local function load_security_config(base_dir) + local data = read_json_file(security_config_path(base_dir)) + if type(data) ~= "table" or type(data.items) ~= "table" then + return { items = {} } + end + return data +end + +local function save_security_config(base_dir, data) + local jsonc = require "luci.jsonc" + local sys = require "luci.sys" + local util = require "luci.util" + local path = security_config_path(base_dir) + local dir = base_dir .. "/data/.openclawmgr" + local tmp = path .. ".tmp" + local f + + if trim(path) == "" then + return false + end + sys.call("mkdir -p " .. util.shellquote(dir) .. " >/dev/null 2>&1") + f = io.open(tmp, "w") + if not f then + return false + end + f:write(jsonc.stringify(data) or "{\"items\":[]}") + f:close() + if not os.rename(tmp, path) then + os.remove(tmp) + return false + end + return true +end + +local function security_stat(path) + local sys = require "luci.sys" + local util = require "luci.util" + local raw = sys.exec("stat -c '%u:%g:%a' " .. util.shellquote(path) .. " 2>/dev/null"):gsub("%s+$", "") + local uid, gid, mode = raw:match("^(%d+):(%d+):(%d+)$") + if not uid then + return nil + end + return { + uid = tonumber(uid), + gid = tonumber(gid), + mode = mode, + } +end + +local function security_path_exists(path) + local sys = require "luci.sys" + local util = require "luci.util" + return sys.call("[ -e " .. util.shellquote(path) .. " ] >/dev/null 2>&1") == 0 +end + +local function security_path_is_dir(path) + local sys = require "luci.sys" + local util = require "luci.util" + return sys.call("[ -d " .. util.shellquote(path) .. " ] >/dev/null 2>&1") == 0 +end + +local function security_probe(path) + local sys = require "luci.sys" + local util = require "luci.util" + local raw = sys.exec("stat -Lc '%F|%u|%g|%a' " .. util.shellquote(path) .. " 2>/dev/null"):gsub("%s+$", "") + local kind, uid, gid, mode = raw:match("^(.-)|(%d+)|(%d+)|(%d+)$") + if kind then + return { + kind = kind, + uid = tonumber(uid), + gid = tonumber(gid), + mode = mode, + } + end + if security_path_is_dir(path) then + return { kind = "directory" } + end + if security_path_exists(path) then + return { kind = "other" } + end + return nil +end + +local function security_apply(path) + local sys = require "luci.sys" + local util = require "luci.util" + local quoted = util.shellquote(path) + if sys.call("chown root:root " .. quoted .. " >/dev/null 2>&1") ~= 0 then + return false, "chown failed" + end + if sys.call("chmod 0750 " .. quoted .. " >/dev/null 2>&1") ~= 0 then + return false, "chmod failed" + end + return true +end + +local function security_restore(path, uid, gid, mode) + local sys = require "luci.sys" + local util = require "luci.util" + local quoted = util.shellquote(path) + if sys.call("chown " .. tostring(uid) .. ":" .. tostring(gid) .. " " .. quoted .. " >/dev/null 2>&1") ~= 0 then + return false, "restore chown failed" + end + if sys.call("chmod " .. tostring(mode) .. " " .. quoted .. " >/dev/null 2>&1") ~= 0 then + return false, "restore chmod failed" + end + return true +end + +local function security_protection_mode() + return "仅允许 root 和 root 组访问" +end + +local function security_check_item(item) + if security_path_is_dir(item.path) then + local st = security_stat(item.path) + if not st then + return { + id = tostring(item.id or ""), + path = tostring(item.path or ""), + protectionMode = security_protection_mode(), + status = "check-failed", + checkResult = "检测失败", + } + end + if st.uid == 0 and st.gid == 0 and (st.mode == "750" or st.mode == "0750") then + return { + id = tostring(item.id or ""), + path = tostring(item.path or ""), + protectionMode = security_protection_mode(), + status = "active", + checkResult = "openclawmgr 无法进入该目录", + } + end + return { + id = tostring(item.id or ""), + path = tostring(item.path or ""), + protectionMode = security_protection_mode(), + status = "inactive", + checkResult = "目录权限与预期不一致", + } + end + if not security_path_exists(item.path) then + return { + id = tostring(item.id or ""), + path = tostring(item.path or ""), + protectionMode = security_protection_mode(), + status = "not-found", + checkResult = "目录不存在", + } + end + return { + id = tostring(item.id or ""), + path = tostring(item.path or ""), + protectionMode = security_protection_mode(), + status = "check-failed", + checkResult = "目标不是目录", + } +end + +local function validate_security_path(path, base_dir, items) + path = trim(path) + base_dir = trim(base_dir) + if path == "" then + return false, "请输入目录路径" + end + if not path:match("^/") then + return false, "请输入绝对路径" + end + if path == "/" then + return false, "不能添加根目录 /" + end + for _, item in ipairs(items or {}) do + if tostring(item.path or "") == path then + return false, "该目录已在列表中" + end + end + if base_dir ~= "" then + local esc_base = base_dir:gsub("([^%w])", "%%%1") + local esc_path = path:gsub("([^%w])", "%%%1") + if path == base_dir or path:match("^" .. esc_base .. "/") then + return false, "不能添加 OpenClaw 的运行目录" + end + if base_dir:match("^" .. esc_path .. "/") then + return false, "不能添加 OpenClaw 运行目录的父目录" + end + end + return true +end + +local function find_security_item(items, id) + for index, item in ipairs(items or {}) do + if tostring(item.id or "") == tostring(id or "") then + return item, index + end + end + return nil, nil +end + function action_logs() local http = require "luci.http" local sys = require "luci.sys" @@ -472,10 +728,15 @@ function action_status() local task = get_task_state("openclawmgr") local enabled = uci:get("openclawmgr", "main", "enabled") or "0" - local port = uci:get("openclawmgr", "main", "port") or "18789" - local bind = uci:get("openclawmgr", "main", "bind") or "lan" local base_dir = uci:get("openclawmgr", "main", "base_dir") or "" - local token = uci:get("openclawmgr", "main", "token") or "" + local runtime_gateway = get_runtime_gateway_config(base_dir, { + port = uci:get("openclawmgr", "main", "port") or "18789", + bind = uci:get("openclawmgr", "main", "bind") or "lan", + token = uci:get("openclawmgr", "main", "token") or "", + }) + local port = runtime_gateway.port + local bind = runtime_gateway.bind + local token = runtime_gateway.token if not port:match("^%d+$") then port = "18789" end @@ -549,11 +810,13 @@ end function action_ready() local uci = require "luci.model.uci".cursor() - local port = uci:get("openclawmgr", "main", "port") or "18789" - local bind = uci:get("openclawmgr", "main", "bind") or "lan" local base_dir = uci:get("openclawmgr", "main", "base_dir") or "" - - if not port:match("^%d+$") then port = "18789" end + local runtime_gateway = get_runtime_gateway_config(base_dir, { + port = uci:get("openclawmgr", "main", "port") or "18789", + bind = uci:get("openclawmgr", "main", "bind") or "lan", + }) + local port = runtime_gateway.port + local bind = runtime_gateway.bind if base_dir == "" then write_json({ ok = true, ready = false, reason = "base_dir missing" }) @@ -654,25 +917,255 @@ end function action_config_data() local http = require "luci.http" local jsonc = require "luci.jsonc" + local sys = require "luci.sys" + local util = require "luci.util" local uci = require "luci.model.uci".cursor() local model = require "luci.model.openclawmgr" - local function read_json_file(path) - local f = io.open(path, "r") - if not f then return nil end - local raw = f:read("*a") + local function write_json_file(path, obj) + local dir = path:match("^(.+)/[^/]+$") + if dir and dir ~= "" then + sys.call("mkdir -p " .. util.shellquote(dir) .. " >/dev/null 2>&1") + end + local encoded = jsonc.stringify(obj, true) or "{}" + encoded = encoded:gsub("\\/", "/") + local f = io.open(path, "w") + if not f then + return false + end + f:write(encoded) + f:write("\n") f:close() - if not raw or raw == "" then return nil end - return jsonc.parse(raw) + return true end - local function infer_custom_provider_model(base_dir) + local function config_path(base_dir) + return openclaw_config_path(base_dir) + end + + local function ensure_table(parent, key) + if type(parent[key]) ~= "table" then + parent[key] = {} + end + return parent[key] + end + + local infer_custom_provider_model + local display_model_name + + local function env_key_for_agent(agent) + if agent == "openai" then return "OPENAI_API_KEY" end + if agent == "anthropic" then return "ANTHROPIC_API_KEY" end + if agent == "minimax-cn" then return "MINIMAX_API_KEY" end + if agent == "moonshot" then return "MOONSHOT_API_KEY" end + return "" + end + + local function default_model_for_agent(agent, current_custom_model) + if agent == "openai" then return "gpt-5.2" end + if agent == "anthropic" then return "claude-sonnet-4-6" end + if agent == "minimax-cn" then return "MiniMax-M2.5" end + if agent == "moonshot" then return "kimi-k2.5" end + if agent == "custom-provider" then return trim(current_custom_model) ~= "" and trim(current_custom_model) or "custom-model" end + return "claude-sonnet-4-6" + end + + local function normalized_model_path(agent, value, current_custom_model) + local model_name = display_model_name(value) + if model_name == "" then + model_name = default_model_for_agent(agent, current_custom_model) + end + return agent .. "/" .. model_name + end + + local function infer_agent_from_cfg(cfg) + local primary = cfg.agents and cfg.agents.defaults and cfg.agents.defaults.model and cfg.agents.defaults.model.primary + if type(primary) == "string" and primary:match("^[^/]+/.+") then + return primary:match("^([^/]+)/") or "" + end + local providers = cfg.models and cfg.models.providers + if type(providers) == "table" then + for _, agent in ipairs({ "openai", "anthropic", "minimax-cn", "moonshot", "custom-provider" }) do + if type(providers[agent]) == "table" then + return agent + end + end + end + return "" + end + + local function get_runtime_config(base_dir) + local cfg = read_json_file(config_path(base_dir)) or {} + local gateway_cfg = get_runtime_gateway_config(base_dir, { + port = uci:get("openclawmgr", "main", "port") or "18789", + bind = uci:get("openclawmgr", "main", "bind") or "lan", + token = uci:get("openclawmgr", "main", "token") or "", + }) + local gateway = cfg.gateway or {} + local control = gateway.controlUi or {} + local auth = gateway.auth or {} + local primary = cfg.agents and cfg.agents.defaults and cfg.agents.defaults.model and cfg.agents.defaults.model.primary + local agent = infer_agent_from_cfg(cfg) + if agent == "" then + agent = uci:get("openclawmgr", "main", "default_agent") or "anthropic" + end + + local default_model = "" + if type(primary) == "string" and primary ~= "" then + default_model = display_model_name(primary) + elseif agent == "custom-provider" then + default_model = infer_custom_provider_model(base_dir) + else + default_model = display_model_name(uci:get("openclawmgr", "main", "default_model") or "") + end + + local provider = cfg.models and cfg.models.providers and cfg.models.providers[agent] or {} + local env = cfg.env or {} + local provider_api_key = "" + local env_key = env_key_for_agent(agent) + if env_key ~= "" and type(env[env_key]) == "string" then + provider_api_key = env[env_key] + elseif type(provider.apiKey) == "string" then + provider_api_key = provider.apiKey + else + provider_api_key = uci:get("openclawmgr", "main", "provider_api_key") or "" + end + + local allowed_origins = {} + if type(control.allowedOrigins) == "table" then + for _, item in ipairs(control.allowedOrigins) do + item = trim(item) + if item ~= "" then + allowed_origins[#allowed_origins + 1] = item + end + end + elseif #allowed_origins == 0 then + for _, item in ipairs(uci:get_list("openclawmgr", "main", "allowed_origins") or {}) do + item = trim(item) + if item ~= "" then + allowed_origins[#allowed_origins + 1] = item + end + end + end + + local allow_insecure_auth = control.allowInsecureAuth + if type(allow_insecure_auth) ~= "boolean" then + allow_insecure_auth = (uci:get("openclawmgr", "main", "allow_insecure_auth") or "1") == "1" + end + + local disable_device_auth = control.dangerouslyDisableDeviceAuth + if type(disable_device_auth) ~= "boolean" then + disable_device_auth = (uci:get("openclawmgr", "main", "disable_device_auth") or "1") == "1" + end + + local provider_base_url = "" + if type(provider.baseUrl) == "string" then + provider_base_url = provider.baseUrl + else + provider_base_url = uci:get("openclawmgr", "main", "provider_base_url") or "" + end + + return { + port = gateway_cfg.port, + bind = gateway_cfg.bind, + token = gateway_cfg.token, + allowed_origins = allowed_origins, + allow_insecure_auth = allow_insecure_auth, + disable_device_auth = disable_device_auth, + default_agent = agent, + default_model = default_model, + provider_api_key = provider_api_key, + provider_base_url = provider_base_url, + } + end + + local function write_runtime_config(base_dir, service_cfg, runtime_cfg) + local path = config_path(base_dir) + if path == "" then + return false + end + local cfg = read_json_file(path) or {} + local gateway = ensure_table(cfg, "gateway") + gateway.mode = "local" + gateway.port = tonumber(service_cfg.port) or 18789 + gateway.bind = service_cfg.bind or "lan" + local auth = ensure_table(gateway, "auth") + auth.mode = "token" + auth.token = runtime_cfg.token or "" + local control = ensure_table(gateway, "controlUi") + control.enabled = true + control.allowedOrigins = runtime_cfg.allowed_origins or {} + control.allowInsecureAuth = runtime_cfg.allow_insecure_auth == true + control.dangerouslyDisableDeviceAuth = runtime_cfg.disable_device_auth == true + control.dangerouslyAllowHostHeaderOriginFallback = service_cfg.bind ~= "loopback" + + local env = type(cfg.env) == "table" and cfg.env or {} + for _, key in ipairs({ "OPENAI_API_KEY", "ANTHROPIC_API_KEY", "MINIMAX_API_KEY", "MOONSHOT_API_KEY" }) do + env[key] = nil + end + local env_key = env_key_for_agent(runtime_cfg.default_agent) + if env_key ~= "" and trim(runtime_cfg.provider_api_key) ~= "" then + env[env_key] = runtime_cfg.provider_api_key + end + cfg.env = next(env) and env or nil + + local models = ensure_table(cfg, "models") + if type(models.mode) ~= "string" or models.mode == "" then + models.mode = "merge" + end + local providers = {} + models.providers = providers + local provider = {} + providers[runtime_cfg.default_agent] = provider + local model_name = display_model_name(runtime_cfg.default_model) + if model_name == "" then + model_name = default_model_for_agent(runtime_cfg.default_agent, infer_custom_provider_model(base_dir)) + end + if runtime_cfg.default_agent == "openai" then + provider.api = "openai-completions" + provider.baseUrl = trim(runtime_cfg.provider_base_url) ~= "" and runtime_cfg.provider_base_url or "https://api.openai.com/v1" + provider.apiKey = trim(runtime_cfg.provider_api_key) ~= "" and runtime_cfg.provider_api_key or nil + provider.authHeader = nil + elseif runtime_cfg.default_agent == "anthropic" then + provider.api = "anthropic-messages" + provider.baseUrl = trim(runtime_cfg.provider_base_url) ~= "" and runtime_cfg.provider_base_url or "https://api.anthropic.com" + provider.apiKey = trim(runtime_cfg.provider_api_key) ~= "" and runtime_cfg.provider_api_key or nil + provider.authHeader = nil + elseif runtime_cfg.default_agent == "minimax-cn" then + provider.api = "anthropic-messages" + provider.baseUrl = trim(runtime_cfg.provider_base_url) ~= "" and runtime_cfg.provider_base_url or "https://api.minimaxi.com/anthropic" + provider.apiKey = trim(runtime_cfg.provider_api_key) ~= "" and runtime_cfg.provider_api_key or nil + provider.authHeader = true + elseif runtime_cfg.default_agent == "moonshot" then + provider.api = "openai-completions" + provider.baseUrl = trim(runtime_cfg.provider_base_url) ~= "" and runtime_cfg.provider_base_url or "https://api.moonshot.cn/v1" + provider.apiKey = trim(runtime_cfg.provider_api_key) ~= "" and runtime_cfg.provider_api_key or nil + provider.authHeader = nil + else + provider.api = "openai-completions" + provider.baseUrl = runtime_cfg.provider_base_url or "" + provider.apiKey = trim(runtime_cfg.provider_api_key) ~= "" and runtime_cfg.provider_api_key or nil + provider.authHeader = nil + end + provider.models = { + { id = model_name, name = model_name } + } + + local agents = ensure_table(cfg, "agents") + local defaults = ensure_table(agents, "defaults") + local model_cfg = ensure_table(defaults, "model") + model_cfg.primary = normalized_model_path(runtime_cfg.default_agent, model_name, infer_custom_provider_model(base_dir)) + + return write_json_file(path, cfg) + end + + infer_custom_provider_model = function(base_dir) base_dir = tostring(base_dir or "") if base_dir == "" then return "" end local cfg = read_json_file(base_dir .. "/data/.openclaw/openclaw.json") or {} local primary = cfg.agents and cfg.agents.defaults and cfg.agents.defaults.model and cfg.agents.defaults.model.primary if type(primary) == "string" and primary:match("^custom%-provider/.+") then - return primary + return primary:gsub("^[^/]+/", "") end local providers = cfg.models and cfg.models.providers local custom = providers and providers["custom-provider"] @@ -680,11 +1173,19 @@ function action_config_data() local first = type(models) == "table" and models[1] or nil local id = first and first.id if type(id) == "string" and id ~= "" then - return "custom-provider/" .. id + return id end return "" end + display_model_name = function(value) + value = tostring(value or "") + if value == "" then + return "" + end + return value:gsub("^[^/]+/", "") + end + if (http.getenv("REQUEST_METHOD") or "GET") == "POST" then if not require_csrf() then return @@ -701,7 +1202,8 @@ function action_config_data() return body[key] ~= nil end - local requested_default_agent = tostring(has("default_agent") and body.default_agent or (uci:get("openclawmgr", section, "default_agent") or "anthropic")) + local current = get_runtime_config(uci:get("openclawmgr", section, "base_dir") or "") + local requested_default_agent = tostring(has("default_agent") and body.default_agent or current.default_agent or "anthropic") if has("enabled") then uci:set("openclawmgr", section, "enabled", bool_to_uci(body.enabled == true or body.enabled == "1")) @@ -718,7 +1220,6 @@ function action_config_data() write_json({ ok = false, error = "invalid port (must be 1025-65535)" }) return end - uci:set("openclawmgr", section, "port", port) end if has("bind") then @@ -727,7 +1228,6 @@ function action_config_data() write_json({ ok = false, error = "invalid bind" }) return end - uci:set("openclawmgr", section, "bind", bind) end if has("base_dir") then @@ -745,21 +1245,12 @@ function action_config_data() write_json({ ok = false, error = "invalid default_agent" }) return end - uci:set("openclawmgr", section, "default_agent", agent) - end - - if has("default_model") then - uci:set("openclawmgr", section, "default_model", tostring(body.default_model or "")) end if has("install_accelerated") then uci:set("openclawmgr", section, "install_accelerated", bool_to_uci(body.install_accelerated == true or body.install_accelerated == "1")) end - if has("provider_api_key") then - uci:set("openclawmgr", section, "provider_api_key", tostring(body.provider_api_key or "")) - end - if has("provider_base_url") then local value = tostring(body.provider_base_url or "") if requested_default_agent == "custom-provider" and value == "" then @@ -770,45 +1261,78 @@ function action_config_data() write_json({ ok = false, error = "invalid provider_base_url" }) return end - uci:set("openclawmgr", section, "provider_base_url", value) end if has("token") then - uci:set("openclawmgr", section, "token", tostring(body.token or "")) + body.token = tostring(body.token or "") end + local effective_base_dir = tostring(has("base_dir") and body.base_dir or (uci:get("openclawmgr", section, "base_dir") or "")) + local effective_port = tostring(has("port") and body.port or current.port or "18789") + local effective_bind = tostring(has("bind") and body.bind or current.bind or "lan") + local runtime_cfg = { + token = tostring(has("token") and body.token or current.token or ""), + allowed_origins = current.allowed_origins, + allow_insecure_auth = current.allow_insecure_auth, + disable_device_auth = current.disable_device_auth, + default_agent = requested_default_agent, + default_model = tostring(has("default_model") and body.default_model or current.default_model or ""), + provider_api_key = tostring(has("provider_api_key") and body.provider_api_key or current.provider_api_key or ""), + provider_base_url = tostring(has("provider_base_url") and body.provider_base_url or current.provider_base_url or ""), + } + if has("allowed_origins") then local origins = {} if type(body.allowed_origins) == "table" then for _, item in ipairs(body.allowed_origins) do - item = tostring(item or ""):match("^%s*(.-)%s*$") - if item and item ~= "" then - table.insert(origins, item) + item = trim(item) + if item ~= "" then + origins[#origins + 1] = item end end end - if #origins > 0 then - uci:set_list("openclawmgr", section, "allowed_origins", origins) - else - uci:delete("openclawmgr", section, "allowed_origins") - end + runtime_cfg.allowed_origins = origins end if has("allow_insecure_auth") then - uci:set("openclawmgr", section, "allow_insecure_auth", bool_to_uci(body.allow_insecure_auth == true or body.allow_insecure_auth == "1")) + runtime_cfg.allow_insecure_auth = (body.allow_insecure_auth == true or body.allow_insecure_auth == "1") end if has("disable_device_auth") then - uci:set("openclawmgr", section, "disable_device_auth", bool_to_uci(body.disable_device_auth == true or body.disable_device_auth == "1")) + runtime_cfg.disable_device_auth = (body.disable_device_auth == true or body.disable_device_auth == "1") end + if runtime_cfg.default_agent == "custom-provider" and trim(runtime_cfg.provider_base_url) == "" then + write_json({ ok = false, error = "provider_base_url required for custom-provider" }) + return + end + if trim(runtime_cfg.provider_base_url) ~= "" and not tostring(runtime_cfg.provider_base_url):match("^https?://") then + write_json({ ok = false, error = "invalid provider_base_url" }) + return + end + + uci:commit("openclawmgr") + if effective_base_dir == "" then + write_json({ ok = false, error = "base_dir required" }) + return + end + local ok = write_runtime_config(effective_base_dir, { + port = effective_port, + bind = effective_bind, + }, runtime_cfg) + if not ok then + write_json({ ok = false, error = "write openclaw.json failed" }) + return + end + for _, key in ipairs({ "port", "bind", "token", "allowed_origins", "allow_insecure_auth", "disable_device_auth", "default_agent", "default_model", "provider_api_key", "provider_base_url" }) do + uci:delete("openclawmgr", section, key) + end uci:commit("openclawmgr") write_json({ ok = true }) return end local base_dir = uci:get("openclawmgr", "main", "base_dir") or "" - local port = uci:get("openclawmgr", "main", "port") or "18789" local blocks = model.blocks() local home = model.home() local paths, default_path = model.find_paths(blocks, home, "Configs") @@ -830,42 +1354,165 @@ function action_config_data() end add_choice(default_path or "/root/Configs/OpenClawMgr") - local allowed_origins = {} - for _, item in ipairs(uci:get_list("openclawmgr", "main", "allowed_origins") or {}) do - allowed_origins[#allowed_origins + 1] = item - end - - local current_default_agent = uci:get("openclawmgr", "main", "default_agent") or "anthropic" - local current_default_model = uci:get("openclawmgr", "main", "default_model") or "" - if current_default_agent == "custom-provider" and current_default_model == "" then - current_default_model = infer_custom_provider_model(base_dir) - end + local runtime_cfg = get_runtime_config(base_dir) write_json({ ok = true, config = { enabled = (uci:get("openclawmgr", "main", "enabled") or "0") == "1", - port = port, - bind = uci:get("openclawmgr", "main", "bind") or "lan", + port = runtime_cfg.port, + bind = runtime_cfg.bind, base_dir = base_dir, - token = uci:get("openclawmgr", "main", "token") or "", - allowed_origins = allowed_origins, - allow_insecure_auth = (uci:get("openclawmgr", "main", "allow_insecure_auth") or "0") == "1", - disable_device_auth = (uci:get("openclawmgr", "main", "disable_device_auth") or "0") == "1", - default_agent = current_default_agent, - default_model = current_default_model, + token = runtime_cfg.token, + allowed_origins = runtime_cfg.allowed_origins, + allow_insecure_auth = runtime_cfg.allow_insecure_auth, + disable_device_auth = runtime_cfg.disable_device_auth, + default_agent = runtime_cfg.default_agent, + default_model = runtime_cfg.default_model, install_accelerated = (uci:get("openclawmgr", "main", "install_accelerated") or "1") == "1", - provider_api_key = uci:get("openclawmgr", "main", "provider_api_key") or "", - provider_base_url = uci:get("openclawmgr", "main", "provider_base_url") or "", + provider_api_key = runtime_cfg.provider_api_key, + provider_base_url = runtime_cfg.provider_base_url, }, options = { base_dir_choices = choices, suggested_base_dir = default_path or "", - default_origin = default_allowed_origin(port), + default_origin = default_allowed_origin(runtime_cfg.port), } }) end +function action_security_data() + local uci = require "luci.model.uci".cursor() + local base_dir = trim(uci:get("openclawmgr", "main", "base_dir") or "") + local data, items = nil, {} + if base_dir == "" then + write_json({ ok = true, items = items }) + return + end + data = load_security_config(base_dir) + for _, item in ipairs(data.items or {}) do + items[#items + 1] = security_check_item(item) + end + write_json({ ok = true, items = items }) +end + +function action_security_add() + local uci = require "luci.model.uci".cursor() + if not require_csrf() then + return + end + local base_dir = trim(uci:get("openclawmgr", "main", "base_dir") or "") + local body = read_json_body() or {} + local path = trim(body.path or "") + local data, ok, err, item, st, probe = nil, nil, nil, nil, nil, nil + if base_dir == "" then + write_json({ ok = false, error = "base_dir required" }) + return + end + data = load_security_config(base_dir) + ok, err = validate_security_path(path, base_dir, data.items) + if not ok then + write_json({ ok = false, error = err }) + return + end + item = { + id = "dir_" .. tostring(os.time()) .. tostring(math.random(1000, 9999)), + path = path, + orig_uid = 0, + orig_gid = 0, + orig_mode = "755", + } + probe = security_probe(path) + if not probe then + write_json({ ok = false, error = "目录不存在" }) + return + end + if probe.kind ~= "directory" then + write_json({ ok = false, error = "目标不是目录" }) + return + end + st = security_stat(path) + if not st then + write_json({ ok = false, error = "读取目录权限失败" }) + return + end + item.orig_uid = st.uid + item.orig_gid = st.gid + item.orig_mode = st.mode + ok, err = security_apply(path) + if not ok then + write_json({ ok = false, error = err or "apply failed" }) + return + end + data.items[#data.items + 1] = item + if not save_security_config(base_dir, data) then + write_json({ ok = false, error = "save security config failed" }) + return + end + write_json({ ok = true, item = security_check_item(item) }) +end + +function action_security_remove() + local uci = require "luci.model.uci".cursor() + if not require_csrf() then + return + end + local base_dir = trim(uci:get("openclawmgr", "main", "base_dir") or "") + local body = read_json_body() or {} + local id = tostring(body.id or "") + local mode = tostring(body.mode or "direct") + local data, item, index = nil, nil, nil + if base_dir == "" then + write_json({ ok = false, error = "base_dir required" }) + return + end + if mode ~= "direct" and mode ~= "restore" then + write_json({ ok = false, error = "invalid mode" }) + return + end + data = load_security_config(base_dir) + item, index = find_security_item(data.items, id) + if not item then + write_json({ ok = false, error = "item not found" }) + return + end + if mode == "restore" and security_path_exists(item.path) then + local ok, err = security_restore(item.path, item.orig_uid, item.orig_gid, item.orig_mode) + if not ok then + write_json({ ok = false, error = err or "restore failed" }) + return + end + end + table.remove(data.items, index) + if not save_security_config(base_dir, data) then + write_json({ ok = false, error = "save security config failed" }) + return + end + write_json({ ok = true }) +end + +function action_security_recheck() + local uci = require "luci.model.uci".cursor() + if not require_csrf() then + return + end + local base_dir = trim(uci:get("openclawmgr", "main", "base_dir") or "") + local body = read_json_body() or {} + local id = tostring(body.id or "") + local data, item = nil, nil + if base_dir == "" then + write_json({ ok = false, error = "base_dir required" }) + return + end + data = load_security_config(base_dir) + item = find_security_item(data.items, id) + if not item then + write_json({ ok = false, error = "item not found" }) + return + end + write_json({ ok = true, item = security_check_item(item) }) +end + function action_op() local http = require "luci.http" local i18n = require "luci.i18n" @@ -980,11 +1627,13 @@ function action_diag_info() local uci = require "luci.model.uci".cursor() local base_dir = uci:get("openclawmgr", "main", "base_dir") or "" - local port = uci:get("openclawmgr", "main", "port") or "18789" - local bind = uci:get("openclawmgr", "main", "bind") or "lan" local enabled = uci:get("openclawmgr", "main", "enabled") or "0" - - if not port:match("^%d+$") then port = "18789" end + local runtime_gateway = get_runtime_gateway_config(base_dir, { + port = uci:get("openclawmgr", "main", "port") or "18789", + bind = uci:get("openclawmgr", "main", "bind") or "lan", + }) + local port = runtime_gateway.port + local bind = runtime_gateway.bind local avail_mb = 0 if base_dir ~= "" then diff --git a/luci-app-openclawmgr/luasrc/model/cbi/openclawmgr/cli.lua b/luci-app-openclawmgr/luasrc/model/cbi/openclawmgr/cli.lua index c1a2d64e..e1c171c1 100644 --- a/luci-app-openclawmgr/luasrc/model/cbi/openclawmgr/cli.lua +++ b/luci-app-openclawmgr/luasrc/model/cbi/openclawmgr/cli.lua @@ -32,13 +32,14 @@ local data_dir = base_dir .. "/data" s = m:section(SimpleSection) o = s:option(Value, "mode", translate("Mode")) +o:value("cli-env", translate("CLI终端 (仅注入环境)")) o:value("configure", translate("官方配置向导 (openclaw configure)")) o:value("backup", translate("备份配置")) o:value("restore", translate("恢复配置")) -o.default = "configure" +o.default = "cli-env" o.forcewrite = true -o = s:option(DummyValue, "_tip", translate("CLI Config")) +o = s:option(DummyValue, "_tip", translate("CLI终端")) o.rawhtml = true o.cfgvalue = function() return translate("Starts a web terminal (LAN only) for common OpenClaw maintenance tasks.") @@ -93,7 +94,7 @@ o.render = function(self, section, scope) end o.write = function(self, section) local mode = m:formvalue("mode") or m:formvalue("cbid.OpenClawCLI.1.mode") or "configure" - if mode ~= "configure" and mode ~= "backup" and mode ~= "restore" then + if mode ~= "configure" and mode ~= "cli-env" and mode ~= "backup" and mode ~= "restore" then mode = "configure" end start_ttyd(mode) diff --git a/luci-app-openclawmgr/luasrc/view/openclawmgr/app.htm b/luci-app-openclawmgr/luasrc/view/openclawmgr/app.htm index d97b31a5..bf4f4831 100644 --- a/luci-app-openclawmgr/luasrc/view/openclawmgr/app.htm +++ b/luci-app-openclawmgr/luasrc/view/openclawmgr/app.htm @@ -11,6 +11,10 @@ checkUpdateUrl: "<%=url('admin/services/openclawmgr/check_update')%>", configUrl: "<%=url('admin/services/openclawmgr/config_data')%>", applyUrl: "<%=url('admin/services/openclawmgr/apply_config')%>", + securityDataUrl: "<%=url('admin/services/openclawmgr/security_data')%>", + securityAddUrl: "<%=url('admin/services/openclawmgr/security_add')%>", + securityRemoveUrl: "<%=url('admin/services/openclawmgr/security_remove')%>", + securityRecheckUrl: "<%=url('admin/services/openclawmgr/security_recheck')%>", staticBase: "<%=resource%>/openclawmgr" }; })(); diff --git a/luci-app-openclawmgr/root/etc/config/openclawmgr b/luci-app-openclawmgr/root/etc/config/openclawmgr index 28c61369..0c07d4ca 100644 --- a/luci-app-openclawmgr/root/etc/config/openclawmgr +++ b/luci-app-openclawmgr/root/etc/config/openclawmgr @@ -1,12 +1,4 @@ config openclawmgr 'main' option enabled '0' - option port '18789' - option bind 'lan' - option token '' - option allow_insecure_auth '1' - option disable_device_auth '1' + option base_dir '' option install_accelerated '1' - option default_agent 'anthropic' - option default_model '' - option provider_api_key '' - option provider_base_url '' diff --git a/luci-app-openclawmgr/root/etc/init.d/openclawmgr b/luci-app-openclawmgr/root/etc/init.d/openclawmgr index e83b099d..01d7200f 100755 --- a/luci-app-openclawmgr/root/etc/init.d/openclawmgr +++ b/luci-app-openclawmgr/root/etc/init.d/openclawmgr @@ -14,16 +14,34 @@ _find_entry() { return 1 } +_json_get() { + local file="$1" expr="$2" + [ -f "$file" ] || return 0 + command -v jsonfilter >/dev/null 2>&1 || return 0 + jsonfilter -i "$file" -e "$expr" 2>/dev/null || true +} + start_service() { config_load openclawmgr config_get_bool enabled main enabled 0 - config_get port main port 18789 - config_get bind main bind lan config_get base_dir main base_dir "" - config_get token main token "" + local port="18789" + local bind="lan" + local token="" [ "$enabled" -eq 1 ] || return 0 [ -n "$base_dir" ] || return 1 + + local data_dir="${base_dir}/data" + local config_file="${data_dir}/.openclaw/openclaw.json" + local json_port json_bind json_token + json_port="$(_json_get "$config_file" '@.gateway.port')" + json_bind="$(_json_get "$config_file" '@.gateway.bind')" + json_token="$(_json_get "$config_file" '@.gateway.auth.token')" + [ -n "$json_port" ] && port="$json_port" + [ -n "$json_bind" ] && bind="$json_bind" + [ -n "$json_token" ] && token="$json_token" + if echo "$port" | grep -Eq '^[0-9]+$'; then if [ "$port" -le 1024 ] 2>/dev/null; then logger -t openclawmgr "Refusing to start: unsafe port ${port} (must be >1024)" @@ -35,7 +53,6 @@ start_service() { local node_bin="${base_dir}/node/bin/node" local global_dir="${base_dir}/global" - local data_dir="${base_dir}/data" local env_file="${data_dir}/.openclaw/openclaw.env" local entry="$(_find_entry "$global_dir")" local openai_api_key="" diff --git a/luci-app-openclawmgr/root/etc/uci-defaults/99-openclawmgr b/luci-app-openclawmgr/root/etc/uci-defaults/99-openclawmgr index 009acb49..8e1df06d 100755 --- a/luci-app-openclawmgr/root/etc/uci-defaults/99-openclawmgr +++ b/luci-app-openclawmgr/root/etc/uci-defaults/99-openclawmgr @@ -1,5 +1,17 @@ #!/bin/sh +default_base_dir() { + local main_dir conf_dir + + main_dir="$(uci -q get quickstart.main.main_dir 2>/dev/null || true)" + conf_dir="$(uci -q get quickstart.main.conf_dir 2>/dev/null || true)" + + [ -n "$main_dir" ] || main_dir="/root" + [ -n "$conf_dir" ] || conf_dir="${main_dir%/}/Configs" + + printf '%s/OpenClawMgr\n' "${conf_dir%/}" +} + # Ensure section exists if ! uci -q get openclawmgr.main >/dev/null 2>&1; then uci -q set openclawmgr.main=openclawmgr >/dev/null 2>&1 || true @@ -7,16 +19,8 @@ fi # Fill defaults (only if missing) [ -n "$(uci -q get openclawmgr.main.enabled 2>/dev/null)" ] || uci -q set openclawmgr.main.enabled='0' -[ -n "$(uci -q get openclawmgr.main.port 2>/dev/null)" ] || uci -q set openclawmgr.main.port='18789' -[ -n "$(uci -q get openclawmgr.main.bind 2>/dev/null)" ] || uci -q set openclawmgr.main.bind='lan' +[ -n "$(uci -q get openclawmgr.main.base_dir 2>/dev/null)" ] || uci -q set openclawmgr.main.base_dir="$(default_base_dir)" [ -n "$(uci -q get openclawmgr.main.install_accelerated 2>/dev/null)" ] || uci -q set openclawmgr.main.install_accelerated='1' -[ -n "$(uci -q get openclawmgr.main.token 2>/dev/null)" ] || uci -q set openclawmgr.main.token='' -[ -n "$(uci -q get openclawmgr.main.allow_insecure_auth 2>/dev/null)" ] || uci -q set openclawmgr.main.allow_insecure_auth='1' -[ -n "$(uci -q get openclawmgr.main.disable_device_auth 2>/dev/null)" ] || uci -q set openclawmgr.main.disable_device_auth='1' -[ -n "$(uci -q get openclawmgr.main.default_agent 2>/dev/null)" ] || uci -q set openclawmgr.main.default_agent='anthropic' -[ -n "$(uci -q get openclawmgr.main.default_model 2>/dev/null)" ] || uci -q set openclawmgr.main.default_model='' -[ -n "$(uci -q get openclawmgr.main.provider_api_key 2>/dev/null)" ] || uci -q set openclawmgr.main.provider_api_key='' -[ -n "$(uci -q get openclawmgr.main.provider_base_url 2>/dev/null)" ] || uci -q set openclawmgr.main.provider_base_url='' uci -q commit openclawmgr >/dev/null 2>&1 || true diff --git a/luci-app-openclawmgr/root/usr/libexec/istorec/openclawmgr.sh b/luci-app-openclawmgr/root/usr/libexec/istorec/openclawmgr.sh index 82aa16b1..432346d4 100755 --- a/luci-app-openclawmgr/root/usr/libexec/istorec/openclawmgr.sh +++ b/luci-app-openclawmgr/root/usr/libexec/istorec/openclawmgr.sh @@ -41,6 +41,25 @@ uci_get_list() { sed -n "s/^${UCI_NS}\\.main\\.${key}='\\(.*\\)'$/\\1/p" } +json_get() { + local file="$1" expr="$2" + [ -f "$file" ] || return 0 + command -v jsonfilter >/dev/null 2>&1 || return 0 + jsonfilter -i "$file" -e "$expr" 2>/dev/null || true +} + +load_gateway_runtime_from_json() { + local cfg="${DATA_DIR}/.openclaw/openclaw.json" + [ -f "$cfg" ] || return 0 + local json_port json_bind json_token + json_port="$(json_get "$cfg" '@.gateway.port')" + json_bind="$(json_get "$cfg" '@.gateway.bind')" + json_token="$(json_get "$cfg" '@.gateway.auth.token')" + [ -n "$json_port" ] && PORT="$json_port" + [ -n "$json_bind" ] && BIND="$json_bind" + [ -n "$json_token" ] && TOKEN="$json_token" +} + fmt_elapsed() { local total="${1:-0}" h m s case "$total" in ''|*[!0-9]*) total=0 ;; esac @@ -254,6 +273,12 @@ gen_token() { (date +%s | md5sum 2>/dev/null | awk '{print $1}') } +ensure_token() { + if [ -z "${TOKEN:-}" ]; then + TOKEN="$(gen_token)" + fi +} + is_musl() { ldd --version 2>&1 | grep -qi musl && return 0 [ -e /lib/ld-musl-*.so.1 ] 2>/dev/null && return 0 @@ -573,46 +598,58 @@ ensure_gateway_config() { host_header_fallback="true" fi - local allow_insecure="false" - if [ "${ALLOW_INSECURE_AUTH:-0}" = "1" ]; then - allow_insecure="true" + local allow_insecure="" + if [ -n "${ALLOW_INSECURE_AUTH:-}" ]; then + if [ "$ALLOW_INSECURE_AUTH" = "1" ]; then + allow_insecure="true" + else + allow_insecure="false" + fi fi - local disable_device_auth="false" - if [ "${DISABLE_DEVICE_AUTH:-0}" = "1" ]; then - disable_device_auth="true" + local disable_device_auth="" + if [ -n "${DISABLE_DEVICE_AUTH:-}" ]; then + if [ "$DISABLE_DEVICE_AUTH" = "1" ]; then + disable_device_auth="true" + else + disable_device_auth="false" + fi fi local allowed_origins="$ALLOWED_ORIGINS" - if [ -z "$allowed_origins" ]; then - allowed_origins="$(default_allowed_origins)" - fi local selected_key selected_model selected_base_url override_base_url base_url_mode - selected_key="$(agent_key_name)" - selected_model="$(agent_default_model)" - selected_base_url="$(agent_default_base_url)" + selected_key="" + selected_model="" + selected_base_url="" override_base_url="" - base_url_mode="default" - if [ -n "${PROVIDER_BASE_URL:-}" ]; then - if is_valid_http_url "$PROVIDER_BASE_URL"; then - override_base_url="$PROVIDER_BASE_URL" - base_url_mode="override" - else - write_installer_log "Ignoring invalid relay URL for ${DEFAULT_AGENT:-anthropic}: ${PROVIDER_BASE_URL}" - base_url_mode="preserve" + base_url_mode="" + if [ -n "${DEFAULT_AGENT:-}" ]; then + selected_key="$(agent_key_name)" + selected_model="$(agent_default_model)" + selected_base_url="$(agent_default_base_url)" + base_url_mode="default" + if [ -n "${PROVIDER_BASE_URL:-}" ]; then + if is_valid_http_url "$PROVIDER_BASE_URL"; then + override_base_url="$PROVIDER_BASE_URL" + base_url_mode="override" + else + write_installer_log "Ignoring invalid relay URL for ${DEFAULT_AGENT}: ${PROVIDER_BASE_URL}" + base_url_mode="preserve" + fi fi fi mkdir -p "$(dirname "$cfg")" 2>/dev/null || true CFG_PATH="$cfg" \ ALLOWED_ORIGINS_RAW="$allowed_origins" \ + DEFAULT_ALLOWED_ORIGINS_RAW="$(default_allowed_origins)" \ GATEWAY_PORT="$PORT" \ GATEWAY_BIND="$BIND" \ GATEWAY_TOKEN="$TOKEN" \ GATEWAY_ALLOW_INSECURE="$allow_insecure" \ GATEWAY_DISABLE_DEVICE_AUTH="$disable_device_auth" \ GATEWAY_HOST_HEADER_FALLBACK="$host_header_fallback" \ - DEFAULT_AGENT_NAME="${DEFAULT_AGENT:-anthropic}" \ + DEFAULT_AGENT_NAME="${DEFAULT_AGENT:-}" \ DEFAULT_AGENT_KEY="$selected_key" \ DEFAULT_AGENT_MODEL="$selected_model" \ DEFAULT_AGENT_BASE_URL="$selected_base_url" \ @@ -635,6 +672,25 @@ local function bool_env(name) return os.getenv(name) == "true" end +local function optional_env(name) + local value = os.getenv(name) + if value == nil or value == "" then + return nil + end + return value +end + +local function optional_bool_env(name) + local value = optional_env(name) + if value == "true" then + return true + end + if value == "false" then + return false + end + return nil +end + local function split_lines(raw) local out = {} raw = raw or "" @@ -685,123 +741,166 @@ local gateway = ensure_table(cfg, "gateway") gateway.mode = "local" gateway.port = tonumber(os.getenv("GATEWAY_PORT")) or 18789 gateway.bind = os.getenv("GATEWAY_BIND") or "lan" -gateway.auth = { mode = "token", token = os.getenv("GATEWAY_TOKEN") or "" } +local auth = ensure_table(gateway, "auth") +auth.mode = "token" +auth.token = os.getenv("GATEWAY_TOKEN") or "" local control = ensure_table(gateway, "controlUi") control.enabled = true -control.basePath = nil -control.allowedOrigins = split_lines(os.getenv("ALLOWED_ORIGINS_RAW")) -control.allowInsecureAuth = bool_env("GATEWAY_ALLOW_INSECURE") -control.dangerouslyDisableDeviceAuth = bool_env("GATEWAY_DISABLE_DEVICE_AUTH") +local configured_origins = optional_env("ALLOWED_ORIGINS_RAW") +if configured_origins then + control.allowedOrigins = split_lines(configured_origins) +elseif type(control.allowedOrigins) ~= "table" or next(control.allowedOrigins) == nil then + control.allowedOrigins = split_lines(os.getenv("DEFAULT_ALLOWED_ORIGINS_RAW") or "") +end +local allow_insecure = optional_bool_env("GATEWAY_ALLOW_INSECURE") +if allow_insecure ~= nil then + control.allowInsecureAuth = allow_insecure +elseif type(control.allowInsecureAuth) ~= "boolean" then + control.allowInsecureAuth = true +end +local disable_device_auth = optional_bool_env("GATEWAY_DISABLE_DEVICE_AUTH") +if disable_device_auth ~= nil then + control.dangerouslyDisableDeviceAuth = disable_device_auth +elseif type(control.dangerouslyDisableDeviceAuth) ~= "boolean" then + control.dangerouslyDisableDeviceAuth = true +end control.dangerouslyAllowHostHeaderOriginFallback = bool_env("GATEWAY_HOST_HEADER_FALLBACK") -local env = {} -local selected_env_key = os.getenv("DEFAULT_AGENT_KEY") -local selected_api_key = os.getenv("DEFAULT_AGENT_API_KEY") or "" -if selected_env_key and selected_env_key ~= "" and selected_api_key ~= "" then +local env = ensure_table(cfg, "env") +local selected_env_key = optional_env("DEFAULT_AGENT_KEY") +local selected_api_key = optional_env("DEFAULT_AGENT_API_KEY") +if selected_env_key and selected_api_key then env[selected_env_key] = selected_api_key end cfg.env = next(env) and env or nil +local function update_api_key(provider) + if selected_api_key ~= nil then + provider.apiKey = selected_api_key ~= "" and selected_api_key or nil + end +end + +local function env_key_for_provider(id) + if id == "openai" then return "OPENAI_API_KEY" end + if id == "anthropic" then return "ANTHROPIC_API_KEY" end + if id == "minimax-cn" then return "MINIMAX_API_KEY" end + if id == "moonshot" then return "MOONSHOT_API_KEY" end + return nil +end + local models = ensure_table(cfg, "models") if type(models.mode) ~= "string" or models.mode == "" then models.mode = "merge" end - local providers = ensure_table(models, "providers") - local current_provider_id = os.getenv("DEFAULT_AGENT_NAME") or "anthropic" - local current_provider = ensure_table(providers, current_provider_id) + local current_provider_id = optional_env("DEFAULT_AGENT_NAME") + local primary_model = optional_env("DEFAULT_AGENT_MODEL") + local current_primary = cfg.agents and cfg.agents.defaults and cfg.agents.defaults.model and cfg.agents.defaults.model.primary + if not primary_model and type(current_primary) == "string" and current_primary ~= "" then + primary_model = current_primary + end + if not current_provider_id and type(primary_model) == "string" and primary_model:match("^[^/]+/.+") then + current_provider_id = primary_model:match("^([^/]+)/") + end + if not current_provider_id or current_provider_id == "" then + current_provider_id = "anthropic" + end + if not primary_model or primary_model == "" then + if current_provider_id == "openai" then + primary_model = "openai/gpt-5.2" + elseif current_provider_id == "anthropic" then + primary_model = "anthropic/claude-sonnet-4-6" + elseif current_provider_id == "minimax-cn" then + primary_model = "minimax-cn/MiniMax-M2.5" + elseif current_provider_id == "moonshot" then + primary_model = "moonshot/kimi-k2.5" + elseif current_provider_id == "custom-provider" then + primary_model = "custom-provider/custom-model" + local custom = models.providers and models.providers["custom-provider"] + local first = custom and custom.models and custom.models[1] + if type(first) == "table" and type(first.id) == "string" and first.id ~= "" then + primary_model = "custom-provider/" .. first.id + end + else + primary_model = "anthropic/claude-sonnet-4-6" + end + end + local current_model_id = primary_model:match("^[^/]+/(.+)$") or primary_model + if current_model_id == "" then + current_model_id = "claude-sonnet-4-6" + end + + local old_providers = type(models.providers) == "table" and models.providers or {} + local preserved_provider = type(old_providers[current_provider_id]) == "table" and old_providers[current_provider_id] or {} + local providers = {} + models.providers = providers + local current_provider = preserved_provider + providers[current_provider_id] = current_provider if current_provider_id == "openai" then current_provider.api = "openai-completions" current_provider.baseUrl = "https://api.openai.com/v1" - current_provider.apiKey = selected_api_key + update_api_key(current_provider) current_provider.models = { - { id = "gpt-5.2", name = "GPT-5.2" }, + { id = current_model_id, name = current_model_id }, } elseif current_provider_id == "anthropic" then current_provider.api = "anthropic-messages" current_provider.baseUrl = "https://api.anthropic.com" - current_provider.apiKey = selected_api_key + update_api_key(current_provider) current_provider.models = { - { id = "claude-sonnet-4-6", name = "Claude Sonnet 4.6" }, + { id = current_model_id, name = current_model_id }, } elseif current_provider_id == "minimax-cn" then current_provider.api = "anthropic-messages" current_provider.baseUrl = "https://api.minimaxi.com/anthropic" - current_provider.apiKey = selected_api_key + update_api_key(current_provider) current_provider.authHeader = true current_provider.models = { - { id = "MiniMax-M2.5", name = "MiniMax M2.5" }, + { id = current_model_id, name = current_model_id }, } elseif current_provider_id == "moonshot" then current_provider.api = "openai-completions" current_provider.baseUrl = "https://api.moonshot.cn/v1" - current_provider.apiKey = selected_api_key + update_api_key(current_provider) current_provider.models = { - { id = "kimi-k2.5", name = "Kimi K2.5" }, + { id = current_model_id, name = current_model_id }, } elseif current_provider_id == "custom-provider" then - local primary_model = os.getenv("DEFAULT_AGENT_MODEL") or "custom-provider/custom-model" - local custom_model_id = primary_model:match("^[^/]+/(.+)$") or primary_model - if custom_model_id == "" then - custom_model_id = "custom-model" + if current_model_id == "" then + current_model_id = "custom-model" end current_provider.api = "openai-completions" - current_provider.baseUrl = os.getenv("DEFAULT_AGENT_OVERRIDE_BASE_URL") or current_provider.baseUrl - current_provider.apiKey = selected_api_key + current_provider.baseUrl = optional_env("DEFAULT_AGENT_OVERRIDE_BASE_URL") or current_provider.baseUrl + update_api_key(current_provider) current_provider.authHeader = nil current_provider.models = { - { - reasoning = false, - name = custom_model_id .. " (Custom Provider)", - cost = { - input = 0, - cacheRead = 0, - cacheWrite = 0, - output = 0, - }, - id = custom_model_id, - maxTokens = 4096, - contextWindow = 16000, - input = { "text" }, - }, + { id = current_model_id, name = current_model_id }, } end - local override_base = os.getenv("DEFAULT_AGENT_OVERRIDE_BASE_URL") or "" - local base_url_mode = os.getenv("DEFAULT_AGENT_BASE_URL_MODE") or "default" + local override_base = optional_env("DEFAULT_AGENT_OVERRIDE_BASE_URL") or "" + local base_url_mode = optional_env("DEFAULT_AGENT_BASE_URL_MODE") or "" if current_provider_id == "custom-provider" and override_base ~= "" then current_provider.baseUrl = override_base elseif base_url_mode == "override" and override_base ~= "" then current_provider.baseUrl = override_base elseif base_url_mode == "default" then - current_provider.baseUrl = os.getenv("DEFAULT_AGENT_BASE_URL") or current_provider.baseUrl - end - - -- luci.jsonc encodes empty Lua tables as JSON arrays ([]). To avoid producing - -- invalid provider entries like {"deepseek/deepseek-chat":[]}, drop provider - -- records that are empty or look like a provider/model string. - do - local to_del = {} - for k, v in pairs(providers) do - if type(k) == "string" and k:find("/", 1, true) then - table.insert(to_del, k) - elseif type(v) == "table" and next(v) == nil then - table.insert(to_del, k) - end - end - for _, k in ipairs(to_del) do - providers[k] = nil - end + current_provider.baseUrl = optional_env("DEFAULT_AGENT_BASE_URL") or current_provider.baseUrl end local agents = ensure_table(cfg, "agents") local defaults = ensure_table(agents, "defaults") local model = ensure_table(defaults, "model") -model.primary = os.getenv("DEFAULT_AGENT_MODEL") or "anthropic/claude-sonnet-4-6" +model.primary = primary_model or "anthropic/claude-sonnet-4-6" -prune_empty_tables(cfg) +local current_env_key = env_key_for_provider(current_provider_id) +local next_env = {} +if current_env_key and type(current_provider.apiKey) == "string" and current_provider.apiKey ~= "" then + next_env[current_env_key] = current_provider.apiKey +end +cfg.env = next(next_env) and next_env or nil local encoded = json.stringify(cfg, true) if encoded then @@ -814,7 +913,7 @@ f:close() local env_path = cfg_path:gsub("openclaw%.json$", "openclaw.env") local envf = assert(io.open(env_path, "w")) -if selected_env_key and selected_env_key ~= "" and selected_api_key ~= "" then +if selected_env_key and selected_env_key ~= "" and selected_api_key and selected_api_key ~= "" then local val = tostring(selected_api_key) val = val:gsub("\\", "\\\\"):gsub("\n", "\\n"):gsub('"', '\\"') envf:write(selected_env_key .. '="' .. val .. '"\n') @@ -1147,11 +1246,7 @@ upgrade_openclaw() { uci -q commit "$UCI_NS" >/dev/null 2>&1 || true # Ensure token exists even if runtime is already installed (service start requires it). - TOKEN="$(uci_get token)" - if [ -z "$TOKEN" ]; then - TOKEN="$(gen_token)" - uci -q set "${UCI_NS}.main.token=$TOKEN" && uci -q commit "$UCI_NS" || true - fi + ensure_token ensure_gateway_config || true if have_openclaw_runtime; then @@ -1233,6 +1328,7 @@ do_start() { write_installer_log "== start begin ==" ensure_dirs fix_data_permissions || true + ensure_token ensure_safe_port_for_start || exit 1 /etc/init.d/openclawmgr enable >/dev/null 2>&1 || true uci -q set "${UCI_NS}.main.enabled=1" && uci -q commit "$UCI_NS" || true @@ -1255,6 +1351,7 @@ do_restart() { write_installer_log "== restart begin ==" ensure_dirs fix_data_permissions || true + ensure_token ensure_safe_port_for_start || exit 1 ensure_gateway_config || true /etc/init.d/openclawmgr restart >/dev/null 2>&1 || true @@ -1266,6 +1363,7 @@ do_restart() { write_installer_log "== apply_config begin ==" ensure_dirs fix_data_permissions || true + ensure_token ensure_gateway_config || true local pid="" @@ -1425,14 +1523,8 @@ PROVIDER_BASE_URL="$(uci_get provider_base_url)" [ -n "$BIND" ] || BIND="lan" [ -n "$ENABLED" ] || ENABLED="0" NODE_VERSION="24.14.0" - [ -n "$ALLOW_INSECURE_AUTH" ] || ALLOW_INSECURE_AUTH="1" - [ -n "$DISABLE_DEVICE_AUTH" ] || DISABLE_DEVICE_AUTH="1" -[ -n "$DEFAULT_AGENT" ] || DEFAULT_AGENT="anthropic" -[ -n "$DEFAULT_MODEL" ] || DEFAULT_MODEL="" [ -n "$INSTALL_ACCELERATED" ] || INSTALL_ACCELERATED="1" [ -n "$INSTALL_CHANNEL" ] || INSTALL_CHANNEL="stable" -[ -n "$PROVIDER_API_KEY" ] || PROVIDER_API_KEY="" -[ -n "$PROVIDER_BASE_URL" ] || PROVIDER_BASE_URL="" case "$PORT" in ''|*[!0-9]*) PORT="18789" ;; @@ -1449,14 +1541,17 @@ case "$ENABLED" in *) ENABLED="0" ;; esac case "$ALLOW_INSECURE_AUTH" in + '') ;; 1|true|yes|on) ALLOW_INSECURE_AUTH="1" ;; *) ALLOW_INSECURE_AUTH="0" ;; esac case "$DISABLE_DEVICE_AUTH" in + '') ;; 1|true|yes|on) DISABLE_DEVICE_AUTH="1" ;; *) DISABLE_DEVICE_AUTH="0" ;; esac case "$DEFAULT_AGENT" in + '') ;; openai|anthropic|minimax-cn|moonshot|custom-provider) ;; *) DEFAULT_AGENT="anthropic" ;; esac @@ -1496,6 +1591,21 @@ NODE_DIR="${BASE_DIR}/node" GLOBAL_DIR="${BASE_DIR}/global" DATA_DIR="${BASE_DIR}/data" +if [ -n "$BASE_DIR" ]; then + load_gateway_runtime_from_json +fi + +case "$PORT" in + ''|*[!0-9]*) PORT="18789" ;; +esac +if [ "$PORT" -lt 1 ] 2>/dev/null || [ "$PORT" -gt 65535 ] 2>/dev/null; then + PORT="18789" +fi +case "$BIND" in + loopback|lan|auto|tailnet|custom) ;; + *) BIND="lan" ;; +esac + NODE_BIN="${NODE_DIR}/bin/node" NPM_BIN="${NODE_DIR}/bin/npm" diff --git a/luci-app-openclawmgr/root/usr/share/openclawmgr/openclawmgr-cli.sh b/luci-app-openclawmgr/root/usr/share/openclawmgr/openclawmgr-cli.sh index dc61921a..b0cd9eed 100755 --- a/luci-app-openclawmgr/root/usr/share/openclawmgr/openclawmgr-cli.sh +++ b/luci-app-openclawmgr/root/usr/share/openclawmgr/openclawmgr-cli.sh @@ -33,6 +33,45 @@ prompt_default() { uci_get() { uci -q get "openclawmgr.main.$1" 2>/dev/null || true; } +is_musl() { + ldd --version 2>&1 | grep -qi musl && return 0 + [ -e /lib/ld-musl-*.so.1 ] 2>/dev/null && return 0 + return 1 +} + +init_git_transport() { + command -v git >/dev/null 2>&1 || return 0 + mkdir -p "$DATA_DIR" 2>/dev/null || true + git config --file "$DATA_DIR/.gitconfig" --add url."https://github.com/".insteadOf "ssh://git@github.com/" 2>/dev/null || true + git config --file "$DATA_DIR/.gitconfig" --add url."https://github.com/".insteadOf "ssh://git@github.com" 2>/dev/null || true + git config --file "$DATA_DIR/.gitconfig" --add url."https://github.com/".insteadOf "git@github.com:" 2>/dev/null || true +} + +init_npm_env() { + INSTALL_ACCELERATED="${INSTALL_ACCELERATED:-$(uci_get install_accelerated)}" + [ -n "$INSTALL_ACCELERATED" ] || INSTALL_ACCELERATED="1" + case "$INSTALL_ACCELERATED" in + 1|true|yes|on) INSTALL_ACCELERATED="1" ;; + *) INSTALL_ACCELERATED="0" ;; + esac + + NPM_CACHE_DIR="${BASE_DIR}/npm-cache" + export npm_config_cache="$NPM_CACHE_DIR" + export npm_config_prefix="$GLOBAL_DIR" + export npm_config_audit="false" + export npm_config_fund="false" + export npm_config_progress="false" + export npm_config_update_notifier="false" + + if is_musl; then + export npm_config_ignore_scripts="true" + fi + + if [ "$INSTALL_ACCELERATED" = "1" ]; then + export npm_config_registry="https://registry.npmmirror.com" + fi +} + init_paths() { BASE_DIR="${BASE_DIR:-$(uci_get base_dir)}" if [ -z "$BASE_DIR" ]; then @@ -54,6 +93,8 @@ init_paths() { export OPENCLAW_STATE_DIR="${DATA_DIR}/.openclaw" export OPENCLAW_CONFIG_PATH="$CONFIG_FILE" export PATH="${NODE_DIR}/bin:${GLOBAL_DIR}/bin:/usr/sbin:/usr/bin:/sbin:/bin" + init_git_transport + init_npm_env } find_openclaw_entry() { @@ -81,6 +122,51 @@ openclaw_cmd() { return 127 } +openclaw() { + openclaw_cmd "$@" +} + +first_line_or_empty() { + sed -n '1p' 2>/dev/null || true +} + +detect_openclaw_version() { + local v="" + v="$(openclaw_cmd --version 2>/dev/null | first_line_or_empty)" + if [ -z "$v" ]; then + v="$(openclaw_cmd version 2>/dev/null | first_line_or_empty)" + fi + printf '%s' "$v" +} + +print_cli_env_summary() { + local node_v npm_v openclaw_v npm_registry musl_state ignore_scripts + node_v="$(node -v 2>/dev/null | first_line_or_empty)" + npm_v="$(npm -v 2>/dev/null | first_line_or_empty)" + openclaw_v="$(detect_openclaw_version)" + npm_registry="$(npm config get registry 2>/dev/null | tr -d '\r' | first_line_or_empty)" + musl_state="no" + ignore_scripts="${npm_config_ignore_scripts:-false}" + is_musl && musl_state="yes" + + [ -n "$node_v" ] || node_v="未安装" + [ -n "$npm_v" ] || npm_v="未安装" + [ -n "$openclaw_v" ] || openclaw_v="未安装" + [ -n "$npm_registry" ] || npm_registry="unknown" + + printf '%s\n' "${BOLD}环境摘要${NC}" + printf '%s\n' " base_dir ${BASE_DIR}" + printf '%s\n' " config ${CONFIG_FILE}" + printf '%s\n' " node ${node_v}" + printf '%s\n' " npm ${npm_v}" + printf '%s\n' " npm prefix ${npm_config_prefix:-${GLOBAL_DIR}}" + printf '%s\n' " npm cache ${npm_config_cache:-${NPM_CACHE_DIR:-}}" + printf '%s\n' " npm registry ${npm_registry}" + printf '%s\n' " musl ${musl_state}" + printf '%s\n' " ignore scripts ${ignore_scripts}" + printf '%s\n' " openclaw ${openclaw_v}" +} + action_backup_config() { mkdir -p "$BACKUP_DIR" 2>/dev/null || true if [ ! -f "$CONFIG_FILE" ]; then @@ -117,15 +203,35 @@ action_configure() { openclaw_cmd configure || true } +action_cli_env() { + printf '\n' + info "=== OpenClaw CLI 环境 ===" + printf '%s\n' "${DIM}已注入 BASE_DIR / NODE_DIR / GLOBAL_DIR / DATA_DIR / OPENCLAW_* / PATH / npm_config_*${NC}" + printf '%s\n' "${DIM}可直接执行 openclaw doctor / openclaw configure / node -v / npm -v 等命令${NC}" + printf '%s\n' "${DIM}此环境下 npm -g 默认安装到 ${GLOBAL_DIR},并复用 OpenClawMgr 的缓存/镜像配置${NC}" + printf '%s\n' "${DIM}若系统为 musl,将自动启用 ignore-scripts,并预置 GitHub HTTPS 重写${NC}" + printf '%s\n' "${DIM}输入 exit 可退出终端${NC}" + printf '\n' + print_cli_env_summary + if cd "$DATA_DIR" 2>/dev/null; then + printf '%s\n' "${DIM}当前目录: ${DATA_DIR}${NC}" + else + warn "无法切换到数据目录,保持当前目录不变。" + fi + printf '\n' + exec sh -i +} + main_menu() { while true; do printf '\n' printf '%s\n' "${BOLD}OpenClaw AI Gateway — CLI 配置入口(OpenClawMgr)${NC}" printf '%s\n' "${DIM}base_dir: ${BASE_DIR}${NC}" printf '\n' - printf '%s\n' " ${CYAN}1)${NC} 🧭 官方配置向导 ${DIM}(openclaw configure)${NC}" - printf '%s\n' " ${CYAN}2)${NC} 💾 备份配置" - printf '%s\n' " ${CYAN}3)${NC} 📥 恢复配置" + printf '%s\n' " ${CYAN}1)${NC} 💻 CLI环境 ${DIM}(仅注入环境,不执行 configure)${NC}" + printf '%s\n' " ${CYAN}2)${NC} 🧭 官方配置向导 ${DIM}(openclaw configure)${NC}" + printf '%s\n' " ${CYAN}3)${NC} 💾 备份配置" + printf '%s\n' " ${CYAN}4)${NC} 📥 恢复配置" printf '\n' printf '%s\n' " ${CYAN}0)${NC} 退出" printf '\n' @@ -133,9 +239,10 @@ main_menu() { local c="" c="$(prompt_default "请选择" "1")" case "$c" in - 1) action_configure; pause_enter ;; - 2) action_backup_config || true; pause_enter ;; - 3) action_restore_config || true; pause_enter ;; + 1) action_cli_env ;; + 2) action_configure; pause_enter ;; + 3) action_backup_config || true; pause_enter ;; + 4) action_restore_config || true; pause_enter ;; 0) ok "再见!"; exit 0 ;; *) warn "无效选择" ;; esac @@ -146,12 +253,13 @@ init_paths case "${1:-}" in --help|-h) - echo "Usage: openclawmgr-cli.sh [configure|backup|restore]" + echo "Usage: openclawmgr-cli.sh [configure|cli-env|backup|restore]" ;; *) case "${1:-menu}" in menu) main_menu ;; configure) action_configure; pause_enter ;; + cli-env) action_cli_env ;; backup) action_backup_config || true; pause_enter ;; restore) action_restore_config || true; pause_enter ;; *) echo "Unknown command: ${1:-}" >&2; exit 2 ;; diff --git a/luci-app-passwall2/htdocs/luci-static/resources/view/passwall2/Sortable.min.js b/luci-app-passwall2/htdocs/luci-static/resources/view/passwall2/Sortable.min.js index 95423a64..8148b9dd 100644 --- a/luci-app-passwall2/htdocs/luci-static/resources/view/passwall2/Sortable.min.js +++ b/luci-app-passwall2/htdocs/luci-static/resources/view/passwall2/Sortable.min.js @@ -1,2 +1,2 @@ -/*! Sortable 1.15.6 - MIT | git://github.com/SortableJS/Sortable.git */ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t=t||self).Sortable=e()}(this,function(){"use strict";function e(e,t){var n,o=Object.keys(e);return Object.getOwnPropertySymbols&&(n=Object.getOwnPropertySymbols(e),t&&(n=n.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),o.push.apply(o,n)),o}function I(o){for(var t=1;tt.length)&&(e=t.length);for(var n=0,o=new Array(e);n"===e[0]&&(e=e.substring(1)),t))try{if(t.matches)return t.matches(e);if(t.msMatchesSelector)return t.msMatchesSelector(e);if(t.webkitMatchesSelector)return t.webkitMatchesSelector(e)}catch(t){return}}function g(t){return t.host&&t!==document&&t.host.nodeType?t.host:t.parentNode}function P(t,e,n,o){if(t){n=n||document;do{if(null!=e&&(">"!==e[0]||t.parentNode===n)&&f(t,e)||o&&t===n)return t}while(t!==n&&(t=g(t)))}return null}var m,v=/\s+/g;function k(t,e,n){var o;t&&e&&(t.classList?t.classList[n?"add":"remove"](e):(o=(" "+t.className+" ").replace(v," ").replace(" "+e+" "," "),t.className=(o+(n?" "+e:"")).replace(v," ")))}function R(t,e,n){var o=t&&t.style;if(o){if(void 0===n)return document.defaultView&&document.defaultView.getComputedStyle?n=document.defaultView.getComputedStyle(t,""):t.currentStyle&&(n=t.currentStyle),void 0===e?n:n[e];o[e=!(e in o||-1!==e.indexOf("webkit"))?"-webkit-"+e:e]=n+("string"==typeof n?"":"px")}}function b(t,e){var n="";if("string"==typeof t)n=t;else do{var o=R(t,"transform")}while(o&&"none"!==o&&(n=o+" "+n),!e&&(t=t.parentNode));var i=window.DOMMatrix||window.WebKitCSSMatrix||window.CSSMatrix||window.MSCSSMatrix;return i&&new i(n)}function D(t,e,n){if(t){var o=t.getElementsByTagName(e),i=0,r=o.length;if(n)for(;i=n.left-e&&i<=n.right+e,e=r>=n.top-e&&r<=n.bottom+e;return o&&e?a=t:void 0}}),a);if(e){var n,o={};for(n in t)t.hasOwnProperty(n)&&(o[n]=t[n]);o.target=o.rootEl=e,o.preventDefault=void 0,o.stopPropagation=void 0,e[K]._onDragOver(o)}}var i,r,a}function Ft(t){Z&&Z.parentNode[K]._isOutsideThisEl(t.target)}function jt(t,e){if(!t||!t.nodeType||1!==t.nodeType)throw"Sortable: `el` must be an HTMLElement, not ".concat({}.toString.call(t));this.el=t,this.options=e=a({},e),t[K]=this;var n,o,i={group:null,sort:!0,disabled:!1,store:null,handle:null,draggable:/^[uo]l$/i.test(t.nodeName)?">li":">*",swapThreshold:1,invertSwap:!1,invertedSwapThreshold:null,removeCloneOnHide:!0,direction:function(){return kt(t,this.options)},ghostClass:"sortable-ghost",chosenClass:"sortable-chosen",dragClass:"sortable-drag",ignore:"a, img",filter:null,preventOnFilter:!0,animation:0,easing:null,setData:function(t,e){t.setData("Text",e.textContent)},dropBubble:!1,dragoverBubble:!1,dataIdAttr:"data-id",delay:0,delayOnTouchOnly:!1,touchStartThreshold:(Number.parseInt?Number:window).parseInt(window.devicePixelRatio,10)||1,forceFallback:!1,fallbackClass:"sortable-fallback",fallbackOnBody:!1,fallbackTolerance:0,fallbackOffset:{x:0,y:0},supportPointer:!1!==jt.supportPointer&&"PointerEvent"in window&&(!u||c),emptyInsertThreshold:5};for(n in z.initializePlugins(this,t,i),i)n in e||(e[n]=i[n]);for(o in Rt(e),this)"_"===o.charAt(0)&&"function"==typeof this[o]&&(this[o]=this[o].bind(this));this.nativeDraggable=!e.forceFallback&&It,this.nativeDraggable&&(this.options.touchStartThreshold=1),e.supportPointer?h(t,"pointerdown",this._onTapStart):(h(t,"mousedown",this._onTapStart),h(t,"touchstart",this._onTapStart)),this.nativeDraggable&&(h(t,"dragover",this),h(t,"dragenter",this)),St.push(this.el),e.store&&e.store.get&&this.sort(e.store.get(this)||[]),a(this,A())}function Ht(t,e,n,o,i,r,a,l){var s,c,u=t[K],d=u.options.onMove;return!window.CustomEvent||y||w?(s=document.createEvent("Event")).initEvent("move",!0,!0):s=new CustomEvent("move",{bubbles:!0,cancelable:!0}),s.to=e,s.from=t,s.dragged=n,s.draggedRect=o,s.related=i||e,s.relatedRect=r||X(e),s.willInsertAfter=l,s.originalEvent=a,t.dispatchEvent(s),c=d?d.call(u,s,a):c}function Lt(t){t.draggable=!1}function Kt(){xt=!1}function Wt(t){return setTimeout(t,0)}function zt(t){return clearTimeout(t)}jt.prototype={constructor:jt,_isOutsideThisEl:function(t){this.el.contains(t)||t===this.el||(vt=null)},_getDirection:function(t,e){return"function"==typeof this.options.direction?this.options.direction.call(this,t,e,Z):this.options.direction},_onTapStart:function(e){if(e.cancelable){var n=this,o=this.el,t=this.options,i=t.preventOnFilter,r=e.type,a=e.touches&&e.touches[0]||e.pointerType&&"touch"===e.pointerType&&e,l=(a||e).target,s=e.target.shadowRoot&&(e.path&&e.path[0]||e.composedPath&&e.composedPath()[0])||l,c=t.filter;if(!function(t){Ot.length=0;var e=t.getElementsByTagName("input"),n=e.length;for(;n--;){var o=e[n];o.checked&&Ot.push(o)}}(o),!Z&&!(/mousedown|pointerdown/.test(r)&&0!==e.button||t.disabled)&&!s.isContentEditable&&(this.nativeDraggable||!u||!l||"SELECT"!==l.tagName.toUpperCase())&&!((l=P(l,t.draggable,o,!1))&&l.animated||et===l)){if(it=j(l),at=j(l,t.draggable),"function"==typeof c){if(c.call(this,e,l,this))return V({sortable:n,rootEl:s,name:"filter",targetEl:l,toEl:o,fromEl:o}),U("filter",n,{evt:e}),void(i&&e.preventDefault())}else if(c=c&&c.split(",").some(function(t){if(t=P(s,t.trim(),o,!1))return V({sortable:n,rootEl:t,name:"filter",targetEl:l,fromEl:o,toEl:o}),U("filter",n,{evt:e}),!0}))return void(i&&e.preventDefault());t.handle&&!P(s,t.handle,o,!1)||this._prepareDragStart(e,a,l)}}},_prepareDragStart:function(t,e,n){var o,i=this,r=i.el,a=i.options,l=r.ownerDocument;n&&!Z&&n.parentNode===r&&(o=X(n),J=r,$=(Z=n).parentNode,tt=Z.nextSibling,et=n,st=a.group,ut={target:jt.dragged=Z,clientX:(e||t).clientX,clientY:(e||t).clientY},ft=ut.clientX-o.left,gt=ut.clientY-o.top,this._lastX=(e||t).clientX,this._lastY=(e||t).clientY,Z.style["will-change"]="all",o=function(){U("delayEnded",i,{evt:t}),jt.eventCanceled?i._onDrop():(i._disableDelayedDragEvents(),!s&&i.nativeDraggable&&(Z.draggable=!0),i._triggerDragStart(t,e),V({sortable:i,name:"choose",originalEvent:t}),k(Z,a.chosenClass,!0))},a.ignore.split(",").forEach(function(t){D(Z,t.trim(),Lt)}),h(l,"dragover",Bt),h(l,"mousemove",Bt),h(l,"touchmove",Bt),a.supportPointer?(h(l,"pointerup",i._onDrop),this.nativeDraggable||h(l,"pointercancel",i._onDrop)):(h(l,"mouseup",i._onDrop),h(l,"touchend",i._onDrop),h(l,"touchcancel",i._onDrop)),s&&this.nativeDraggable&&(this.options.touchStartThreshold=4,Z.draggable=!0),U("delayStart",this,{evt:t}),!a.delay||a.delayOnTouchOnly&&!e||this.nativeDraggable&&(w||y)?o():jt.eventCanceled?this._onDrop():(a.supportPointer?(h(l,"pointerup",i._disableDelayedDrag),h(l,"pointercancel",i._disableDelayedDrag)):(h(l,"mouseup",i._disableDelayedDrag),h(l,"touchend",i._disableDelayedDrag),h(l,"touchcancel",i._disableDelayedDrag)),h(l,"mousemove",i._delayedDragTouchMoveHandler),h(l,"touchmove",i._delayedDragTouchMoveHandler),a.supportPointer&&h(l,"pointermove",i._delayedDragTouchMoveHandler),i._dragStartTimer=setTimeout(o,a.delay)))},_delayedDragTouchMoveHandler:function(t){t=t.touches?t.touches[0]:t;Math.max(Math.abs(t.clientX-this._lastX),Math.abs(t.clientY-this._lastY))>=Math.floor(this.options.touchStartThreshold/(this.nativeDraggable&&window.devicePixelRatio||1))&&this._disableDelayedDrag()},_disableDelayedDrag:function(){Z&&Lt(Z),clearTimeout(this._dragStartTimer),this._disableDelayedDragEvents()},_disableDelayedDragEvents:function(){var t=this.el.ownerDocument;p(t,"mouseup",this._disableDelayedDrag),p(t,"touchend",this._disableDelayedDrag),p(t,"touchcancel",this._disableDelayedDrag),p(t,"pointerup",this._disableDelayedDrag),p(t,"pointercancel",this._disableDelayedDrag),p(t,"mousemove",this._delayedDragTouchMoveHandler),p(t,"touchmove",this._delayedDragTouchMoveHandler),p(t,"pointermove",this._delayedDragTouchMoveHandler)},_triggerDragStart:function(t,e){e=e||"touch"==t.pointerType&&t,!this.nativeDraggable||e?this.options.supportPointer?h(document,"pointermove",this._onTouchMove):h(document,e?"touchmove":"mousemove",this._onTouchMove):(h(Z,"dragend",this),h(J,"dragstart",this._onDragStart));try{document.selection?Wt(function(){document.selection.empty()}):window.getSelection().removeAllRanges()}catch(t){}},_dragStarted:function(t,e){var n;Dt=!1,J&&Z?(U("dragStarted",this,{evt:e}),this.nativeDraggable&&h(document,"dragover",Ft),n=this.options,t||k(Z,n.dragClass,!1),k(Z,n.ghostClass,!0),jt.active=this,t&&this._appendGhost(),V({sortable:this,name:"start",originalEvent:e})):this._nulling()},_emulateDragOver:function(){if(dt){this._lastX=dt.clientX,this._lastY=dt.clientY,Xt();for(var t=document.elementFromPoint(dt.clientX,dt.clientY),e=t;t&&t.shadowRoot&&(t=t.shadowRoot.elementFromPoint(dt.clientX,dt.clientY))!==e;)e=t;if(Z.parentNode[K]._isOutsideThisEl(t),e)do{if(e[K])if(e[K]._onDragOver({clientX:dt.clientX,clientY:dt.clientY,target:t,rootEl:e})&&!this.options.dragoverBubble)break}while(e=g(t=e));Yt()}},_onTouchMove:function(t){if(ut){var e=this.options,n=e.fallbackTolerance,o=e.fallbackOffset,i=t.touches?t.touches[0]:t,r=Q&&b(Q,!0),a=Q&&r&&r.a,l=Q&&r&&r.d,e=At&&wt&&E(wt),a=(i.clientX-ut.clientX+o.x)/(a||1)+(e?e[0]-Tt[0]:0)/(a||1),l=(i.clientY-ut.clientY+o.y)/(l||1)+(e?e[1]-Tt[1]:0)/(l||1);if(!jt.active&&!Dt){if(n&&Math.max(Math.abs(i.clientX-this._lastX),Math.abs(i.clientY-this._lastY))E.right+10||S.clientY>x.bottom&&S.clientX>x.left:S.clientY>E.bottom+10||S.clientX>x.right&&S.clientY>x.top)||m.animated)){if(m&&(t=n,e=r,C=X(B((_=this).el,0,_.options,!0)),_=L(_.el,_.options,Q),e?t.clientX<_.left-10||t.clientYt.length)&&(e=t.length);for(var n=0,o=Array(e);n"===e[0]&&(e=e.substring(1)),t))try{if(t.matches)return t.matches(e);if(t.msMatchesSelector)return t.msMatchesSelector(e);if(t.webkitMatchesSelector)return t.webkitMatchesSelector(e)}catch(t){return}}function m(t){return t.host&&t!==document&&t.host.nodeType&&t.host!==t?t.host:t.parentNode}function P(t,e,n,o){if(t){n=n||document;do{if(null!=e&&(">"!==e[0]||t.parentNode===n)&&g(t,e)||o&&t===n)return t}while(t!==n&&(t=m(t)))}return null}var v,b=/\s+/g;function k(t,e,n){var o;t&&e&&(t.classList?t.classList[n?"add":"remove"](e):(o=(" "+t.className+" ").replace(b," ").replace(" "+e+" "," "),t.className=(o+(n?" "+e:"")).replace(b," ")))}function R(t,e,n){var o=t&&t.style;if(o){if(void 0===n)return document.defaultView&&document.defaultView.getComputedStyle?n=document.defaultView.getComputedStyle(t,""):t.currentStyle&&(n=t.currentStyle),void 0===e?n:n[e];o[e=!(e in o||-1!==e.indexOf("webkit"))?"-webkit-"+e:e]=n+("string"==typeof n?"":"px")}}function D(t,e){var n="";if("string"==typeof t)n=t;else do{var o=R(t,"transform")}while(o&&"none"!==o&&(n=o+" "+n),!e&&(t=t.parentNode));var i=window.DOMMatrix||window.WebKitCSSMatrix||window.CSSMatrix||window.MSCSSMatrix;return i&&new i(n)}function E(t,e,n){if(t){var o=t.getElementsByTagName(e),i=0,r=o.length;if(n)for(;i=n.left-e&&i<=n.right+e,e=r>=n.top-e&&r<=n.bottom+e;return o&&e?a=t:void 0}}),a);if(e){var n,o={};for(n in t)t.hasOwnProperty(n)&&(o[n]=t[n]);o.target=o.rootEl=e,o.preventDefault=void 0,o.stopPropagation=void 0,e[K]._onDragOver(o)}}var i,r,a}function jt(t){$&&$.parentNode[K]._isOutsideThisEl(t.target)}function Ht(t,e){if(!t||!t.nodeType||1!==t.nodeType)throw"Sortable: `el` must be an HTMLElement, not ".concat({}.toString.call(t));this.el=t,this.options=e=a({},e),t[K]=this;var n,o,i={group:null,sort:!0,disabled:!1,store:null,handle:null,draggable:/^[uo]l$/i.test(t.nodeName)?">li":">*",swapThreshold:1,invertSwap:!1,invertedSwapThreshold:null,removeCloneOnHide:!0,direction:function(){return Rt(t,this.options)},ghostClass:"sortable-ghost",chosenClass:"sortable-chosen",dragClass:"sortable-drag",ignore:"a, img",filter:null,preventOnFilter:!0,animation:0,easing:null,setData:function(t,e){t.setData("Text",e.textContent)},dropBubble:!1,dragoverBubble:!1,dataIdAttr:"data-id",delay:0,delayOnTouchOnly:!1,touchStartThreshold:(Number.parseInt?Number:window).parseInt(window.devicePixelRatio,10)||1,forceFallback:!1,fallbackClass:"sortable-fallback",fallbackOnBody:!1,fallbackTolerance:0,fallbackOffset:{x:0,y:0},supportPointer:!1!==Ht.supportPointer&&"PointerEvent"in window&&(!u||d),emptyInsertThreshold:5};for(n in G.initializePlugins(this,t,i),i)n in e||(e[n]=i[n]);for(o in Xt(e),this)"_"===o.charAt(0)&&"function"==typeof this[o]&&(this[o]=this[o].bind(this));this.nativeDraggable=!e.forceFallback&&Pt,this.nativeDraggable&&(this.options.touchStartThreshold=1),e.supportPointer?f(t,"pointerdown",this._onTapStart):(f(t,"mousedown",this._onTapStart),f(t,"touchstart",this._onTapStart)),this.nativeDraggable&&(f(t,"dragover",this),f(t,"dragenter",this)),_t.push(this.el),e.store&&e.store.get&&this.sort(e.store.get(this)||[]),a(this,N())}function Lt(t,e,n,o,i,r,a,l){var s,c,u=t[K],d=u.options.onMove;return!window.CustomEvent||y||w?(s=document.createEvent("Event")).initEvent("move",!0,!0):s=new CustomEvent("move",{bubbles:!0,cancelable:!0}),s.to=e,s.from=t,s.dragged=n,s.draggedRect=o,s.related=i||e,s.relatedRect=r||X(e),s.willInsertAfter=l,s.originalEvent=a,t.dispatchEvent(s),c=d?d.call(u,s,a):c}function Kt(t){t.draggable=!1}function Wt(){Ot=!1}function zt(t){return setTimeout(t,0)}function Gt(t){return clearTimeout(t)}Ht.prototype={constructor:Ht,_isOutsideThisEl:function(t){this.el.contains(t)||t===this.el||(bt=null)},_getDirection:function(t,e){return"function"==typeof this.options.direction?this.options.direction.call(this,t,e,$):this.options.direction},_onTapStart:function(e){if(e.cancelable){var n=this,o=this.el,t=this.options,i=t.preventOnFilter,r=e.type,a=e.touches&&e.touches[0]||e.pointerType&&"touch"===e.pointerType&&e,l=(a||e).target,s=e.target.shadowRoot&&(e.path&&e.path[0]||e.composedPath&&e.composedPath()[0])||l,c=t.filter;if(!function(t){Mt.length=0;var e=t.getElementsByTagName("input"),n=e.length;for(;n--;){var o=e[n];o.checked&&Mt.push(o)}}(o),!$&&!(/mousedown|pointerdown/.test(r)&&0!==e.button||t.disabled)&&!s.isContentEditable&&(this.nativeDraggable||!u||!l||"SELECT"!==l.tagName.toUpperCase())&&!((l=P(l,t.draggable,o,!1))&&l.animated||nt===l)){if(rt=j(l),lt=j(l,t.draggable),"function"==typeof c){if(c.call(this,e,l,this))return Z({sortable:n,rootEl:s,name:"filter",targetEl:l,toEl:o,fromEl:o}),q("filter",n,{evt:e}),void(i&&e.preventDefault())}else if(c=c&&c.split(",").some(function(t){if(t=P(s,t.trim(),o,!1))return Z({sortable:n,rootEl:t,name:"filter",targetEl:l,fromEl:o,toEl:o}),q("filter",n,{evt:e}),!0}))return void(i&&e.preventDefault());t.handle&&!P(s,t.handle,o,!1)||this._prepareDragStart(e,a,l)}}},_prepareDragStart:function(t,e,n){var o,i=this,r=i.el,a=i.options,l=r.ownerDocument;n&&!$&&n.parentNode===r&&(o=X(n),tt=r,Q=($=n).parentNode,et=$.nextSibling,nt=n,ct=a.group,dt={target:Ht.dragged=$,clientX:(e||t).clientX,clientY:(e||t).clientY},gt=dt.clientX-o.left,mt=dt.clientY-o.top,this._lastX=(e||t).clientX,this._lastY=(e||t).clientY,$.style["will-change"]="all",o=function(){q("delayEnded",i,{evt:t}),Ht.eventCanceled?i._onDrop():(i._disableDelayedDragEvents(),!c&&i.nativeDraggable&&($.draggable=!0),i._triggerDragStart(t,e),Z({sortable:i,name:"choose",originalEvent:t}),k($,a.chosenClass,!0))},a.ignore.split(",").forEach(function(t){E($,t.trim(),Kt)}),f(l,"dragover",Ft),f(l,"mousemove",Ft),f(l,"touchmove",Ft),a.supportPointer?(f(l,"pointerup",i._onDrop),this.nativeDraggable||f(l,"pointercancel",i._onDrop)):(f(l,"mouseup",i._onDrop),f(l,"touchend",i._onDrop),f(l,"touchcancel",i._onDrop)),c&&this.nativeDraggable&&(this.options.touchStartThreshold=4,$.draggable=!0),q("delayStart",this,{evt:t}),!a.delay||a.delayOnTouchOnly&&!e||this.nativeDraggable&&(w||y)?o():Ht.eventCanceled?this._onDrop():(a.supportPointer?(f(l,"pointerup",i._disableDelayedDrag),f(l,"pointercancel",i._disableDelayedDrag)):(f(l,"mouseup",i._disableDelayedDrag),f(l,"touchend",i._disableDelayedDrag),f(l,"touchcancel",i._disableDelayedDrag)),f(l,"mousemove",i._delayedDragTouchMoveHandler),f(l,"touchmove",i._delayedDragTouchMoveHandler),a.supportPointer&&f(l,"pointermove",i._delayedDragTouchMoveHandler),i._dragStartTimer=setTimeout(o,a.delay)))},_delayedDragTouchMoveHandler:function(t){t=t.touches?t.touches[0]:t;Math.max(Math.abs(t.clientX-this._lastX),Math.abs(t.clientY-this._lastY))>=Math.floor(this.options.touchStartThreshold/(this.nativeDraggable&&window.devicePixelRatio||1))&&this._disableDelayedDrag()},_disableDelayedDrag:function(){$&&Kt($),clearTimeout(this._dragStartTimer),this._disableDelayedDragEvents()},_disableDelayedDragEvents:function(){var t=this.el.ownerDocument;p(t,"mouseup",this._disableDelayedDrag),p(t,"touchend",this._disableDelayedDrag),p(t,"touchcancel",this._disableDelayedDrag),p(t,"pointerup",this._disableDelayedDrag),p(t,"pointercancel",this._disableDelayedDrag),p(t,"mousemove",this._delayedDragTouchMoveHandler),p(t,"touchmove",this._delayedDragTouchMoveHandler),p(t,"pointermove",this._delayedDragTouchMoveHandler)},_triggerDragStart:function(t,e){e=e||"touch"==t.pointerType&&t,!this.nativeDraggable||e?this.options.supportPointer?f(document,"pointermove",this._onTouchMove):f(document,e?"touchmove":"mousemove",this._onTouchMove):(f($,"dragend",this),f(tt,"dragstart",this._onDragStart));try{document.selection?zt(function(){document.selection.empty()}):window.getSelection().removeAllRanges()}catch(t){}},_dragStarted:function(t,e){var n;Et=!1,tt&&$?(q("dragStarted",this,{evt:e}),this.nativeDraggable&&f(document,"dragover",jt),n=this.options,t||k($,n.dragClass,!1),k($,n.ghostClass,!0),Ht.active=this,t&&this._appendGhost(),Z({sortable:this,name:"start",originalEvent:e})):this._nulling()},_emulateDragOver:function(){if(ht){this._lastX=ht.clientX,this._lastY=ht.clientY,Yt();for(var t=document.elementFromPoint(ht.clientX,ht.clientY),e=t;t&&t.shadowRoot&&(t=t.shadowRoot.elementFromPoint(ht.clientX,ht.clientY))!==e;)e=t;if($.parentNode[K]._isOutsideThisEl(t),e)do{if(e[K])if(e[K]._onDragOver({clientX:ht.clientX,clientY:ht.clientY,target:t,rootEl:e})&&!this.options.dragoverBubble)break}while(e=m(t=e));Bt()}},_onTouchMove:function(t){if(dt){var e=this.options,n=e.fallbackTolerance,o=e.fallbackOffset,i=t.touches?t.touches[0]:t,r=J&&D(J,!0),a=J&&r&&r.a,l=J&&r&&r.d,e=Nt&&Dt&&S(Dt),a=(i.clientX-dt.clientX+o.x)/(a||1)+(e?e[0]-xt[0]:0)/(a||1),l=(i.clientY-dt.clientY+o.y)/(l||1)+(e?e[1]-xt[1]:0)/(l||1);if(!Ht.active&&!Et){if(n&&Math.max(Math.abs(i.clientX-this._lastX),Math.abs(i.clientY-this._lastY))E.right+10||S.clientY>x.bottom&&S.clientX>x.left:S.clientY>E.bottom+10||S.clientX>x.right&&S.clientY>x.top)||m.animated)){if(m&&(t=n,e=r,C=X(B((_=this).el,0,_.options,!0)),_=L(_.el,_.options,J),e?t.clientX<_.left-10||t.clientY - +