From 82e97b2f574740df6d2d7540b95b5e51148d8bdc Mon Sep 17 00:00:00 2001 From: DaTekShaman Date: Sun, 4 Jan 2026 20:31:45 +0300 Subject: [PATCH] Refactor icon and country detection rules in external-proxies-sanitizer.js for improved accuracy and maintainability --- .../scripts/external-proxies-sanitizer.js | 81 +++++++++++++++---- 1 file changed, 67 insertions(+), 14 deletions(-) diff --git a/config-sub-converter/scripts/external-proxies-sanitizer.js b/config-sub-converter/scripts/external-proxies-sanitizer.js index b156d2b..0a6f21c 100644 --- a/config-sub-converter/scripts/external-proxies-sanitizer.js +++ b/config-sub-converter/scripts/external-proxies-sanitizer.js @@ -42,15 +42,13 @@ const NOISE_PATTERNS = [ // 2) Keyword -> icon tags (if found in original name, icon is added; the keyword is removed from base name) const ICON_RULES = [ - { regex: /\bYT\b/gi, icon: "๐Ÿ“บ" }, - { regex: /\bIPv6\b/gi, icon: "โป" }, - { regex: /\bNetflix\b|\bNF\b/gi, icon: "๐ŸŽฌ" }, - { regex: /\bDisney\+?\b|\bDSNY\b/gi, icon: "๐Ÿฐ" }, - { regex: /\bHBO\b/gi, icon: "๐Ÿ“ผ" }, - { regex: /\bPrime\b|\bAmazon\b/gi, icon: "๐Ÿ“ฆ" }, - { regex: /\bChatGPT\b|\bOpenAI\b/gi, icon: "๐Ÿค–" }, - { regex: /\bSteam\b/gi, icon: "๐ŸŽฎ" }, - { regex: /\bTorrentโœ…\b|Torrent|\bP2P\b|\bP2P-Torrents\b/gi, icon: "๐Ÿงฒ" } + { regex: /TEST/gi, icon: "๐Ÿงช" }, + { regex: /\bโšก๏ธLow Ping\b/gi, icon: "โšก๏ธ" }, + { regex: /\bโšก๏ธ10 Gbit \b/gi, icon: "๐Ÿ›ค๏ธ" }, + { regex: /\bYT\b|\bRussia\b|\bะ ะพััะธั\b/gi, icon: "๐Ÿ“บ" }, + { regex: /\bIPv6\b/gi, icon: "6๏ธโƒฃ" }, + { regex: /\bGemini\b|\bAI Studio\b/gi, icon: "๐Ÿค–" }, + { regex: /\bTorrentโœ…\b|Torrent|\bP2P\b|\bP2P-Torrents\b/gi, icon: "๐Ÿงฒ" } ]; // 3) Optional โ€œnetworkโ€ tag rules based on NAME text (not $server.network) @@ -63,9 +61,9 @@ const NAME_NETWORK_TAGS = [ // 4) Country detection rules by NAME (regex). First match wins (priority = lower is earlier) const COUNTRY_RULES = [ - { regex: /\b(ะญัั‚ะพะฝะธั|EE|EST|ESTONIA|TALLINN)\b/i, iso3: "EST", flag: "๐Ÿ‡ช๐Ÿ‡ช", priority: 110 }, // Estonia - { regex: /\b(ะคะธะฝะปัะฝะดะธั|FI|FIN|FINLAND|HELSINKI)\b/i, iso3: "FIN", flag: "๐Ÿ‡ซ๐Ÿ‡ฎ", priority: 70 }, // Finland - { regex: /\b(ะฏะฟะพะฝะธั|JP|JPN|JAPAN|TOKYO|OSAKA)\b/i, iso3: "JPN", flag: "๐Ÿ‡ฏ๐Ÿ‡ต", priority: 210 }, // Japan + { regex: uWordBoundaryGroup("(ะญัั‚ะพะฝะธั|EE|EST|ESTONIA|TALLINN)"), iso3: "EST", flag: "๐Ÿ‡ช๐Ÿ‡ช", priority: 110 }, + { regex: uWordBoundaryGroup("(ะคะธะฝะปัะฝะดะธั|FI|FIN|FINLAND|HELSINKI)"), iso3: "FIN", flag: "๐Ÿ‡ซ๐Ÿ‡ฎ", priority: 70 }, + { regex: uWordBoundaryGroup("(ะฏะฟะพะฝะธั|JP|JPN|JAPAN|TOKYO|OSAKA)"), iso3: "JPN", flag: "๐Ÿ‡ฏ๐Ÿ‡ต", priority: 210 }, { regex: /\b(ะ“ะพะฝะบะพะฝะณ|HK|HKG|HONG\s*KONG)\b/i, iso3: "HKG", flag: "๐Ÿ‡ญ๐Ÿ‡ฐ", priority: 230 }, // Hong Kong { regex: /\b(ะ“ะตั€ะผะฐะฝะธั|DE|DEU|GER(MANY)?|FRANKFURT|BERLIN|MUNICH)\b/i, iso3: "DEU", flag: "๐Ÿ‡ฉ๐Ÿ‡ช", priority: 20 }, // Germany { regex: /\b(ะคั€ะฐะฝั†ะธั|FR|FRA|FRANCE|PARIS|MARSEILLE)\b/i, iso3: "FRA", flag: "๐Ÿ‡ซ๐Ÿ‡ท", priority: 50 }, // France @@ -77,11 +75,11 @@ const COUNTRY_RULES = [ { regex: /\b(ะกะธะฝะณะฐะฟัƒั€|SG|SGP|SINGAPORE)\b/i, iso3: "SGP", flag: "๐Ÿ‡ธ๐Ÿ‡ฌ", priority: 200 }, // Singapore { regex: /\b(South Korea|ะšะพั€ะตั|KR|KOR|KOREA|SEOUL)\b/i, iso3: "KOR", flag: "๐Ÿ‡ฐ๐Ÿ‡ท", priority: 220 }, // South Korea { regex: /\b(ะจะฒะตั†ะธั|SE|SWE|SWEDEN|STOCKHOLM)\b/i, iso3: "SWE", flag: "๐Ÿ‡ธ๐Ÿ‡ช", priority: 80 }, // Sweden - { regex: /\b(ะจะฒะตะนั†ะฐั€ะธั|CH|CHE|SWITZERLAND|ZURICH|GENEVA)\b/i, iso3: "CHE", flag: "๐Ÿ‡จ๐Ÿ‡ญ", priority: 100 }, // Switzerland + { regex: /\b(ะจะฒะตะนั†ะฐั€ะธั|CH|CHE|SWITZERLAND|Switzerl)\b/i, iso3: "CHE", flag: "๐Ÿ‡จ๐Ÿ‡ญ", priority: 100 }, // Switzerland { regex: /\b(ะขัƒั€ั†ะธั|TR|TUR|TURKEY|ISTANBUL)\b/i, iso3: "TUR", flag: "๐Ÿ‡น๐Ÿ‡ท", priority: 140 }, // Turkey { regex: /\b(ะ’ะตะปะธะบะพะฑั€ะธั‚ะฐะฝะธั|ะะฝะณะปะธั|England|UK|GB|GBR|UNITED\s*KINGDOM)\b/i, iso3: "GBR", flag: "๐Ÿ‡ฌ๐Ÿ‡ง", priority: 40 }, // UK { regex: /\b(ะกะจะ|USA|US|UNITED\s*STATES|AMERICA|NEW\s*YORK|NYC)\b/i, iso3: "USA", flag: "๐Ÿ‡บ๐Ÿ‡ธ", priority: 10 }, // USA - { regex: /\b(Argentina|AR|ARG|ARGENTINA|BUENOS\s*AIRES)\b/i, iso3: "ARG", flag: "๐Ÿ‡ฆ๐Ÿ‡ท", priority: 240 }, // Argentina + { regex: /\b(ะั€ะณะตะฝั‚ะธะฝะฐ|Argentina|AR|ARG|ARGENTINA|BUENOS\s*AIRES)\b/i, iso3: "ARG", flag: "๐Ÿ‡ฆ๐Ÿ‡ท", priority: 240 }, // Argentina { regex: /\b(Australia|AU|AUS|AUSTRALIA|SYDNEY)\b/i, iso3: "AUS", flag: "๐Ÿ‡ฆ๐Ÿ‡บ", priority: 250 }, // Australia { regex: /\b(Austria|AT|AUT|AUSTRIA|VIENNA)\b/i, iso3: "AUT", flag: "๐Ÿ‡ฆ๐Ÿ‡น", priority: 260 }, // Austria { regex: /\b(Brazil|BR|BRA|BRAZIL|SAO\s*PAULO)\b/i, iso3: "BRA", flag: "๐Ÿ‡ง๐Ÿ‡ท", priority: 270 }, // Brazil @@ -152,6 +150,12 @@ const PROTOCOL_ICONS = { // HELPERS /////////////////////// +function uWordBoundaryGroup(inner) { + // Match if surrounded by non-letter/non-digit (Unicode-aware) + // We don't use lookbehind for max compatibility. + return new RegExp(`(?:^|[^\\p{L}\\p{N}])(?:${inner})(?=$|[^\\p{L}\\p{N}])`, "iu"); +} + function isIPv4(str) { if (typeof str !== "string") return false; const m = str.match(/^(\d{1,3})(\.\d{1,3}){3}$/); @@ -201,6 +205,55 @@ function extractIconTagsAndStrip(name) { function detectCountryByName(name) { const n = String(name || ""); // Order by priority, then first match wins + + // Fast path: flag emoji + if (n.includes("๐Ÿ‡ฆ๐Ÿ‡ช")) return { iso3: "ARE", flag: "๐Ÿ‡ฆ๐Ÿ‡ช", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ฆ๐Ÿ‡ท")) return { iso3: "ARG", flag: "๐Ÿ‡ฆ๐Ÿ‡ท", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ฆ๐Ÿ‡น")) return { iso3: "AUT", flag: "๐Ÿ‡ฆ๐Ÿ‡น", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ฆ๐Ÿ‡บ")) return { iso3: "AUS", flag: "๐Ÿ‡ฆ๐Ÿ‡บ", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ง๐Ÿ‡ฌ")) return { iso3: "BGR", flag: "๐Ÿ‡ง๐Ÿ‡ฌ", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ง๐Ÿ‡ท")) return { iso3: "BRA", flag: "๐Ÿ‡ง๐Ÿ‡ท", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡จ๐Ÿ‡ฆ")) return { iso3: "CAN", flag: "๐Ÿ‡จ๐Ÿ‡ฆ", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡จ๐Ÿ‡ญ")) return { iso3: "CHE", flag: "๐Ÿ‡จ๐Ÿ‡ญ", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡จ๐Ÿ‡ฟ")) return { iso3: "CZE", flag: "๐Ÿ‡จ๐Ÿ‡ฟ", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ฉ๐Ÿ‡ช")) return { iso3: "DEU", flag: "๐Ÿ‡ฉ๐Ÿ‡ช", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ฉ๐Ÿ‡ฐ")) return { iso3: "DNK", flag: "๐Ÿ‡ฉ๐Ÿ‡ฐ", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ช๐Ÿ‡ช")) return { iso3: "EST", flag: "๐Ÿ‡ช๐Ÿ‡ช", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ช๐Ÿ‡ฌ")) return { iso3: "EGY", flag: "๐Ÿ‡ช๐Ÿ‡ฌ", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ช๐Ÿ‡ธ")) return { iso3: "ESP", flag: "๐Ÿ‡ช๐Ÿ‡ธ", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ซ๐Ÿ‡ฎ")) return { iso3: "FIN", flag: "๐Ÿ‡ซ๐Ÿ‡ฎ", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ซ๐Ÿ‡ท")) return { iso3: "FRA", flag: "๐Ÿ‡ซ๐Ÿ‡ท", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ฌ๐Ÿ‡ง")) return { iso3: "GBR", flag: "๐Ÿ‡ฌ๐Ÿ‡ง", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ฌ๐Ÿ‡ช")) return { iso3: "GEO", flag: "๐Ÿ‡ฌ๐Ÿ‡ช", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ญ๐Ÿ‡ฐ")) return { iso3: "HKG", flag: "๐Ÿ‡ญ๐Ÿ‡ฐ", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ฎ๐Ÿ‡ช")) return { iso3: "IRL", flag: "๐Ÿ‡ฎ๐Ÿ‡ช", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ฎ๐Ÿ‡ฑ")) return { iso3: "ISR", flag: "๐Ÿ‡ฎ๐Ÿ‡ฑ", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ฎ๐Ÿ‡ณ")) return { iso3: "IND", flag: "๐Ÿ‡ฎ๐Ÿ‡ณ", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ฎ๐Ÿ‡น")) return { iso3: "ITA", flag: "๐Ÿ‡ฎ๐Ÿ‡น", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ฏ๐Ÿ‡ต")) return { iso3: "JPN", flag: "๐Ÿ‡ฏ๐Ÿ‡ต", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ฐ๐Ÿ‡ท")) return { iso3: "KOR", flag: "๐Ÿ‡ฐ๐Ÿ‡ท", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ฐ๐Ÿ‡ฟ")) return { iso3: "KAZ", flag: "๐Ÿ‡ฐ๐Ÿ‡ฟ", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ฑ๐Ÿ‡น")) return { iso3: "LTU", flag: "๐Ÿ‡ฑ๐Ÿ‡น", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ฑ๐Ÿ‡ป")) return { iso3: "LVA", flag: "๐Ÿ‡ฑ๐Ÿ‡ป", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ฒ๐Ÿ‡ฉ")) return { iso3: "MDA", flag: "๐Ÿ‡ฒ๐Ÿ‡ฉ", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ฒ๐Ÿ‡พ")) return { iso3: "MYS", flag: "๐Ÿ‡ฒ๐Ÿ‡พ", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ณ๐Ÿ‡ฌ")) return { iso3: "NGA", flag: "๐Ÿ‡ณ๐Ÿ‡ฌ", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ณ๐Ÿ‡ฑ")) return { iso3: "NLD", flag: "๐Ÿ‡ณ๐Ÿ‡ฑ", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ณ๐Ÿ‡ด")) return { iso3: "NOR", flag: "๐Ÿ‡ณ๐Ÿ‡ด", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ต๐Ÿ‡ญ")) return { iso3: "PHL", flag: "๐Ÿ‡ต๐Ÿ‡ญ", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ต๐Ÿ‡ฑ")) return { iso3: "POL", flag: "๐Ÿ‡ต๐Ÿ‡ฑ", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ต๐Ÿ‡น")) return { iso3: "PRT", flag: "๐Ÿ‡ต๐Ÿ‡น", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ท๐Ÿ‡ด")) return { iso3: "ROU", flag: "๐Ÿ‡ท๐Ÿ‡ด", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ท๐Ÿ‡บ")) return { iso3: "RUS", flag: "๐Ÿ‡ท๐Ÿ‡บ", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ธ๐Ÿ‡ช")) return { iso3: "SWE", flag: "๐Ÿ‡ธ๐Ÿ‡ช", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ธ๐Ÿ‡ฌ")) return { iso3: "SGP", flag: "๐Ÿ‡ธ๐Ÿ‡ฌ", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡น๐Ÿ‡ญ")) return { iso3: "THA", flag: "๐Ÿ‡น๐Ÿ‡ญ", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡น๐Ÿ‡ท")) return { iso3: "TUR", flag: "๐Ÿ‡น๐Ÿ‡ท", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡น๐Ÿ‡ผ")) return { iso3: "TWN", flag: "๐Ÿ‡น๐Ÿ‡ผ", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡บ๐Ÿ‡ธ")) return { iso3: "USA", flag: "๐Ÿ‡บ๐Ÿ‡ธ", priority: 1, source: "flag" }; + if (n.includes("๐Ÿ‡ป๐Ÿ‡ณ")) return { iso3: "VNM", flag: "๐Ÿ‡ป๐Ÿ‡ณ", priority: 1, source: "flag" }; + + const sorted = COUNTRY_RULES.slice().sort((a, b) => a.priority - b.priority); for (const c of sorted) { if (c.regex.test(n)) return { iso3: c.iso3, flag: c.flag, priority: c.priority, source: "name" };