mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-10-31 01:25:13 +08:00
🎁 Sync 2026-07-31 00:21:49
This commit is contained in:
1 parent
f6c3fbbbbe
commit
c71b32c9fb
204 files changed
+187145
-10038
No files matched your search
@@ -0,0 +1,89 @@
|
||||
#!/usr/bin/ucode
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Headless import of proxy share-link(s) (vless://, vmess://, trojan://, ss://,
|
||||
* hysteria://, hysteria2://, tuic://, …) into homeproxy `node` sections. This is
|
||||
* the SSH/agent-callable equivalent of the browser-only "Import share links"
|
||||
* button (handleLinkImport / parseShareLink) in the LuCI node view. It reuses the
|
||||
* shared parser in node_parse.uc — the SAME parse_uri the subscription importer
|
||||
* uses — so there is no second link-parsing implementation to drift out of sync.
|
||||
*
|
||||
* Usage: ucode import_link.uc <path-to-file-with-one-link-per-line | single-link> [label]
|
||||
* Output: one JSON line, e.g.
|
||||
* { "result": true, "imported": [ { "section": "…", "label": "…", "type": "vless" } ], "failed": 0 }
|
||||
* or { "error": "…" } with a non-zero exit code.
|
||||
*
|
||||
* Imported nodes carry NO grouphash, so they are treated as user-created and are
|
||||
* never removed by a subsequent subscription update.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
import { readfile } from 'fs';
|
||||
import { cursor } from 'uci';
|
||||
import { parse_uri } from 'node_parse';
|
||||
|
||||
const uciconfig = 'homeproxy';
|
||||
|
||||
function emit(o) { printf('%s\n', o); }
|
||||
|
||||
/* Dependency-free stable hash (FNV-1a, 32-bit) — md5/digest is absent on the
|
||||
* OpenWrt 23.05 legacy build, so keep section naming pure-ucode like import_conf.uc. */
|
||||
function strhash(s) {
|
||||
let h = 2166136261;
|
||||
const n = length(s);
|
||||
for (let i = 0; i < n; i++) {
|
||||
h = (h ^ ord(s, i)) & 0xFFFFFFFF;
|
||||
h = (h * 16777619) & 0xFFFFFFFF;
|
||||
}
|
||||
return sprintf('%08x', h);
|
||||
}
|
||||
|
||||
const arg = ARGV[0];
|
||||
const want_label = ARGV[1];
|
||||
|
||||
if (!arg) {
|
||||
emit({ error: 'usage: import_link.uc <file-with-links|link> [label]' });
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* arg is either a readable file (one link per line) or the link itself. */
|
||||
let text = readfile(arg);
|
||||
if (!text)
|
||||
text = arg;
|
||||
|
||||
const lines = split(trim(text), '\n');
|
||||
const uci = cursor();
|
||||
|
||||
let imported = [];
|
||||
let failed = 0;
|
||||
|
||||
for (let line in lines) {
|
||||
line = trim(line);
|
||||
if (!length(line))
|
||||
continue;
|
||||
|
||||
const config = parse_uri(line);
|
||||
if (type(config) !== 'object' || !config.type) {
|
||||
failed++;
|
||||
continue;
|
||||
}
|
||||
|
||||
const label = (want_label && length(lines) === 1)
|
||||
? want_label
|
||||
: (config.label || (config.type + '-' + (config.address || 'node')));
|
||||
config.label = label;
|
||||
|
||||
const name = strhash(label + '|' + (config.address || '') + ':' + (config.port || ''));
|
||||
uci.set(uciconfig, name, 'node');
|
||||
for (let k in config)
|
||||
if (config[k] !== null && config[k] !== '')
|
||||
uci.set(uciconfig, name, k, config[k]);
|
||||
|
||||
push(imported, { section: name, label: label, type: config.type });
|
||||
}
|
||||
|
||||
if (length(imported))
|
||||
uci.commit(uciconfig);
|
||||
|
||||
emit({ result: length(imported) > 0, imported: imported, failed: failed });
|
||||
Reference in new issue
Block a user