From e4f332db28d62c52aab0492d332e0d29316eb3b9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 7 Mar 2026 13:56:51 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=8C=B4=20Sync=202026-03-07=2013:56:51?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- luci-app-advancedplus/Makefile | 2 +- .../root/etc/init.d/advancedplus | 1 - .../luci-static/resources/view/wifidogx.js | 351 +++++++++--------- .../resources/view/wifidogx/status.js | 2 + .../po/zh_Hans/apfree-wifidog.po | 237 ++++++++++++ .../luasrc/passwall/util_xray.lua | 38 +- luci-app-passwall2/Makefile | 40 +- openwrt-fastfetch/Makefile | 4 +- 8 files changed, 462 insertions(+), 213 deletions(-) diff --git a/luci-app-advancedplus/Makefile b/luci-app-advancedplus/Makefile index 0b28c5c4e..1c1c6eb07 100644 --- a/luci-app-advancedplus/Makefile +++ b/luci-app-advancedplus/Makefile @@ -11,7 +11,7 @@ LUCI_DEPENDS:=+luci-compat +curl LUCI_PKGARCH:=all PKG_VERSION:=1.8.9 -PKG_RELEASE:=1 +PKG_RELEASE:=2 define Package/$(PKG_NAME)/conffiles /etc/config/advancedplus diff --git a/luci-app-advancedplus/root/etc/init.d/advancedplus b/luci-app-advancedplus/root/etc/init.d/advancedplus index 82f6f3dd4..c24feb5a6 100755 --- a/luci-app-advancedplus/root/etc/init.d/advancedplus +++ b/luci-app-advancedplus/root/etc/init.d/advancedplus @@ -92,7 +92,6 @@ advancedset(){ start_service() { [ -f $LOCK ] && exit - [ "x$(uci -q get advancedplus.@basic[0].uhttpd)" = "x1" ] && uhttpd_service touch $LOCK rm -rf /tmp/luci-* rm -f $LOCK 2>/dev/null diff --git a/luci-app-apfree-wifidog/htdocs/luci-static/resources/view/wifidogx.js b/luci-app-apfree-wifidog/htdocs/luci-static/resources/view/wifidogx.js index d5ba630bc..ca2a0619f 100644 --- a/luci-app-apfree-wifidog/htdocs/luci-static/resources/view/wifidogx.js +++ b/luci-app-apfree-wifidog/htdocs/luci-static/resources/view/wifidogx.js @@ -48,12 +48,12 @@ function generateLocationId() { var adminCode = '110101'; // Default to Beijing Dongcheng District (positions 1-6) var serviceType = '100'; // Commercial internet service location (positions 7-9) var sequenceNum = ''; - + // Generate 5-digit random sequence number (positions 10-14) for (var i = 0; i < 5; i++) { sequenceNum += Math.floor(Math.random() * 10); } - + return adminCode + serviceType + sequenceNum; // 6 + 3 + 5 = 14 digits } @@ -78,58 +78,58 @@ function updateMacStatus(macAddr, isSuccess, errorMsg, isFallback) { var statusElement = document.getElementById('mac-status'); if (isSuccess) { var prefix = isFallback ? _('✓ WAN MAC address obtained (fallback): ') : _('✓ WAN MAC address obtained: '); - var suffix = isFallback ? '' : ' (interface: ' + arguments[4] + ')'; + var suffix = isFallback ? '' : _(' (interface: ') + arguments[4] + _(')'); statusElement.innerHTML = prefix + macAddr + suffix; } else { - statusElement.innerHTML = _('✗ Failed to get WAN MAC address: ') + (errorMsg || 'Unknown error'); + statusElement.innerHTML = _('✗ Failed to get WAN MAC address: ') + (errorMsg || _('Unknown error')); } } function generateAndUpdateIds(macAddr) { var deviceId = generateDeviceId(macAddr); var locationId = generateLocationId(); - + document.getElementById('device-id-status').innerHTML = _('✓ Device ID generated: ') + deviceId; document.getElementById('location-id-status').innerHTML = _('✓ Location ID generated: ') + locationId; - + return { deviceId: deviceId, locationId: locationId }; } function getMacAddressPromise(results) { - return callGetWanMac().then(function(response) { + return callGetWanMac().then(function (response) { if (response && response.status === 'success') { var macAddr = response.mac.toUpperCase().replace(/:/g, '-'); results.macAddress = macAddr; updateMacStatus(macAddr, true, null, false, response.interface); - + var ids = generateAndUpdateIds(macAddr); results.deviceId = ids.deviceId; results.locationId = ids.locationId; } else { return getMacAddressFallback(results); } - }).catch(function(error) { + }).catch(function (error) { return getMacAddressFallback(results); }); } function getMacAddressFallback(results) { document.getElementById('mac-status').innerHTML = _('RPC failed, trying fallback...'); - - return fs.exec('/bin/sh', ['-c', 'ip route | grep default | awk \'{print $5}\' | head -n1 | xargs -I {} cat /sys/class/net/{}/address 2>/dev/null || echo "failed"']).then(function(response) { + + return fs.exec('/bin/sh', ['-c', 'ip route | grep default | awk \'{print $5}\' | head -n1 | xargs -I {} cat /sys/class/net/{}/address 2>/dev/null || echo "failed"']).then(function (response) { if (response.code === 0 && response.stdout && response.stdout.trim() !== 'failed') { var macAddr = response.stdout.trim().toUpperCase().replace(/:/g, '-'); results.macAddress = macAddr; updateMacStatus(macAddr, true, null, true); - + var ids = generateAndUpdateIds(macAddr); results.deviceId = ids.deviceId; results.locationId = ids.locationId; } else { - updateMacStatus(null, false, 'Unknown error'); + updateMacStatus(null, false, _('Unknown error')); document.getElementById('device-id-status').innerHTML = _('✗ Cannot generate Device ID without MAC address'); } - }).catch(function(error) { + }).catch(function (error) { updateMacStatus(null, false, error.message); document.getElementById('device-id-status').innerHTML = _('✗ Cannot generate Device ID due to MAC error'); }); @@ -145,32 +145,32 @@ function formatCoordinate(coord) { } function getLocationPromise(results) { - return callGetLocation().then(function(response) { + return callGetLocation().then(function (response) { if (response && response.status === 'success') { var lat = formatCoordinate(response.lat); var lon = formatCoordinate(response.lon); - + results.longitude = lon; results.latitude = lat; document.getElementById('location-status').innerHTML = _('✓ Location obtained: ') + lat + ', ' + lon; } else { - var errorMsg = (response && response.message) ? response.message : 'Unknown error'; + var errorMsg = (response && response.message) ? response.message : _('Unknown error'); document.getElementById('location-status').innerHTML = _('✗ Failed to get location: ') + errorMsg; } - }).catch(function(error) { + }).catch(function (error) { return getLocationFallback(results); }); } function getLocationFallback(results) { document.getElementById('location-status').innerHTML = _('RPC failed, trying direct method...'); - - return fs.exec('/bin/sh', ['-c', 'curl -s --connect-timeout 10 --max-time 30 "https://ipapi.co/json" 2>/dev/null || curl -s --connect-timeout 10 --max-time 30 "http://ipinfo.io/json" 2>/dev/null || echo "failed"']).then(function(response) { + + return fs.exec('/bin/sh', ['-c', 'curl -s --connect-timeout 10 --max-time 30 "https://ipapi.co/json" 2>/dev/null || curl -s --connect-timeout 10 --max-time 30 "http://ipinfo.io/json" 2>/dev/null || echo "failed"']).then(function (response) { if (response.code === 0 && response.stdout && response.stdout.trim() !== 'failed') { try { var data = JSON.parse(response.stdout); var lat, lon; - + if (data.latitude && data.longitude) { lat = formatCoordinate(data.latitude); lon = formatCoordinate(data.longitude); @@ -179,7 +179,7 @@ function getLocationFallback(results) { lat = formatCoordinate(coords[0]); lon = formatCoordinate(coords[1]); } - + if (lat && lon) { results.longitude = lon; results.latitude = lat; @@ -193,7 +193,7 @@ function getLocationFallback(results) { } else { document.getElementById('location-status').innerHTML = _('✗ Failed to get location data'); } - }).catch(function(fallbackError) { + }).catch(function (fallbackError) { document.getElementById('location-status').innerHTML = _('✗ Error getting location: ') + fallbackError.message; }); } @@ -209,14 +209,14 @@ function fillFormFields(results) { { result: 'longitude', selector: 'ap_longitude', label: _('Longitude: ') }, { result: 'latitude', selector: 'ap_latitude', label: _('Latitude: ') } ]; - - fieldMappings.forEach(function(mapping) { + + fieldMappings.forEach(function (mapping) { if (results[mapping.result]) { var field = document.querySelector('input[data-name="' + mapping.selector + '"]') || - document.querySelector('input[name*="' + mapping.selector + '"]') || - document.querySelector('input[id*="' + mapping.selector + '"]') || - document.querySelector('#cbid\\.wifidogx\\.default\\.' + mapping.selector); - + document.querySelector('input[name*="' + mapping.selector + '"]') || + document.querySelector('input[id*="' + mapping.selector + '"]') || + document.querySelector('#cbid\\.wifidogx\\.default\\.' + mapping.selector); + if (field) { field.value = results[mapping.result]; field.dispatchEvent(new Event('input', { bubbles: true })); @@ -227,13 +227,13 @@ function fillFormFields(results) { totalFields++; } }); - + return { successCount: successCount, totalFields: totalFields, messages: messages }; } function showAutoFillResult(stats) { ui.hideModal(); - + if (stats.successCount === stats.totalFields && stats.totalFields > 0) { ui.addNotification(null, E('p', _('Auto fill completed successfully! All fields have been filled.') + '
' + stats.messages.join('
')), 'info'); } else if (stats.successCount > 0) { @@ -267,20 +267,20 @@ function renderStatus(isRunning) { } return view.extend({ - render: function() { + render: function () { var m, s, o, ss; m = new form.Map('wifidogx', _('ApFree-WiFiDog')); m.description = github.desc('apfree-wifidog offers a stable and secure captive portal solution.', 'liudf0716', 'apfree-wifidog'); - - s = m.section(form.NamedSection, 'common', _('Configuration')); + + s = m.section(form.NamedSection, 'common', _('Configuration')); s.addremove = false; s.anonymous = true; - + s.tab('basic', _('Basic Settings')); - s.tab('gateway', _('Gateway Settings')); s.tab('auth', _('Auth Server Settings')); + s.tab('gateway', _('Gateway Settings')); s.tab('advanced', _('Advanced Settings')); s.tab('rule', _('Rule Settings')); s.tab('qos', _('QoS Settings')); @@ -291,7 +291,7 @@ return view.extend({ o.rmempty = false; o = s.taboption('basic', form.ListValue, 'auth_server_mode', _('Auth Server Mode'), - _('The mode of the authentication server.')); + _('The mode of the authentication server.')); o.value('cloud', _('Cloud Auth')); o.value('local', _('Local Auth')); o.value('bypass', _('Bypass Auth')); @@ -300,30 +300,30 @@ return view.extend({ // 添加一个下拉框,列出当前定义的认证服务列表,并选择当前选中的认证服务 o = s.taboption('basic', form.ListValue, 'selected_auth_server', _('Authentication Server'), - _('Select the authentication server to use for cloud authentication.')); + _('Select the authentication server to use for cloud authentication.')); o.rmempty = false; o.optional = false; o.depends('auth_server_mode', 'cloud'); - o.load = function(section_id) { + o.load = function (section_id) { this.keylist = []; this.vallist = []; - + var sections = uci.sections('wifidogx', 'auth'); if (sections.length == 0) { this.value('', _('Please create an authentication server first')); } else { - sections.forEach(L.bind(function(section) { + sections.forEach(L.bind(function (section) { var name = section['.name']; - var hostname = section.auth_server_hostname || 'Unknown'; + var hostname = section.auth_server_hostname || _('Unknown'); this.value(name, '%s (%s)'.format(name, hostname)); }, this)); } - + return this.super('load', [section_id]); }; o = s.taboption('basic', widgets.NetworkSelect, 'external_interface', _('External Interface'), - _('The external interface of the device, if bypass mode, do not choose.')); + _('The external interface of the device, if bypass mode, do not choose.')); o.rmempty = true; o.nocreate = true; o.loopback = false; @@ -337,7 +337,7 @@ return view.extend({ o.depends('auth_server_mode', 'bypass'); o = s.taboption('basic', form.Value, 'local_portal', _('Local Portal'), - _('The local portal url.')); + _('The local portal url.')); o.rmempty = false; o.datatype = 'string'; o.optional = true; @@ -345,12 +345,12 @@ return view.extend({ o.depends('auth_server_mode', 'local'); o = s.taboption('basic', form.Flag, 'disable_portal_auth', _('Disable Portal Authentication'), - _('When enabled, users can access the internet without portal authentication. Firewall redirect rules will not be created. Use this mode for pure traffic statistics without captive portal.')); + _('When enabled, users can access the internet without portal authentication. Firewall redirect rules will not be created. Use this mode for pure traffic statistics without captive portal.')); o.rmempty = false; o.default = '1'; o = s.taboption('basic', form.ListValue, 'log_level', _('Log Level'), - _('The log level of the apfree-wifidog.')); + _('The log level of the apfree-wifidog.')); o.value(7, _('Debug')); o.value(6, _('Info')); o.value(5, _('Notice')); @@ -367,9 +367,9 @@ return view.extend({ ss = o.subsection; ss.addremove = true; ss.nodescriptions = true; - + o = ss.option(form.Flag, 'gateway_auth_enabled', _('Auth Enabled'), - _('Enable the authentication of the gateway.')); + _('Enable the authentication of the gateway.')); o.rmempty = false; o.defaulValue = true; @@ -380,19 +380,19 @@ return view.extend({ o.default = 'lan'; o = ss.option(form.Value, 'gateway_channel', _('Gateway Channel'), - _('The channel of the gateway.')); + _('The channel of the gateway.')); o.datatype = 'string'; o.rmempty = false; o.optional = false; o = ss.option(form.Value, 'gateway_id', _('Gateway ID'), - _('The ID of the gateway.')); + _('The ID of the gateway.')); o.datatype = 'string'; o.rmempty = false; o.optional = true; - + o = ss.option(form.Value, 'gateway_subnetv4', _('Gateway Subnetv4'), - _('The ipv4 subnet of the gateway.')); + _('The ipv4 subnet of the gateway.')); o.datatype = 'cidr4'; o.rmempty = false; o.optional = false; @@ -400,53 +400,53 @@ return view.extend({ // advanced settings o = s.taboption('advanced', form.Value, 'check_interval', _('Check Interval'), - _('The interval of the check(s).')); + _('The interval of the check(s).')); o.datatype = 'uinteger'; o.rmempty = false; o.optional = false; o.defaulValue = 60; o = s.taboption('advanced', form.Value, 'client_timeout', _('Client Timeout'), - _('The timeout of the client.')); + _('The timeout of the client.')); o.datatype = 'uinteger'; o.rmempty = false; o.optional = false; o.defaulValue = 5; o = s.taboption('advanced', form.Flag, 'wired_passed', _('Wired Passed'), - _('Wired users do not need to authenticate to access the internet.')); + _('Wired users do not need to authenticate to access the internet.')); o.rmempty = false; o = s.taboption('advanced', form.Flag, 'apple_cna', _('Apple CNA'), - _('Enable Apple Captive Network Assistant.')); + _('Enable Apple Captive Network Assistant.')); o.rmempty = false; o.defaulValue = false; o = s.taboption('advanced', form.Flag, 'js_filter', _('JS Filter'), - _('Enable JS redirect.')); + _('Enable JS redirect.')); o.rmempty = false; o.defaulValue = true; o = s.taboption('advanced', form.Flag, 'enable_anti_nat', _('Enable Anti NAT'), - _('Enable Anti NAT devices.')); + _('Enable Anti NAT devices.')); o.rmempty = false; o.defaulValue = false; o = s.taboption('advanced', form.Value, 'ttl_value', _('TTL Value'), - _('The TTL value of the gateway support.')); + _('The TTL value of the gateway support.')); o.datatype = 'string'; o.rmempty = false; o.defaulValue = '64,128'; o.depends('enable_anti_nat', '1'); o = s.taboption('advanced', form.Value, 'anti_nat_permit_macs', _('Anti NAT Permit MAC'), - _('The MAC address of the Anti NAT permit.')); + _('The MAC address of the Anti NAT permit.')); o.datatype = 'macaddr'; o.rmempty = true; o.depends('enable_anti_nat', '1'); o = s.taboption('advanced', form.Flag, 'enable_event_log', _('Enable Internet Access Log'), - _('Enable logging of internet access events and user activities.')); + _('Enable logging of internet access events and user activities.')); o.rmempty = false; o.defaulValue = false; @@ -456,100 +456,115 @@ return view.extend({ ss.addremove = true; ss.nodescriptions = true; - o = ss.option(form.Value, 'auth_server_hostname', _('Auth Server Hostname'), - _('The domain or IP address of the authentication server.')); + o = ss.option(form.Value, 'auth_server_hostname', _('Auth Server Hostname'), + _('The domain or IP address of the authentication server.')); o.rmempty = false; o.datatype = 'or(host,ip4addr)'; o.optional = false; - + o = ss.option(form.Value, 'auth_server_port', _('Auth Server Port'), - _('The port of the authentication server.')); + _('The port of the authentication server.')); o.rmempty = false; o.datatype = 'port'; o.optional = false; o.default = '443'; - + o = ss.option(form.Value, 'auth_server_path', _('Auth Server URI path'), - _('The URI path of the authentication server.')); + _('The URI path of the authentication server.')); o.rmempty = false; o.datatype = 'string'; o.optional = false; o.default = '/wifidog/'; - + o = ss.option(form.ListValue, 'long_conn_mode', _('Persistent Connection Mode'), - _('The persistent connection mode of the device to auth server.')); + _('The persistent connection mode of the device to auth server.')); o.value('ws', _('WebSocket Connection Mode')); o.value('wss', _('WebSocket Secure Connection Mode')); o.value('mqtt', _('MQTT Connection Mode')); + o.value('mqtts', _('MQTT Secure Connection Mode')) o.rmempty = false; o.defaulValue = 'wss'; o.optional = false; + o.modalonly = true; + o = ss.option(form.Value, 'ws_server_hostname', _('WebSocket Hostname'), - _('The hostname of the websocket, if the field is left empty, automatically use the same hostname as the auth server.')); + _('The hostname of the websocket, if the field is left empty, automatically use the same hostname as the auth server.')); o.datatype = 'or(host,ip4addr)'; o.rmempty = true; o.optional = true; o.depends('long_conn_mode', 'ws'); o.depends('long_conn_mode', 'wss'); + o.modalonly = true; o = ss.option(form.Value, 'ws_server_port', _('WebSocket Port'), - _('The port of the websocket, if the field is left empty, automatically use the same port as the auth server.')); + _('The port of the websocket, if the field is left empty, automatically use the same port as the auth server.')); o.datatype = 'port'; o.rmempty = true; o.optional = true; o.default = '443'; o.depends('long_conn_mode', 'wss'); - + o.depends('long_conn_mode', 'ws'); + o.modalonly = true; + o = ss.option(form.Value, 'ws_server_path', _('WebSocket URI path'), - _('The URI path of the websocket.')); + _('The URI path of the websocket.')); o.datatype = 'string'; o.rmempty = true; o.optional = true; o.default = '/ws/wifidogx'; o.depends('long_conn_mode', 'ws'); o.depends('long_conn_mode', 'wss'); + o.modalonly = true; o = ss.option(form.Value, 'mqtt_server_hostname', _('MQTT Hostname'), - _('The hostname of the mqtt.')); + _('The hostname of the mqtt.')); o.datatype = 'or(host,ip4addr)'; o.rmempty = true; o.optional = true; o.depends('long_conn_mode', 'mqtt'); + o.depends('long_conn_mode', 'mqtts'); + o.modalonly = true; o = ss.option(form.Value, 'mqtt_server_port', _('MQTT Port'), - _('The port of the mqtt.')); + _('The port of the mqtt.')); o.datatype = 'port'; o.rmempty = false; o.optional = false; o.depends('long_conn_mode', 'mqtt'); + o.depends('long_conn_mode', 'mqtts'); o.default = 1883; + o.modalonly = true; o = ss.option(form.Value, 'mqtt_username', _('MQTT Username'), - _('The username of the mqtt.')); + _('The username of the mqtt.')); o.datatype = 'string'; o.rmempty = true; o.optional = true; o.depends('long_conn_mode', 'mqtt'); + o.depends('long_conn_mode', 'mqtts'); + o.modalonly = true; o = ss.option(form.Value, 'mqtt_password', _('MQTT Password'), - _('The password of the mqtt.')); + _('The password of the mqtt.')); o.datatype = 'string'; o.rmempty = true; o.optional = true; o.depends('long_conn_mode', 'mqtt'); + o.depends('long_conn_mode', 'mqtts'); + o.modalonly = true; // QoS settings o = s.taboption('qos', form.Flag, 'enable_qos', _('Enable Global QoS'), - _('Enable Global QoS.')); + _('Enable Global QoS.')); o.rmempty = false; o.defaulValue = false; o = s.taboption('qos', form.Value, 'qos_up', _('Global QoS Up'), - _('The global QoS up value(Mbps).')); + _('The global QoS up value(Mbps).')); o.datatype = 'uinteger'; o.rmempty = true; o.optional = true; @@ -557,7 +572,7 @@ return view.extend({ o.depends('enable_qos', '1'); o = s.taboption('qos', form.Value, 'qos_down', _('Global QoS Down'), - _('The global QoS down value(Mbps).')); + _('The global QoS down value(Mbps).')); o.datatype = 'uinteger'; o.rmempty = true; o.optional = true; @@ -567,12 +582,12 @@ return view.extend({ // Authentication Location Settings // Add auto-fill button o = s.taboption('location', form.Button, '_auto_fill', _('Auto Fill All Fields'), - _('Automatically fill AP MAC address, Device ID, Location ID, Longitude, and Latitude')); + _('Automatically fill AP MAC address, Device ID, Location ID, Longitude, and Latitude')); o.inputtitle = _('Auto Fill All Fields'); o.inputstyle = 'apply'; - o.onclick = function() { + o.onclick = function () { showAutoFillModal(); - + var results = { macAddress: null, deviceId: null, @@ -580,20 +595,20 @@ return view.extend({ longitude: null, latitude: null }; - + var promises = [ getMacAddressPromise(results), getLocationPromise(results) ]; - + // Wait for all promises to complete and fill form fields - Promise.all(promises).then(function() { - setTimeout(function() { + Promise.all(promises).then(function () { + setTimeout(function () { fillFormFields(results); }, 2000); }); }; - + // Helper function to show the auto-fill modal function showAutoFillModal() { ui.showModal(_('Auto Fill'), [ @@ -610,40 +625,40 @@ return view.extend({ ]) ]); } - + // Helper function to get MAC address with fallback function getMacAddressPromise(results) { - return callGetWanMac().then(function(response) { + return callGetWanMac().then(function (response) { if (response && response.status === 'success') { var macAddr = response.mac.toUpperCase().replace(/:/g, '-'); results.macAddress = macAddr; document.getElementById('mac-status').innerHTML = _('✓ WAN MAC address obtained: ') + macAddr + ' (interface: ' + response.interface + ')'; - + results.deviceId = generateDeviceId(macAddr); document.getElementById('device-id-status').innerHTML = _('✓ Device ID generated: ') + results.deviceId; - + results.locationId = generateLocationId(); document.getElementById('location-id-status').innerHTML = _('✓ Location ID generated: ') + results.locationId; } else { return getMacAddressFallback(results); } - }).catch(function(error) { + }).catch(function (error) { document.getElementById('mac-status').innerHTML = _('✗ RPC call failed, trying fallback...'); return getMacAddressFallback(results); }); } - + // Helper function for MAC address fallback function getMacAddressFallback(results) { - return fs.exec('/bin/sh', ['-c', 'ip route | grep default | awk \'{print $5}\' | head -n1 | xargs -I {} cat /sys/class/net/{}/address 2>/dev/null || echo "failed"']).then(function(response) { + return fs.exec('/bin/sh', ['-c', 'ip route | grep default | awk \'{print $5}\' | head -n1 | xargs -I {} cat /sys/class/net/{}/address 2>/dev/null || echo "failed"']).then(function (response) { if (response.code === 0 && response.stdout && response.stdout.trim() !== 'failed') { var macAddr = response.stdout.trim().toUpperCase().replace(/:/g, '-'); results.macAddress = macAddr; document.getElementById('mac-status').innerHTML = _('✓ WAN MAC address obtained (fallback): ') + macAddr; - + results.deviceId = generateDeviceId(macAddr); document.getElementById('device-id-status').innerHTML = _('✓ Device ID generated: ') + results.deviceId; - + results.locationId = generateLocationId(); document.getElementById('location-id-status').innerHTML = _('✓ Location ID generated: ') + results.locationId; } else { @@ -651,39 +666,39 @@ return view.extend({ document.getElementById('mac-status').innerHTML = _('✗ Failed to get WAN MAC address: ') + errorMsg; document.getElementById('device-id-status').innerHTML = _('✗ Cannot generate Device ID without MAC address'); } - }).catch(function(error) { + }).catch(function (error) { document.getElementById('mac-status').innerHTML = _('✗ Error getting WAN MAC address: ') + error.message; document.getElementById('device-id-status').innerHTML = _('✗ Cannot generate Device ID due to MAC error'); }); } - + // Helper function to get location with fallback function getLocationPromise(results) { - return callGetLocation().then(function(response) { + return callGetLocation().then(function (response) { if (response && response.status === 'success') { var lat = parseFloat(response.lat).toFixed(6); var lon = parseFloat(response.lon).toFixed(6); - + formatAndSetCoordinates(results, lat, lon); document.getElementById('location-status').innerHTML = _('✓ Location obtained: ') + results.latitude + ', ' + results.longitude; } else { var errorMsg = (response && response.message) ? response.message : 'Unknown error'; document.getElementById('location-status').innerHTML = _('✗ Failed to get location: ') + errorMsg; } - }).catch(function(error) { + }).catch(function (error) { document.getElementById('location-status').innerHTML = _('RPC failed, trying direct method...'); return getLocationFallback(results); }); } - + // Helper function for location fallback function getLocationFallback(results) { - return fs.exec('/bin/sh', ['-c', 'curl -s --connect-timeout 10 --max-time 30 "https://ipapi.co/json" 2>/dev/null || curl -s --connect-timeout 10 --max-time 30 "http://ipinfo.io/json" 2>/dev/null || echo "failed"']).then(function(response) { + return fs.exec('/bin/sh', ['-c', 'curl -s --connect-timeout 10 --max-time 30 "https://ipapi.co/json" 2>/dev/null || curl -s --connect-timeout 10 --max-time 30 "http://ipinfo.io/json" 2>/dev/null || echo "failed"']).then(function (response) { if (response.code === 0 && response.stdout && response.stdout.trim() !== 'failed') { try { var data = JSON.parse(response.stdout); var lat, lon; - + if (data.latitude && data.longitude) { lat = parseFloat(data.latitude).toFixed(6); lon = parseFloat(data.longitude).toFixed(6); @@ -692,7 +707,7 @@ return view.extend({ lat = parseFloat(coords[0]).toFixed(6); lon = parseFloat(coords[1]).toFixed(6); } - + if (lat && lon) { formatAndSetCoordinates(results, lat, lon); document.getElementById('location-status').innerHTML = _('✓ Location obtained (fallback): ') + results.latitude + ', ' + results.longitude; @@ -705,11 +720,11 @@ return view.extend({ } else { document.getElementById('location-status').innerHTML = _('✗ Failed to get location data'); } - }).catch(function(fallbackError) { + }).catch(function (fallbackError) { document.getElementById('location-status').innerHTML = _('✗ Error getting location: ') + fallbackError.message; }); } - + // Helper function to format coordinates function formatAndSetCoordinates(results, lat, lon) { // Pad coordinates to required format @@ -718,23 +733,23 @@ return view.extend({ } else { lat = '-' + Math.abs(lat).toFixed(6).padStart(9, '0'); } - + if (lon >= 0) { lon = lon.padStart(10, '0'); } else { lon = '-' + Math.abs(lon).toFixed(6).padStart(9, '0'); } - + results.longitude = lon; results.latitude = lat; } - + // Helper function to fill form fields function fillFormFields(results) { var successCount = 0; var totalFields = 0; var messages = []; - + var fieldMappings = [ { key: 'macAddress', selectors: ['input[data-name="ap_mac_address"]', 'input[name*="ap_mac_address"]', 'input[id*="ap_mac_address"]', '#cbid\\.wifidogx\\.default\\.ap_mac_address'], label: _('MAC Address: ') }, { key: 'deviceId', selectors: ['input[data-name="ap_device_id"]', 'input[name*="ap_device_id"]', 'input[id*="ap_device_id"]', '#cbid\\.wifidogx\\.default\\.ap_device_id'], label: _('Device ID: ') }, @@ -742,15 +757,15 @@ return view.extend({ { key: 'longitude', selectors: ['input[data-name="ap_longitude"]', 'input[name*="ap_longitude"]', 'input[id*="ap_longitude"]', '#cbid\\.wifidogx\\.default\\.ap_longitude'], label: _('Longitude: ') }, { key: 'latitude', selectors: ['input[data-name="ap_latitude"]', 'input[name*="ap_latitude"]', 'input[id*="ap_latitude"]', '#cbid\\.wifidogx\\.default\\.ap_latitude'], label: _('Latitude: ') } ]; - - fieldMappings.forEach(function(mapping) { + + fieldMappings.forEach(function (mapping) { if (results[mapping.key]) { var field = null; for (var i = 0; i < mapping.selectors.length; i++) { field = document.querySelector(mapping.selectors[i]); if (field) break; } - + if (field) { field.value = results[mapping.key]; field.dispatchEvent(new Event('input', { bubbles: true })); @@ -761,14 +776,14 @@ return view.extend({ totalFields++; } }); - + showAutoFillResult(successCount, totalFields, messages); } - + // Helper function to show auto-fill results function showAutoFillResult(successCount, totalFields, messages) { ui.hideModal(); - + if (successCount === totalFields && totalFields > 0) { ui.addNotification(null, E('p', _('Auto fill completed successfully! All fields have been filled.') + '
' + messages.join('
')), 'info'); } else if (successCount > 0) { @@ -786,123 +801,123 @@ return view.extend({ o.depends('auth_server_mode', 'cloud'); o.depends('auth_server_mode', 'bypass'); o.placeholder = '110101100123456'; - o.validate = function(section_id, value) { + o.validate = function (section_id, value) { if (!value || value === '') return _('Location ID is required'); - + // Check total length if (value.length !== 14) { return _('Location ID must be exactly 14 digits long'); } - + // Check if all characters are digits if (!/^\d{14}$/.test(value)) { return _('Location ID must contain only digits (0-9)'); } - + // Validate administrative division code (first 6 digits) var adminCode = value.substring(0, 6); if (!/^\d{6}$/.test(adminCode)) { return _('First 6 digits must be valid administrative division code (GB/T 2260)'); } - + // Validate service type code (7-9 digits) var serviceType = value.substring(6, 9); if (serviceType !== '100' && serviceType !== '2' + value.charAt(7) + value.charAt(8) && serviceType !== '3' + value.charAt(7) + value.charAt(8)) { return _('Service type code (7-9 digits) must be "100" for commercial internet service locations, "2XX" for non-commercial locations, or "3XX" for WiFi wireless collection terminals'); } - + // Validate sequence number (10-14 digits) var sequenceNum = value.substring(9); if (!/^\d{5}$/.test(sequenceNum)) { return _('Last 5 digits must be sequence number (00000-99999)'); } - + return true; }; o = s.taboption('location', form.Value, 'ap_device_id', _('AP Device ID'), - _('The unique identifier of the AP device. Must be 21 characters: 9-character vendor code + 12-character MAC address (uppercase).')); + _('The unique identifier of the AP device. Must be 21 characters: 9-character vendor code + 12-character MAC address (uppercase).')); o.rmempty = true; o.optional = true; - o.validate = function(section_id, value) { + o.validate = function (section_id, value) { if (!value || value === '') return true; // Optional field, empty is allowed - + // Check total length if (value.length !== 21) { return _('AP Device ID must be exactly 21 characters long'); } - + // Check if all characters are alphanumeric (letters and digits) if (!/^[A-Z0-9]+$/.test(value)) { return _('AP Device ID must contain only uppercase letters and digits'); } - + // Extract MAC address part (last 12 characters) var macPart = value.substring(9); - + // Validate MAC address format (12 hexadecimal characters) if (!/^[A-F0-9]{12}$/.test(macPart)) { return _('Last 12 characters must be a valid MAC address in uppercase hexadecimal format (e.g., 00E04C3B7D2F)'); } - + return true; }; o.placeholder = 'AW123456700E04C3B7D2F'; o = s.taboption('location', form.Value, 'ap_mac_address', _('AP MAC Address'), - _('The MAC address of the AP device. Must be 17 characters in format XX-XX-XX-XX-XX-XX (uppercase, separated by hyphens).')); + _('The MAC address of the AP device. Must be 17 characters in format XX-XX-XX-XX-XX-XX (uppercase, separated by hyphens).')); o.rmempty = true; o.optional = true; o.placeholder = '00-E0-4C-3B-7D-2F'; - o.validate = function(section_id, value) { + o.validate = function (section_id, value) { if (!value || value === '') return true; // Optional field, empty is allowed - + // Check total length if (value.length !== 17) { return _('MAC address must be exactly 17 characters long'); } - + // Check format: XX-XX-XX-XX-XX-XX where X is uppercase hex digit if (!/^[A-F0-9]{2}-[A-F0-9]{2}-[A-F0-9]{2}-[A-F0-9]{2}-[A-F0-9]{2}-[A-F0-9]{2}$/.test(value)) { return _('MAC address must be in format XX-XX-XX-XX-XX-XX (uppercase hexadecimal separated by hyphens)'); } - + // Get the AP Device ID to check consistency var deviceId = uci.get('wifidogx', section_id, 'ap_device_id'); if (deviceId && deviceId.length === 21) { var deviceMacPart = deviceId.substring(9); var normalizedMac = value.replace(/-/g, ''); - + if (normalizedMac !== deviceMacPart) { return _('MAC address should match the MAC address part (last 12 characters) in AP Device ID'); } } - + return true; }; o = s.taboption('location', form.Value, 'ap_longitude', _('Mobile AP Longitude'), - _('The longitude coordinate using format: ±XXX.XXXXXX (3 integer digits + 6 decimal digits). Positive for East, negative for West.')); + _('The longitude coordinate using format: ±XXX.XXXXXX (3 integer digits + 6 decimal digits). Positive for East, negative for West.')); o.rmempty = true; o.optional = true; o.placeholder = '123.230000'; - o.validate = function(section_id, value) { + o.validate = function (section_id, value) { if (!value || value === '') return true; // Optional field, empty is allowed - + // Allow more flexible input, then validate and suggest correct format var numValue = parseFloat(value); if (isNaN(numValue)) { return _('Longitude must be a valid number'); } - + if (numValue < -180 || numValue > 180) { return _('Longitude must be between -180.000000 and 180.000000'); } - + // Check if the input matches the strict format requirement if (!/^[+-]?\d{3}\.\d{6}$/.test(value)) { // Format the number to the required format and suggest it @@ -911,41 +926,41 @@ return view.extend({ var parts = formatted.split('.'); var intPart = parts[0]; var decPart = parts[1]; - + // Pad integer part to 3 digits if (intPart.startsWith('-')) { intPart = '-' + intPart.substring(1).padStart(3, '0'); } else { intPart = intPart.padStart(3, '0'); } - + formatted = intPart + '.' + decPart; } return _('Longitude must be in format ±XXX.XXXXXX (3 integer digits + 6 decimal digits, e.g., 123.230000 or -133.000000). Suggested format: ') + formatted; } - + return true; }; o = s.taboption('location', form.Value, 'ap_latitude', _('Mobile AP Latitude'), - _('The latitude coordinate using format: ±XXX.XXXXXX (3 integer digits + 6 decimal digits). Positive for North, negative for South.')); + _('The latitude coordinate using format: ±XXX.XXXXXX (3 integer digits + 6 decimal digits). Positive for North, negative for South.')); o.rmempty = true; o.optional = true; o.placeholder = '39.900000'; - o.validate = function(section_id, value) { + o.validate = function (section_id, value) { if (!value || value === '') return true; // Optional field, empty is allowed - + // Allow more flexible input, then validate and suggest correct format var numValue = parseFloat(value); if (isNaN(numValue)) { return _('Latitude must be a valid number'); } - + if (numValue < -90 || numValue > 90) { return _('Latitude must be between -90.000000 and 90.000000'); } - + // Check if the input matches the strict format requirement if (!/^[+-]?\d{3}\.\d{6}$/.test(value)) { // Format the number to the required format and suggest it @@ -954,70 +969,70 @@ return view.extend({ var parts = formatted.split('.'); var intPart = parts[0]; var decPart = parts[1]; - + // Pad integer part to 3 digits if (intPart.startsWith('-')) { intPart = '-' + intPart.substring(1).padStart(3, '0'); } else { intPart = intPart.padStart(3, '0'); } - + formatted = intPart + '.' + decPart; } return _('Latitude must be in format ±XXX.XXXXXX (3 integer digits + 6 decimal digits, e.g., 39.900000 or -33.000000). Suggested format: ') + formatted; } - + return true; }; // rule settings o = s.taboption('rule', form.DynamicList, 'trusted_wildcard_domains', _('Trusted Wildcard Domains'), - _('The trusted wildcard domains of the gateway')); + _('The trusted wildcard domains of the gateway')); o.rmempty = true; o.optional = true; o.datatype = 'wildcard'; o.placeholder = '.example.com'; - + o = s.taboption('rule', form.DynamicList, 'trusted_domains', _('Trusted Domains'), - _('The trusted domains of the gateway')); + _('The trusted domains of the gateway')); o.rmempty = true; o.optional = true; o.datatype = 'hostname'; o.placeholder = 'www.example.com'; o = s.taboption('rule', form.DynamicList, 'trusted_macs', _('Trusted MACs'), - _('The trusted wildcard domains of the gateway.')); + _('The trusted wildcard domains of the gateway.')); o.rmempty = true; o.optional = true; o.datatype = 'macaddr'; o.placeholder = 'A0:B1:C2:D3:44:55'; - + o = s.taboption('rule', widgets.WifidogxGroupSelect, 'app_white_list', _('App White List'), - _('The app white list of the gateway.')); + _('The app white list of the gateway.')); o.rmempty = true; o.multiple = true; o.nocreate = true; - + o = s.taboption('rule', widgets.WifidogxGroupSelect, 'mac_white_list', _('MAC White List'), - _('The MAC white list of the gateway.')); + _('The MAC white list of the gateway.')); o.rmempty = true; o.multiple = true; o.nocreate = true; o.setGroupType('mac'); o = s.taboption('rule', widgets.WifidogxGroupSelect, 'wildcard_white_list', _('Wildcard White List'), - _('The wildcard domain white list of the gateway.')); + _('The wildcard domain white list of the gateway.')); o.rmempty = true; o.multiple = true; o.nocreate = true; o.setGroupType('wildcard'); - - s = m.section(form.GridSection, 'group', _('Group Define')); + + s = m.section(form.GridSection, 'group', _('Group Define')); s.addremove = true; s.anonymous = false; s.nodescriptions = true; - s.handleRemove = function(section_id, ev) { + s.handleRemove = function (section_id, ev) { // according section_id to check whether it is used by app_white_list or mac_white_list var group = uci.get('wifidogx', section_id, 'g_type') === '1' ? 'app_white_list' : 'mac_white_list'; var groupList = uci.get('wifidogx', 'common', group); diff --git a/luci-app-apfree-wifidog/htdocs/luci-static/resources/view/wifidogx/status.js b/luci-app-apfree-wifidog/htdocs/luci-static/resources/view/wifidogx/status.js index 9e69ab869..8cf833629 100644 --- a/luci-app-apfree-wifidog/htdocs/luci-static/resources/view/wifidogx/status.js +++ b/luci-app-apfree-wifidog/htdocs/luci-static/resources/view/wifidogx/status.js @@ -99,6 +99,8 @@ return view.extend({ [_('Uptime'), uptime], [_('Internet Connected'), data.is_internet_connected ? _('Yes') : _('No')], [_('Auth Server Connected'), data.is_auth_server_connected ? _('Yes') : _('No')], + [_('MQTT Connected'), data.is_mqtt_connected ? _('Yes') : _('No')], + [_('WebSocket Connected'), data.is_websocket_connected ? _('Yes') : _('No')], [_('Auth Server Mode'), authModeText] ]; diff --git a/luci-app-apfree-wifidog/po/zh_Hans/apfree-wifidog.po b/luci-app-apfree-wifidog/po/zh_Hans/apfree-wifidog.po index 968ee9dde..961e83a40 100644 --- a/luci-app-apfree-wifidog/po/zh_Hans/apfree-wifidog.po +++ b/luci-app-apfree-wifidog/po/zh_Hans/apfree-wifidog.po @@ -654,6 +654,12 @@ msgstr "互联网连接" msgid "Auth Server Connected" msgstr "认证服务器连接" +msgid "MQTT Connected" +msgstr "MQTT 连接" + +msgid "WebSocket Connected" +msgstr "WebSocket 连接" + msgid "Auth Server Mode" msgstr "认证服务器模式" @@ -791,3 +797,234 @@ msgstr "实时下载速度" msgid "Real-time Upload Speed" msgstr "实时上传速度" + +msgid "AP Device ID" +msgstr "AP设备ID" + +msgid "AP Device ID must be exactly 21 characters long" +msgstr "AP设备ID必须是21个字符长" + +msgid "AP Device ID must contain only uppercase letters and digits" +msgstr "AP设备ID只能包含大写字母和数字" + +msgid "AP MAC Address" +msgstr "AP MAC地址" + +msgid "Auto Fill" +msgstr "自动填充" + +msgid "Auto Fill All Fields" +msgstr "自动填充所有字段" + +msgid "Auto fill completed successfully! All fields have been filled." +msgstr "自动填充成功!所有字段已填写。" + +msgid "Auto fill failed. No fields could be filled. Please check your network connection and try again." +msgstr "自动填充失败。无法填写任何字段。请检查您的网络连接并重试。" + +msgid "Auto fill partially completed." +msgstr "自动填充部分完成。" + +msgid "Automatically fill AP MAC address, Device ID, Location ID, Longitude, and Latitude" +msgstr "自动填充 AP MAC地址、设备ID、位置ID、经度和纬度" + +msgid "Device ID: " +msgstr "设备ID: " + +msgid "First 6 digits must be valid administrative division code (GB/T 2260)" +msgstr "前6位必须是有效的行政区划代码 (GB/T 2260)" + +msgid "Generating Device ID..." +msgstr "生成设备ID..." + +msgid "Generating Location ID..." +msgstr "生成位置ID..." + +msgid "Getting WAN MAC address..." +msgstr "正在获取 WAN MAC 地址..." + +msgid "Getting device information and location data, please wait..." +msgstr "正在获取设备信息和位置数据,请稍候..." + +msgid "Getting location coordinates..." +msgstr "正在获取位置坐标..." + +msgid "Last 12 characters must be a valid MAC address in uppercase hexadecimal format (e.g., 00E04C3B7D2F)" +msgstr "最后12个字符必须是大写十六进制格式的有效MAC地址(例如:00E04C3B7D2F)" + +msgid "Last 5 digits must be sequence number (00000-99999)" +msgstr "最后5位必须是序列号 (00000-99999)" + +msgid "Latitude must be a valid number" +msgstr "纬度必须是一个有效的数字" + +msgid "Latitude must be between -90.000000 and 90.000000" +msgstr "纬度必须在 -90.000000 到 90.000000 之间" + +msgid "Latitude must be in format ±XXX.XXXXXX (3 integer digits + 6 decimal digits, e.g., 39.900000 or -33.000000). Suggested format: " +msgstr "纬度格式必须为 ±XXX.XXXXXX(3位整数 + 6位小数,例如:39.900000 或 -33.000000)。建议格式:" + +msgid "Latitude: " +msgstr "纬度: " + +msgid "Location ID" +msgstr "位置ID" + +msgid "Location ID is required" +msgstr "必须填写位置ID" + +msgid "Location ID must be exactly 14 digits long" +msgstr "位置ID必须是14位数字" + +msgid "Location ID must contain only digits (0-9)" +msgstr "位置ID只能包含数字 (0-9)" + +msgid "Location ID: " +msgstr "位置ID: " + +msgid "Longitude must be a valid number" +msgstr "经度必须是一个有效的数字" + +msgid "Longitude must be between -180.000000 and 180.000000" +msgstr "经度必须在 -180.000000 到 180.000000 之间" + +msgid "Longitude must be in format ±XXX.XXXXXX (3 integer digits + 6 decimal digits, e.g., 123.230000 or -133.000000). Suggested format: " +msgstr "经度格式必须为 ±XXX.XXXXXX(3位整数 + 6位小数,例如:123.230000 或 -133.000000)。建议格式:" + +msgid "Longitude: " +msgstr "经度: " + +msgid "MAC Address: " +msgstr "MAC地址: " + +msgid "MAC address must be exactly 17 characters long" +msgstr "MAC地址必须是17个字符长" + +msgid "MAC address must be in format XX-XX-XX-XX-XX-XX (uppercase hexadecimal separated by hyphens)" +msgstr "MAC地址格式必须为 XX-XX-XX-XX-XX-XX(大写十六进制,由连字符分隔)" + +msgid "MAC address should match the MAC address part (last 12 characters) in AP Device ID" +msgstr "MAC地址应与 AP设备ID 中的 MAC地址部分(最后12个字符)匹配" + +msgid "MQTT Connection Mode" +msgstr "MQTT连接模式" + +msgid "MQTT Secure Connection Mode" +msgstr "MQTT安全连接模式" + +msgid "MQTT Hostname" +msgstr "MQTT主机名" + +msgid "Mobile AP Latitude" +msgstr "移动AP纬度" + +msgid "Mobile AP Longitude" +msgstr "移动AP经度" + +msgid "Persistent Connection Mode" +msgstr "持久连接模式" + +msgid "RPC failed, trying direct method..." +msgstr "RPC失败,正在尝试直接方法..." + +msgid "RPC failed, trying fallback..." +msgstr "RPC失败,正在尝试备用方法..." + +msgid "Service type code (7-9 digits) must be \"100\" for commercial internet service locations, \"2XX\" for non-commercial locations, or \"3XX\" for WiFi wireless collection terminals" +msgstr "服务类型代码(第7-9位)必须是:商业上网场所为\"100\",非商业场所为\"2XX\",或WiFi无线采集终端为\"3XX\"" + +msgid "The MAC address of the AP device. Must be 17 characters in format XX-XX-XX-XX-XX-XX (uppercase, separated by hyphens)." +msgstr "AP设备的MAC地址。必须为17个字符,格式为 XX-XX-XX-XX-XX-XX(大写,由连字符分隔)。" + +msgid "The hostname of the mqtt." +msgstr "MQTT的主机名。" + +msgid "The latitude coordinate using format: ±XXX.XXXXXX (3 integer digits + 6 decimal digits). Positive for North, negative for South." +msgstr "纬度坐标,使用格式:±XXX.XXXXXX(3位整数 + 6位小数)。北纬为正,南纬为负。" + +msgid "The longitude coordinate using format: ±XXX.XXXXXX (3 integer digits + 6 decimal digits). Positive for East, negative for West." +msgstr "经度坐标,使用格式:±XXX.XXXXXX(3位整数 + 6位小数)。东经为正,西经为负。" + +msgid "The mode of the authentication server." +msgstr "认证服务器的模式。" + +msgid "The persistent connection mode of the device to auth server." +msgstr "设备到认证服务器的持久连接模式。" + +msgid "The trusted wildcard domains of the gateway" +msgstr "网关信任的通配符域名" + +msgid "The unique identifier of the AP device. Must be 21 characters: 9-character vendor code + 12-character MAC address (uppercase)." +msgstr "AP设备的唯一标识符。必须是21个字符:9位厂商代码 + 12位MAC地址(大写)。" + +msgid "The unique identifier of the internet service location." +msgstr "上网服务场所的唯一标识符。" + +msgid "WebSocket Connection Mode" +msgstr "WebSocket连接模式" + +msgid "WebSocket Secure Connection Mode" +msgstr "WebSocket加密连接模式" + +msgid "fields filled successfully." +msgstr "个字段已填充。" + +msgid "✓ Device ID generated: " +msgstr "✓ 设备ID已生成: " + +msgid "✓ Location ID generated: " +msgstr "✓ 位置ID已生成: " + +msgid "✓ Location obtained (fallback): " +msgstr "✓ 已获取位置(备用方法): " + +msgid "✓ Location obtained: " +msgstr "✓ 已获取位置: " + +msgid "✓ WAN MAC address obtained (fallback): " +msgstr "✓ 已获取 WAN MAC 地址(备用方法): " + +msgid "✓ WAN MAC address obtained: " +msgstr "✓ 已获取 WAN MAC 地址: " + +msgid "✗ Cannot generate Device ID due to MAC error" +msgstr "✗ 由于 MAC 错误,无法生成设备 ID" + +msgid "✗ Cannot generate Device ID without MAC address" +msgstr "✗ 没有 MAC 地址,无法生成设备 ID" + +msgid "✗ Error getting WAN MAC address: " +msgstr "✗ 获取 WAN MAC 地址错误: " + +msgid "✗ Error getting location: " +msgstr "✗ 获取位置错误: " + +msgid "✗ Failed to get WAN MAC address: " +msgstr "✗ 获取 WAN MAC 地址失败: " + +msgid "✗ Failed to get location data" +msgstr "✗ 获取位置数据失败" + +msgid "✗ Failed to get location: " +msgstr "✗ 获取位置失败: " + +msgid "✗ Failed to parse location data" +msgstr "✗ 解析位置数据失败" + +msgid "✗ No valid coordinates found" +msgstr "✗ 未找到有效的坐标" + +msgid "✗ RPC call failed, trying fallback..." +msgstr "✗ RPC 调用失败,正在尝试备用方法..." + +msgid " (interface: " +msgstr " (接口: " + +msgid ")" +msgstr ")" + +msgid "Unknown error" +msgstr "未知错误" + +msgid "Unknown" +msgstr "未知" diff --git a/luci-app-passwall/luasrc/passwall/util_xray.lua b/luci-app-passwall/luasrc/passwall/util_xray.lua index 69ff385b9..49b054640 100644 --- a/luci-app-passwall/luasrc/passwall/util_xray.lua +++ b/luci-app-passwall/luasrc/passwall/util_xray.lua @@ -749,7 +749,6 @@ function gen_config(var) local fakedns = nil local routing = nil local observatory = nil - local burstObservatory = nil local strategy = nil local inbounds = {} local outbounds = {} @@ -975,29 +974,19 @@ function gen_config(var) fallbackTag = fallback_node_tag, strategy = strategy }) - if _node.balancingStrategy == "leastPing" or _node.balancingStrategy == "leastLoad" or fallback_node_tag then - if _node.balancingStrategy == "leastLoad" then - if not burstObservatory then - burstObservatory = { - subjectSelector = { "blc-" }, - pingConfig = { - destination = _node.useCustomProbeUrl and _node.probeUrl or nil, - interval = (api.format_go_time(_node.probeInterval) ~= "0s") and api.format_go_time(_node.probeInterval) or "1m", - sampling = 3, - timeout = "5s" - } - } - end - else - if not observatory then - observatory = { - subjectSelector = { "blc-" }, - probeUrl = _node.useCustomProbeUrl and _node.probeUrl or nil, - probeInterval = (api.format_go_time(_node.probeInterval) ~= "0s") and api.format_go_time(_node.probeInterval) or "1m", - enableConcurrency = true - } - end + if not observatory and (_node.balancingStrategy == "leastPing" or _node.balancingStrategy == "leastLoad" or fallback_node_tag) then + local t = api.format_go_time(_node.probeInterval) + if t == "0s" then + t = "60s" + elseif not t:find("[hm]") and tonumber(t:match("%d+")) < 10 then + t = "10s" end + observatory = { + subjectSelector = { "blc-" }, + probeUrl = _node.useCustomProbeUrl and _node.probeUrl or "https://www.google.com/generate_204", + probeInterval = t, + enableConcurrency = true + } end local loopback_outbound = gen_loopback(loopback_tag, loopback_dst) local inbound_tag = loopback_outbound.settings.inboundTag @@ -1652,8 +1641,7 @@ function gen_config(var) -- 传出连接 outbounds = outbounds, -- 连接观测 - observatory = (not burstObservatory) and observatory or nil, - burstObservatory = burstObservatory, + observatory = observatory, -- 路由 routing = routing, -- 本地策略 diff --git a/luci-app-passwall2/Makefile b/luci-app-passwall2/Makefile index 88904b2b9..783a25f37 100644 --- a/luci-app-passwall2/Makefile +++ b/luci-app-passwall2/Makefile @@ -34,21 +34,21 @@ LUCI_DEPENDS:=+coreutils +coreutils-base64 +coreutils-nohup +curl \ +ip-full +libuci-lua +lua +luci-compat +luci-lib-jsonc +resolveip +tcping \ +xray-core +geoview +v2ray-geoip +v2ray-geosite \ +unzip \ - +PACKAGE_$(PKG_NAME)_INCLUDE_Haproxy:haproxy \ - +PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria:hysteria \ - +PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy:naiveproxy \ - +PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Client:shadowsocks-libev-ss-local \ - +PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Client:shadowsocks-libev-ss-redir \ - +PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Server:shadowsocks-libev-ss-server \ - +PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Client:shadowsocks-rust-sslocal \ - +PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Server:shadowsocks-rust-ssserver \ - +PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Client:shadowsocksr-libev-ssr-local \ - +PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Client:shadowsocksr-libev-ssr-redir \ - +PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Server:shadowsocksr-libev-ssr-server \ - +PACKAGE_$(PKG_NAME)_INCLUDE_Simple_Obfs:simple-obfs-client \ - +PACKAGE_$(PKG_NAME)_INCLUDE_SingBox:sing-box \ - +PACKAGE_$(PKG_NAME)_INCLUDE_tuic_client:tuic-client \ - +PACKAGE_$(PKG_NAME)_INCLUDE_V2ray_Plugin:v2ray-plugin \ ++ +PACKAGE_$(PKG_NAME)_INCLUDE_Haproxy:haproxy \ ++ +PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria:hysteria \ ++ +PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy:naiveproxy \ ++ +PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Client:shadowsocks-libev-ss-local \ ++ +PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Client:shadowsocks-libev-ss-redir \ ++ +PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Server:shadowsocks-libev-ss-server \ ++ +PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Client:shadowsocks-rust-sslocal \ ++ +PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Server:shadowsocks-rust-ssserver \ ++ +PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Client:shadowsocksr-libev-ssr-local \ ++ +PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Client:shadowsocksr-libev-ssr-redir \ ++ +PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Server:shadowsocksr-libev-ssr-server \ ++ +PACKAGE_$(PKG_NAME)_INCLUDE_Simple_Obfs:simple-obfs-client \ ++ +PACKAGE_$(PKG_NAME)_INCLUDE_SingBox:sing-box \ ++ +PACKAGE_$(PKG_NAME)_INCLUDE_tuic_client:tuic-client \ ++ +PACKAGE_$(PKG_NAME)_INCLUDE_V2ray_Plugin:v2ray-plugin \ +PACKAGE_$(PKG_NAME)_INCLUDE_IPv6_Nat:ip6tables-mod-nat define Package/$(PKG_NAME)/config @@ -90,6 +90,7 @@ config PACKAGE_$(PKG_NAME)_Nftables_Transparent_Proxy config PACKAGE_$(PKG_NAME)_INCLUDE_Haproxy bool "Include Haproxy" + select PACKAGE_haproxy default y if aarch64||arm||i386||x86_64 config PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria @@ -105,6 +106,8 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Client bool "Include Shadowsocks Libev Client" + select PACKAGE_shadowsocks-libev-ss-local + select PACKAGE_shadowsocks-libev-ss-redir default y config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Server @@ -115,6 +118,7 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Server config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Client bool "Include Shadowsocks Rust Client" depends on !i386 + select PACKAGE_shadowsocks-rust-sslocal default y if aarch64||x86_64 config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Server @@ -125,6 +129,8 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Server config PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Client bool "Include ShadowsocksR Libev Client" + select PACKAGE_shadowsocksr-libev-ssr-local + select PACKAGE_shadowsocksr-libev-ssr-redir default y config PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Server @@ -134,11 +140,12 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Server config PACKAGE_$(PKG_NAME)_INCLUDE_Simple_Obfs bool "Include Simple-Obfs (Shadowsocks Plugin)" + select PACKAGE_simple-obfs-client default y config PACKAGE_$(PKG_NAME)_INCLUDE_SingBox bool "Include Sing-Box" - default y if aarch64||arm||i386||x86_64 + default y config PACKAGE_$(PKG_NAME)_INCLUDE_tuic_client bool "Include tuic-client" @@ -148,6 +155,7 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_tuic_client config PACKAGE_$(PKG_NAME)_INCLUDE_V2ray_Plugin bool "Include V2ray-Plugin (Shadowsocks Plugin)" + select PACKAGE_v2ray-plugin default y if aarch64||arm||i386||x86_64 endif diff --git a/openwrt-fastfetch/Makefile b/openwrt-fastfetch/Makefile index 7b7b55425..27b20c037 100644 --- a/openwrt-fastfetch/Makefile +++ b/openwrt-fastfetch/Makefile @@ -5,8 +5,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=fastfetch -PKG_VERSION:=2.59.0 -PKG_RELEASE:=1 +PKG_VERSION:=2.60.0 +PKG_RELEASE:=2 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/fastfetch-cli/fastfetch/tar.gz/$(PKG_VERSION)?