feat(core): 新增 alphaair 重命名脚本并移除旧节点清理脚本

This commit is contained in:
Orion
2026-06-03 09:38:03 +08:00
parent 0dafef595a
commit 3f3e4731c4
5 changed files with 204 additions and 278 deletions
+3 -223
View File
@@ -7,11 +7,7 @@
function operator(proxies) {
const globalCount = Object.create(null);
const currentCount = Object.create(null);
const serialCount = Object.create(null);
const currentSerial = Object.create(null);
const countryOrder = Object.create(null);
const baseNames = new Array(proxies.length);
const renamedItems = new Array(proxies.length);
const suffixRegexCache = Object.create(null);
const regionAliases = [
@@ -554,9 +550,6 @@ function operator(proxies) {
const knownRegionCodes = new Set(
regionAliases.map(([, replacement]) => replacement.split(/\s+/)[0])
);
const knownRegionPrefixes = new Set(
regionAliases.map(([, replacement]) => replacement)
);
Object.values(flagCodeOverrides).forEach(code => knownRegionCodes.add(code));
const escapeRegex = value => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
@@ -580,26 +573,6 @@ function operator(proxies) {
.join('');
};
const regionCodeToFlag = regionCode => {
if (!regionCode) return '';
const flagCode = regionCode === 'UK' ? 'GB' : regionCode;
if (!/^[A-Z]{2}$/.test(flagCode)) return '';
return flagCode
.split('')
.map(char => String.fromCodePoint(char.charCodeAt(0) - 65 + 0x1F1E6))
.join('');
};
const normalizedFlagForCore = (flag, coreName) => {
if (!flag) return '';
const regionPrefix = leadingRegionPrefixOf(coreName) || regionPrefixInName(coreName);
const regionCode = regionPrefix.split(/\s+/)[0];
return regionCodeToFlag(regionCode) || flag;
};
const stripExistingSuffix = (name, subName) => {
if (!subName) return name.trim();
const suffixRegex = suffixRegexCache[subName] || (
@@ -684,158 +657,6 @@ function operator(proxies) {
.trim();
};
const isProviderTag = tag => /^(JC|毕业)$/i.test(tag.trim());
const isRouteTag = tag => /^(三网\d*|COP|CM)$/i.test(tag.trim());
const splitPipeFields = name => name
.split('|')
.map(part => part.trim())
.filter(Boolean);
const cleanupPipeFields = name => {
const fields = splitPipeFields(name);
if (fields.length <= 1) return name.trim();
const [head, ...tailFields] = fields;
const keptFields = tailFields.filter(field => !isRouteTag(field));
return [head, ...keptFields].join('|').trim();
};
const leadingRegionPrefixOf = name => {
const match = name.match(/^([A-Z]{2})(?:\s+([A-Z]{3}))?(?=\s|$|-|\d|\|)/);
if (!match) return '';
const fullPrefix = match[2] ? `${match[1]} ${match[2]}` : match[1];
if (match[2] && knownRegionPrefixes.has(fullPrefix)) return fullPrefix;
return knownRegionCodes.has(match[1]) ? match[1] : '';
};
const hasAliasInName = (name, alias, aliasLower) => {
const nameLower = name.toLowerCase();
const aliasIndex = nameLower.indexOf(aliasLower);
if (aliasIndex === -1) return false;
if (/^[A-Za-z]/.test(alias)) {
const before = aliasIndex > 0 ? name[aliasIndex - 1] : '';
const after = name[aliasIndex + alias.length] || '';
return !/[A-Za-z]/.test(before) && !/[A-Za-z]/.test(after);
}
return true;
};
const regionPrefixInName = name => {
for (const [alias, replacement, aliasLower] of sortedRegionAliases) {
if (hasAliasInName(name, alias, aliasLower)) return replacement;
}
return leadingRegionPrefixOf(name);
};
const multiplierOf = name => {
const match = name.match(/\b(\d+(?:\.\d+)?X)\b/i);
return match ? match[1].toUpperCase() : '';
};
const compactHomeBroadbandName = name => {
if (!/家宽/.test(name)) return name;
const regionPrefix = /(?:Hinet|Seednet)/i.test(name) ? 'TW' : regionPrefixInName(name);
const multiplier = multiplierOf(name);
const compactFields = [regionPrefix, multiplier].filter(Boolean);
return compactFields.join(' ').trim();
};
const compactRegionOnlyName = name => {
const regionPrefix = regionPrefixInName(name);
return regionPrefix || name;
};
const compactKnownLineName = name => {
const cleanName = cleanupPipeFields(name);
const compactName = /家宽/.test(cleanName)
? compactHomeBroadbandName(cleanName)
: compactRegionOnlyName(cleanName);
return compactName
.replace(/\s*\|\s*/g, '|')
.replace(/\s{2,}/g, ' ')
.trim();
};
const serialGroupOf = coreName => {
const nameWithoutFlag = coreName.replace(leadingFlagRegex, '').trim();
const regionPrefix = leadingRegionPrefixOf(nameWithoutFlag) || regionPrefixInName(nameWithoutFlag);
if (!regionPrefix) return '';
return `${regionPrefix.split(/\s+/)[0]}|region`;
};
const appendSerialToCoreName = (coreName, serialNumber) => {
const fields = splitPipeFields(coreName);
const serialText = String(serialNumber).padStart(2, '0');
if (fields.length <= 1) return `${coreName} ${serialText}`;
const providers = [];
const bodyFields = [];
fields.forEach((field, fieldIndex) => {
if (fieldIndex > 0 && isProviderTag(field)) {
providers.push(field);
} else {
bodyFields.push(field);
}
});
const body = `${bodyFields.join('|')} ${serialText}`.trim();
return providers.length ? `${body}|${providers.join('|')}` : body;
};
const sortInfoOf = (coreName, originalIndex) => {
const nameWithoutFlag = coreName.replace(leadingFlagRegex, '').trim();
const regionPrefix = leadingRegionPrefixOf(nameWithoutFlag) || regionPrefixInName(nameWithoutFlag);
const [countryCode, cityCode = ''] = regionPrefix.split(/\s+/);
const multiplierMatch = nameWithoutFlag.match(/\b(\d+(?:\.\d+)?)X\b/i);
return {
originalIndex,
countryCode: countryCode || '',
cityCode,
regionPrefix,
multiplier: multiplierMatch ? Number(multiplierMatch[1]) : Number.NEGATIVE_INFINITY
};
};
const compareSortInfo = (firstInfo, secondInfo) => {
if (!firstInfo.countryCode || !secondInfo.countryCode) {
return firstInfo.originalIndex - secondInfo.originalIndex;
}
const firstCountryOrder = countryOrder[firstInfo.countryCode];
const secondCountryOrder = countryOrder[secondInfo.countryCode];
if (firstCountryOrder !== secondCountryOrder) {
return firstCountryOrder - secondCountryOrder;
}
if (firstInfo.multiplier !== secondInfo.multiplier) {
return firstInfo.multiplier - secondInfo.multiplier;
}
const firstCityRank = firstInfo.cityCode ? 1 : 0;
const secondCityRank = secondInfo.cityCode ? 1 : 0;
if (firstCityRank !== secondCityRank) {
return firstCityRank - secondCityRank;
}
if (firstInfo.regionPrefix !== secondInfo.regionPrefix) {
return firstInfo.regionPrefix < secondInfo.regionPrefix ? -1 : 1;
}
return firstInfo.originalIndex - secondInfo.originalIndex;
};
const normalizeBilingualName = name => {
const bilingualMatch = name.match(/^(.+?)\s*\s*(.+)$/);
if (!bilingualMatch) return name;
@@ -899,10 +720,9 @@ function operator(proxies) {
core = joinAlias(flagRegionCode, core);
}
core = compactKnownLineName(simplifyCoreName(core));
core = simplifyCoreName(core);
const normalizedFlag = normalizedFlagForCore(flag, core);
return normalizedFlag ? `${normalizedFlag} ${core}` : core;
return flag ? `${flag} ${core}` : core;
};
proxies.forEach((proxy, proxyIndex) => {
@@ -911,53 +731,13 @@ function operator(proxies) {
const coreName = stripExistingSuffix(proxyName, subName);
const normalizedCoreName = normalizeCoreName(coreName);
const baseName = subName ? `${normalizedCoreName} - ${subName}` : normalizedCoreName;
const serialGroup = serialGroupOf(normalizedCoreName);
const scopedSerialGroup = serialGroup ? `${serialGroup}|${subName}` : '';
const sortInfo = sortInfoOf(normalizedCoreName, proxyIndex);
if (sortInfo.countryCode && countryOrder[sortInfo.countryCode] === undefined) {
countryOrder[sortInfo.countryCode] = Object.keys(countryOrder).length;
}
baseNames[proxyIndex] = baseName;
renamedItems[proxyIndex] = {
normalizedCoreName,
subName,
scopedSerialGroup,
sortInfo
};
globalCount[baseName] = (globalCount[baseName] || 0) + 1;
if (scopedSerialGroup) {
serialCount[scopedSerialGroup] = (serialCount[scopedSerialGroup] || 0) + 1;
}
});
const sortedProxyIndexes = proxies
.map((proxy, proxyIndex) => proxyIndex)
.sort((firstIndex, secondIndex) => {
return compareSortInfo(
renamedItems[firstIndex].sortInfo,
renamedItems[secondIndex].sortInfo
);
});
return sortedProxyIndexes.map(proxyIndex => {
const proxy = proxies[proxyIndex];
return proxies.map((proxy, proxyIndex) => {
const baseName = baseNames[proxyIndex];
const renamedItem = renamedItems[proxyIndex];
if (renamedItem.scopedSerialGroup) {
currentSerial[renamedItem.scopedSerialGroup] = (
currentSerial[renamedItem.scopedSerialGroup] || 0
) + 1;
const serialCoreName = appendSerialToCoreName(
renamedItem.normalizedCoreName,
currentSerial[renamedItem.scopedSerialGroup]
);
proxy.name = renamedItem.subName ? `${serialCoreName} - ${renamedItem.subName}` : serialCoreName;
return proxy;
}
if (globalCount[baseName] > 1) {
currentCount[baseName] = (currentCount[baseName] || 0) + 1;