🌴 Sync 2026-03-07 13:56:51

This commit is contained in:
github-actions[bot] committed 2026-03-07 13:56:51 +08:00
1 parent 4b2774df9b
commit 07fec25725
8 files changed
+379 -130

No files matched your search

+1 -1
View File
@@ -11,7 +11,7 @@ LUCI_DEPENDS:=+luci-compat +curl
LUCI_PKGARCH:=all LUCI_PKGARCH:=all
PKG_VERSION:=1.8.9 PKG_VERSION:=1.8.9
PKG_RELEASE:=1 PKG_RELEASE:=2
define Package/$(PKG_NAME)/conffiles define Package/$(PKG_NAME)/conffiles
/etc/config/advancedplus /etc/config/advancedplus
@@ -92,7 +92,6 @@ advancedset(){
start_service() { start_service() {
[ -f $LOCK ] && exit [ -f $LOCK ] && exit
[ "x$(uci -q get advancedplus.@basic[0].uhttpd)" = "x1" ] && uhttpd_service
touch $LOCK touch $LOCK
rm -rf /tmp/luci-* rm -rf /tmp/luci-*
rm -f $LOCK 2>/dev/null rm -f $LOCK 2>/dev/null
@@ -78,10 +78,10 @@ function updateMacStatus(macAddr, isSuccess, errorMsg, isFallback) {
var statusElement = document.getElementById('mac-status'); var statusElement = document.getElementById('mac-status');
if (isSuccess) { if (isSuccess) {
var prefix = isFallback ? _('✓ WAN MAC address obtained (fallback): ') : _('✓ WAN MAC address obtained: '); 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; statusElement.innerHTML = prefix + macAddr + suffix;
} else { } else {
statusElement.innerHTML = _('✗ Failed to get WAN MAC address: ') + (errorMsg || 'Unknown error'); statusElement.innerHTML = _('✗ Failed to get WAN MAC address: ') + (errorMsg || _('Unknown error'));
} }
} }
@@ -96,7 +96,7 @@ function generateAndUpdateIds(macAddr) {
} }
function getMacAddressPromise(results) { function getMacAddressPromise(results) {
return callGetWanMac().then(function(response) { return callGetWanMac().then(function (response) {
if (response && response.status === 'success') { if (response && response.status === 'success') {
var macAddr = response.mac.toUpperCase().replace(/:/g, '-'); var macAddr = response.mac.toUpperCase().replace(/:/g, '-');
results.macAddress = macAddr; results.macAddress = macAddr;
@@ -108,7 +108,7 @@ function getMacAddressPromise(results) {
} else { } else {
return getMacAddressFallback(results); return getMacAddressFallback(results);
} }
}).catch(function(error) { }).catch(function (error) {
return getMacAddressFallback(results); return getMacAddressFallback(results);
}); });
} }
@@ -116,7 +116,7 @@ function getMacAddressPromise(results) {
function getMacAddressFallback(results) { function getMacAddressFallback(results) {
document.getElementById('mac-status').innerHTML = _('RPC failed, trying fallback...'); 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') { if (response.code === 0 && response.stdout && response.stdout.trim() !== 'failed') {
var macAddr = response.stdout.trim().toUpperCase().replace(/:/g, '-'); var macAddr = response.stdout.trim().toUpperCase().replace(/:/g, '-');
results.macAddress = macAddr; results.macAddress = macAddr;
@@ -126,10 +126,10 @@ function getMacAddressFallback(results) {
results.deviceId = ids.deviceId; results.deviceId = ids.deviceId;
results.locationId = ids.locationId; results.locationId = ids.locationId;
} else { } else {
updateMacStatus(null, false, 'Unknown error'); updateMacStatus(null, false, _('Unknown error'));
document.getElementById('device-id-status').innerHTML = _('✗ Cannot generate Device ID without MAC address'); document.getElementById('device-id-status').innerHTML = _('✗ Cannot generate Device ID without MAC address');
} }
}).catch(function(error) { }).catch(function (error) {
updateMacStatus(null, false, error.message); updateMacStatus(null, false, error.message);
document.getElementById('device-id-status').innerHTML = _('✗ Cannot generate Device ID due to MAC error'); document.getElementById('device-id-status').innerHTML = _('✗ Cannot generate Device ID due to MAC error');
}); });
@@ -145,7 +145,7 @@ function formatCoordinate(coord) {
} }
function getLocationPromise(results) { function getLocationPromise(results) {
return callGetLocation().then(function(response) { return callGetLocation().then(function (response) {
if (response && response.status === 'success') { if (response && response.status === 'success') {
var lat = formatCoordinate(response.lat); var lat = formatCoordinate(response.lat);
var lon = formatCoordinate(response.lon); var lon = formatCoordinate(response.lon);
@@ -154,10 +154,10 @@ function getLocationPromise(results) {
results.latitude = lat; results.latitude = lat;
document.getElementById('location-status').innerHTML = _('✓ Location obtained: ') + lat + ', ' + lon; document.getElementById('location-status').innerHTML = _('✓ Location obtained: ') + lat + ', ' + lon;
} else { } 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; document.getElementById('location-status').innerHTML = _('✗ Failed to get location: ') + errorMsg;
} }
}).catch(function(error) { }).catch(function (error) {
return getLocationFallback(results); return getLocationFallback(results);
}); });
} }
@@ -165,7 +165,7 @@ function getLocationPromise(results) {
function getLocationFallback(results) { function getLocationFallback(results) {
document.getElementById('location-status').innerHTML = _('RPC failed, trying direct method...'); 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') { if (response.code === 0 && response.stdout && response.stdout.trim() !== 'failed') {
try { try {
var data = JSON.parse(response.stdout); var data = JSON.parse(response.stdout);
@@ -193,7 +193,7 @@ function getLocationFallback(results) {
} else { } else {
document.getElementById('location-status').innerHTML = _('✗ Failed to get location data'); 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; document.getElementById('location-status').innerHTML = _('✗ Error getting location: ') + fallbackError.message;
}); });
} }
@@ -210,12 +210,12 @@ function fillFormFields(results) {
{ result: 'latitude', selector: 'ap_latitude', label: _('Latitude: ') } { result: 'latitude', selector: 'ap_latitude', label: _('Latitude: ') }
]; ];
fieldMappings.forEach(function(mapping) { fieldMappings.forEach(function (mapping) {
if (results[mapping.result]) { if (results[mapping.result]) {
var field = document.querySelector('input[data-name="' + mapping.selector + '"]') || var field = document.querySelector('input[data-name="' + mapping.selector + '"]') ||
document.querySelector('input[name*="' + mapping.selector + '"]') || document.querySelector('input[name*="' + mapping.selector + '"]') ||
document.querySelector('input[id*="' + mapping.selector + '"]') || document.querySelector('input[id*="' + mapping.selector + '"]') ||
document.querySelector('#cbid\\.wifidogx\\.default\\.' + mapping.selector); document.querySelector('#cbid\\.wifidogx\\.default\\.' + mapping.selector);
if (field) { if (field) {
field.value = results[mapping.result]; field.value = results[mapping.result];
@@ -267,20 +267,20 @@ function renderStatus(isRunning) {
} }
return view.extend({ return view.extend({
render: function() { render: function () {
var m, s, o, ss; var m, s, o, ss;
m = new form.Map('wifidogx', _('ApFree-WiFiDog')); m = new form.Map('wifidogx', _('ApFree-WiFiDog'));
m.description = github.desc('apfree-wifidog offers a stable and secure captive portal solution.', 'liudf0716', '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.addremove = false;
s.anonymous = true; s.anonymous = true;
s.tab('basic', _('Basic Settings')); s.tab('basic', _('Basic Settings'));
s.tab('gateway', _('Gateway Settings'));
s.tab('auth', _('Auth Server Settings')); s.tab('auth', _('Auth Server Settings'));
s.tab('gateway', _('Gateway Settings'));
s.tab('advanced', _('Advanced Settings')); s.tab('advanced', _('Advanced Settings'));
s.tab('rule', _('Rule Settings')); s.tab('rule', _('Rule Settings'));
s.tab('qos', _('QoS Settings')); s.tab('qos', _('QoS Settings'));
@@ -291,7 +291,7 @@ return view.extend({
o.rmempty = false; o.rmempty = false;
o = s.taboption('basic', form.ListValue, 'auth_server_mode', _('Auth Server Mode'), 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('cloud', _('Cloud Auth'));
o.value('local', _('Local Auth')); o.value('local', _('Local Auth'));
o.value('bypass', _('Bypass Auth')); o.value('bypass', _('Bypass Auth'));
@@ -300,11 +300,11 @@ return view.extend({
// 添加一个下拉框,列出当前定义的认证服务列表,并选择当前选中的认证服务 // 添加一个下拉框,列出当前定义的认证服务列表,并选择当前选中的认证服务
o = s.taboption('basic', form.ListValue, 'selected_auth_server', _('Authentication Server'), 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.rmempty = false;
o.optional = false; o.optional = false;
o.depends('auth_server_mode', 'cloud'); o.depends('auth_server_mode', 'cloud');
o.load = function(section_id) { o.load = function (section_id) {
this.keylist = []; this.keylist = [];
this.vallist = []; this.vallist = [];
@@ -312,9 +312,9 @@ return view.extend({
if (sections.length == 0) { if (sections.length == 0) {
this.value('', _('Please create an authentication server first')); this.value('', _('Please create an authentication server first'));
} else { } else {
sections.forEach(L.bind(function(section) { sections.forEach(L.bind(function (section) {
var name = section['.name']; 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.value(name, '%s (%s)'.format(name, hostname));
}, this)); }, this));
} }
@@ -323,7 +323,7 @@ return view.extend({
}; };
o = s.taboption('basic', widgets.NetworkSelect, 'external_interface', _('External Interface'), 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.rmempty = true;
o.nocreate = true; o.nocreate = true;
o.loopback = false; o.loopback = false;
@@ -337,7 +337,7 @@ return view.extend({
o.depends('auth_server_mode', 'bypass'); o.depends('auth_server_mode', 'bypass');
o = s.taboption('basic', form.Value, 'local_portal', _('Local Portal'), o = s.taboption('basic', form.Value, 'local_portal', _('Local Portal'),
_('The local portal url.')); _('The local portal url.'));
o.rmempty = false; o.rmempty = false;
o.datatype = 'string'; o.datatype = 'string';
o.optional = true; o.optional = true;
@@ -345,12 +345,12 @@ return view.extend({
o.depends('auth_server_mode', 'local'); o.depends('auth_server_mode', 'local');
o = s.taboption('basic', form.Flag, 'disable_portal_auth', _('Disable Portal Authentication'), 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.rmempty = false;
o.default = '1'; o.default = '1';
o = s.taboption('basic', form.ListValue, 'log_level', _('Log Level'), 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(7, _('Debug'));
o.value(6, _('Info')); o.value(6, _('Info'));
o.value(5, _('Notice')); o.value(5, _('Notice'));
@@ -369,7 +369,7 @@ return view.extend({
ss.nodescriptions = true; ss.nodescriptions = true;
o = ss.option(form.Flag, 'gateway_auth_enabled', _('Auth Enabled'), 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.rmempty = false;
o.defaulValue = true; o.defaulValue = true;
@@ -380,19 +380,19 @@ return view.extend({
o.default = 'lan'; o.default = 'lan';
o = ss.option(form.Value, 'gateway_channel', _('Gateway Channel'), o = ss.option(form.Value, 'gateway_channel', _('Gateway Channel'),
_('The channel of the gateway.')); _('The channel of the gateway.'));
o.datatype = 'string'; o.datatype = 'string';
o.rmempty = false; o.rmempty = false;
o.optional = false; o.optional = false;
o = ss.option(form.Value, 'gateway_id', _('Gateway ID'), o = ss.option(form.Value, 'gateway_id', _('Gateway ID'),
_('The ID of the gateway.')); _('The ID of the gateway.'));
o.datatype = 'string'; o.datatype = 'string';
o.rmempty = false; o.rmempty = false;
o.optional = true; o.optional = true;
o = ss.option(form.Value, 'gateway_subnetv4', _('Gateway Subnetv4'), 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.datatype = 'cidr4';
o.rmempty = false; o.rmempty = false;
o.optional = false; o.optional = false;
@@ -400,53 +400,53 @@ return view.extend({
// advanced settings // advanced settings
o = s.taboption('advanced', form.Value, 'check_interval', _('Check Interval'), 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.datatype = 'uinteger';
o.rmempty = false; o.rmempty = false;
o.optional = false; o.optional = false;
o.defaulValue = 60; o.defaulValue = 60;
o = s.taboption('advanced', form.Value, 'client_timeout', _('Client Timeout'), o = s.taboption('advanced', form.Value, 'client_timeout', _('Client Timeout'),
_('The timeout of the client.')); _('The timeout of the client.'));
o.datatype = 'uinteger'; o.datatype = 'uinteger';
o.rmempty = false; o.rmempty = false;
o.optional = false; o.optional = false;
o.defaulValue = 5; o.defaulValue = 5;
o = s.taboption('advanced', form.Flag, 'wired_passed', _('Wired Passed'), 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.rmempty = false;
o = s.taboption('advanced', form.Flag, 'apple_cna', _('Apple CNA'), o = s.taboption('advanced', form.Flag, 'apple_cna', _('Apple CNA'),
_('Enable Apple Captive Network Assistant.')); _('Enable Apple Captive Network Assistant.'));
o.rmempty = false; o.rmempty = false;
o.defaulValue = false; o.defaulValue = false;
o = s.taboption('advanced', form.Flag, 'js_filter', _('JS Filter'), o = s.taboption('advanced', form.Flag, 'js_filter', _('JS Filter'),
_('Enable JS redirect.')); _('Enable JS redirect.'));
o.rmempty = false; o.rmempty = false;
o.defaulValue = true; o.defaulValue = true;
o = s.taboption('advanced', form.Flag, 'enable_anti_nat', _('Enable Anti NAT'), o = s.taboption('advanced', form.Flag, 'enable_anti_nat', _('Enable Anti NAT'),
_('Enable Anti NAT devices.')); _('Enable Anti NAT devices.'));
o.rmempty = false; o.rmempty = false;
o.defaulValue = false; o.defaulValue = false;
o = s.taboption('advanced', form.Value, 'ttl_value', _('TTL Value'), 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.datatype = 'string';
o.rmempty = false; o.rmempty = false;
o.defaulValue = '64,128'; o.defaulValue = '64,128';
o.depends('enable_anti_nat', '1'); o.depends('enable_anti_nat', '1');
o = s.taboption('advanced', form.Value, 'anti_nat_permit_macs', _('Anti NAT Permit MAC'), 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.datatype = 'macaddr';
o.rmempty = true; o.rmempty = true;
o.depends('enable_anti_nat', '1'); o.depends('enable_anti_nat', '1');
o = s.taboption('advanced', form.Flag, 'enable_event_log', _('Enable Internet Access Log'), 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.rmempty = false;
o.defaulValue = false; o.defaulValue = false;
@@ -457,14 +457,14 @@ return view.extend({
ss.nodescriptions = true; ss.nodescriptions = true;
o = ss.option(form.Value, 'auth_server_hostname', _('Auth Server Hostname'), o = ss.option(form.Value, 'auth_server_hostname', _('Auth Server Hostname'),
_('The domain or IP address of the authentication server.')); _('The domain or IP address of the authentication server.'));
o.rmempty = false; o.rmempty = false;
o.datatype = 'or(host,ip4addr)'; o.datatype = 'or(host,ip4addr)';
o.optional = false; o.optional = false;
o = ss.option(form.Value, 'auth_server_port', _('Auth Server Port'), 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.rmempty = false;
o.datatype = 'port'; o.datatype = 'port';
o.optional = false; o.optional = false;
@@ -472,7 +472,7 @@ return view.extend({
o = ss.option(form.Value, 'auth_server_path', _('Auth Server URI path'), 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.rmempty = false;
o.datatype = 'string'; o.datatype = 'string';
o.optional = false; o.optional = false;
@@ -480,76 +480,91 @@ return view.extend({
o = ss.option(form.ListValue, 'long_conn_mode', _('Persistent Connection Mode'), 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('ws', _('WebSocket Connection Mode'));
o.value('wss', _('WebSocket Secure Connection Mode')); o.value('wss', _('WebSocket Secure Connection Mode'));
o.value('mqtt', _('MQTT Connection Mode')); o.value('mqtt', _('MQTT Connection Mode'));
o.value('mqtts', _('MQTT Secure Connection Mode'))
o.rmempty = false; o.rmempty = false;
o.defaulValue = 'wss'; o.defaulValue = 'wss';
o.optional = false; o.optional = false;
o.modalonly = true;
o = ss.option(form.Value, 'ws_server_hostname', _('WebSocket Hostname'), 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.datatype = 'or(host,ip4addr)';
o.rmempty = true; o.rmempty = true;
o.optional = true; o.optional = true;
o.depends('long_conn_mode', 'ws'); o.depends('long_conn_mode', 'ws');
o.depends('long_conn_mode', 'wss'); o.depends('long_conn_mode', 'wss');
o.modalonly = true;
o = ss.option(form.Value, 'ws_server_port', _('WebSocket Port'), 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.datatype = 'port';
o.rmempty = true; o.rmempty = true;
o.optional = true; o.optional = true;
o.default = '443'; o.default = '443';
o.depends('long_conn_mode', 'wss'); 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'), 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.datatype = 'string';
o.rmempty = true; o.rmempty = true;
o.optional = true; o.optional = true;
o.default = '/ws/wifidogx'; o.default = '/ws/wifidogx';
o.depends('long_conn_mode', 'ws'); o.depends('long_conn_mode', 'ws');
o.depends('long_conn_mode', 'wss'); o.depends('long_conn_mode', 'wss');
o.modalonly = true;
o = ss.option(form.Value, 'mqtt_server_hostname', _('MQTT Hostname'), 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.datatype = 'or(host,ip4addr)';
o.rmempty = true; o.rmempty = true;
o.optional = true; o.optional = true;
o.depends('long_conn_mode', 'mqtt'); 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'), o = ss.option(form.Value, 'mqtt_server_port', _('MQTT Port'),
_('The port of the mqtt.')); _('The port of the mqtt.'));
o.datatype = 'port'; o.datatype = 'port';
o.rmempty = false; o.rmempty = false;
o.optional = false; o.optional = false;
o.depends('long_conn_mode', 'mqtt'); o.depends('long_conn_mode', 'mqtt');
o.depends('long_conn_mode', 'mqtts');
o.default = 1883; o.default = 1883;
o.modalonly = true;
o = ss.option(form.Value, 'mqtt_username', _('MQTT Username'), o = ss.option(form.Value, 'mqtt_username', _('MQTT Username'),
_('The username of the mqtt.')); _('The username of the mqtt.'));
o.datatype = 'string'; o.datatype = 'string';
o.rmempty = true; o.rmempty = true;
o.optional = true; o.optional = true;
o.depends('long_conn_mode', 'mqtt'); o.depends('long_conn_mode', 'mqtt');
o.depends('long_conn_mode', 'mqtts');
o.modalonly = true;
o = ss.option(form.Value, 'mqtt_password', _('MQTT Password'), o = ss.option(form.Value, 'mqtt_password', _('MQTT Password'),
_('The password of the mqtt.')); _('The password of the mqtt.'));
o.datatype = 'string'; o.datatype = 'string';
o.rmempty = true; o.rmempty = true;
o.optional = true; o.optional = true;
o.depends('long_conn_mode', 'mqtt'); o.depends('long_conn_mode', 'mqtt');
o.depends('long_conn_mode', 'mqtts');
o.modalonly = true;
// QoS settings // QoS settings
o = s.taboption('qos', form.Flag, 'enable_qos', _('Enable Global QoS'), o = s.taboption('qos', form.Flag, 'enable_qos', _('Enable Global QoS'),
_('Enable Global QoS.')); _('Enable Global QoS.'));
o.rmempty = false; o.rmempty = false;
o.defaulValue = false; o.defaulValue = false;
o = s.taboption('qos', form.Value, 'qos_up', _('Global QoS Up'), 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.datatype = 'uinteger';
o.rmempty = true; o.rmempty = true;
o.optional = true; o.optional = true;
@@ -557,7 +572,7 @@ return view.extend({
o.depends('enable_qos', '1'); o.depends('enable_qos', '1');
o = s.taboption('qos', form.Value, 'qos_down', _('Global QoS Down'), 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.datatype = 'uinteger';
o.rmempty = true; o.rmempty = true;
o.optional = true; o.optional = true;
@@ -567,10 +582,10 @@ return view.extend({
// Authentication Location Settings // Authentication Location Settings
// Add auto-fill button // Add auto-fill button
o = s.taboption('location', form.Button, '_auto_fill', _('Auto Fill All Fields'), 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.inputtitle = _('Auto Fill All Fields');
o.inputstyle = 'apply'; o.inputstyle = 'apply';
o.onclick = function() { o.onclick = function () {
showAutoFillModal(); showAutoFillModal();
var results = { var results = {
@@ -587,8 +602,8 @@ return view.extend({
]; ];
// Wait for all promises to complete and fill form fields // Wait for all promises to complete and fill form fields
Promise.all(promises).then(function() { Promise.all(promises).then(function () {
setTimeout(function() { setTimeout(function () {
fillFormFields(results); fillFormFields(results);
}, 2000); }, 2000);
}); });
@@ -613,7 +628,7 @@ return view.extend({
// Helper function to get MAC address with fallback // Helper function to get MAC address with fallback
function getMacAddressPromise(results) { function getMacAddressPromise(results) {
return callGetWanMac().then(function(response) { return callGetWanMac().then(function (response) {
if (response && response.status === 'success') { if (response && response.status === 'success') {
var macAddr = response.mac.toUpperCase().replace(/:/g, '-'); var macAddr = response.mac.toUpperCase().replace(/:/g, '-');
results.macAddress = macAddr; results.macAddress = macAddr;
@@ -627,7 +642,7 @@ return view.extend({
} else { } else {
return getMacAddressFallback(results); return getMacAddressFallback(results);
} }
}).catch(function(error) { }).catch(function (error) {
document.getElementById('mac-status').innerHTML = _('✗ RPC call failed, trying fallback...'); document.getElementById('mac-status').innerHTML = _('✗ RPC call failed, trying fallback...');
return getMacAddressFallback(results); return getMacAddressFallback(results);
}); });
@@ -635,7 +650,7 @@ return view.extend({
// Helper function for MAC address fallback // Helper function for MAC address fallback
function getMacAddressFallback(results) { 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') { if (response.code === 0 && response.stdout && response.stdout.trim() !== 'failed') {
var macAddr = response.stdout.trim().toUpperCase().replace(/:/g, '-'); var macAddr = response.stdout.trim().toUpperCase().replace(/:/g, '-');
results.macAddress = macAddr; results.macAddress = macAddr;
@@ -651,7 +666,7 @@ return view.extend({
document.getElementById('mac-status').innerHTML = _('✗ Failed to get WAN MAC address: ') + errorMsg; 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'); 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('mac-status').innerHTML = _('✗ Error getting WAN MAC address: ') + error.message;
document.getElementById('device-id-status').innerHTML = _('✗ Cannot generate Device ID due to MAC error'); document.getElementById('device-id-status').innerHTML = _('✗ Cannot generate Device ID due to MAC error');
}); });
@@ -659,7 +674,7 @@ return view.extend({
// Helper function to get location with fallback // Helper function to get location with fallback
function getLocationPromise(results) { function getLocationPromise(results) {
return callGetLocation().then(function(response) { return callGetLocation().then(function (response) {
if (response && response.status === 'success') { if (response && response.status === 'success') {
var lat = parseFloat(response.lat).toFixed(6); var lat = parseFloat(response.lat).toFixed(6);
var lon = parseFloat(response.lon).toFixed(6); var lon = parseFloat(response.lon).toFixed(6);
@@ -670,7 +685,7 @@ return view.extend({
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; 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...'); document.getElementById('location-status').innerHTML = _('RPC failed, trying direct method...');
return getLocationFallback(results); return getLocationFallback(results);
}); });
@@ -678,7 +693,7 @@ return view.extend({
// Helper function for location fallback // Helper function for location fallback
function getLocationFallback(results) { 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') { if (response.code === 0 && response.stdout && response.stdout.trim() !== 'failed') {
try { try {
var data = JSON.parse(response.stdout); var data = JSON.parse(response.stdout);
@@ -705,7 +720,7 @@ return view.extend({
} else { } else {
document.getElementById('location-status').innerHTML = _('✗ Failed to get location data'); 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; document.getElementById('location-status').innerHTML = _('✗ Error getting location: ') + fallbackError.message;
}); });
} }
@@ -743,7 +758,7 @@ return view.extend({
{ key: 'latitude', selectors: ['input[data-name="ap_latitude"]', 'input[name*="ap_latitude"]', 'input[id*="ap_latitude"]', '#cbid\\.wifidogx\\.default\\.ap_latitude'], label: _('Latitude: ') } { 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]) { if (results[mapping.key]) {
var field = null; var field = null;
for (var i = 0; i < mapping.selectors.length; i++) { for (var i = 0; i < mapping.selectors.length; i++) {
@@ -786,7 +801,7 @@ return view.extend({
o.depends('auth_server_mode', 'cloud'); o.depends('auth_server_mode', 'cloud');
o.depends('auth_server_mode', 'bypass'); o.depends('auth_server_mode', 'bypass');
o.placeholder = '110101100123456'; o.placeholder = '110101100123456';
o.validate = function(section_id, value) { o.validate = function (section_id, value) {
if (!value || value === '') if (!value || value === '')
return _('Location ID is required'); return _('Location ID is required');
@@ -822,10 +837,10 @@ return view.extend({
}; };
o = s.taboption('location', form.Value, 'ap_device_id', _('AP Device ID'), 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.rmempty = true;
o.optional = true; o.optional = true;
o.validate = function(section_id, value) { o.validate = function (section_id, value) {
if (!value || value === '') if (!value || value === '')
return true; // Optional field, empty is allowed return true; // Optional field, empty is allowed
@@ -852,11 +867,11 @@ return view.extend({
o.placeholder = 'AW123456700E04C3B7D2F'; o.placeholder = 'AW123456700E04C3B7D2F';
o = s.taboption('location', form.Value, 'ap_mac_address', _('AP MAC Address'), 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.rmempty = true;
o.optional = true; o.optional = true;
o.placeholder = '00-E0-4C-3B-7D-2F'; o.placeholder = '00-E0-4C-3B-7D-2F';
o.validate = function(section_id, value) { o.validate = function (section_id, value) {
if (!value || value === '') if (!value || value === '')
return true; // Optional field, empty is allowed return true; // Optional field, empty is allowed
@@ -885,11 +900,11 @@ return view.extend({
}; };
o = s.taboption('location', form.Value, 'ap_longitude', _('Mobile AP Longitude'), 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.rmempty = true;
o.optional = true; o.optional = true;
o.placeholder = '123.230000'; o.placeholder = '123.230000';
o.validate = function(section_id, value) { o.validate = function (section_id, value) {
if (!value || value === '') if (!value || value === '')
return true; // Optional field, empty is allowed return true; // Optional field, empty is allowed
@@ -928,11 +943,11 @@ return view.extend({
}; };
o = s.taboption('location', form.Value, 'ap_latitude', _('Mobile AP Latitude'), 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.rmempty = true;
o.optional = true; o.optional = true;
o.placeholder = '39.900000'; o.placeholder = '39.900000';
o.validate = function(section_id, value) { o.validate = function (section_id, value) {
if (!value || value === '') if (!value || value === '')
return true; // Optional field, empty is allowed return true; // Optional field, empty is allowed
@@ -972,52 +987,52 @@ return view.extend({
// rule settings // rule settings
o = s.taboption('rule', form.DynamicList, 'trusted_wildcard_domains', _('Trusted Wildcard Domains'), 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.rmempty = true;
o.optional = true; o.optional = true;
o.datatype = 'wildcard'; o.datatype = 'wildcard';
o.placeholder = '.example.com'; o.placeholder = '.example.com';
o = s.taboption('rule', form.DynamicList, 'trusted_domains', _('Trusted Domains'), 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.rmempty = true;
o.optional = true; o.optional = true;
o.datatype = 'hostname'; o.datatype = 'hostname';
o.placeholder = 'www.example.com'; o.placeholder = 'www.example.com';
o = s.taboption('rule', form.DynamicList, 'trusted_macs', _('Trusted MACs'), 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.rmempty = true;
o.optional = true; o.optional = true;
o.datatype = 'macaddr'; o.datatype = 'macaddr';
o.placeholder = 'A0:B1:C2:D3:44:55'; o.placeholder = 'A0:B1:C2:D3:44:55';
o = s.taboption('rule', widgets.WifidogxGroupSelect, 'app_white_list', _('App White List'), 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.rmempty = true;
o.multiple = true; o.multiple = true;
o.nocreate = true; o.nocreate = true;
o = s.taboption('rule', widgets.WifidogxGroupSelect, 'mac_white_list', _('MAC White List'), 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.rmempty = true;
o.multiple = true; o.multiple = true;
o.nocreate = true; o.nocreate = true;
o.setGroupType('mac'); o.setGroupType('mac');
o = s.taboption('rule', widgets.WifidogxGroupSelect, 'wildcard_white_list', _('Wildcard White List'), 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.rmempty = true;
o.multiple = true; o.multiple = true;
o.nocreate = true; o.nocreate = true;
o.setGroupType('wildcard'); o.setGroupType('wildcard');
s = m.section(form.GridSection, 'group', _('Group Define')); s = m.section(form.GridSection, 'group', _('Group Define'));
s.addremove = true; s.addremove = true;
s.anonymous = false; s.anonymous = false;
s.nodescriptions = true; 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 // 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 group = uci.get('wifidogx', section_id, 'g_type') === '1' ? 'app_white_list' : 'mac_white_list';
var groupList = uci.get('wifidogx', 'common', group); var groupList = uci.get('wifidogx', 'common', group);
@@ -99,6 +99,8 @@ return view.extend({
[_('Uptime'), uptime], [_('Uptime'), uptime],
[_('Internet Connected'), data.is_internet_connected ? _('Yes') : _('No')], [_('Internet Connected'), data.is_internet_connected ? _('Yes') : _('No')],
[_('Auth Server Connected'), data.is_auth_server_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] [_('Auth Server Mode'), authModeText]
]; ];
@@ -654,6 +654,12 @@ msgstr "互联网连接"
msgid "Auth Server Connected" msgid "Auth Server Connected"
msgstr "认证服务器连接" msgstr "认证服务器连接"
msgid "MQTT Connected"
msgstr "MQTT 连接"
msgid "WebSocket Connected"
msgstr "WebSocket 连接"
msgid "Auth Server Mode" msgid "Auth Server Mode"
msgstr "认证服务器模式" msgstr "认证服务器模式"
@@ -791,3 +797,234 @@ msgstr "实时下载速度"
msgid "Real-time Upload Speed" msgid "Real-time Upload Speed"
msgstr "实时上传速度" 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 "未知"
+13 -25
View File
@@ -749,7 +749,6 @@ function gen_config(var)
local fakedns = nil local fakedns = nil
local routing = nil local routing = nil
local observatory = nil local observatory = nil
local burstObservatory = nil
local strategy = nil local strategy = nil
local inbounds = {} local inbounds = {}
local outbounds = {} local outbounds = {}
@@ -975,29 +974,19 @@ function gen_config(var)
fallbackTag = fallback_node_tag, fallbackTag = fallback_node_tag,
strategy = strategy strategy = strategy
}) })
if _node.balancingStrategy == "leastPing" or _node.balancingStrategy == "leastLoad" or fallback_node_tag then if not observatory and (_node.balancingStrategy == "leastPing" or _node.balancingStrategy == "leastLoad" or fallback_node_tag) then
if _node.balancingStrategy == "leastLoad" then local t = api.format_go_time(_node.probeInterval)
if not burstObservatory then if t == "0s" then
burstObservatory = { t = "60s"
subjectSelector = { "blc-" }, elseif not t:find("[hm]") and tonumber(t:match("%d+")) < 10 then
pingConfig = { t = "10s"
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
end end
observatory = {
subjectSelector = { "blc-" },
probeUrl = _node.useCustomProbeUrl and _node.probeUrl or "https://www.google.com/generate_204",
probeInterval = t,
enableConcurrency = true
}
end end
local loopback_outbound = gen_loopback(loopback_tag, loopback_dst) local loopback_outbound = gen_loopback(loopback_tag, loopback_dst)
local inbound_tag = loopback_outbound.settings.inboundTag local inbound_tag = loopback_outbound.settings.inboundTag
@@ -1652,8 +1641,7 @@ function gen_config(var)
-- 传出连接 -- 传出连接
outbounds = outbounds, outbounds = outbounds,
-- 连接观测 -- 连接观测
observatory = (not burstObservatory) and observatory or nil, observatory = observatory,
burstObservatory = burstObservatory,
-- 路由 -- 路由
routing = routing, routing = routing,
-- 本地策略 -- 本地策略
+24 -16
View File
@@ -34,21 +34,21 @@ LUCI_DEPENDS:=+coreutils +coreutils-base64 +coreutils-nohup +curl \
+ip-full +libuci-lua +lua +luci-compat +luci-lib-jsonc +resolveip +tcping \ +ip-full +libuci-lua +lua +luci-compat +luci-lib-jsonc +resolveip +tcping \
+xray-core +geoview +v2ray-geoip +v2ray-geosite \ +xray-core +geoview +v2ray-geoip +v2ray-geosite \
+unzip \ +unzip \
+PACKAGE_$(PKG_NAME)_INCLUDE_Haproxy:haproxy \ + +PACKAGE_$(PKG_NAME)_INCLUDE_Haproxy:haproxy \
+PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria:hysteria \ + +PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria:hysteria \
+PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy:naiveproxy \ + +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-local \
+PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Client:shadowsocks-libev-ss-redir \ + +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_Libev_Server:shadowsocks-libev-ss-server \
+PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Client:shadowsocks-rust-sslocal \ + +PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Client:shadowsocks-rust-sslocal \
+PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Server:shadowsocks-rust-ssserver \ + +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-local \
+PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Client:shadowsocksr-libev-ssr-redir \ + +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_ShadowsocksR_Libev_Server:shadowsocksr-libev-ssr-server \
+PACKAGE_$(PKG_NAME)_INCLUDE_Simple_Obfs:simple-obfs-client \ + +PACKAGE_$(PKG_NAME)_INCLUDE_Simple_Obfs:simple-obfs-client \
+PACKAGE_$(PKG_NAME)_INCLUDE_SingBox:sing-box \ + +PACKAGE_$(PKG_NAME)_INCLUDE_SingBox:sing-box \
+PACKAGE_$(PKG_NAME)_INCLUDE_tuic_client:tuic-client \ + +PACKAGE_$(PKG_NAME)_INCLUDE_tuic_client:tuic-client \
+PACKAGE_$(PKG_NAME)_INCLUDE_V2ray_Plugin:v2ray-plugin \ + +PACKAGE_$(PKG_NAME)_INCLUDE_V2ray_Plugin:v2ray-plugin \
+PACKAGE_$(PKG_NAME)_INCLUDE_IPv6_Nat:ip6tables-mod-nat +PACKAGE_$(PKG_NAME)_INCLUDE_IPv6_Nat:ip6tables-mod-nat
define Package/$(PKG_NAME)/config define Package/$(PKG_NAME)/config
@@ -90,6 +90,7 @@ config PACKAGE_$(PKG_NAME)_Nftables_Transparent_Proxy
config PACKAGE_$(PKG_NAME)_INCLUDE_Haproxy config PACKAGE_$(PKG_NAME)_INCLUDE_Haproxy
bool "Include Haproxy" bool "Include Haproxy"
select PACKAGE_haproxy
default y if aarch64||arm||i386||x86_64 default y if aarch64||arm||i386||x86_64
config PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria config PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria
@@ -105,6 +106,8 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy
config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Client config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Client
bool "Include Shadowsocks Libev Client" bool "Include Shadowsocks Libev Client"
select PACKAGE_shadowsocks-libev-ss-local
select PACKAGE_shadowsocks-libev-ss-redir
default y default y
config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Server 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 config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Client
bool "Include Shadowsocks Rust Client" bool "Include Shadowsocks Rust Client"
depends on !i386 depends on !i386
select PACKAGE_shadowsocks-rust-sslocal
default y if aarch64||x86_64 default y if aarch64||x86_64
config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Server 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 config PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Client
bool "Include ShadowsocksR Libev Client" bool "Include ShadowsocksR Libev Client"
select PACKAGE_shadowsocksr-libev-ssr-local
select PACKAGE_shadowsocksr-libev-ssr-redir
default y default y
config PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Server 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 config PACKAGE_$(PKG_NAME)_INCLUDE_Simple_Obfs
bool "Include Simple-Obfs (Shadowsocks Plugin)" bool "Include Simple-Obfs (Shadowsocks Plugin)"
select PACKAGE_simple-obfs-client
default y default y
config PACKAGE_$(PKG_NAME)_INCLUDE_SingBox config PACKAGE_$(PKG_NAME)_INCLUDE_SingBox
bool "Include Sing-Box" bool "Include Sing-Box"
default y if aarch64||arm||i386||x86_64 default y
config PACKAGE_$(PKG_NAME)_INCLUDE_tuic_client config PACKAGE_$(PKG_NAME)_INCLUDE_tuic_client
bool "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 config PACKAGE_$(PKG_NAME)_INCLUDE_V2ray_Plugin
bool "Include V2ray-Plugin (Shadowsocks Plugin)" bool "Include V2ray-Plugin (Shadowsocks Plugin)"
select PACKAGE_v2ray-plugin
default y if aarch64||arm||i386||x86_64 default y if aarch64||arm||i386||x86_64
endif endif
+2 -2
View File
@@ -5,8 +5,8 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=fastfetch PKG_NAME:=fastfetch
PKG_VERSION:=2.59.0 PKG_VERSION:=2.60.0
PKG_RELEASE:=1 PKG_RELEASE:=2
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/fastfetch-cli/fastfetch/tar.gz/$(PKG_VERSION)? PKG_SOURCE_URL:=https://codeload.github.com/fastfetch-cli/fastfetch/tar.gz/$(PKG_VERSION)?