✨ feat(core): 新增 alphaair 重命名脚本并移除旧节点清理脚本
This commit is contained in:
+19
-2
@@ -9,7 +9,8 @@
|
||||
1. `sntp-rename.js`:放在 SNTP 单订阅里,注入线路标签。
|
||||
2. `yuetong-rename.js`:只清理 YueTong 的品牌前缀和装饰符号。
|
||||
3. `peiqian-rename.js`:只清理 PeiQian 的推荐/用途描述。
|
||||
4. `rename.js`:整合订阅最终重命名,负责国家短码、国旗归位、订阅后缀和去重。
|
||||
4. `alphaair-rename.js`:只处理 Alpha Air 的供应商压缩、倍率排序和连续编号。
|
||||
5. `rename.js`:整合订阅最终重命名,负责国家短码、国旗归位、订阅后缀和去重。
|
||||
|
||||
如果某个订阅没有对应的专属脚本,直接进入最后的 `rename.js` 即可。
|
||||
|
||||
@@ -20,6 +21,7 @@
|
||||
| `sntp-rename.js` | SNTP 单订阅 | 注入 `[三网]`、`[CF]`、`[直连]`、`[cn2]` 等线路标签 |
|
||||
| `yuetong-rename.js` | YueTong 单订阅 | 去掉 `悦·`、`💎`,把 `AI解锁` 压成 `AI` |
|
||||
| `peiqian-rename.js` | PeiQian 单订阅 | 压短 `电信联通推荐`、`移动联通推荐`、`高速专线`、`hy2`、倍率和用途描述 |
|
||||
| `alphaair-rename.js` | Alpha Air 单订阅 | 去掉供应商/提供者/三网/家宽文案,保留地区、城市码、倍率并连续编号 |
|
||||
| `rename.js` | 整合订阅 | 统一国家/城市短码,移动国旗到首部,追加 `- _subName`,处理重名编号 |
|
||||
|
||||
## SNTP 规则
|
||||
@@ -88,6 +90,21 @@
|
||||
🇼🇸 TW - PeiQian
|
||||
```
|
||||
|
||||
## Alpha Air 规则
|
||||
|
||||
`alphaair-rename.js` 建议挂在 Alpha Air 单条订阅里使用。它会把 Alpha Air 的供应商、提供者和线路文案压掉,并在该订阅内部按地区和倍率编号;之后再交给全局 `rename.js` 追加订阅后缀。
|
||||
|
||||
```text
|
||||
🇺🇸 4X|美国夏威夷家宽|三网1
|
||||
=> 🇺🇸 US HNL 4X 01
|
||||
|
||||
3X 🇨🇳 台湾家宽Hinet|COP
|
||||
=> 🇹🇼 TW 3X 01
|
||||
|
||||
🇳🇱 搬瓦工荷兰|JC
|
||||
=> 🇳🇱 NL 01
|
||||
```
|
||||
|
||||
## 全局重命名
|
||||
|
||||
`rename.js` 适合放在整合订阅最后。它做的事情更通用:
|
||||
@@ -119,4 +136,4 @@ Pro-🇭🇰 Sharon|守夜人 - Alpha 8K Snell
|
||||
- `sntp-rename.js` 不带 `_subName` 判断,适合挂在 SNTP 单订阅里;如果放进整合订阅,可能会误伤其他带 `BGP`、`D`、`CT` 的节点。
|
||||
- `yuetong-rename.js` 和 `peiqian-rename.js` 也不带 `_subName` 判断,适合挂在对应单订阅里;如果放进整合订阅,需要确认规则不会误伤其他订阅。
|
||||
- `rename.js` 会剥离并重新追加 `- _subName`,重复运行不会叠加订阅后缀。
|
||||
- 如果新增订阅里出现很短、很泛的关键词,例如 `D`、`CT`、`BGP`、`S1`,优先拆成单订阅脚本,不建议放进全局 `rename.js`。
|
||||
- 如果新增订阅里出现很短、很泛的关键词,例如 `D`、`CT`、`BGP`、`S1`,或像 Alpha Air 这种强绑定单机场的供应商压缩规则,优先拆成单订阅脚本,不建议放进全局 `rename.js`。
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
/**
|
||||
* Alpha Air 专用节点清理脚本
|
||||
* - 压掉供应商、提供者、三网、家宽等 Alpha Air 专属文案
|
||||
* - 保留地区、城市码和倍率,按地区内倍率排序并连续编号
|
||||
* - 不追加订阅后缀,整合订阅最后仍交给 rename.js 处理
|
||||
*/
|
||||
function operator(proxies) {
|
||||
const regionAliases = [
|
||||
['美国夏威夷', 'US HNL'],
|
||||
['家宽夏威夷', 'US HNL'],
|
||||
['夏威夷', 'US HNL'],
|
||||
['Hawaii', 'US HNL'],
|
||||
['United States', 'US'],
|
||||
['America', 'US'],
|
||||
['USA', 'US'],
|
||||
['美国', 'US'],
|
||||
['美西', 'US'],
|
||||
['Japan', 'JP'],
|
||||
['日本', 'JP'],
|
||||
['Taiwan', 'TW'],
|
||||
['台湾', 'TW'],
|
||||
['Hong Kong', 'HK'],
|
||||
['香港', 'HK'],
|
||||
['Singapore', 'SG'],
|
||||
['新加坡', 'SG'],
|
||||
['Netherlands', 'NL'],
|
||||
['荷兰', 'NL'],
|
||||
['Korea', 'KR'],
|
||||
['韩国', 'KR'],
|
||||
['Germany', 'DE'],
|
||||
['德国', 'DE'],
|
||||
['United Kingdom', 'UK'],
|
||||
['英国', 'UK']
|
||||
];
|
||||
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 inlineFlagRegex = /^(.{1,24}?)([\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 regionCodeToFlag = regionCode => {
|
||||
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 stripExistingSuffix = name => name
|
||||
.replace(/\s+-\s*Alpha Air(?:\s+\d{2})?\s*$/i, '')
|
||||
.trim();
|
||||
|
||||
const stripFlag = name => {
|
||||
const leadingFlagMatch = name.match(leadingFlagRegex);
|
||||
if (leadingFlagMatch) {
|
||||
return {
|
||||
flag: leadingFlagMatch[1],
|
||||
text: name.slice(leadingFlagMatch[0].length).trim()
|
||||
};
|
||||
}
|
||||
|
||||
const inlineFlagMatch = name.match(inlineFlagRegex);
|
||||
if (!inlineFlagMatch) return { flag: '', text: name.trim() };
|
||||
|
||||
const prefix = inlineFlagMatch[1].trim();
|
||||
const rest = inlineFlagMatch[3].trim();
|
||||
return {
|
||||
flag: inlineFlagMatch[2],
|
||||
text: rest ? `${prefix} ${rest}`.trim() : prefix
|
||||
};
|
||||
};
|
||||
|
||||
const multiplierOf = name => {
|
||||
const match = name.match(/\b(\d+(?:\.\d+)?)(?:\s*[xX]|倍)\b/i);
|
||||
return match ? `${match[1]}X` : '';
|
||||
};
|
||||
|
||||
const leadingRegionPrefixOf = name => {
|
||||
const match = name.match(/^([A-Z]{2})(?:\s+([A-Z]{3}))?(?=\s|$|-|\d|\|)/);
|
||||
if (!match) return '';
|
||||
return match[2] ? `${match[1]} ${match[2]}` : match[1];
|
||||
};
|
||||
|
||||
const aliasRegionPrefixOf = name => {
|
||||
const cleanNameLower = name.toLowerCase();
|
||||
for (const [alias, replacement, aliasLower] of sortedRegionAliases) {
|
||||
if (cleanNameLower.includes(aliasLower)) return replacement;
|
||||
}
|
||||
|
||||
if (/\bhk\b/i.test(name)) return 'HK';
|
||||
if (/\bsg\b/i.test(name)) return 'SG';
|
||||
if (/\bjp\b/i.test(name)) return 'JP';
|
||||
if (/\btw\b/i.test(name)) return 'TW';
|
||||
if (/\bus\b/i.test(name)) return 'US';
|
||||
|
||||
return '';
|
||||
};
|
||||
|
||||
const regionPrefixOf = (name, flagRegionCode) => {
|
||||
if (/(?:Hinet|Seednet)/i.test(name)) return 'TW';
|
||||
|
||||
return aliasRegionPrefixOf(name) ||
|
||||
leadingRegionPrefixOf(name) ||
|
||||
flagRegionCode ||
|
||||
'';
|
||||
};
|
||||
|
||||
const normalizeProxy = (proxy, originalIndex) => {
|
||||
const rawName = typeof proxy.name === 'string' ? proxy.name : '';
|
||||
const cleanName = stripExistingSuffix(rawName);
|
||||
const { flag, text } = stripFlag(cleanName);
|
||||
const flagRegionCode = flagToRegionCode(flag);
|
||||
const regionPrefix = regionPrefixOf(text, flagRegionCode);
|
||||
const regionCode = regionPrefix.split(/\s+/)[0];
|
||||
const cityCode = regionPrefix.split(/\s+/)[1] || '';
|
||||
const multiplier = multiplierOf(text);
|
||||
const normalizedFlag = regionCodeToFlag(regionCode);
|
||||
|
||||
return {
|
||||
proxy,
|
||||
originalIndex,
|
||||
countryCode: regionCode,
|
||||
cityCode,
|
||||
multiplierValue: multiplier ? Number(multiplier.replace(/X$/i, '')) : Number.NEGATIVE_INFINITY,
|
||||
normalizedName: [normalizedFlag, regionPrefix, multiplier].filter(Boolean).join(' ').trim()
|
||||
};
|
||||
};
|
||||
|
||||
const countryOrder = Object.create(null);
|
||||
const normalizedItems = proxies.map((proxy, proxyIndex) => {
|
||||
const normalizedItem = normalizeProxy(proxy, proxyIndex);
|
||||
if (
|
||||
normalizedItem.countryCode &&
|
||||
countryOrder[normalizedItem.countryCode] === undefined
|
||||
) {
|
||||
countryOrder[normalizedItem.countryCode] = Object.keys(countryOrder).length;
|
||||
}
|
||||
return normalizedItem;
|
||||
});
|
||||
|
||||
normalizedItems.sort((firstItem, secondItem) => {
|
||||
const firstOrder = countryOrder[firstItem.countryCode];
|
||||
const secondOrder = countryOrder[secondItem.countryCode];
|
||||
if (firstOrder !== secondOrder) return firstOrder - secondOrder;
|
||||
if (firstItem.multiplierValue !== secondItem.multiplierValue) {
|
||||
return firstItem.multiplierValue - secondItem.multiplierValue;
|
||||
}
|
||||
|
||||
const firstCityRank = firstItem.cityCode ? 1 : 0;
|
||||
const secondCityRank = secondItem.cityCode ? 1 : 0;
|
||||
if (firstCityRank !== secondCityRank) return firstCityRank - secondCityRank;
|
||||
|
||||
return firstItem.originalIndex - secondItem.originalIndex;
|
||||
});
|
||||
|
||||
const currentCount = Object.create(null);
|
||||
return normalizedItems.map(item => {
|
||||
if (!item.normalizedName || !item.countryCode) return item.proxy;
|
||||
|
||||
currentCount[item.countryCode] = (currentCount[item.countryCode] || 0) + 1;
|
||||
item.proxy.name = `${item.normalizedName} ${String(currentCount[item.countryCode]).padStart(2, '0')}`;
|
||||
return item.proxy;
|
||||
});
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/**
|
||||
* PeiQian 专用节点清理脚本
|
||||
* 负责清理推荐、用途、hy2、倍率等 PeiQian 节点文案。
|
||||
*/
|
||||
function operator(proxies) {
|
||||
return proxies.map(proxy => {
|
||||
if (typeof proxy.name !== 'string') {
|
||||
return proxy;
|
||||
}
|
||||
|
||||
proxy.name = proxy.name
|
||||
.replace(/^AWS\s*新加坡\s*/i, '新加坡 AWS ')
|
||||
.replace(/\s*\|\s*合适下载使用\s*-\s*(\d+(?:\.\d+)?)倍/gi, ' $1x')
|
||||
.replace(/\s*\|\s*合适下载使用/gi, '')
|
||||
.replace(/\s*\|\s*避免晚高峰使用/gi, '')
|
||||
.replace(/\s*\|\s*电信联通移动推荐\s*-\s*hy2/gi, ' [三网 HY2]')
|
||||
.replace(/\s*\|\s*电信联通移动推荐/gi, ' [三网]')
|
||||
.replace(/\s*\|\s*电信联通推荐\s*-\s*hy2/gi, ' [电联 HY2]')
|
||||
.replace(/\s*\|\s*电信联通推荐/gi, ' [电联]')
|
||||
.replace(/\s*\|\s*移动联通推荐\s*-\s*hy2/gi, ' [移联 HY2]')
|
||||
.replace(/\s*\|\s*移动联通推荐/gi, ' [移联]')
|
||||
.replace(/\s*\|\s*高速专线(?:推荐)?\s*-\s*hy2/gi, ' [HY2]')
|
||||
.replace(/\s*\|\s*高速专线推荐/gi, ' [专线]')
|
||||
.replace(/\s*\|\s*三网推荐/gi, ' [三网]')
|
||||
.replace(/-\s*(\d+(?:\.\d+)?)倍/gi, ' $1x')
|
||||
.replace(/(\d+(?:\.\d+)?)倍/gi, '$1x')
|
||||
.replace(/\s+\[/g, ' [')
|
||||
.replace(/\s{2,}/g, ' ')
|
||||
.trim();
|
||||
|
||||
return proxy;
|
||||
});
|
||||
}
|
||||
+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;
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
/**
|
||||
* YueTong 专用节点清理脚本
|
||||
* 负责去掉“悦·”品牌前缀、钻石等装饰,以及压短 AI 解锁文案。
|
||||
*/
|
||||
function operator(proxies) {
|
||||
return proxies.map(proxy => {
|
||||
if (typeof proxy.name !== 'string') {
|
||||
return proxy;
|
||||
}
|
||||
|
||||
proxy.name = proxy.name
|
||||
.replace(/悦[·・]\s*/g, '')
|
||||
.replace(/AI解锁/g, 'AI')
|
||||
.replace(/[💎]/gu, '')
|
||||
.replace(/\s{2,}/g, ' ')
|
||||
.trim();
|
||||
|
||||
return proxy;
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user