update 2026-09-06 22:47:17

This commit is contained in:
action
2026-09-06 22:47:17 +08:00
parent 51ed2622f8
commit 7b5d12b8ec
15 changed files with 1229 additions and 30 deletions
+1 -1
View File
@@ -10,7 +10,7 @@ LUCI_DEPENDS:=+luci-base +luci-lib-jsonc +curl +bandix
PKG_MAINTAINER:=timsaya
PKG_VERSION:=0.12.10
PKG_VERSION:=0.12.11
PKG_RELEASE:=1
include $(TOPDIR)/feeds/luci/luci.mk
@@ -470,6 +470,26 @@ var callSetDefaultRateLimit = rpc.declare({
expect: {}
});
var callGetTrafficQuotas = rpc.declare({
object: 'luci.bandix',
method: 'getTrafficQuotas',
expect: {}
});
var callSetTrafficQuota = rpc.declare({
object: 'luci.bandix',
method: 'setTrafficQuota',
params: ['mac', 'minute_bytes', 'hourly_bytes', 'daily_bytes', 'weekly_bytes', 'monthly_bytes', 'total_bytes'],
expect: {}
});
var callDeleteTrafficQuota = rpc.declare({
object: 'luci.bandix',
method: 'deleteTrafficQuota',
params: ['mac'],
expect: {}
});
return view.extend({
load: function () {
return Promise.all([
@@ -1902,6 +1922,74 @@ return view.extend({
.schedule-rules-info {
}
.traffic-quota-section {
margin-top: 18px;
padding-top: 16px;
border-top: 1px solid ${scheme === 'dark' ? 'rgba(255,255,255,0.16)' : 'rgba(0,0,0,0.12)'};
}
.traffic-quota-header {
display: flex;
justify-content: space-between;
align-items: center;
gap: 12px;
margin-bottom: 6px;
}
.traffic-quota-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 10px 14px;
margin-top: 12px;
}
.traffic-quota-input-row {
display: flex;
gap: 6px;
}
.traffic-quota-input-row .form-input { min-width: 0; flex: 1; }
.traffic-quota-input-row .cbi-input-select { width: 82px; flex-shrink: 0; }
.traffic-quota-usage {
margin-top: 12px;
padding: 10px 12px;
border-radius: 6px;
background: ${scheme === 'dark' ? 'rgba(255,255,255,0.06)' : 'rgba(0,0,0,0.04)'};
font-size: 0.8125rem;
}
.traffic-quota-usage-row {
display: flex;
justify-content: space-between;
gap: 12px;
padding: 2px 0;
}
.traffic-quota-status {
font-size: 0.75rem;
font-weight: 600;
border-radius: 999px;
padding: 2px 8px;
color: #fff;
background: #10b981;
}
.traffic-quota-status.blocked { background: #ef4444; }
.traffic-quota-status.unconfigured { background: #6b7280; }
.traffic-quota-cell {
margin-top: 6px;
padding-top: 6px;
border-top: 1px dashed ${scheme === 'dark' ? 'rgba(255,255,255,0.18)' : 'rgba(0,0,0,0.14)'};
font-size: 0.75rem;
}
.traffic-quota-blocked-badge {
display: inline-block;
margin-left: 6px;
padding: 1px 6px;
border-radius: 999px;
color: #fff;
background: #ef4444;
font-size: 0.6875rem;
font-weight: 600;
}
@media (max-width: 600px) {
.traffic-quota-grid { grid-template-columns: 1fr; }
}
/* 统计区域样式 */
.traffic-stats-container {
@@ -2904,7 +2992,7 @@ return view.extend({
E('th', {}, _('Device Info')),
E('th', {}, _('LAN Traffic')),
E('th', {}, _('WAN Traffic')),
E('th', {}, _('Rate Limit')),
E('th', {}, _('Rules / Quota')),
E('th', {}, _('Actions'))
])
]),
@@ -3171,7 +3259,30 @@ return view.extend({
});
}
// 创建限速设置模态框
function createQuotaInput(period, label) {
return E('div', { 'class': 'form-group', 'style': 'margin-bottom: 0;' }, [
E('label', { 'class': 'form-label' }, label),
E('div', { 'class': 'traffic-quota-input-row' }, [
E('input', {
'type': 'number',
'min': '0',
'step': '0.01',
'class': 'form-input',
'id': 'traffic-quota-' + period + '-value',
'placeholder': '0'
}),
E('select', { 'class': 'cbi-input-select', 'id': 'traffic-quota-' + period + '-unit' }, [
E('option', { 'value': '1' }, 'B'),
E('option', { 'value': '1024' }, 'KB'),
E('option', { 'value': '1048576' }, 'MB'),
E('option', { 'value': '1073741824' }, 'GB'),
E('option', { 'value': '1099511627776' }, 'TB')
])
])
]);
}
// 创建设备设置模态框
var bandixModal = E('div', { 'class': 'bandix-modal-overlay', 'id': 'rate-limit-bandix-modal' }, [
E('div', { 'class': 'modal-content bandix-modal' }, [
E('div', { 'class': 'bandix-modal-body', }, [
@@ -3211,6 +3322,46 @@ return view.extend({
document.body.appendChild(bandixModal);
// 创建独立的流量配额模态框
var trafficQuotaModal = E('div', { 'class': 'bandix-modal-overlay', 'id': 'traffic-quota-bandix-modal' }, [
E('div', { 'class': 'modal-content bandix-modal' }, [
E('div', { 'class': 'bandix-modal-header' }, [
E('h3', { 'class': 'bandix-modal-title' }, _('Traffic Quota'))
]),
E('div', { 'class': 'bandix-modal-body' }, [
E('div', { 'class': 'device-summary', 'id': 'traffic-quota-device-summary' }),
E('div', { 'class': 'traffic-quota-section', 'style': 'margin-top: 0; padding-top: 0; border-top: none;' }, [
E('div', { 'class': 'traffic-quota-header' }, [
E('div', { 'style': 'font-weight: 600;' }, _('Quota Status')),
E('span', { 'class': 'traffic-quota-status', 'id': 'traffic-quota-status' }, _('Not configured'))
]),
E('div', { 'style': 'font-size: 0.75rem; opacity: 0.7;' },
_('WAN upload and download are counted together. Enter 0 for unlimited.')),
E('div', { 'class': 'traffic-quota-grid' }, [
createQuotaInput('minute', _('Minute Quota')),
createQuotaInput('hourly', _('Hourly Quota')),
createQuotaInput('daily', _('Daily Quota')),
createQuotaInput('weekly', _('Weekly Quota')),
createQuotaInput('monthly', _('Monthly Quota')),
createQuotaInput('total', _('Lifetime Quota'))
]),
E('div', { 'class': 'traffic-quota-usage', 'id': 'traffic-quota-usage' }, [
E('div', { 'style': 'opacity: 0.7;' }, _('No quota usage data'))
]),
E('div', { 'style': 'display: flex; justify-content: flex-end; gap: 8px; margin-top: 12px;' }, [
E('button', { 'class': 'cbi-button cbi-button-negative', 'id': 'traffic-quota-delete-btn', 'style': 'display: none;' }, _('Delete Quota')),
E('button', { 'class': 'cbi-button cbi-button-positive', 'id': 'traffic-quota-save-btn' }, _('Save Quota'))
])
])
]),
E('div', { 'class': 'bandix-modal-footer' }, [
E('button', { 'class': 'cbi-button cbi-button-reset', 'id': 'traffic-quota-modal-close' }, _('Close'))
])
])
]);
document.body.appendChild(trafficQuotaModal);
// 创建添加规则模态框
var addRuleModal = E('div', { 'class': 'bandix-modal-overlay', 'id': 'add-rule-bandix-modal' }, [
E('div', { 'class': 'modal-content bandix-modal' }, [
@@ -3946,9 +4097,17 @@ return view.extend({
// 模态框事件处理
var currentDevice = null;
var currentQuotaDevice = null;
var quotaFormDirty = false;
var editingRule = null;
var showRateLimitModal;
trafficQuotaModal.querySelectorAll('.traffic-quota-input-row input, .traffic-quota-input-row select').forEach(function (input) {
input.addEventListener(input.tagName === 'SELECT' ? 'change' : 'input', function () {
quotaFormDirty = true;
});
});
// 显示模态框
showRateLimitModal = function (device) {
currentDevice = device;
@@ -3994,6 +4153,33 @@ return view.extend({
}, 300);
}
function showTrafficQuotaModal(device) {
currentQuotaDevice = device;
quotaFormDirty = false;
var modal = document.getElementById('traffic-quota-bandix-modal');
var deviceSummary = document.getElementById('traffic-quota-device-summary');
var modalContent = [
E('div', { 'class': 'device-summary-name' }, device.host || device.ip4),
E('div', { 'class': 'device-summary-details' }, device.ip4 + ' (' + device.mac + ')')
];
var modalBadges = buildDeviceUplinkChBadges(device);
if (modalBadges.length) {
modalContent.push(E('div', { 'class': 'device-summary-badges device-uplink-badges-wrap' }, modalBadges));
}
deviceSummary.innerHTML = E('div', {}, modalContent).innerHTML;
renderTrafficQuotaForm(getTrafficQuotaForDevice(device.mac), false);
modal.classList.add('show');
loadTrafficQuotaForm();
}
function hideTrafficQuotaModal() {
document.getElementById('traffic-quota-bandix-modal').classList.remove('show');
setTimeout(function () {
currentQuotaDevice = null;
quotaFormDirty = false;
}, 300);
}
// 加载定时限速规则列表
function loadScheduleRules() {
if (!currentDevice) return;
@@ -4163,8 +4349,60 @@ return view.extend({
// 绑定 hostname 保存按钮事件
document.getElementById('hostname-save-btn').addEventListener('click', saveHostname);
document.getElementById('traffic-quota-save-btn').addEventListener('click', function () {
if (!currentQuotaDevice) return;
var mac = currentQuotaDevice.mac;
var values = ['minute', 'hourly', 'daily', 'weekly', 'monthly', 'total'].map(readQuotaInput);
if (values.some(function (value) { return value === null; })) {
ui.addNotification(null, E('p', {}, _('Quota values must be non-negative and within the supported range.')), 'error');
return;
}
var button = this;
button.disabled = true;
setTrafficQuotaFormDisabled(true);
callSetTrafficQuota(mac, values[0], values[1], values[2], values[3], values[4], values[5]).then(function (result) {
if (result && result.success === false) throw new Error(result.error || _('Failed to save traffic quota'));
return fetchAllTrafficQuotas(true);
}).then(function () {
if (currentQuotaDevice && currentQuotaDevice.mac === mac) {
quotaFormDirty = false;
renderTrafficQuotaForm(getTrafficQuotaForDevice(mac), false);
}
updateDeviceData();
}).catch(function (error) {
ui.addNotification(null, E('p', {}, _('Failed to save traffic quota') + ': ' + (error.message || error)), 'error');
}).finally(function () {
button.disabled = false;
setTrafficQuotaFormDisabled(false);
});
});
document.getElementById('traffic-quota-delete-btn').addEventListener('click', function () {
if (!currentQuotaDevice) return;
var mac = currentQuotaDevice.mac;
showConfirmDialog(
_('Delete Traffic Quota'),
_('Delete this quota and all of its accumulated usage?'),
function () {
callDeleteTrafficQuota(mac).then(function (result) {
if (result && result.success === false) throw new Error(result.error || _('Failed to delete traffic quota'));
return fetchAllTrafficQuotas(true);
}).then(function () {
if (currentQuotaDevice && currentQuotaDevice.mac === mac) {
quotaFormDirty = false;
renderTrafficQuotaForm(null, false);
}
updateDeviceData();
}).catch(function (error) {
ui.addNotification(null, E('p', {}, _('Failed to delete traffic quota') + ': ' + (error.message || error)), 'error');
});
}
);
});
// 绑定关闭按钮事件
document.getElementById('bandix-modal-close').addEventListener('click', hideRateLimitModal);
document.getElementById('traffic-quota-modal-close').addEventListener('click', hideTrafficQuotaModal);
// 历史趋势:状态与工具
var latestDevices = [];
@@ -4175,6 +4413,154 @@ return view.extend({
var allScheduleRules = []; // 存储所有设备的定时限速规则
var isScheduleRulesLoading = false; // 防止轮询重入
var allTrafficQuotas = [];
var trafficQuotasRequest = null;
var trafficQuotasLoadError = null;
function fetchAllTrafficQuotas(forceRefresh) {
if (trafficQuotasRequest) {
if (!forceRefresh) return trafficQuotasRequest;
return trafficQuotasRequest.then(function () {
return fetchAllTrafficQuotas(true);
});
}
trafficQuotasRequest = callGetTrafficQuotas().then(function (res) {
if (!res || res.success === false || res.status === 'error') {
throw new Error((res && (res.error || res.message)) || _('Failed to load traffic quotas'));
}
var quotas = [];
if (res && res.data && Array.isArray(res.data.quotas)) {
quotas = res.data.quotas;
} else if (res && Array.isArray(res.quotas)) {
quotas = res.quotas;
}
allTrafficQuotas = quotas;
trafficQuotasLoadError = null;
return quotas;
}).catch(function (error) {
console.error('Failed to fetch traffic quotas:', error);
allTrafficQuotas = [];
trafficQuotasLoadError = error && error.message ? error.message : _('Failed to load traffic quotas');
return [];
}).finally(function () {
trafficQuotasRequest = null;
});
return trafficQuotasRequest;
}
function getTrafficQuotaForDevice(mac) {
for (var i = 0; i < allTrafficQuotas.length; i++) {
if (allTrafficQuotas[i] && allTrafficQuotas[i].mac === mac) {
return allTrafficQuotas[i];
}
}
return null;
}
function quotaPeriods(quota) {
return [
{ key: 'minute', label: _('Minute'), limit: quota.minute_bytes || 0, used: quota.minute_used_bytes || 0 },
{ key: 'hourly', label: _('Hourly'), limit: quota.hourly_bytes || 0, used: quota.hourly_used_bytes || 0 },
{ key: 'daily', label: _('Daily'), limit: quota.daily_bytes || 0, used: quota.daily_used_bytes || 0 },
{ key: 'weekly', label: _('Weekly'), limit: quota.weekly_bytes || 0, used: quota.weekly_used_bytes || 0 },
{ key: 'monthly', label: _('Monthly'), limit: quota.monthly_bytes || 0, used: quota.monthly_used_bytes || 0 },
{ key: 'total', label: _('Lifetime'), limit: quota.total_bytes || 0, used: quota.total_used_bytes || 0 }
];
}
function setQuotaInput(period, bytes) {
var valueInput = document.getElementById('traffic-quota-' + period + '-value');
var unitSelect = document.getElementById('traffic-quota-' + period + '-unit');
if (!valueInput || !unitSelect) return;
var units = [1099511627776, 1073741824, 1048576, 1024, 1];
var unit = period === 'minute' ? 1048576 : 1073741824;
if (bytes > 0) {
for (var i = 0; i < units.length; i++) {
if (bytes >= units[i] && bytes % units[i] === 0) {
unit = units[i];
break;
}
}
}
unitSelect.value = String(unit);
valueInput.value = bytes > 0 ? String(bytes / unit) : '0';
}
function readQuotaInput(period) {
var value = Number(document.getElementById('traffic-quota-' + period + '-value').value || 0);
var unit = Number(document.getElementById('traffic-quota-' + period + '-unit').value || 1);
var bytes = Math.round(value * unit);
if (!Number.isFinite(bytes) || bytes < 0 || !Number.isSafeInteger(bytes)) return null;
return bytes;
}
function setTrafficQuotaFormDisabled(disabled) {
trafficQuotaModal.querySelectorAll('.traffic-quota-input-row input, .traffic-quota-input-row select').forEach(function (input) {
input.disabled = disabled;
});
}
function renderTrafficQuotaForm(quota, preserveInputs) {
if (!preserveInputs) {
var periods = ['minute', 'hourly', 'daily', 'weekly', 'monthly', 'total'];
periods.forEach(function (period) {
setQuotaInput(period, quota ? (quota[period + '_bytes'] || 0) : 0);
});
}
var status = document.getElementById('traffic-quota-status');
var usage = document.getElementById('traffic-quota-usage');
var deleteBtn = document.getElementById('traffic-quota-delete-btn');
if (!status || !usage || !deleteBtn) return;
status.classList.toggle('blocked', !!(quota && quota.blocked));
status.classList.toggle('unconfigured', !quota);
status.textContent = !quota ? (trafficQuotasLoadError ? _('Unavailable') : _('Not configured')) : (quota.blocked ? _('Blocked') : _('Active'));
deleteBtn.style.display = quota ? '' : 'none';
usage.innerHTML = '';
if (!quota) {
usage.appendChild(E('div', { 'style': 'opacity: 0.7;' }, trafficQuotasLoadError || _('Usage starts when a quota is first saved.')));
return;
}
quotaPeriods(quota).forEach(function (period) {
usage.appendChild(E('div', { 'class': 'traffic-quota-usage-row' }, [
E('span', {}, period.label),
E('span', {}, formatSize(period.used) + ' / ' + (period.limit > 0 ? formatSize(period.limit) : _('Unlimited')))
]));
});
}
function loadTrafficQuotaForm() {
if (!currentQuotaDevice) return Promise.resolve();
var mac = currentQuotaDevice.mac;
renderTrafficQuotaForm(getTrafficQuotaForDevice(mac), quotaFormDirty);
return fetchAllTrafficQuotas().then(function () {
if (currentQuotaDevice && currentQuotaDevice.mac === mac) {
renderTrafficQuotaForm(getTrafficQuotaForDevice(mac), quotaFormDirty);
}
});
}
function buildTrafficQuotaCell(mac) {
var quota = getTrafficQuotaForDevice(mac);
if (!quota) return null;
var periods = quotaPeriods(quota).filter(function (period) { return period.limit > 0; });
var mostUsed = null;
periods.forEach(function (period) {
var ratio = period.used / period.limit;
if (!mostUsed || ratio > mostUsed.ratio) mostUsed = { period: period, ratio: ratio };
});
var text = quota.blocked ? _('Quota exceeded') : _('Quota active');
if (mostUsed) {
text = mostUsed.period.label + ': ' + formatSize(mostUsed.period.used) + ' / ' + formatSize(mostUsed.period.limit);
}
return E('div', {
'class': 'traffic-quota-cell',
'style': quota.blocked ? 'color: #ef4444; font-weight: 600;' : '',
'title': quota.blocked ? _('WAN traffic is blocked because a quota was reached.') : _('Traffic Quota')
}, text);
}
// 获取所有定时限速规则
function fetchAllScheduleRules() {
if (isScheduleRulesLoading) return Promise.resolve();
@@ -5862,7 +6248,7 @@ return view.extend({
createSortableHeader(_('Device Info'), 'online'),
createSplitHeader(_('LAN Traffic'), 'lan_speed', 'lan_traffic'),
createSplitHeader(_('WAN Traffic'), 'wan_speed', 'wan_traffic'),
E('th', {}, _('Schedule Rules')),
E('th', {}, _('Rules / Quota')),
E('th', {}, _('Actions'))
])
]),
@@ -5890,9 +6276,9 @@ return view.extend({
// 填充数据
filteredDevices.forEach(function (device) {
var isOnline = isDeviceOnline(device);
var deviceQuota = getTrafficQuotaForDevice(device.mac);
// 默认使用窄主题样式
var buttonText = '⚙';
var buttonText = 'R';
var actionButton = E('button', {
'class': 'cbi-button cbi-button-action',
@@ -5903,6 +6289,15 @@ return view.extend({
showRateLimitModal(device);
});
var quotaButton = E('button', {
'class': 'cbi-button cbi-button-neutral',
'title': _('Traffic Quota')
}, 'Q');
quotaButton.addEventListener('click', function () {
showTrafficQuotaModal(device);
});
var deleteButton = E('button', {
'class': 'cbi-button cbi-button-reset',
'title': _('Delete Device')
@@ -5935,7 +6330,10 @@ return view.extend({
E('span', {
'class': 'device-status ' + (isOnline ? 'online' : 'offline')
}),
device.host || '-'
device.host || '-',
deviceQuota && deviceQuota.blocked
? E('span', { 'class': 'traffic-quota-blocked-badge' }, _('Quota blocked'))
: ''
]),
E('div', { 'class': 'device-ip' }, [
device.conn ? E('span', {
@@ -6149,12 +6547,14 @@ return view.extend({
};
}
return E('td', {}, rulesInfo);
var quotaCell = buildTrafficQuotaCell(device.mac);
return E('td', {}, quotaCell ? [rulesInfo, quotaCell] : rulesInfo);
})(),
// 操作
E('td', { 'class': 'device-actions' }, [
actionButton,
quotaButton,
deleteButton
])
]);
@@ -6193,6 +6593,16 @@ return view.extend({
});
return cardActionBtn;
})(),
(function () {
var cardQuotaBtn = E('button', {
'class': 'cbi-button cbi-button-neutral',
'title': _('Traffic Quota')
}, 'Q');
cardQuotaBtn.addEventListener('click', function () {
showTrafficQuotaModal(device);
});
return cardQuotaBtn;
})(),
(function () {
var cardDeleteBtn = E('button', {
'class': 'cbi-button cbi-button-reset',
@@ -6279,6 +6689,14 @@ return view.extend({
rulesContent
]);
})(),
(function () {
var quotaCell = buildTrafficQuotaCell(device.mac);
if (!quotaCell) return '';
return E('div', { 'class': 'device-card-section' }, [
E('div', { 'class': 'device-card-section-label' }, _('Traffic Quota')),
quotaCell
]);
})(),
// LAN流量(直接显示,不需要展开/收起)
E('div', { 'class': 'device-card-section', 'style': 'margin-top: 12px; padding-top: 12px; border-top: 1px solid rgba(0, 0, 0, 0.1);' }, [
E('div', { 'class': 'device-card-section-label' }, _('LAN Traffic')),
@@ -7499,12 +7917,25 @@ return view.extend({
});
}, 5000);
// 轮询获取流量配额状态(每1秒)
poll.add(function () {
return fetchAllTrafficQuotas().then(function () {
if (window.__bandixRenderTable) window.__bandixRenderTable();
if (currentQuotaDevice) {
renderTrafficQuotaForm(getTrafficQuotaForDevice(currentQuotaDevice.mac), quotaFormDirty);
}
});
}, 1);
// Traffic Statistics 不再自动刷新,改为手动查询
// 立即执行一次,不等待轮询
updateDeviceData();
refreshWhitelistStatus();
fetchAllScheduleRules();
fetchAllTrafficQuotas().then(function () {
if (window.__bandixRenderTable) window.__bandixRenderTable();
});
// 初始化时间范围查询功能
setTimeout(function () {
+90
View File
@@ -1258,3 +1258,93 @@ msgstr "ID de programa ancla de egreso TCX"
msgid "Used when tc_order is before/after. Must be a valid egress program id on the same interface."
msgstr "Se usa cuando tc_order es before/after. Debe ser un ID de programa de egreso valido en la misma interfaz."
msgid "Traffic Quota"
msgstr "Cuota de tráfico"
msgid "Quota Status"
msgstr "Estado de la cuota"
msgid "Minute Quota"
msgstr "Cuota por minuto"
msgid "Hourly Quota"
msgstr "Cuota por hora"
msgid "Daily Quota"
msgstr "Cuota diaria"
msgid "Weekly Quota"
msgstr "Cuota semanal"
msgid "Monthly Quota"
msgstr "Cuota mensual"
msgid "Lifetime Quota"
msgstr "Cuota total acumulada"
msgid "WAN upload and download are counted together. Enter 0 for unlimited."
msgstr "La subida y la descarga WAN se contabilizan juntas. Introduzca 0 para no establecer límite."
msgid "Not configured"
msgstr "Sin configurar"
msgid "Blocked"
msgstr "Bloqueado"
msgid "Active"
msgstr "Activa"
msgid "No quota usage data"
msgstr "No hay datos de uso de la cuota"
msgid "Delete Quota"
msgstr "Eliminar cuota"
msgid "Save Quota"
msgstr "Guardar cuota"
msgid "Usage starts when a quota is first saved."
msgstr "El uso comienza a contabilizarse al guardar una cuota por primera vez."
msgid "Minute"
msgstr "Minuto"
msgid "Lifetime"
msgstr "Total acumulado"
msgid "Quota exceeded"
msgstr "Cuota excedida"
msgid "Quota active"
msgstr "Cuota activa"
msgid "WAN traffic is blocked because a quota was reached."
msgstr "El tráfico WAN está bloqueado porque se alcanzó una cuota."
msgid "Quota blocked"
msgstr "Bloqueado por cuota"
msgid "Quota values must be non-negative and within the supported range."
msgstr "Los valores de cuota deben ser no negativos y estar dentro del rango admitido."
msgid "Failed to save traffic quota"
msgstr "No se pudo guardar la cuota de tráfico"
msgid "Delete Traffic Quota"
msgstr "Eliminar cuota de tráfico"
msgid "Delete this quota and all of its accumulated usage?"
msgstr "¿Eliminar esta cuota y todo su uso acumulado?"
msgid "Failed to delete traffic quota"
msgstr "No se pudo eliminar la cuota de tráfico"
msgid "Rules / Quota"
msgstr "Reglas / Cuota"
msgid "Failed to load traffic quotas"
msgstr "No se pudieron cargar las cuotas de tráfico"
msgid "Unavailable"
msgstr "No disponible"
+90
View File
@@ -1258,3 +1258,93 @@ msgstr "ID du programme d ancrage egress TCX"
msgid "Used when tc_order is before/after. Must be a valid egress program id on the same interface."
msgstr "Utilise lorsque tc_order est before/after. Doit etre un ID de programme egress valide sur la meme interface."
msgid "Traffic Quota"
msgstr "Quota de trafic"
msgid "Quota Status"
msgstr "État du quota"
msgid "Minute Quota"
msgstr "Quota par minute"
msgid "Hourly Quota"
msgstr "Quota par heure"
msgid "Daily Quota"
msgstr "Quota journalier"
msgid "Weekly Quota"
msgstr "Quota hebdomadaire"
msgid "Monthly Quota"
msgstr "Quota mensuel"
msgid "Lifetime Quota"
msgstr "Quota total cumulé"
msgid "WAN upload and download are counted together. Enter 0 for unlimited."
msgstr "Le trafic montant et descendant WAN est comptabilisé ensemble. Saisissez 0 pour un trafic illimité."
msgid "Not configured"
msgstr "Non configuré"
msgid "Blocked"
msgstr "Bloqué"
msgid "Active"
msgstr "Actif"
msgid "No quota usage data"
msgstr "Aucune donnée d'utilisation du quota"
msgid "Delete Quota"
msgstr "Supprimer le quota"
msgid "Save Quota"
msgstr "Enregistrer le quota"
msgid "Usage starts when a quota is first saved."
msgstr "Le suivi de l'utilisation commence lors du premier enregistrement d'un quota."
msgid "Minute"
msgstr "Minute"
msgid "Lifetime"
msgstr "Total cumulé"
msgid "Quota exceeded"
msgstr "Quota dépassé"
msgid "Quota active"
msgstr "Quota actif"
msgid "WAN traffic is blocked because a quota was reached."
msgstr "Le trafic WAN est bloqué car un quota a été atteint."
msgid "Quota blocked"
msgstr "Blocage par quota"
msgid "Quota values must be non-negative and within the supported range."
msgstr "Les valeurs de quota doivent être positives ou nulles et respecter la plage prise en charge."
msgid "Failed to save traffic quota"
msgstr "Impossible d'enregistrer le quota de trafic"
msgid "Delete Traffic Quota"
msgstr "Supprimer le quota de trafic"
msgid "Delete this quota and all of its accumulated usage?"
msgstr "Supprimer ce quota et toutes ses données d'utilisation cumulées ?"
msgid "Failed to delete traffic quota"
msgstr "Impossible de supprimer le quota de trafic"
msgid "Rules / Quota"
msgstr "Règles / Quota"
msgid "Failed to load traffic quotas"
msgstr "Impossible de charger les quotas de trafic"
msgid "Unavailable"
msgstr "Indisponible"
+90
View File
@@ -1258,3 +1258,93 @@ msgstr "TCX egressアンカープログラムID"
msgid "Used when tc_order is before/after. Must be a valid egress program id on the same interface."
msgstr "tc_orderがbefore/afterのときに使用します。同じインターフェース上の有効なegressプログラムIDである必要があります。"
msgid "Traffic Quota"
msgstr "トラフィッククォータ"
msgid "Quota Status"
msgstr "クォータの状態"
msgid "Minute Quota"
msgstr "1分あたりのクォータ"
msgid "Hourly Quota"
msgstr "1時間あたりのクォータ"
msgid "Daily Quota"
msgstr "1日あたりのクォータ"
msgid "Weekly Quota"
msgstr "1週間あたりのクォータ"
msgid "Monthly Quota"
msgstr "1か月あたりのクォータ"
msgid "Lifetime Quota"
msgstr "累計クォータ"
msgid "WAN upload and download are counted together. Enter 0 for unlimited."
msgstr "WANのアップロードとダウンロードは合算されます。無制限にするには0を入力してください。"
msgid "Not configured"
msgstr "未設定"
msgid "Blocked"
msgstr "ブロック中"
msgid "Active"
msgstr "有効"
msgid "No quota usage data"
msgstr "クォータ使用量データはありません"
msgid "Delete Quota"
msgstr "クォータを削除"
msgid "Save Quota"
msgstr "クォータを保存"
msgid "Usage starts when a quota is first saved."
msgstr "クォータを初めて保存した時点から使用量の計測を開始します。"
msgid "Minute"
msgstr "1分"
msgid "Lifetime"
msgstr "累計"
msgid "Quota exceeded"
msgstr "クォータ超過"
msgid "Quota active"
msgstr "クォータ有効"
msgid "WAN traffic is blocked because a quota was reached."
msgstr "クォータに達したためWANトラフィックがブロックされています。"
msgid "Quota blocked"
msgstr "クォータによりブロック"
msgid "Quota values must be non-negative and within the supported range."
msgstr "クォータ値は0以上で、サポートされている範囲内である必要があります。"
msgid "Failed to save traffic quota"
msgstr "トラフィッククォータを保存できませんでした"
msgid "Delete Traffic Quota"
msgstr "トラフィッククォータを削除"
msgid "Delete this quota and all of its accumulated usage?"
msgstr "このクォータと累積された使用量をすべて削除しますか?"
msgid "Failed to delete traffic quota"
msgstr "トラフィッククォータを削除できませんでした"
msgid "Rules / Quota"
msgstr "ルール / クォータ"
msgid "Failed to load traffic quotas"
msgstr "トラフィッククォータを読み込めませんでした"
msgid "Unavailable"
msgstr "利用不可"
+90
View File
@@ -1258,3 +1258,93 @@ msgstr "ID programu kotwicy TCX egress"
msgid "Used when tc_order is before/after. Must be a valid egress program id on the same interface."
msgstr "Uzywane, gdy tc_order to before/after. Musi to byc prawidlowe ID programu egress na tym samym interfejsie."
msgid "Traffic Quota"
msgstr "Limit transferu"
msgid "Quota Status"
msgstr "Stan limitu"
msgid "Minute Quota"
msgstr "Limit minutowy"
msgid "Hourly Quota"
msgstr "Limit godzinowy"
msgid "Daily Quota"
msgstr "Limit dzienny"
msgid "Weekly Quota"
msgstr "Limit tygodniowy"
msgid "Monthly Quota"
msgstr "Limit miesięczny"
msgid "Lifetime Quota"
msgstr "Łączny limit"
msgid "WAN upload and download are counted together. Enter 0 for unlimited."
msgstr "Ruch wysyłany i pobierany przez WAN jest sumowany. Wpisz 0, aby wyłączyć limit."
msgid "Not configured"
msgstr "Nie skonfigurowano"
msgid "Blocked"
msgstr "Zablokowano"
msgid "Active"
msgstr "Aktywny"
msgid "No quota usage data"
msgstr "Brak danych o wykorzystaniu limitu"
msgid "Delete Quota"
msgstr "Usuń limit"
msgid "Save Quota"
msgstr "Zapisz limit"
msgid "Usage starts when a quota is first saved."
msgstr "Naliczanie użycia rozpoczyna się po pierwszym zapisaniu limitu."
msgid "Minute"
msgstr "Minuta"
msgid "Lifetime"
msgstr "Łącznie"
msgid "Quota exceeded"
msgstr "Limit przekroczony"
msgid "Quota active"
msgstr "Limit aktywny"
msgid "WAN traffic is blocked because a quota was reached."
msgstr "Ruch WAN jest zablokowany, ponieważ osiągnięto limit."
msgid "Quota blocked"
msgstr "Blokada przez limit"
msgid "Quota values must be non-negative and within the supported range."
msgstr "Wartości limitu muszą być nieujemne i mieścić się w obsługiwanym zakresie."
msgid "Failed to save traffic quota"
msgstr "Nie udało się zapisać limitu transferu"
msgid "Delete Traffic Quota"
msgstr "Usuń limit transferu"
msgid "Delete this quota and all of its accumulated usage?"
msgstr "Usunąć ten limit i wszystkie dane o naliczonym użyciu?"
msgid "Failed to delete traffic quota"
msgstr "Nie udało się usunąć limitu transferu"
msgid "Rules / Quota"
msgstr "Reguły / Limit"
msgid "Failed to load traffic quotas"
msgstr "Nie udało się wczytać limitów transferu"
msgid "Unavailable"
msgstr "Niedostępne"
+90
View File
@@ -1258,3 +1258,93 @@ msgstr "ID якорной программы TCX egress"
msgid "Used when tc_order is before/after. Must be a valid egress program id on the same interface."
msgstr "Используется, когда tc_order имеет значение before/after. Должен быть корректный ID egress-программы на том же интерфейсе."
msgid "Traffic Quota"
msgstr "Квота трафика"
msgid "Quota Status"
msgstr "Состояние квоты"
msgid "Minute Quota"
msgstr "Минутная квота"
msgid "Hourly Quota"
msgstr "Часовая квота"
msgid "Daily Quota"
msgstr "Суточная квота"
msgid "Weekly Quota"
msgstr "Недельная квота"
msgid "Monthly Quota"
msgstr "Месячная квота"
msgid "Lifetime Quota"
msgstr "Общая квота"
msgid "WAN upload and download are counted together. Enter 0 for unlimited."
msgstr "Входящий и исходящий трафик WAN учитываются вместе. Введите 0, чтобы отключить ограничение."
msgid "Not configured"
msgstr "Не настроено"
msgid "Blocked"
msgstr "Заблокировано"
msgid "Active"
msgstr "Активна"
msgid "No quota usage data"
msgstr "Нет данных об использовании квоты"
msgid "Delete Quota"
msgstr "Удалить квоту"
msgid "Save Quota"
msgstr "Сохранить квоту"
msgid "Usage starts when a quota is first saved."
msgstr "Учет трафика начинается после первого сохранения квоты."
msgid "Minute"
msgstr "Минута"
msgid "Lifetime"
msgstr "Всего"
msgid "Quota exceeded"
msgstr "Квота превышена"
msgid "Quota active"
msgstr "Квота активна"
msgid "WAN traffic is blocked because a quota was reached."
msgstr "Трафик WAN заблокирован, так как достигнута квота."
msgid "Quota blocked"
msgstr "Блокировка по квоте"
msgid "Quota values must be non-negative and within the supported range."
msgstr "Значения квоты должны быть неотрицательными и находиться в поддерживаемом диапазоне."
msgid "Failed to save traffic quota"
msgstr "Не удалось сохранить квоту трафика"
msgid "Delete Traffic Quota"
msgstr "Удалить квоту трафика"
msgid "Delete this quota and all of its accumulated usage?"
msgstr "Удалить эту квоту и все накопленные данные об использовании?"
msgid "Failed to delete traffic quota"
msgstr "Не удалось удалить квоту трафика"
msgid "Rules / Quota"
msgstr "Правила / Квота"
msgid "Failed to load traffic quotas"
msgstr "Не удалось загрузить квоты трафика"
msgid "Unavailable"
msgstr "Недоступно"
+90
View File
@@ -1285,3 +1285,93 @@ msgstr "TCX 出站锚点程序 ID"
msgid "Used when tc_order is before/after. Must be a valid egress program id on the same interface."
msgstr "当 tc_order 为 before/after 时使用。必须是同一接口上的有效出站程序 ID。"
msgid "Traffic Quota"
msgstr "流量配额"
msgid "Quota Status"
msgstr "配额状态"
msgid "Hourly Quota"
msgstr "每小时配额"
msgid "Daily Quota"
msgstr "每天配额"
msgid "Weekly Quota"
msgstr "每周配额"
msgid "Monthly Quota"
msgstr "每月配额"
msgid "Lifetime Quota"
msgstr "累计总量配额"
msgid "WAN upload and download are counted together. Enter 0 for unlimited."
msgstr "WAN 上传和下载合并计算;输入 0 表示不限量。"
msgid "Not configured"
msgstr "未配置"
msgid "Blocked"
msgstr "已阻断"
msgid "Active"
msgstr "生效中"
msgid "No quota usage data"
msgstr "暂无配额用量数据"
msgid "Delete Quota"
msgstr "删除配额"
msgid "Save Quota"
msgstr "保存配额"
msgid "Usage starts when a quota is first saved."
msgstr "首次保存配额后开始累计用量。"
msgid "Lifetime"
msgstr "累计"
msgid "Quota exceeded"
msgstr "配额已用尽"
msgid "Quota active"
msgstr "配额生效中"
msgid "WAN traffic is blocked because a quota was reached."
msgstr "因达到流量配额,WAN 流量已被阻断。"
msgid "Quota blocked"
msgstr "配额阻断"
msgid "Quota values must be non-negative and within the supported range."
msgstr "配额必须是支持范围内的非负数。"
msgid "Failed to save traffic quota"
msgstr "保存流量配额失败"
msgid "Delete Traffic Quota"
msgstr "删除流量配额"
msgid "Delete this quota and all of its accumulated usage?"
msgstr "确定删除此配额及其全部累计用量吗?"
msgid "Failed to delete traffic quota"
msgstr "删除流量配额失败"
msgid "Rules / Quota"
msgstr "规则 / 配额"
msgid "Failed to load traffic quotas"
msgstr "加载流量配额失败"
msgid "Unavailable"
msgstr "不可用"
msgid "Minute Quota"
msgstr "每分钟配额"
msgid "Minute"
msgstr "每分钟"
+90
View File
@@ -1258,3 +1258,93 @@ msgstr "TCX 出站錨點程式 ID"
msgid "Used when tc_order is before/after. Must be a valid egress program id on the same interface."
msgstr "當 tc_order 為 before/after 時使用。必須是同一介面上的有效出站程式 ID。"
msgid "Traffic Quota"
msgstr "流量配額"
msgid "Quota Status"
msgstr "配額狀態"
msgid "Minute Quota"
msgstr "每分鐘配額"
msgid "Hourly Quota"
msgstr "每小時配額"
msgid "Daily Quota"
msgstr "每天配額"
msgid "Weekly Quota"
msgstr "每週配額"
msgid "Monthly Quota"
msgstr "每月配額"
msgid "Lifetime Quota"
msgstr "累計總量配額"
msgid "WAN upload and download are counted together. Enter 0 for unlimited."
msgstr "WAN 上傳和下載合併計算;輸入 0 表示不限量。"
msgid "Not configured"
msgstr "未設定"
msgid "Blocked"
msgstr "已阻斷"
msgid "Active"
msgstr "生效中"
msgid "No quota usage data"
msgstr "暫無配額用量資料"
msgid "Delete Quota"
msgstr "刪除配額"
msgid "Save Quota"
msgstr "儲存配額"
msgid "Usage starts when a quota is first saved."
msgstr "首次儲存配額後開始累計用量。"
msgid "Minute"
msgstr "每分鐘"
msgid "Lifetime"
msgstr "累計"
msgid "Quota exceeded"
msgstr "配額已用盡"
msgid "Quota active"
msgstr "配額生效中"
msgid "WAN traffic is blocked because a quota was reached."
msgstr "因達到流量配額,WAN 流量已被阻斷。"
msgid "Quota blocked"
msgstr "配額阻斷"
msgid "Quota values must be non-negative and within the supported range."
msgstr "配額必須是支援範圍內的非負數。"
msgid "Failed to save traffic quota"
msgstr "儲存流量配額失敗"
msgid "Delete Traffic Quota"
msgstr "刪除流量配額"
msgid "Delete this quota and all of its accumulated usage?"
msgstr "確定刪除此配額及其全部累計用量嗎?"
msgid "Failed to delete traffic quota"
msgstr "刪除流量配額失敗"
msgid "Rules / Quota"
msgstr "規則 / 配額"
msgid "Failed to load traffic quotas"
msgstr "載入流量配額失敗"
msgid "Unavailable"
msgstr "無法使用"
@@ -19,6 +19,7 @@ readonly BANDIX_TRAFFIC_USAGE_INCREMENTS_API="$BANDIX_API_BASE/api/traffic/usage
readonly BANDIX_RATE_LIMIT_WHITELIST_API="$BANDIX_API_BASE/api/traffic/rate_limit/whitelist"
readonly BANDIX_RATE_LIMIT_WHITELIST_ENABLED_API="$BANDIX_API_BASE/api/traffic/rate_limit/whitelist/enabled"
readonly BANDIX_RATE_LIMIT_DEFAULT_API="$BANDIX_API_BASE/api/traffic/rate_limit/default"
readonly BANDIX_TRAFFIC_QUOTAS_API="$BANDIX_API_BASE/api/traffic/quotas"
# 通用函数:创建简单的JSON响应
make_value() {
@@ -134,6 +135,71 @@ set_default_rate_limit() {
echo "$response"
}
get_traffic_quotas() {
local response=$(curl -s --connect-timeout 2 --max-time 5 -X GET "$BANDIX_TRAFFIC_QUOTAS_API" 2>/dev/null)
if [ $? -ne 0 ] || [ -z "$response" ]; then
make_error "Failed to connect to Bandix service"
return
fi
echo "$response"
}
set_traffic_quota() {
local mac="$1"
local minute_bytes="$2"
local hourly_bytes="$3"
local daily_bytes="$4"
local weekly_bytes="$5"
local monthly_bytes="$6"
local total_bytes="$7"
if [ -z "$mac" ]; then
make_error "MAC address is required"
return
fi
for value in "$minute_bytes" "$hourly_bytes" "$daily_bytes" "$weekly_bytes" "$monthly_bytes" "$total_bytes"; do
case "$value" in
''|*[!0-9]*)
make_error "Quota values must be non-negative integers"
return
;;
esac
done
local mac_escaped=$(escape_json_string "$mac")
local request_data="{
\"mac\": \"$mac_escaped\",
\"minute_bytes\": $minute_bytes,
\"hourly_bytes\": $hourly_bytes,
\"daily_bytes\": $daily_bytes,
\"weekly_bytes\": $weekly_bytes,
\"monthly_bytes\": $monthly_bytes,
\"total_bytes\": $total_bytes
}"
local response=$(curl -s --connect-timeout 3 --max-time 10 -X POST -H "Content-Type: application/json" -d "$request_data" "$BANDIX_TRAFFIC_QUOTAS_API" 2>/dev/null)
if [ $? -eq 0 ] && [ -n "$response" ] && echo "$response" | grep -q '"status":[[:space:]]*"success"'; then
make_success "Traffic quota saved successfully"
else
make_error "Failed to save traffic quota"
fi
}
delete_traffic_quota() {
local mac="$1"
if [ -z "$mac" ]; then
make_error "MAC address is required"
return
fi
local mac_escaped=$(escape_json_string "$mac")
local request_data="{\"mac\": \"$mac_escaped\"}"
local response=$(curl -s --connect-timeout 3 --max-time 10 -X DELETE -H "Content-Type: application/json" -d "$request_data" "$BANDIX_TRAFFIC_QUOTAS_API" 2>/dev/null)
if [ $? -eq 0 ] && [ -n "$response" ] && echo "$response" | grep -q '"status":[[:space:]]*"success"'; then
make_success "Traffic quota deleted successfully"
else
make_error "Failed to delete traffic quota"
fi
}
# 删除设备
delete_device() {
local mac="$1"
@@ -1348,6 +1414,23 @@ case "$1" in
json_add_int "wan_rx_rate_limit"
json_add_int "wan_tx_rate_limit"
json_close_object
json_add_object "getTrafficQuotas"
json_close_object
json_add_object "setTrafficQuota"
json_add_string "mac"
json_add_int "minute_bytes"
json_add_int "hourly_bytes"
json_add_int "daily_bytes"
json_add_int "weekly_bytes"
json_add_int "monthly_bytes"
json_add_int "total_bytes"
json_close_object
json_add_object "deleteTrafficQuota"
json_add_string "mac"
json_close_object
json_dump
json_cleanup
@@ -1793,6 +1876,57 @@ case "$1" in
fi
set_default_rate_limit "$wan_rx_rate_limit" "$wan_tx_rate_limit"
;;
getTrafficQuotas)
get_traffic_quotas
;;
setTrafficQuota)
mac=""
minute_bytes=""
hourly_bytes=""
daily_bytes=""
weekly_bytes=""
monthly_bytes=""
total_bytes=""
input=""
if read -t 1 -r input; then :; fi
if [ -n "$input" ]; then
mac="$(echo "$input" | jsonfilter -e '$[0]' 2>/dev/null)"
[ -z "$mac" ] && mac="$(echo "$input" | jsonfilter -e '$.mac' 2>/dev/null)"
minute_bytes="$(echo "$input" | jsonfilter -e '$[1]' 2>/dev/null)"
[ -z "$minute_bytes" ] && minute_bytes="$(echo "$input" | jsonfilter -e '$.minute_bytes' 2>/dev/null)"
hourly_bytes="$(echo "$input" | jsonfilter -e '$[2]' 2>/dev/null)"
[ -z "$hourly_bytes" ] && hourly_bytes="$(echo "$input" | jsonfilter -e '$.hourly_bytes' 2>/dev/null)"
daily_bytes="$(echo "$input" | jsonfilter -e '$[3]' 2>/dev/null)"
[ -z "$daily_bytes" ] && daily_bytes="$(echo "$input" | jsonfilter -e '$.daily_bytes' 2>/dev/null)"
weekly_bytes="$(echo "$input" | jsonfilter -e '$[4]' 2>/dev/null)"
[ -z "$weekly_bytes" ] && weekly_bytes="$(echo "$input" | jsonfilter -e '$.weekly_bytes' 2>/dev/null)"
monthly_bytes="$(echo "$input" | jsonfilter -e '$[5]' 2>/dev/null)"
[ -z "$monthly_bytes" ] && monthly_bytes="$(echo "$input" | jsonfilter -e '$.monthly_bytes' 2>/dev/null)"
total_bytes="$(echo "$input" | jsonfilter -e '$[6]' 2>/dev/null)"
[ -z "$total_bytes" ] && total_bytes="$(echo "$input" | jsonfilter -e '$.total_bytes' 2>/dev/null)"
else
mac="$3"
minute_bytes="$4"
hourly_bytes="$5"
daily_bytes="$6"
weekly_bytes="$7"
monthly_bytes="$8"
total_bytes="$9"
fi
set_traffic_quota "$mac" "$minute_bytes" "$hourly_bytes" "$daily_bytes" "$weekly_bytes" "$monthly_bytes" "$total_bytes"
;;
deleteTrafficQuota)
mac=""
input=""
if read -t 1 -r input; then :; fi
if [ -n "$input" ]; then
mac="$(echo "$input" | jsonfilter -e '$[0]' 2>/dev/null)"
[ -z "$mac" ] && mac="$(echo "$input" | jsonfilter -e '$.mac' 2>/dev/null)"
else
mac="$3"
fi
delete_traffic_quota "$mac"
;;
esac
;;
esac
@@ -26,7 +26,8 @@
"installUpdate",
"getTrafficUsageRanking",
"getTrafficUsageIncrements",
"getRateLimitWhitelist"
"getRateLimitWhitelist",
"getTrafficQuotas"
]
},
"uci": [
@@ -64,7 +65,10 @@
"addRateLimitWhitelist",
"deleteRateLimitWhitelist",
"setDefaultRateLimit",
"updateScheduleLimit"
"updateScheduleLimit",
"getTrafficQuotas",
"setTrafficQuota",
"deleteTrafficQuota"
]
},
"uci": [
@@ -72,4 +76,4 @@
]
}
}
}
}
+2 -2
View File
@@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-clashoo
PKG_VERSION:=1.30.0
PKG_RELEASE:=11
PKG_RELEASE:=12
PKG_MAINTAINER:=kenzok8
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
@@ -75,7 +75,7 @@ define Package/luci-i18n-clashoo-zh-cn
SECTION:=luci
CATEGORY:=LuCI
TITLE:=luci-app-clashoo - Simplified Chinese (zh-cn)
DEPENDS:=+luci-app-clashoo
DEPENDS:=luci-app-clashoo
DEFAULT:=LUCI_LANG_zh_Hans||(ALL&&m)
HIDDEN:=1
PKGARCH:=all
@@ -3361,9 +3361,9 @@ return { success: false, error: 'missing_yq', message: '缺少 yq,无法注入
if (!access(exploded, "r")) {
system("cp -f " + shell_quote(tmp_tpl) + " " + shell_quote(exploded));
}
/* proxy-providersrule-providers 两处都注入(兼容不同模板格式) */
/* 只替换 proxy-providers.urlrule-providers 指向规则集保持原样 */
let inject_cmd = "URL=" + shell_quote(sub_url)
+ " yq e '.[\"proxy-providers\"][].url = env(URL) | .[\"rule-providers\"][].url = env(URL)' "
+ " yq e '.[\"proxy-providers\"][].url = env(URL)' "
+ shell_quote(exploded) + " > " + shell_quote(tmp_out);
if (system(inject_cmd) != 0 || !access(tmp_out, "r")) {
system("rm -f " + shell_quote(exploded));
+13 -13
View File
@@ -1,7 +1,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=bandix
PKG_VERSION:=0.12.9
PKG_VERSION:=0.12.10
PKG_RELEASE:=1
PKG_LICENSE:=Apache-2.0
@@ -13,7 +13,7 @@ include $(INCLUDE_DIR)/package.mk
include $(TOPDIR)/feeds/packages/lang/rust/rust-values.mk
# 二进制文件的文件名和URL
RUST_BANDIX_VERSION:=0.12.9
RUST_BANDIX_VERSION:=0.12.10
RUST_BINARY_FILENAME:=bandix-$(RUST_BANDIX_VERSION)-$(RUSTC_TARGET_ARCH).tar.gz
@@ -23,7 +23,7 @@ PKG_SOURCE_URL:=https://github.com/timsaya/bandix/releases/download/v$(RUST_BAND
# 修正二进制文件校验值
ifeq ($(ARCH),aarch64)
PKG_HASH:=17803eeb6964187626e6af2e2b0a3b081d87a8017ff2b6505ba313b0c7b8ba7f
PKG_HASH:=653e554a95ff1a336def82b9b4899466b6fc62a6e8fd42ff786eaedebfe0b911
else ifeq ($(ARCH),arm) # update.sh skip this tag, do not delete this comment
# Ref https://github.com/openwrt/packages/blob/master/lang/rust/rust-values.mk
@@ -39,28 +39,28 @@ else ifeq ($(ARCH),arm) # update.sh skip this tag, do not delete this comment
endif
ifeq ($(ARM_CPU_TYPE),arm-armel)
PKG_HASH:=cbf9cf705218211e0a5cd1427049632aa40086831feee2994e9d4b7b2cf46ab4
PKG_HASH:=4b6c96715fbda3e2e60c41aa72286fb10da09997a05ed98311cf377c22848e65
else ifeq ($(ARM_CPU_TYPE),arm-armhf)
PKG_HASH:=2901c5f98e77fce574bcaef1aa8c20acd58ca341f3f3bd5f3bc80d745946f632
PKG_HASH:=4280c24049fb25743a8876b7437e4954fbeb00e58ce940c509cdcc70b7cea576
else ifeq ($(ARM_CPU_TYPE),armv5te-armel)
PKG_HASH:=390840c939cec718570cd8cbf50ed130fd02d7f75b80d74af251bd1ecd0f43a8
PKG_HASH:=7ba5247c674ace48c88e9ea65c4cb6ab754a5e5dd1d4cd2911442018545c33a8
else ifeq ($(ARM_CPU_TYPE),armv7-armel)
PKG_HASH:=965f9e88398f42cf5535612b58629b89c058db46afaf3c814929a7cfc9fa4e3b
PKG_HASH:=6c7f4454b3100fc448149caf8cb97dbcb75b284bab93b53dc885a370c496cc29
else ifeq ($(ARM_CPU_TYPE),armv7-armhf)
PKG_HASH:=f47df37959f73b2188f89faf8c9a3217966ca4c1389f695886f263d28911e8fb
PKG_HASH:=41377aa71c2a2da4481112c45b0129f167b96bc4b0c55d3f77309b4b82001891
else
PKG_HASH:=dummy
endif
else ifeq ($(ARCH),mips)
PKG_HASH:=318587b09b37d1ab8af96466e5191ce32c4dbc92294f5c55826ebe1a88c7bcab
PKG_HASH:=a08fae7eae3c852a8b6c310276c881f135eabf86c18f689edd134800dc270e71
else ifeq ($(ARCH),mipsel)
PKG_HASH:=fd1b12b7cd2034aa8afa89901d0d38784528f10921b6c0f806dac9dcbf523085
PKG_HASH:=499134680d7667fd256425d0f86b846dc4d00023b2315c48ed5337a7dae65926
else ifeq ($(ARCH),powerpc64)
PKG_HASH:=24dab3f89f8930cb925ec1a20d73111e09bae7e6a87954b56a681395660f6ed4
PKG_HASH:=f40f51453c274774bdf64a170fe3ea1d87cf3761ba4a679ca8f08bdd2819f2e4
else ifeq ($(ARCH),riscv64)
PKG_HASH:=916bf42c60c49df5c3ee6f4a60ce542d2b080788445b9bf47f3322eb9a5b66cf
PKG_HASH:=4b18915eab8e3435fb6cc1d50298ad84708b14921fb1b60713f37864140aa1ab
else ifeq ($(ARCH),x86_64)
PKG_HASH:=4909cf2e80861d082c4d4870950259d8c6f14e606f9dfa16c92514f178f3ae40
PKG_HASH:=aeab01d678f92f176ba41d08363765ac53719bdaaff26bbd0e93c4fdc12bea20
else
PKG_HASH:=dummy
endif
+2 -2
View File
@@ -21,13 +21,13 @@ define Download/geoip
HASH:=1cba1f0982cf62502fa079c66047c3d0c608196da5b3305671e68f60e917a482
endef
GEOSITE_VER:=20260904020013
GEOSITE_VER:=20260906035830
GEOSITE_FILE:=dlc.dat.$(GEOSITE_VER)
define Download/geosite
URL:=https://github.com/v2fly/domain-list-community/releases/download/$(GEOSITE_VER)/
URL_FILE:=dlc.dat
FILE:=$(GEOSITE_FILE)
HASH:=f82f26c015f9726c763d96a5f658e5b31b285dc094a985e718051e421f350ed6
HASH:=8d401b06cde720cdfa9eb0e03751cc73ded08c6d53fa80f92d3f24798382eb92
endef
GEOSITE_IRAN_VER:=202608310142