fix(substore): normalize mojibake flag prefixes

This commit is contained in:
Orion
2026-06-03 15:47:30 +08:00
parent 29224499f8
commit 354521d161
8 changed files with 47 additions and 17 deletions
+1 -1
View File
@@ -5,7 +5,7 @@
`common.js` 是公共工具库,各处理脚本会按下面的 raw 地址自动加载:
```text
https://git.orionc.me/orion/script/raw/branch/main/substore/common.js?v=20260603-3
https://git.orionc.me/orion/script/raw/branch/main/substore/common.js?v=20260603-4
```
## 推荐使用顺序
+1 -1
View File
@@ -6,7 +6,7 @@
* - 不追加订阅后缀,整合订阅最后仍交给 rename.js 处理
*/
// noinspection JSUnusedGlobalSymbols
const COMMON_SCRIPT_URL = 'https://git.orionc.me/orion/script/raw/branch/main/substore/common.js?v=20260603-3';
const COMMON_SCRIPT_URL = 'https://git.orionc.me/orion/script/raw/branch/main/substore/common.js?v=20260603-4';
async function loadRenameUtils() {
if (typeof globalThis !== 'undefined' && globalThis.SubStoreRenameUtils) {
+36 -10
View File
@@ -2,12 +2,13 @@
* Sub-Store 节点命名公共工具
*
* 远程引用地址:
* https://git.orionc.me/orion/script/raw/branch/main/substore/common.js?v=20260603-3
* https://git.orionc.me/orion/script/raw/branch/main/substore/common.js?v=20260603-4
*/
(function (root) {
const regexSpecialChars = new Set(['.', '*', '+', '?', '^', '$', '{', '}', '(', ')', '|', '[', ']', '\\']);
const leadingFlagRegex = /^([\u{1F1E6}-\u{1F1FF}]{2}|🏴‍☠️)\s*/u;
const inlineFlagRegex = /^(.{1,24}?)([\u{1F1E6}-\u{1F1FF}]{2}|🏴‍☠️)\s*(.*)$/u;
const leadingMojibakeFlagRegex = /^((?:ð[\u0080-\u00BF]{3}){2})\s*/;
const escapeRegex = value => [...String(value)]
.map(char => regexSpecialChars.has(char) ? `\\${char}` : char)
@@ -17,7 +18,29 @@
.replace(/\s{2,}/g, ' ')
.trim();
const normalizeLeadingFlagSpacing = value => String(value)
const decodeMojibakeUtf8 = value => {
try {
const encoded = [...String(value)]
.map(char => `%${char.charCodeAt(0).toString(16).padStart(2, '0')}`)
.join('');
return decodeURIComponent(encoded);
} catch (error) {
return '';
}
};
const normalizeLeadingMojibakeFlag = value => String(value)
.replace(leadingMojibakeFlagRegex, (match, mojibakeFlag) => {
const decodedFlag = decodeMojibakeUtf8(mojibakeFlag);
return leadingFlagRegex.test(decodedFlag) ? `${decodedFlag} ` : '';
})
.trim();
const stripLeadingMojibakeFlag = value => String(value)
.replace(leadingMojibakeFlagRegex, '')
.trim();
const normalizeLeadingFlagSpacing = value => normalizeLeadingMojibakeFlag(value)
.replace(leadingFlagRegex, '$1 ')
.replace(/\s{2,}/g, ' ')
.trim();
@@ -51,17 +74,18 @@
};
const splitLeadingFlag = name => {
const leadingFlagMatch = String(name).match(leadingFlagRegex);
if (!leadingFlagMatch) return { flag: '', text: String(name).trim() };
const cleanName = normalizeLeadingMojibakeFlag(name);
const leadingFlagMatch = cleanName.match(leadingFlagRegex);
if (!leadingFlagMatch) return { flag: '', text: cleanName.trim() };
return {
flag: leadingFlagMatch[1],
text: String(name).slice(leadingFlagMatch[0].length).trim()
text: cleanName.slice(leadingFlagMatch[0].length).trim()
};
};
const splitLeadingOrInlineFlag = name => {
const cleanName = String(name);
const cleanName = normalizeLeadingMojibakeFlag(name);
const leadingFlagMatch = cleanName.match(leadingFlagRegex);
if (leadingFlagMatch) {
return {
@@ -89,7 +113,7 @@
const sortedAliases = sortRegionAliases(aliases);
const regionCodeOf = name => {
const cleanName = String(name);
const cleanName = normalizeLeadingMojibakeFlag(name);
const leadingFlagMatch = cleanName.match(leadingFlagRegex);
if (leadingFlagMatch) return flagToRegionCode(leadingFlagMatch[1]);
@@ -108,7 +132,7 @@
};
const aliasRegionPrefixOf = name => {
const cleanNameLower = String(name).toLowerCase();
const cleanNameLower = stripLeadingMojibakeFlag(name).toLowerCase();
for (const [, replacement, aliasLower] of sortedAliases) {
if (cleanNameLower.includes(aliasLower)) return replacement;
}
@@ -117,7 +141,7 @@
};
const normalizeLeadingRegion = name => {
const cleanName = String(name).trim();
const cleanName = stripLeadingMojibakeFlag(name);
const cleanNameLower = cleanName.toLowerCase();
for (const [alias, replacement, aliasLower] of sortedAliases) {
@@ -254,7 +278,7 @@
const embeddedDescriptorRegex = new RegExp(`\\s*(?:${descriptorPattern})(?=\\s|\\d|$)`, 'gi');
const bracketDescriptorRegex = new RegExp(`\\s*\\[(?:${descriptorPattern})(?:\\s+(?:${descriptorPattern}))*]\\s*`, 'gi');
const [head, ...segments] = String(name).split('|');
const [head, ...segments] = stripLeadingMojibakeFlag(name).split('|');
const keptSegments = segments
.map(segment => segment.trim())
.filter(segment => segment && !descriptorOnlyRegex.test(segment));
@@ -282,11 +306,13 @@
moveMultiplierToEnd,
normalizeHyphenatedRegionFeatures,
normalizeLeadingFlagSpacing,
normalizeLeadingMojibakeFlag,
normalizeMultiplierText,
normalizeRegionSequence,
normalizeWhitespace,
regionCodeToFlag,
sortRegionAliases,
stripLeadingMojibakeFlag,
splitLeadingFlag,
splitLeadingOrInlineFlag,
stripLineDescriptors
+1 -1
View File
@@ -3,7 +3,7 @@
* 负责去掉高速、BGP、CMCU 等 LiangXin 线路描述,保留地区、序号和倍率。
*/
// noinspection JSUnusedGlobalSymbols
const COMMON_SCRIPT_URL = 'https://git.orionc.me/orion/script/raw/branch/main/substore/common.js?v=20260603-3';
const COMMON_SCRIPT_URL = 'https://git.orionc.me/orion/script/raw/branch/main/substore/common.js?v=20260603-4';
async function loadRenameUtils() {
if (typeof globalThis !== 'undefined' && globalThis.SubStoreRenameUtils) {
+1 -1
View File
@@ -3,7 +3,7 @@
* 负责清理推荐、用途、hy2、倍率、线路特征和提供商等 PeiQian 节点文案。
*/
// noinspection JSUnusedGlobalSymbols
const COMMON_SCRIPT_URL = 'https://git.orionc.me/orion/script/raw/branch/main/substore/common.js?v=20260603-3';
const COMMON_SCRIPT_URL = 'https://git.orionc.me/orion/script/raw/branch/main/substore/common.js?v=20260603-4';
async function loadRenameUtils() {
if (typeof globalThis !== 'undefined' && globalThis.SubStoreRenameUtils) {
+5 -1
View File
@@ -5,7 +5,7 @@
* - 基于归一化后的完整名称做精准去重
*/
// noinspection JSUnusedGlobalSymbols
const COMMON_SCRIPT_URL = 'https://git.orionc.me/orion/script/raw/branch/main/substore/common.js?v=20260603-3';
const COMMON_SCRIPT_URL = 'https://git.orionc.me/orion/script/raw/branch/main/substore/common.js?v=20260603-4';
async function loadRenameUtils() {
if (typeof globalThis !== 'undefined' && globalThis.SubStoreRenameUtils) {
@@ -581,6 +581,9 @@ async function operator(proxies) {
const escapeRegex = utils.escapeRegex;
const leadingFlagRegex = /^([\u{1F1E6}-\u{1F1FF}]{2}|🏴‍☠️)\s*/u;
const inlineFlagRegex = /^(.{1,24}?)([\u{1F1E6}-\u{1F1FF}]{2}|🏴‍☠️)\s*(.*)$/u;
const normalizeLeadingMojibakeFlag = utils.normalizeLeadingMojibakeFlag
|| utils.stripLeadingMojibakeFlag
|| (name => String(name).trim());
const flagToRegionCode = flag => utils.flagToRegionCode(flag, flagCodeOverrides);
@@ -726,6 +729,7 @@ async function operator(proxies) {
};
const normalizeCoreName = name => {
name = normalizeLeadingMojibakeFlag(name);
const leadingFlagMatch = name.match(leadingFlagRegex);
const inlineFlagMatch = leadingFlagMatch
? null
+1 -1
View File
@@ -4,7 +4,7 @@
* 维护说明:仅需修改 featureMap 字典即可,底部逻辑永远无需改动。
*/
// noinspection JSUnusedGlobalSymbols
const COMMON_SCRIPT_URL = 'https://git.orionc.me/orion/script/raw/branch/main/substore/common.js?v=20260603-3';
const COMMON_SCRIPT_URL = 'https://git.orionc.me/orion/script/raw/branch/main/substore/common.js?v=20260603-4';
async function loadRenameUtils() {
if (typeof globalThis !== 'undefined' && globalThis.SubStoreRenameUtils) {
+1 -1
View File
@@ -4,7 +4,7 @@
* 按地区稳定归并后重新连续编号,避免专属/普通节点撞号。
*/
// noinspection JSUnusedGlobalSymbols
const COMMON_SCRIPT_URL = 'https://git.orionc.me/orion/script/raw/branch/main/substore/common.js?v=20260603-3';
const COMMON_SCRIPT_URL = 'https://git.orionc.me/orion/script/raw/branch/main/substore/common.js?v=20260603-4';
async function loadRenameUtils() {
if (typeof globalThis !== 'undefined' && globalThis.SubStoreRenameUtils) {