Files
script/substore/iriscloud-rename.js
T
orion 562e2ffeb8 ♻️ refactor(core): 优化 Iris Cloud 节点重命名逻辑
* 细化香港节点识别规则,支持识别包含 iCable 关键字的节点
* 调整兜底逻辑,无法识别落地地区的节点不再强制归类为香港
* 优化处理流程,未识别节点将原样放行且不参与全局排序与编号
* 同步更新文档中关于节点地区判定和原样放行机制的说明
2026-06-15 00:34:10 +08:00

124 lines
4.5 KiB
JavaScript

/**
* Iris Cloud 专用节点清理脚本
* - Iris Cloud 名称里 HK 是入口/线路名的一部分,落地以尾部 SG、TYO、HKG 等标识为准
* - 包含 SG 的节点归新加坡,包含 TYO/JP 的节点归日本,明确 HK/iCable 的节点归香港
* - 无法识别为 Iris Cloud 节点的名称原样放行,不参与排序和编号
* - 去掉 SZ/HZ/[Edge] 入口标签,保留倍率,压掉供应商和入口线路特征
*/
// noinspection JSUnusedGlobalSymbols
const COMMON_SCRIPT_VERSION = '20260608-1';
const COMMON_SCRIPT_URL = `https://git.orionc.me/orion/script/raw/branch/main/substore/common.js?v=${COMMON_SCRIPT_VERSION}`;
const hasCurrentRenameUtils = utils => Boolean(
utils && utils.version === COMMON_SCRIPT_VERSION
);
async function loadRenameUtils() {
if (typeof globalThis !== 'undefined' && hasCurrentRenameUtils(globalThis.SubStoreRenameUtils)) {
return globalThis.SubStoreRenameUtils;
}
const cache = typeof scriptResourceCache !== 'undefined' ? scriptResourceCache : null;
let script = cache && cache.get(COMMON_SCRIPT_URL);
if (!script) {
const response = await $substore.http.get({ url: COMMON_SCRIPT_URL });
script = response && (response.body || response.data || response);
if (cache) cache.set(COMMON_SCRIPT_URL, script);
}
new Function(String(script))();
if (!hasCurrentRenameUtils(globalThis.SubStoreRenameUtils)) {
throw new Error('Loaded common.js is missing current rename utilities');
}
return globalThis.SubStoreRenameUtils;
}
async function operator(proxies) {
const utils = await loadRenameUtils();
const landingPrefixOf = name => {
if (/(?:^|[-\s])SG(?:$|[-\s.])/i.test(name)) return 'SG';
if (/(?:^|[-\s])TYO(?:$|[-\s])/i.test(name)) return 'JP TYO';
if (/(?:^|[-\s])JP(?:$|[-\s])/i.test(name)) return 'JP';
if (/(?:^|[-\s])HK(?:$|[-\s])/i.test(name)) return 'HK';
if (/iCable/i.test(name)) return 'HK';
return '';
};
const multiplierOf = name => {
const match = name.match(/\b(\d+(?:\.\d+)?)(?:\s*[xX]|倍)\b/i);
return match ? `${match[1]}X` : '';
};
const cleanCoreName = name => {
const { text } = utils.splitLeadingOrInlineFlag(name);
return text
.replace(/\s+-\s*Iris Cloud(?:\s+\d{2})?\s*$/i, '')
.replace(/^\s*(?:SZ|HZ)\s+\d{1,2}\s+/i, '')
.replace(/^\s*\[Edge]\s*/i, '')
.trim();
};
const normalizedItems = proxies.map((proxy, originalIndex) => {
if (typeof proxy.name !== 'string') {
return {
proxy,
originalIndex,
regionPrefix: ''
};
}
const coreName = cleanCoreName(proxy.name);
const regionPrefix = landingPrefixOf(coreName);
if (!regionPrefix) {
return {
proxy,
originalIndex,
regionPrefix: ''
};
}
const regionCode = regionPrefix.split(/\s+/)[0];
return {
proxy,
originalIndex,
regionPrefix,
regionCode,
multiplier: multiplierOf(coreName),
flag: utils.regionCodeToFlag(regionCode)
};
});
const regionOrder = Object.create(null);
let regionOrderCount = 0;
normalizedItems.forEach(item => {
if (!item.regionPrefix || regionOrder[item.regionPrefix] !== undefined) return;
regionOrder[item.regionPrefix] = regionOrderCount++;
});
normalizedItems.sort((firstItem, secondItem) => {
if (!firstItem.regionPrefix || !secondItem.regionPrefix) {
return firstItem.originalIndex - secondItem.originalIndex;
}
const firstRegionOrder = regionOrder[firstItem.regionPrefix];
const secondRegionOrder = regionOrder[secondItem.regionPrefix];
if (firstRegionOrder !== secondRegionOrder) return firstRegionOrder - secondRegionOrder;
return firstItem.originalIndex - secondItem.originalIndex;
});
const regionCount = Object.create(null);
return normalizedItems.map(item => {
if (!item.regionPrefix) return item.proxy;
regionCount[item.regionPrefix] = (regionCount[item.regionPrefix] || 0) + 1;
item.proxy.name = [
item.flag,
item.regionPrefix,
String(regionCount[item.regionPrefix]).padStart(2, '0'),
item.multiplier
].filter(Boolean).join(' ').trim();
return item.proxy;
});
}