167 lines
6.2 KiB
JavaScript
167 lines
6.2 KiB
JavaScript
/**
|
|
* Alpha Air 专用节点清理脚本
|
|
* - 压掉提供者、三网、家宽等 Alpha Air 专属文案
|
|
* - 普通节点只保留地区,非倍率高级节点保留供应商,倍率节点保留倍率
|
|
* - 按地区内“普通 -> 倍率 -> 高级”排序并连续编号
|
|
* - 不追加订阅后缀,整合订阅最后仍交给 rename.js 处理
|
|
*/
|
|
// noinspection JSUnusedGlobalSymbols
|
|
const COMMON_SCRIPT_URL = 'https://git.orionc.me/orion/script/raw/branch/main/substore/common.js?v=20260603-2';
|
|
|
|
async function loadRenameUtils() {
|
|
if (typeof globalThis !== 'undefined' && 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))();
|
|
return globalThis.SubStoreRenameUtils;
|
|
}
|
|
|
|
async function operator(proxies) {
|
|
const utils = await loadRenameUtils();
|
|
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 regionResolver = utils.createRegionResolver(regionAliases);
|
|
|
|
const stripExistingSuffix = name => name
|
|
.replace(/\s+-\s*Alpha Air(?:\s+\d{2})?\s*$/i, '')
|
|
.trim();
|
|
|
|
const multiplierOf = name => {
|
|
const match = name.match(/\b(\d+(?:\.\d+)?)(?:\s*[xX]|倍)\b/i);
|
|
return match ? `${match[1]}X` : '';
|
|
};
|
|
|
|
const providerOf = name => {
|
|
if (/SkyStroll/i.test(name)) return 'SkyStroll';
|
|
if (/isif/i.test(name)) return 'ISIF';
|
|
if (/搬瓦工|Bandwagon|BWH|BWG/i.test(name)) return 'BWH';
|
|
return '';
|
|
};
|
|
|
|
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 alphaAirRegionPrefixOf = name => {
|
|
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 regionResolver.aliasRegionPrefixOf(name);
|
|
};
|
|
|
|
const regionPrefixOf = (name, flagRegionCode) => {
|
|
if (/Hinet|Seednet/i.test(name)) return 'TW';
|
|
|
|
return alphaAirRegionPrefixOf(name) ||
|
|
leadingRegionPrefixOf(name) ||
|
|
flagRegionCode ||
|
|
'';
|
|
};
|
|
|
|
const normalizeProxy = (proxy, originalIndex) => {
|
|
const rawName = typeof proxy.name === 'string' ? proxy.name : '';
|
|
const cleanName = stripExistingSuffix(rawName);
|
|
const { flag, text } = utils.splitLeadingOrInlineFlag(cleanName);
|
|
const flagRegionCode = utils.flagToRegionCode(flag);
|
|
const regionPrefix = regionPrefixOf(text, flagRegionCode);
|
|
const regionCode = regionPrefix.split(/\s+/)[0];
|
|
const cityCode = regionPrefix.split(/\s+/)[1] || '';
|
|
const multiplier = multiplierOf(text);
|
|
const provider = multiplier ? '' : providerOf(text);
|
|
const normalizedFlag = utils.regionCodeToFlag(regionCode);
|
|
|
|
return {
|
|
proxy,
|
|
originalIndex,
|
|
countryCode: regionCode,
|
|
cityCode,
|
|
provider,
|
|
providerRank: provider ? 1 : 0,
|
|
multiplierValue: multiplier ? Number(multiplier.replace(/X$/i, '')) : Number.NEGATIVE_INFINITY,
|
|
normalizedName: [normalizedFlag, regionPrefix, provider, 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) => {
|
|
if (!firstItem.countryCode || !secondItem.countryCode) {
|
|
return firstItem.originalIndex - secondItem.originalIndex;
|
|
}
|
|
|
|
const firstOrder = countryOrder[firstItem.countryCode];
|
|
const secondOrder = countryOrder[secondItem.countryCode];
|
|
if (firstOrder !== secondOrder) return firstOrder - secondOrder;
|
|
if (firstItem.providerRank !== secondItem.providerRank) {
|
|
return firstItem.providerRank - secondItem.providerRank;
|
|
}
|
|
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;
|
|
});
|
|
}
|