/** * YueTong 专用节点清理脚本 * 负责去掉“悦·”品牌前缀、钻石、专属/家宽等线路标识,以及压短 AI 解锁文案。 * 保留线路标识后面的序号,并按地区稳定归并。 */ // noinspection JSUnusedGlobalSymbols function operator(proxies) { const regionAliases = [ ['Hong Kong', 'HK'], ['香港', 'HK'], ['HK', 'HK'], ['Japan', 'JP'], ['日本', 'JP'], ['JP', 'JP'], ['Singapore', 'SG'], ['新加坡', 'SG'], ['狮城', 'SG'], ['SG', 'SG'], ['Taiwan', 'TW'], ['台湾', 'TW'], ['台灣', 'TW'], ['TW', 'TW'], ['United States', 'US'], ['America', 'US'], ['USA', 'US'], ['美国', 'US'], ['美國', 'US'], ['美西', 'US'], ['美东', 'US'], ['美東', 'US'], ['US', 'US'], ['Korea', 'KR'], ['韩国', 'KR'], ['韓國', 'KR'], ['KR', 'KR'], ['United Kingdom', 'UK'], ['Britain', 'UK'], ['英国', 'UK'], ['英國', 'UK'], ['UK', 'UK'], ['Germany', 'DE'], ['德国', 'DE'], ['德國', 'DE'], ['DE', 'DE'], ['Netherlands', 'NL'], ['荷兰', 'NL'], ['荷蘭', 'NL'], ['NL', 'NL'] ]; const sortedRegionAliases = regionAliases .map(([alias, replacement]) => [alias, replacement, alias.toLowerCase()]) .sort((firstAlias, secondAlias) => secondAlias[0].length - firstAlias[0].length); const leadingFlagRegex = /^([\u{1F1E6}-\u{1F1FF}]{2})\s*/u; const flagToRegionCode = flag => { if (!flag) return ''; const codePoints = [...flag].map(char => char.codePointAt(0)); if ( codePoints.length !== 2 || codePoints.some(codePoint => codePoint < 0x1F1E6 || codePoint > 0x1F1FF) ) { return ''; } const regionCode = codePoints .map(codePoint => String.fromCharCode(codePoint - 0x1F1E6 + 65)) .join(''); return regionCode === 'GB' ? 'UK' : regionCode; }; const regionCodeOf = name => { const leadingFlagMatch = name.match(leadingFlagRegex); if (leadingFlagMatch) return flagToRegionCode(leadingFlagMatch[1]); const nameLower = name.toLowerCase(); for (const [alias, replacement, aliasLower] of sortedRegionAliases) { if (/^[A-Z]{2}$/.test(alias)) { const codeMatch = name.match(new RegExp(`(^|[^A-Za-z])${alias}([^A-Za-z]|$)`, 'i')); if (codeMatch) return replacement; continue; } if (nameLower.includes(aliasLower)) return replacement; } return ''; }; const normalizedItems = proxies.map((proxy, originalIndex) => { if (typeof proxy.name !== 'string') { return { proxy, originalIndex, regionCode: '' }; } proxy.name = proxy.name .replace(/悦[·・]\s*/g, '') .replace(/AI解锁/g, 'AI') .replace(/\s*(?:专属|家宽|高速|专线)(?:\s*(\d+)(?!\s*(?:[xX倍]|\.\d)))?/g, '$1') .replace(/💎/gu, '') .replace(/([\u4e00-\u9fff])AI\b/g, '$1 AI') .replace(/\s{2,}/g, ' ') .trim(); return { proxy, originalIndex, regionCode: regionCodeOf(proxy.name) }; }); const regionOrder = Object.create(null); const groupOrder = normalizedItems.map(item => { if (!item.regionCode) return item.originalIndex; if (regionOrder[item.regionCode] === undefined) { regionOrder[item.regionCode] = item.originalIndex; } return regionOrder[item.regionCode]; }); normalizedItems.sort((firstItem, secondItem) => { const firstGroupOrder = groupOrder[firstItem.originalIndex]; const secondGroupOrder = groupOrder[secondItem.originalIndex]; if (firstGroupOrder !== secondGroupOrder) return firstGroupOrder - secondGroupOrder; return firstItem.originalIndex - secondItem.originalIndex; }); return normalizedItems.map(item => item.proxy); }