✨ feat(core): 新增 alphaair 重命名脚本并移除旧节点清理脚本
This commit is contained in:
+3
-223
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user