mirror of
https://github.com/caiwx86/small-packages.git
synced 2026-09-14 12:24:20 +08:00
265 lines
18 KiB
JavaScript
265 lines
18 KiB
JavaScript
'use strict';
|
|
'require baseclass';
|
|
'require rpc';
|
|
'require ui';
|
|
|
|
(function () {
|
|
if (document.getElementById('clashoo-toast-style')) return;
|
|
var css = [
|
|
'#clashoo-toast-stack{position:fixed;top:20px;right:20px;z-index:99999;display:flex;flex-direction:column;gap:8px;max-width:380px;pointer-events:none;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC",sans-serif}',
|
|
'.clashoo-toast{background:rgba(33,37,41,.92);color:#fff;font-size:13px;line-height:1.5;padding:10px 14px;border-radius:8px;box-shadow:0 4px 14px rgba(0,0,0,.18);opacity:0;transform:translateX(24px);transition:opacity .25s ease,transform .25s ease;pointer-events:auto;cursor:pointer;word-break:break-word}',
|
|
'.clashoo-toast.show{opacity:1;transform:translateX(0)}',
|
|
'.clashoo-toast.err{background:rgba(198,40,40,.94)}',
|
|
'.clashoo-toast.ok{background:rgba(46,125,50,.94)}',
|
|
'.clashoo-toast a{color:#8ec5ff;text-decoration:underline}',
|
|
'.clashoo-toast a:hover{color:#b3d7ff}'
|
|
].join('');
|
|
var s = document.createElement('style');
|
|
s.id = 'clashoo-toast-style';
|
|
s.textContent = css;
|
|
document.head.appendChild(s);
|
|
})();
|
|
|
|
function _clashooToastStack() {
|
|
var el = document.getElementById('clashoo-toast-stack');
|
|
if (!el) {
|
|
el = document.createElement('div');
|
|
el.id = 'clashoo-toast-stack';
|
|
document.body.appendChild(el);
|
|
}
|
|
return el;
|
|
}
|
|
|
|
function _clashooLinkify(safeText) {
|
|
var logUrl = L.url('admin/services/clashoo/system');
|
|
return safeText.replace(/(进度|日志)/g,
|
|
'<a href="' + logUrl + '">$1</a>');
|
|
}
|
|
|
|
function _clashooToast(msg, opts) {
|
|
opts = opts || {};
|
|
var stack = _clashooToastStack();
|
|
var el = document.createElement('div');
|
|
el.className = 'clashoo-toast' + (opts.kind ? ' ' + opts.kind : '');
|
|
var text;
|
|
if (msg && msg.nodeType === 1) text = msg.textContent || '';
|
|
else if (typeof msg === 'string') text = msg;
|
|
else text = String(msg || '');
|
|
var safe = text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
el.innerHTML = _clashooLinkify(safe);
|
|
stack.appendChild(el);
|
|
requestAnimationFrame(function () { el.classList.add('show'); });
|
|
|
|
var dur = opts.duration || 3500;
|
|
var timer = null, remain = dur, start = 0;
|
|
function close() {
|
|
if (timer) { clearTimeout(timer); timer = null; }
|
|
el.classList.remove('show');
|
|
setTimeout(function () { if (el.parentNode) el.parentNode.removeChild(el); }, 280);
|
|
}
|
|
function arm() { start = Date.now(); timer = setTimeout(close, remain); }
|
|
el.addEventListener('mouseenter', function () {
|
|
if (timer) { clearTimeout(timer); timer = null; remain = Math.max(800, remain - (Date.now() - start)); }
|
|
});
|
|
el.addEventListener('mouseleave', arm);
|
|
el.addEventListener('click', function (ev) {
|
|
if (ev.target && ev.target.tagName === 'A') return;
|
|
close();
|
|
});
|
|
arm();
|
|
return { close: close };
|
|
}
|
|
|
|
(function () {
|
|
if (!ui || ui._clashooPatched) return;
|
|
ui._clashooPatched = true;
|
|
var orig = ui.addNotification.bind(ui);
|
|
ui.addNotification = function (title, children, classes) {
|
|
try {
|
|
var text = '';
|
|
var collect = function (c) {
|
|
if (c == null) return;
|
|
if (Array.isArray(c)) { c.forEach(collect); return; }
|
|
if (c.nodeType === 1) { text += (c.textContent || '') + ' '; return; }
|
|
text += String(c) + ' ';
|
|
};
|
|
if (title) text += title + ' ';
|
|
collect(children);
|
|
text = text.trim();
|
|
|
|
var kind = '';
|
|
var cls = classes ? String(classes) : '';
|
|
if (/error|danger/i.test(cls) || /失败|错误/.test(text)) kind = 'err';
|
|
else if (/success/i.test(cls) || /成功/.test(text)) kind = 'ok';
|
|
|
|
_clashooToast(text, { kind: kind });
|
|
return null;
|
|
} catch (e) {
|
|
return orig(title, children, classes);
|
|
}
|
|
};
|
|
})();
|
|
|
|
const callStatus = rpc.declare({ object: 'luci.clashoo', method: 'status', expect: {} });
|
|
const callStart = rpc.declare({ object: 'luci.clashoo', method: 'start', expect: {} });
|
|
const callStop = rpc.declare({ object: 'luci.clashoo', method: 'stop', expect: {} });
|
|
const callReload = rpc.declare({ object: 'luci.clashoo', method: 'reload', expect: {} });
|
|
const callRestart = rpc.declare({ object: 'luci.clashoo', method: 'restart', expect: {} });
|
|
const callVersion = rpc.declare({ object: 'luci.clashoo', method: 'version', expect: {} });
|
|
const callListProf = rpc.declare({ object: 'luci.clashoo', method: 'list_profiles', expect: {} });
|
|
const callListConfigs = rpc.declare({ object: 'luci.clashoo', method: 'list_configs', expect: {} });
|
|
const callSetConfig = rpc.declare({ object: 'luci.clashoo', method: 'set_config', params: ['name'], expect: {} });
|
|
const callSetMode = rpc.declare({ object: 'luci.clashoo', method: 'set_mode', params: ['mode'], expect: {} });
|
|
const callSetProxyMode = rpc.declare({ object: 'luci.clashoo', method: 'set_proxy_mode', params: ['mode'], expect: {} });
|
|
const callSetCore = rpc.declare({ object: 'luci.clashoo', method: 'set_core', params: ['core', 'dcore', 'action'], expect: {} });
|
|
const callSetPanel = rpc.declare({ object: 'luci.clashoo', method: 'set_panel', params: ['name'], expect: {} });
|
|
const callUpdatePanel = rpc.declare({ object: 'luci.clashoo', method: 'update_panel', params: ['name'], expect: {} });
|
|
const callPanelStatus = rpc.declare({ object: 'luci.clashoo', method: 'panel_status', expect: {} });
|
|
const callReadLog = rpc.declare({ object: 'luci.clashoo', method: 'read_log', expect: {} });
|
|
const callReadRealLog = rpc.declare({ object: 'luci.clashoo', method: 'read_real_log', expect: {} });
|
|
const callClearLog = rpc.declare({ object: 'luci.clashoo', method: 'clear_log', expect: {} });
|
|
const callReadUpdateLog = rpc.declare({ object: 'luci.clashoo', method: 'read_update_log', expect: {} });
|
|
const callClearUpdateLog= rpc.declare({ object: 'luci.clashoo', method: 'clear_update_log', expect: {} });
|
|
const callReadGeoipLog = rpc.declare({ object: 'luci.clashoo', method: 'read_geoip_log', expect: {} });
|
|
const callClearGeoipLog = rpc.declare({ object: 'luci.clashoo', method: 'clear_geoip_log', expect: {} });
|
|
const callReadCoreLog = rpc.declare({ object: 'luci.clashoo', method: 'read_core_log', expect: {} });
|
|
const callClearCoreLog = rpc.declare({ object: 'luci.clashoo', method: 'clear_core_log', expect: {} });
|
|
const callReadUpdateMergedLog = rpc.declare({ object: 'luci.clashoo', method: 'read_update_merged_log', expect: {} });
|
|
const callClearUpdateMergedLog = rpc.declare({ object: 'luci.clashoo', method: 'clear_update_merged_log', expect: {} });
|
|
const callGetCpuArch = rpc.declare({ object: 'luci.clashoo', method: 'get_cpu_arch', expect: {} });
|
|
const callDownloadCore = rpc.declare({ object: 'luci.clashoo', method: 'download_core', expect: {} });
|
|
const callUpdateGeoip = rpc.declare({ object: 'luci.clashoo', method: 'update_geoip', expect: {} });
|
|
const callGetGeoipVersion = rpc.declare({ object: 'luci.clashoo', method: 'get_geoip_version', expect: {} });
|
|
const callComponentStatus = rpc.declare({ object: 'luci.clashoo', method: 'component_status', expect: {} });
|
|
const callComponentUpdate = rpc.declare({ object: 'luci.clashoo', method: 'component_update', params: ['component', 'variant'], expect: {} });
|
|
const callComponentUpdateLog = rpc.declare({ object: 'luci.clashoo', method: 'component_update_log', expect: {} });
|
|
const callComponentCheckUpdates = rpc.declare({ object: 'luci.clashoo', method: 'component_check_updates', expect: {} });
|
|
const callUpdateChinaIp = rpc.declare({ object: 'luci.clashoo', method: 'update_china_ip', expect: {} });
|
|
const callGetLogStatus = rpc.declare({ object: 'luci.clashoo', method: 'get_log_status', expect: {} });
|
|
const callAccessCheck = rpc.declare({ object: 'luci.clashoo', method: 'access_check', expect: {} });
|
|
const callAccessCheckRefresh= rpc.declare({ object: 'luci.clashoo', method: 'access_check_refresh',expect: {} });
|
|
const callOverviewStats = rpc.declare({ object: 'luci.clashoo', method: 'overview_stats', expect: {} });
|
|
const callOverview = rpc.declare({ object: 'luci.clashoo', method: 'overview', expect: {} });
|
|
const callSmartFlushCache = rpc.declare({ object: 'luci.clashoo', method: 'smart_flush_cache', expect: {} });
|
|
const callListSingboxProfiles = rpc.declare({ object: 'luci.clashoo', method: 'list_singbox_profiles', expect: {} });
|
|
const callGetSingboxProfile = rpc.declare({ object: 'luci.clashoo', method: 'get_singbox_profile', params: ['name'], expect: {} });
|
|
const callSaveSingboxProfileChunk = rpc.declare({ object: 'luci.clashoo', method: 'save_singbox_profile_chunk', params: ['name', 'content', 'index', 'total'], expect: {} });
|
|
const callSetSingboxProfile = rpc.declare({ object: 'luci.clashoo', method: 'set_singbox_profile', params: ['name'], expect: {} });
|
|
const callDeleteSingboxProfile = rpc.declare({ object: 'luci.clashoo', method: 'delete_singbox_profile', params: ['name'], expect: {} });
|
|
const callCreateSingboxConfig = rpc.declare({ object: 'luci.clashoo', method: 'create_singbox_config', params: ['sub_url', 'name'], expect: {} });
|
|
const callCommitConfig = rpc.declare({ object: 'luci.clashoo', method: 'commit_config', expect: {} });
|
|
const callDnsAutoSetup = rpc.declare({ object: 'luci.clashoo', method: 'dns_auto_setup', expect: {} });
|
|
const callFetchSingboxNative = rpc.declare({ object: 'luci.clashoo', method: 'fetch_singbox_native', params: ['url', 'name'], expect: {} });
|
|
const callUpdateSingboxNative = rpc.declare({ object: 'luci.clashoo', method: 'update_singbox_native', params: ['name'], expect: {} });
|
|
|
|
// 把脚本输出的英文 log 行翻成中文(去掉前导时间戳)
|
|
function localizeLogLine(line) {
|
|
var msg = String(line || '').replace(/^\s*\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}\s*-?\s*/, '');
|
|
var rules = [
|
|
// LightGBM 模型更新
|
|
[/^Start downloading LightGBM model from:?\s*(.*)$/i, _("Start downloading LightGBM model: $1")],
|
|
[/^Model unchanged, no update needed$/i, _("Model is already up to date")],
|
|
[/^LightGBM model updated successfully$/i, _("LightGBM model updated successfully")],
|
|
[/^Download failed \(rc=(\d+)\)$/i, _("Download failed (error code $1)")],
|
|
[/^Failed to install model to (.*)$/i, _("Model install failed: $1")],
|
|
[/^No curl or wget found$/i, _("curl or wget not found")],
|
|
// GeoIP / GeoSite 更新
|
|
[/^Updating (.+)$/i, _("Updating $1")],
|
|
[/^(.+) updated$/i, _("$1 updated")],
|
|
[/^GeoIP update completed, apply on next Clashoo restart$/i, _("GeoIP update completed, applies after Clashoo restarts")],
|
|
[/^GeoIP update completed$/i, _("GeoIP update completed")],
|
|
[/^GeoIP update failed$/i, _("GeoIP update failed")],
|
|
// 通用
|
|
[/^Download succeeded$/i, _("Download succeeded")],
|
|
[/^Already up to date$/i, _("Already up to date")]
|
|
];
|
|
for (var i = 0; i < rules.length; i++) {
|
|
if (rules[i][0].test(msg)) return msg.replace(rules[i][0], rules[i][1]);
|
|
}
|
|
return msg;
|
|
}
|
|
|
|
return baseclass.extend({
|
|
localizeLogLine: localizeLogLine,
|
|
status: function () { return L.resolveDefault(callStatus(), {}); },
|
|
start: function () { return L.resolveDefault(callStart(), {}); },
|
|
stop: function () { return L.resolveDefault(callStop(), {}); },
|
|
reload: function () { return L.resolveDefault(callReload(), {}); },
|
|
restart: function () { return L.resolveDefault(callRestart(), {}); },
|
|
version: function () { return L.resolveDefault(callVersion(), {}); },
|
|
|
|
listProfiles: function () { return L.resolveDefault(callListProf(), { profiles: [] }).then(r => r.profiles || []); },
|
|
listConfigs: function () { return L.resolveDefault(callListConfigs(), { configs: [], current: '' }); },
|
|
setConfig: function (name) { return L.resolveDefault(callSetConfig(name), {}); },
|
|
setMode: function (mode) { return L.resolveDefault(callSetMode(mode), {}); },
|
|
setProxyMode: function (mode) { return L.resolveDefault(callSetProxyMode(mode), {}); },
|
|
setCore: function (core, dcore, action) { return L.resolveDefault(callSetCore(core, dcore, action), {}); },
|
|
setPanel: function (name) { return L.resolveDefault(callSetPanel(name), {}); },
|
|
updatePanel: function (name) { return L.resolveDefault(callUpdatePanel(name || 'zashboard'), {}); },
|
|
panelStatus: function () { return L.resolveDefault(callPanelStatus(), {}); },
|
|
|
|
readLog: function () { return L.resolveDefault(callReadLog(), { content: '' }).then(r => r.content || ''); },
|
|
readRealLog: function () { return L.resolveDefault(callReadRealLog(), { content: '' }).then(r => r.content || ''); },
|
|
clearLog: function () { return L.resolveDefault(callClearLog(), {}); },
|
|
readUpdateLog: function () { return L.resolveDefault(callReadUpdateLog(), { content: '' }).then(r => r.content || ''); },
|
|
clearUpdateLog: function () { return L.resolveDefault(callClearUpdateLog(), {}); },
|
|
readGeoipLog: function () { return L.resolveDefault(callReadGeoipLog(), { content: '' }).then(r => r.content || ''); },
|
|
clearGeoipLog: function () { return L.resolveDefault(callClearGeoipLog(), {}); },
|
|
readCoreLog: function () { return L.resolveDefault(callReadCoreLog(), { content: '' }).then(r => r.content || ''); },
|
|
clearCoreLog: function () { return L.resolveDefault(callClearCoreLog(), {}); },
|
|
readUpdateMergedLog: function () { return L.resolveDefault(callReadUpdateMergedLog(), { content: '' }).then(r => r.content || ''); },
|
|
clearUpdateMergedLog: function () { return L.resolveDefault(callClearUpdateMergedLog(), {}); },
|
|
|
|
getCpuArch: function () { return L.resolveDefault(callGetCpuArch(), { arch: '' }).then(r => r.arch || ''); },
|
|
downloadCore: function (dcore, arch) { return L.resolveDefault(callDownloadCore({ dcore: dcore, arch: arch }), {}); },
|
|
updateGeoip: function () { return L.resolveDefault(callUpdateGeoip(), {}); },
|
|
getGeoipVersion: function () { return L.resolveDefault(callGetGeoipVersion(), { version: '' }); },
|
|
componentStatus: function () { return L.resolveDefault(callComponentStatus(), { running: false, components: [] }); },
|
|
componentUpdate: function (component, variant) { return L.resolveDefault(callComponentUpdate(component, variant || ''), { success: false }); },
|
|
componentUpdateLog: function () { return L.resolveDefault(callComponentUpdateLog(), { running: false, content: '' }); },
|
|
componentCheckUpdates: function () { return L.resolveDefault(callComponentCheckUpdates(), { ok: false, latest: {} }); },
|
|
updateChinaIp: function () { return L.resolveDefault(callUpdateChinaIp(), {}); },
|
|
getLogStatus: function () { return L.resolveDefault(callGetLogStatus(), {}); },
|
|
accessCheck: function () { return L.resolveDefault(callAccessCheck(), {}); },
|
|
accessCheckRefresh: function () { return L.resolveDefault(callAccessCheckRefresh(), { success: false }); },
|
|
overviewStats: function () { return L.resolveDefault(callOverviewStats(), {}); },
|
|
overview: function () {
|
|
return L.resolveDefault(callOverview(), {
|
|
status: {},
|
|
stats: {},
|
|
configs: { configs: [], current: '', core_type: '' },
|
|
access: {}
|
|
});
|
|
},
|
|
smartFlushCache: function () { return L.resolveDefault(callSmartFlushCache(), { success: false }); },
|
|
|
|
listSingboxProfiles: function () { return L.resolveDefault(callListSingboxProfiles(), { profiles: [], active: '' }); },
|
|
getSingboxProfile: function (name) { return L.resolveDefault(callGetSingboxProfile(name), {}); },
|
|
saveSingboxProfile: function (name, content) {
|
|
var chunkSize = 24576;
|
|
var total = Math.max(1, Math.ceil((content || '').length / chunkSize));
|
|
var index = 0;
|
|
|
|
function sendNext() {
|
|
var chunk = (content || '').slice(index * chunkSize, (index + 1) * chunkSize);
|
|
return L.resolveDefault(callSaveSingboxProfileChunk(name, chunk, String(index), String(total)), {}).then(function (r) {
|
|
if (!r || !r.success)
|
|
return { success: false, error: (r && r.error) || 'upload_failed', message: (r && (r.message || r.error)) || _('Upload failed') };
|
|
index++;
|
|
return index < total ? sendNext() : r;
|
|
});
|
|
}
|
|
|
|
return sendNext();
|
|
},
|
|
setSingboxProfile: function (name) { return L.resolveDefault(callSetSingboxProfile(name), {}); },
|
|
deleteSingboxProfile: function (name) { return L.resolveDefault(callDeleteSingboxProfile(name), {}); },
|
|
createSingboxConfig: function (url, name) { return L.resolveDefault(callCreateSingboxConfig(url, name), {}); },
|
|
commitConfig: function () { return L.resolveDefault(callCommitConfig(), { success: false }); },
|
|
dnsAutoSetup: function () { return L.resolveDefault(callDnsAutoSetup(), { success: false }); },
|
|
fetchSingboxNative: function (url, name) { return L.resolveDefault(callFetchSingboxNative(url, name), {}); },
|
|
updateSingboxNative: function (name) { return L.resolveDefault(callUpdateSingboxNative(name), {}); },
|
|
|
|
toast: _clashooToast
|
|
});
|