/** * 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 (/^(?:US)(?:$|[\s|.-])/i.test(name)) return 'US'; 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 multiplierValueOf = multiplier => ( multiplier ? Number(multiplier.replace(/X$/i, '')) : Number.NEGATIVE_INFINITY ); 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; const firstMultiplierValue = multiplierValueOf(firstItem.multiplier); const secondMultiplierValue = multiplierValueOf(secondItem.multiplier); if (firstMultiplierValue !== secondMultiplierValue) { return firstMultiplierValue - secondMultiplierValue; } 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; }); }