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
+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