Last active
December 11, 2025 11:33
-
-
Save YRLi904/ee20ed1667614e218261f69b43f7d7dd to your computer and use it in GitHub Desktop.
mihomo-override
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| 前言 | |
| 因为是自己用着修修补补 | |
| 所以注释写得不是很全还请见谅 | |
| 本脚本的主要目的是实现 | |
| 1. 根据拥有的节点自动生成xx地区的节点组 | |
| 2. 为落地节点自动添加中转节点组 | |
| 3. 识别Fam关键词,建立家宽组 | |
| 推荐搭配substore使用该脚本 | |
| 多数mihomo系列客户端自身有带 | |
| 可以先在yt等地学习一下如何使用 | |
| 常用内容 | |
| https://raw.githubusercontent.com/Keywos/rule/main/rename.js | |
| https://clashparty.org/docs/guide/override/yaml | |
| https://wiki.metacubex.one/en/config/ | |
| 颜值党推荐搭配 | |
| zashboard | |
| 同理 多数mihomo系列客户端自身也有带的 | |
| 记得在设置里开启概览,那个连接拓扑真好看~ | |
| --- | |
| 正文说明 | |
| 主体参考自 Substore 订阅转换脚本 | |
| https://github.com/powerfullz/override-rules | |
| DNS修改参考自 Linuxdo DNS防泄露配置 | |
| https://linux.do/t/topic/1061825 | |
| 参数乱糟糟的 推荐直接在yaml里写好拿去用 | |
| 传入参数: | |
| - loadbalance: 启用负载均衡 (默认false) | |
| - full: 启用完整配置,用于纯内核启动 (默认false) | |
| - keepalive: 启用 tcp-keep-alive (默认false) | |
| 新加入的: | |
| - cleanManual: 从"手动选择"中移除已有地区分组的节点 (默认true) | |
| - landingRegions: 指定额外生成落地节点组的地区,用逗号分隔 (默认空) | |
| 示例: landingRegions=澳门,麻大,英国 | |
| 默认总是检查的地区: 香港、美国、日本、狮城 | |
| 如指定参数,则同时检查这些额外地区,仅当存在符合条件的节点时生成对应组 | |
| - landingKeywords: 自定义落地节点的识别关键词,用逗号分隔 (默认"落地") | |
| 示例: landingKeywords=Bage,Alice | |
| 说明: "落地"关键词始终默认启用,参数中指定的关键词会追加到默认值 | |
| 若参数为空或不指定,仅使用默认的"落地"关键词进行识别 | |
| 默认启用参数: | |
| - IPv6 支持(始终启用) | |
| - DNS FakeIP 模式(始终启用) | |
| - 落地节点功能(始终启用) | |
| - 中转节点前置代理功能(始终启用) | |
| 注意事项: | |
| - 有些偏冷地区的家宽/节点可能因数量不足 (<=2个) 而未建立地区组 | |
| 如需使用这些节点,请前往"手动选择"代理组进行设置 | |
| - 中转节点会自动识别并配置前置代理: | |
| · 节点名包含"中转M"的节点使用"美国前置"作为前置代理 | |
| · 节点名包含"中转R"的节点使用"日本前置"作为前置代理 | |
| · 节点名包含"中转G"的节点使用"香港前置"作为前置代理 | |
| · 节点名包含"中转A"的节点使用"前置代理"作为前置代理 | |
| - 有些参数没有提,可以看看代码开头那一连串的常量 | |
| */ | |
| const inArg = typeof $arguments !== 'undefined' ? $arguments : {}; | |
| const loadBalance = parseBool(inArg.loadbalance) || false, | |
| fullConfig = parseBool(inArg.full) || false, | |
| keepAliveEnabled = parseBool(inArg.keepalive) || false, | |
| cleanManualEnabled = parseBool(inArg.cleanManual) || true, | |
| landingRegionsInput = (inArg.landingRegions || '').trim(), | |
| landingKeywordsInput = (inArg.landingKeywords || '落地,独享').trim(); | |
| const LOW_COST_KEYWORDS = "0\\.[0-5]|低倍率|省流|大流量|实验性"; | |
| const LOW_COST_REGEX = new RegExp(LOW_COST_KEYWORDS, "i"); | |
| const LOW_COST_AUTO_GROUP_NAME = "低倍率自动"; | |
| const LOW_COST_MANUAL_GROUP_NAME = "低倍率手动"; | |
| const CUSTOM_PROXIED_NAME = "自定义代理"; | |
| const CUSTOM_DIRECT_NAME = "自定义直连"; | |
| const CUSTOM_MATCH_NAME = "漏网之鱼"; | |
| const FRONT_PROXY_KEYWORDS = ["香港", "日本", "美国"]; | |
| // 下面的东西尽量别动,除非知道要干什么;更下面有可以修改的地方 | |
| // 中转节点前置代理映射 | |
| const RELAY_KEYWORDS = { | |
| "中转M": "美国前置", | |
| "中转R": "日本前置", | |
| "中转G": "香港前置", | |
| "中转A": "前置代理" | |
| }; | |
| // 默认落地地区 | |
| const DEFAULT_LANDING_REGIONS = ["香港", "美国", "日本", "狮城"]; | |
| // 解析额外指定的落地地区 | |
| const extraLandingRegions = landingRegionsInput | |
| ? landingRegionsInput.split(',').map(r => r.trim()).filter(r => r && countriesMeta[r]) | |
| : []; | |
| // 合并默认和额外地区,去重 | |
| const allLandingRegions = Array.from(new Set([...DEFAULT_LANDING_REGIONS, ...extraLandingRegions])); | |
| // 解析落地节点识别关键词,支持多个关键词用逗号分隔 | |
| const userLandingKeywords = landingKeywordsInput | |
| ? landingKeywordsInput.split(',').map(k => k.trim()).filter(k => k) | |
| : []; | |
| const landingKeywords = ["落地", ...userLandingKeywords]; | |
| // 去重处理,避免重复的关键词 | |
| const uniqueLandingKeywords = Array.from(new Set(landingKeywords)); | |
| // 下面的配置可以自定义 但是记得前后保持一致性 | |
| const ruleProviders = { | |
| "FakeipFilter": { | |
| "url": "https://cdn.jsdelivr.net/gh/juewuy/ShellCrash@dev/public/fake_ip_filter.list", | |
| "path": "./ruleset/FakeipFilter.list", | |
| "behavior": "domain", "interval": 86400, "format": "text", "type": "http" | |
| }, | |
| "ADBlock": { | |
| "type": "http", "behavior": "domain", "format": "text", "interval": 86400, | |
| "url": "https://adrules.top/adrules_domainset.txt", | |
| "path": "./ruleset/ADBlock.txt" | |
| }, | |
| "AI": { | |
| "type": "http", "behavior": "classical", "format": "text", "interval": 86400, | |
| "url": "https://ruleset.skk.moe/Clash/non_ip/ai.txt", | |
| "path": "./ruleset/AI.txt" | |
| }, | |
| "TikTok": { | |
| "type": "http", "behavior": "classical", "format": "text", "interval": 86400, | |
| "url": "https://cdn.jsdelivr.net/gh/powerfullz/override-rules@master/ruleset/TikTok.list", | |
| "path": "./ruleset/TikTok.list" | |
| }, | |
| "EHentai": { | |
| "type": "http", "behavior": "classical", "format": "text", "interval": 86400, | |
| "url": "https://cdn.jsdelivr.net/gh/powerfullz/override-rules@master/ruleset/EHentai.list", | |
| "path": "./ruleset/EHentai.list" | |
| }, | |
| "SteamFix": { | |
| "type": "http", "behavior": "classical", "format": "text", "interval": 86400, | |
| "url": "https://cdn.jsdelivr.net/gh/powerfullz/override-rules@master/ruleset/SteamFix.list", | |
| "path": "./ruleset/SteamFix.list" | |
| }, | |
| "GoogleFCM": { | |
| "type": "http", "behavior": "classical", "interval": 86400, "format": "text", | |
| "path": "./ruleset/FirebaseCloudMessaging.list", | |
| "url": "https://cdn.jsdelivr.net/gh/powerfullz/override-rules@master/ruleset/FirebaseCloudMessaging.list", | |
| }, | |
| "AdditionalFilter": { | |
| "type": "http", "behavior": "classical", "format": "text", "interval": 86400, | |
| "url": "https://cdn.jsdelivr.net/gh/powerfullz/override-rules@master/ruleset/AdditionalFilter.list", | |
| "path": "./ruleset/AdditionalFilter.list" | |
| }, | |
| "Crypto": { | |
| "type": "http", "behavior": "classical", "format": "text", "interval": 86400, | |
| "url": "https://cdn.jsdelivr.net/gh/powerfullz/override-rules@master/ruleset/Crypto.list", | |
| "path": "./ruleset/Crypto.list" | |
| } | |
| } | |
| const rules = [ | |
| "DOMAIN-SUFFIX,ping0.cc,AI", | |
| "DOMAIN-SUFFIX,ipdata.co,AI", | |
| "DOMAIN-SUFFIX,pingip.cn,AI", | |
| // 把一些ip检查地址丢给AI组了 | |
| "RULE-SET,ADBlock,广告拦截", | |
| "RULE-SET,AdditionalFilter,广告拦截", | |
| "RULE-SET,AI,AI", | |
| "RULE-SET,Crypto,Crypto", | |
| "RULE-SET,EHentai,E-Hentai", | |
| "RULE-SET,TikTok,TikTok", | |
| "RULE-SET,SteamFix,DIRECT", | |
| "RULE-SET,GoogleFCM,DIRECT", | |
| "GEOSITE,GOOGLE-PLAY@CN,DIRECT", | |
| "GEOSITE,TELEGRAM,Telegram", | |
| "GEOSITE,YOUTUBE,YouTube", | |
| "GEOSITE,NETFLIX,Netflix", | |
| "GEOSITE,SPOTIFY,Spotify", | |
| "GEOSITE,BAHAMUT,Bahamut", | |
| "GEOSITE,BILIBILI,Bilibili", | |
| "GEOSITE,MICROSOFT@CN,DIRECT", | |
| "GEOSITE,PIKPAK,PikPak", | |
| "GEOSITE,GOOGLE,Google", | |
| "GEOSITE,GFW,选择节点", | |
| "GEOSITE,CN,DIRECT", | |
| "GEOSITE,PRIVATE,DIRECT", | |
| "GEOIP,NETFLIX,Netflix,no-resolve", | |
| "GEOIP,TELEGRAM,Telegram,no-resolve", | |
| "GEOIP,CN,DIRECT", | |
| "GEOIP,PRIVATE,DIRECT", | |
| "DST-PORT,22,SSH", | |
| "MATCH,漏网之鱼" | |
| ]; | |
| const snifferConfig = { | |
| "sniff": { | |
| "TLS": { | |
| "ports": [443, 8443], | |
| }, | |
| "HTTP": { | |
| "ports": [80, 8080, 8880], | |
| }, | |
| "QUIC": { | |
| "ports": [443, 8443], | |
| } | |
| }, | |
| "override-destination": false, | |
| "enable": true, | |
| "force-dns-mapping": true, | |
| "skip-domain": [ | |
| "Mijia Cloud", | |
| "dlg.io.mi.com", | |
| "+.push.apple.com" | |
| ] | |
| }; | |
| const dnsConfig = { | |
| "enable": true, | |
| "respect-rules": true, | |
| // 让连接DNS服务器时能够遵循规则,也就是通过代理节点连接到上面设置的国外DNS,因为直连可能连接不上 | |
| "ipv6": true, | |
| "prefer-h3": true, | |
| "enhanced-mode": "fake-ip", | |
| "fake-ip-filter": [ | |
| "rule-set:FakeipFilter", | |
| "dig.io.mi.com", | |
| ], | |
| "default-nameserver": [ | |
| // 基础DNS服务器,必须先有它才能使用域名类型的DNS配置,因此必须为IP\ | |
| "119.29.29.29", | |
| "223.5.5.5", | |
| ], | |
| "nameserver": [ | |
| // 在访问的国外网站没有匹配到任何域名规则,最终走了MATCH兜底规则时使用的DNS,为了确保不发生DNS泄漏和DNS污染,必须使用国外DNS | |
| "https://cloudflare-dns.com/dns-query", | |
| "https://dns.google/dns-query", | |
| ], | |
| "direct-nameserver": [ | |
| // 规则匹配到直连时使用的DNS,既然是可以直连的,当然要用国内DNS | |
| "https://dns.alidns.com/dns-query", | |
| "https://doh.pub/dns-query", | |
| ], | |
| "proxy-server-nameserver": [ | |
| // 解析代理节点时使用的DNS,为了使respect-rules生效必须设置,最好设置为国内DNS,否则在代理的第一步就可能因为连接不上国外DNS而解析不出代理节点的IP,最终倒在起点 | |
| "https://dns.alidns.com/dns-query", | |
| "https://doh.pub/dns-query", | |
| ] | |
| }; | |
| const geoxURL = { | |
| "geoip": "https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geoip.dat", | |
| "geosite": "https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geosite.dat", | |
| "mmdb": "https://cdn.jsdelivr.net/gh/Loyalsoldier/geoip@release/Country.mmdb", | |
| "asn": "https://cdn.jsdelivr.net/gh/Loyalsoldier/geoip@release/GeoLite2-ASN.mmdb" | |
| }; | |
| // 地区元数据 | |
| const countriesMeta = { | |
| "香港": { | |
| pattern: "(?i)香港|港|HK|hk|Hong Kong|HongKong|hongkong|🇭🇰", | |
| icon: "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Hong_Kong.png" | |
| }, | |
| "澳门": { | |
| pattern: "(?i)澳门|MO|Macau|🇲🇴", | |
| icon: "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Macao.png" | |
| }, | |
| "台湾": { | |
| pattern: "(?i)台|新北|彰化|TW|Taiwan|🇹🇼", | |
| icon: "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Taiwan.png" | |
| }, | |
| "狮城": { | |
| pattern: "(?i)新加坡|坡|狮城|SG|Singapore|🇸🇬", | |
| icon: "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Singapore.png" | |
| }, | |
| "日本": { | |
| pattern: "(?i)日本|川日|东京|大阪|泉日|埼玉|沪日|深日|JP|Japan|🇯🇵", | |
| icon: "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Japan.png" | |
| }, | |
| "韩国": { | |
| pattern: "(?i)KR|Korea|KOR|首尔|韩|韓|🇰🇷", | |
| icon: "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Korea.png" | |
| }, | |
| "美国": { | |
| pattern: "(?i)美国|美|US|United States|🇺🇸", | |
| icon: "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/United_States.png" | |
| }, | |
| "麻大": { | |
| pattern: "(?i)加拿大|Canada|CA|🇨🇦", | |
| icon: "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Canada.png" | |
| }, | |
| "英国": { | |
| pattern: "(?i)英国|United Kingdom|UK|伦敦|London|🇬🇧", | |
| icon: "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/United_Kingdom.png" | |
| }, | |
| "澳洲": { | |
| pattern: "(?i)澳洲|澳大利亚|AU|Australia|🇦🇺", | |
| icon: "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Australia.png" | |
| }, | |
| "德国": { | |
| pattern: "(?i)德国|德|DE|Germany|🇩🇪", | |
| icon: "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Germany.png" | |
| }, | |
| "法国": { | |
| pattern: "(?i)法国|法|FR|France|🇫🇷", | |
| icon: "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/France.png" | |
| }, | |
| "俄联": { | |
| pattern: "(?i)俄罗斯|俄|RU|Russia|🇷🇺", | |
| icon: "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Russia.png" | |
| }, | |
| "泰国": { | |
| pattern: "(?i)泰国|泰|TH|Thailand|🇹🇭", | |
| icon: "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Thailand.png" | |
| }, | |
| "印度": { | |
| pattern: "(?i)印度|IN|India|🇮🇳", | |
| icon: "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/India.png" | |
| }, | |
| "马来": { | |
| pattern: "(?i)马来西亚|马来|MY|Malaysia|🇲🇾", | |
| icon: "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Malaysia.png" | |
| }, | |
| }; | |
| // 此处我因为使用了substore格式化了节点名称,故而进行了个性化调整 | |
| // 预编译地区匹配规则,国旗优先,其次按文本/代码匹配 | |
| const FLAG_SEQUENCE_REGEX = /[\u{1F1E6}-\u{1F1FF}]{2}/gu; | |
| const countryMatchers = Object.freeze(Object.entries(countriesMeta).reduce((acc, [country, meta]) => { | |
| const patternBody = meta.pattern.replace(/^\(\?i\)/, ''); | |
| const flags = patternBody.match(FLAG_SEQUENCE_REGEX) || []; | |
| acc[country] = { | |
| flags, | |
| regex: new RegExp(patternBody, "i") | |
| }; | |
| return acc; | |
| }, {})); | |
| function matchCountryFromName(name, candidateCountries) { | |
| if (!name) return null; | |
| const candidates = (candidateCountries && candidateCountries.length | |
| ? candidateCountries | |
| : Object.keys(countryMatchers)).filter(country => countryMatchers[country]); | |
| for (const country of candidates) { | |
| const matcher = countryMatchers[country]; | |
| if (matcher.flags.length && matcher.flags.some(flag => name.includes(flag))) { | |
| return country; | |
| } | |
| } | |
| for (const country of candidates) { | |
| const matcher = countryMatchers[country]; | |
| if (matcher.regex.test(name)) { | |
| return country; | |
| } | |
| } | |
| return null; | |
| } | |
| // ==================== 工具函数 ==================== | |
| function parseBool(value) { | |
| if (typeof value === "boolean") return value; | |
| if (typeof value === "string") { | |
| return value.toLowerCase() === "true" || value === "1"; | |
| } | |
| return false; | |
| } | |
| // 检查节点是否为落地节点 | |
| function isLandingNode(nodeName) { | |
| return uniqueLandingKeywords.some(keyword => nodeName.includes(keyword)); | |
| } | |
| // 构建落地节点排斥模式(用于正则表达式) | |
| function buildLandingExcludePattern() { | |
| return uniqueLandingKeywords.map(k => k.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|'); | |
| } | |
| function identifyRelayNodes(proxies) { | |
| // 为中转节点添加 dialer-proxy 字段 | |
| for (const proxy of proxies) { | |
| const name = proxy.name || ''; | |
| // 按照优先级匹配:先匹配具体地区,最后匹配通用中转 | |
| if (name.includes("中转M")) { | |
| proxy["dialer-proxy"] = "美国前置"; | |
| } else if (name.includes("中转R")) { | |
| proxy["dialer-proxy"] = "日本前置"; | |
| } else if (name.includes("中转G")) { | |
| proxy["dialer-proxy"] = "香港前置"; | |
| } else if (name.includes("中转")) { | |
| proxy["dialer-proxy"] = "前置代理"; | |
| } | |
| } | |
| } | |
| // ==================== 数据解析函数 ==================== | |
| function parseLandingNodesByCountry(config, targetCountries) { | |
| // 解析落地节点,并按地区分类 | |
| // 返回: { country: [nodeNames...] } 的对象 | |
| const proxies = config.proxies || []; | |
| const landingByCountry = Object.create(null); | |
| // 逐个节点进行匹配与统计 | |
| for (const proxy of proxies) { | |
| const name = proxy.name || ''; | |
| // 检查是否为落地节点 | |
| if (!isLandingNode(name)) continue; | |
| const matchedCountry = matchCountryFromName(name, targetCountries); | |
| // 如果找到匹配的地区,添加到结果中 | |
| if (matchedCountry) { | |
| if (!landingByCountry[matchedCountry]) { | |
| landingByCountry[matchedCountry] = []; | |
| } | |
| landingByCountry[matchedCountry].push(name); | |
| } | |
| } | |
| return landingByCountry; | |
| } | |
| function hasLowCost(config) { | |
| // 检查是否有低倍率节点 | |
| const proxies = config["proxies"]; | |
| for (const proxy of proxies) { | |
| if (LOW_COST_REGEX.test(proxy.name)) { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| function parseCountries(config) { | |
| const proxies = config.proxies || []; | |
| // 用来累计各国节点数 | |
| const countryCounts = Object.create(null); | |
| const famCounts = Object.create(null); // 家宽节点计数 | |
| const selfBuiltCounts = Object.create(null); // 自建节点计数 | |
| const manualCounts = Object.create(null); // 手动组节点计数 | |
| const allCountries = Object.keys(countryMatchers); | |
| // 逐个节点进行匹配与统计 | |
| for (const proxy of proxies) { | |
| const name = proxy.name || ''; | |
| const isFam = /Fam/i.test(name); // 检查是否为家宽节点 | |
| const isSelfBuilt = /自建/i.test(name); // 检查是否为自建节点 | |
| const isLanding = isLandingNode(name); // 检查是否为落地节点 | |
| const matchedCountry = matchCountryFromName(name, allCountries); | |
| if (!matchedCountry) continue; | |
| // 常规地区节点统计(排除Fam\自建\落地) | |
| if (!isFam && !isSelfBuilt) { | |
| countryCounts[matchedCountry] = (countryCounts[matchedCountry] || 0) + 1; | |
| } | |
| // 家宽节点单独统计 | |
| if (isFam) { | |
| famCounts[matchedCountry] = (famCounts[matchedCountry] || 0) + 1; | |
| } | |
| // 自建节点单独统计 | |
| if (isSelfBuilt) { | |
| selfBuiltCounts[matchedCountry] = (selfBuiltCounts[matchedCountry] || 0) + 1; | |
| } | |
| // 手动组节点统计(包含所有节点) | |
| if (!isLanding) { | |
| manualCounts[matchedCountry] = (manualCounts[matchedCountry] || 0) + 1; | |
| } | |
| } | |
| // 将结果对象转成数组形式 | |
| const result = []; | |
| for (const [country, count] of Object.entries(countryCounts)) { | |
| result.push({ country, count }); | |
| } | |
| const famResult = []; | |
| for (const [country, count] of Object.entries(famCounts)) { | |
| famResult.push({ country, count }); | |
| } | |
| const selfBuiltResult = []; | |
| for (const [country, count] of Object.entries(selfBuiltCounts)) { | |
| selfBuiltResult.push({ country, count }); | |
| } | |
| const manualResult = []; | |
| for (const [country, count] of Object.entries(manualCounts)) { | |
| manualResult.push({ country, count }); | |
| } | |
| return { | |
| regular: result, | |
| fam: famResult, | |
| selfBuilt: selfBuiltResult, | |
| manual: manualResult | |
| }; | |
| } | |
| // ==================== 列表构建函数 ==================== | |
| function buildBaseLists({ manualInfo, selfBuiltInfo, lowCost, famInfo, countryInfo, landingNodesByCountry }) { | |
| const countryGroupNames = countryInfo | |
| .filter(item => item.count > 2) | |
| .map(item => item.country + "节点"); | |
| const famGroupNames = famInfo | |
| .filter(item => item.count > 0) | |
| .map(item => item.country + "家宽"); | |
| const famAvailableGroupNames = famInfo | |
| .filter(item => item.count > 0) | |
| .map(item => item.country + "家宽可用"); | |
| const selfBuiltGroupNames = selfBuiltInfo | |
| .filter(item => item.count > 0) | |
| .map(item => item.country + "自建"); | |
| const manualGroupNames = manualInfo | |
| .filter(item => item.count > 2) | |
| .map(item => item.country + "手动"); | |
| // 落地地区组名称 | |
| const landingCountryGroupNames = landingNodesByCountry | |
| ? Object.keys(landingNodesByCountry) | |
| .filter(country => landingNodesByCountry[country] && landingNodesByCountry[country].length > 0) | |
| .map(country => country + "落地") | |
| : []; | |
| const selector = ["故障转移", "落地节点", "手动选择", "DIRECT"]; | |
| selector.push(...selfBuiltGroupNames); | |
| selector.push(...landingCountryGroupNames); | |
| selector.push(...famAvailableGroupNames); | |
| selector.push(...famGroupNames); | |
| selector.push(...countryGroupNames); | |
| selector.push(...manualGroupNames); | |
| if (lowCost) { | |
| selector.push(LOW_COST_AUTO_GROUP_NAME); | |
| selector.push(LOW_COST_MANUAL_GROUP_NAME); | |
| } | |
| const defaultProxies = ["选择节点", "落地节点", "手动选择", "DIRECT"]; | |
| defaultProxies.push(...selfBuiltGroupNames); | |
| defaultProxies.push(...landingCountryGroupNames); | |
| defaultProxies.push(...famAvailableGroupNames); | |
| defaultProxies.push(...famGroupNames); | |
| defaultProxies.push(...countryGroupNames); | |
| defaultProxies.push(...manualGroupNames); | |
| if (lowCost) { | |
| defaultProxies.push(LOW_COST_AUTO_GROUP_NAME); | |
| defaultProxies.push(LOW_COST_MANUAL_GROUP_NAME); | |
| } | |
| const defaultProxiesDirect = ["选择节点", "手动选择", "DIRECT"]; | |
| defaultProxiesDirect.push(...selfBuiltGroupNames); | |
| defaultProxiesDirect.push(...landingCountryGroupNames); | |
| defaultProxiesDirect.push(...famAvailableGroupNames); | |
| defaultProxiesDirect.push(...famGroupNames); | |
| defaultProxiesDirect.push(...countryGroupNames); | |
| defaultProxiesDirect.push(...manualGroupNames); | |
| if (lowCost) { | |
| defaultProxiesDirect.push(LOW_COST_AUTO_GROUP_NAME); | |
| defaultProxiesDirect.push(LOW_COST_MANUAL_GROUP_NAME); | |
| } | |
| const defaultFallback = ["落地节点"]; | |
| defaultFallback.push(...selfBuiltGroupNames); | |
| defaultFallback.push(...landingCountryGroupNames); | |
| defaultFallback.push(...famAvailableGroupNames); | |
| defaultFallback.push(...famGroupNames); | |
| defaultFallback.push(...countryGroupNames); | |
| defaultFallback.push(...manualGroupNames); | |
| if (lowCost) { | |
| defaultFallback.push(LOW_COST_AUTO_GROUP_NAME); | |
| defaultFallback.push(LOW_COST_MANUAL_GROUP_NAME); | |
| } | |
| defaultFallback.push("手动选择"); | |
| defaultFallback.push("DIRECT"); | |
| return { | |
| defaultProxies, | |
| defaultProxiesDirect, | |
| defaultSelector: selector, | |
| defaultFallback, | |
| countryGroupNames, | |
| landingCountryGroupNames, | |
| famGroupNames, | |
| selfBuiltGroupNames, | |
| manualGroupNames | |
| }; | |
| } | |
| // ==================== 代理组构建函数 ==================== | |
| function buildCountryProxyGroups(countryList) { | |
| // 获取实际存在的地区列表 | |
| const countryProxyGroups = []; | |
| const landingExcludePattern = buildLandingExcludePattern(); | |
| // 为实际存在的地区创建节点组 | |
| for (const country of countryList) { | |
| // 确保地区名称在预设的地区配置中存在 | |
| if (countriesMeta[country]) { | |
| const groupName = `${country}节点`; | |
| const pattern = countriesMeta[country].pattern; | |
| // 构建排除过滤器:排除 Fam、落地节点、低倍率节点 | |
| const excludePattern = `(?i)Fam|${landingExcludePattern}|${LOW_COST_KEYWORDS}`; | |
| const groupConfig = { | |
| "name": groupName, | |
| "icon": countriesMeta[country].icon, | |
| "include-all": true, | |
| "filter": pattern, | |
| "exclude-filter": excludePattern, | |
| "type": (loadBalance) ? "load-balance" : "url-test", | |
| "hidden": true // 隐藏节点列表,用户无需看到内部节点 | |
| }; | |
| if (!loadBalance) { | |
| Object.assign(groupConfig, { | |
| "url": "https://cp.cloudflare.com/generate_204", | |
| "interval": 60, | |
| "tolerance": 20, | |
| "lazy": false | |
| }); | |
| } | |
| countryProxyGroups.push(groupConfig); | |
| } | |
| } | |
| return countryProxyGroups; | |
| } | |
| function buildFamProxyGroups(famCountryList) { | |
| const famProxyGroups = []; | |
| for (const country of famCountryList) { | |
| if (countriesMeta[country]) { | |
| const pattern = countriesMeta[country].pattern; | |
| const filterPattern = `(?i)(?=.*Fam)(?=.*(?:${pattern.replace(/^\(\?i\)/, '')}))`; // 同时匹配Fam和地区 | |
| // 1. URLTEST 子组 (选延迟最低) | |
| const urltestSubGroupConfig = { | |
| "name": `${country}-01-URLTEST`, | |
| "icon": countriesMeta[country].icon, | |
| "include-all": true, | |
| "filter": filterPattern, | |
| "type": "url-test", | |
| "url": "https://cp.cloudflare.com/generate_204", | |
| "interval": 180, | |
| "tolerance": 20, | |
| "lazy": false, | |
| "hidden": true // 隐藏节点列表 | |
| }; | |
| // 2. FALLBACK 子组 (逐个容错) | |
| const fallbackSubGroupConfig = { | |
| "name": `${country}-02-FALLBACK`, | |
| "icon": countriesMeta[country].icon, | |
| "include-all": true, | |
| "filter": filterPattern, | |
| "type": "fallback", | |
| "url": "https://cp.cloudflare.com/generate_204", | |
| "interval": 180, | |
| "tolerance": 20, | |
| "lazy": false, | |
| "hidden": true // 隐藏节点列表 | |
| }; | |
| // 3. 家宽可用组 (fallback,优先 URLTEST,URLTEST 全挂才用 FALLBACK) | |
| const availableGroupConfig = { | |
| "name": `${country}家宽可用`, | |
| "icon": countriesMeta[country].icon, | |
| "type": "fallback", | |
| "url": "https://cp.cloudflare.com/generate_204", | |
| "interval": 180, | |
| "tolerance": 20, | |
| "lazy": false, | |
| "hidden": true, // 隐藏节点列表 | |
| "proxies": [`${country}-01-URLTEST`, `${country}-02-FALLBACK`] | |
| }; | |
| // 4. 家宽手动组 (select 手动选择) | |
| const selectGroupConfig = { | |
| "name": `${country}家宽`, | |
| "icon": countriesMeta[country].icon, | |
| "include-all": true, | |
| "filter": filterPattern, | |
| "type": "select", | |
| "proxies": [`${country}家宽可用`] // 首选自动选择组 | |
| }; | |
| famProxyGroups.push(urltestSubGroupConfig, fallbackSubGroupConfig, availableGroupConfig, selectGroupConfig); | |
| } | |
| } | |
| return famProxyGroups; | |
| } | |
| function buildManualProxyGroups(manualCountryList) { | |
| // 为手动组创建地区分组(selector类型,包含所有节点) | |
| const manualProxyGroups = []; | |
| for (const country of manualCountryList) { | |
| if (countriesMeta[country]) { | |
| const groupName = `${country}手动`; | |
| const pattern = countriesMeta[country].pattern; | |
| const groupConfig = { | |
| "name": groupName, | |
| "icon": countriesMeta[country].icon, | |
| "include-all": true, | |
| "filter": pattern, | |
| "exclude-filter": "(?i)Fam", // 仅排除家宽节点,允许自建和落地节点 | |
| "type": "select" | |
| }; | |
| manualProxyGroups.push(groupConfig); | |
| } | |
| } | |
| return manualProxyGroups; | |
| } | |
| function buildSelfBuiltProxyGroups(selfBuiltCountryList) { | |
| // 为自建节点创建地区分组(selector类型,包含所有自建节点) | |
| const selfBuiltProxyGroups = []; | |
| for (const country of selfBuiltCountryList) { | |
| if (countriesMeta[country]) { | |
| const groupName = `${country}自建`; | |
| const pattern = countriesMeta[country].pattern; | |
| const filterPattern = `(?i)(?=.*自建)(?=.*(?:${pattern.replace(/^\(\?i\)/, '')}))`; // 同时匹配"自建"和地区 | |
| const groupConfig = { | |
| "name": groupName, | |
| "icon": countriesMeta[country].icon, | |
| "include-all": true, | |
| "filter": filterPattern, | |
| "type": "select" | |
| }; | |
| selfBuiltProxyGroups.push(groupConfig); | |
| } | |
| } | |
| return selfBuiltProxyGroups; | |
| } | |
| function buildCustomGroupProxies(defaultSelector) { | |
| const proxies = Array.isArray(defaultSelector) ? defaultSelector.filter(Boolean) : []; | |
| const ordered = ["DIRECT", ...proxies.filter(name => name !== "DIRECT")]; | |
| return ordered; | |
| } | |
| function buildRegionalFrontProxyGroups(countryGroupNames, frontProxySelector) { | |
| // 构建三个地域前置代理组:美国前置、日本前置、香港前置 | |
| // 本质上复制前置代理组的选项,但如果有对应地区的节点组则优先选择 | |
| const regionalFrontGroups = []; | |
| const regions = ["美国", "日本", "香港"]; | |
| for (const region of regions) { | |
| const regionalNodeGroup = `${region}节点`; | |
| // 过滤出不重复的proxies:排除该地区已经存在的节点组 | |
| let proxies = frontProxySelector.filter(name => name !== regionalNodeGroup); | |
| // 如果存在该地区的节点组,将其置于首位作为默认选择 | |
| if (countryGroupNames.includes(regionalNodeGroup)) { | |
| proxies.unshift(regionalNodeGroup); | |
| } | |
| regionalFrontGroups.push({ | |
| "name": `${region}前置`, | |
| "icon": "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Area.png", | |
| "type": "select", | |
| "proxies": proxies | |
| }); | |
| } | |
| return regionalFrontGroups; | |
| } | |
| // ==================== 主代理组构建函数 ==================== | |
| function buildProxyGroups({ | |
| countryList, | |
| countryProxyGroups, | |
| famProxyGroups, | |
| selfBuiltProxyGroups, | |
| manualProxyGroups, | |
| lowCost, | |
| defaultProxies, | |
| defaultProxiesDirect, | |
| defaultSelector, | |
| defaultFallback, | |
| cleanManual, | |
| countryGroupNames, | |
| famGroupNames, | |
| selfBuiltGroupNames, | |
| landingNodesByCountry | |
| }) { | |
| // 查看是否有特定地区的节点 | |
| const hasTW = countryList.includes("台湾"); | |
| const hasHK = countryList.includes("香港"); | |
| const hasUS = countryList.includes("美国"); | |
| // 排除落地节点、选择节点和故障转移以避免死循环,并限制可作为前置的地区 | |
| const frontProxyCandidates = defaultSelector | |
| .filter(name => name !== "落地节点" && name !== "故障转移"); | |
| const filteredFrontProxyCandidates = frontProxyCandidates | |
| .filter(name => FRONT_PROXY_KEYWORDS.some(keyword => name.includes(keyword))); | |
| const frontProxySelector = filteredFrontProxyCandidates.length > 0 | |
| ? filteredFrontProxyCandidates | |
| : frontProxyCandidates; | |
| // 构建手动选择的排除过滤器 | |
| let manualSelectConfig = { | |
| "name": "手动选择", | |
| "icon": "https://cdn.jsdelivr.net/gh/shindgewongxj/WHATSINStash@master/icon/select.png", | |
| "include-all": true, | |
| "type": "select" | |
| }; | |
| // 如果启用 cleanManual,构建排除已有地区分组节点的过滤器 | |
| if (cleanManual) { | |
| const excludePatterns = []; | |
| // 收集所有已建立地区组的地区正则(包括常规地区组、家宽组、自建组) | |
| const allCountries = new Set([ | |
| ...countryList, // 常规地区组的地区 | |
| ...famGroupNames.map(n => n.replace(/家宽$/, '')), // 家宽组的地区 | |
| ...selfBuiltGroupNames.map(n => n.replace(/自建$/, '')) // 自建组的地区 | |
| ]); | |
| for (const country of allCountries) { | |
| if (countriesMeta[country]) { | |
| const pattern = countriesMeta[country].pattern.replace(/^\(\?i\)/, ''); | |
| excludePatterns.push(`(?:${pattern})`); | |
| } | |
| } | |
| // 构建排除正则:排除所有已有地区组的节点和落地节点 | |
| if (excludePatterns.length > 0) { | |
| const combinedPattern = `(?i)(?=.*(?:${excludePatterns.join('|')}))(?!.*(?:${LOW_COST_KEYWORDS}))`; | |
| manualSelectConfig["exclude-filter"] = combinedPattern; | |
| } | |
| // 同时排除落地节点 | |
| const landingExcludePattern = buildLandingExcludePattern(); | |
| if (manualSelectConfig["exclude-filter"]) { | |
| manualSelectConfig["exclude-filter"] = `(?:${manualSelectConfig["exclude-filter"]})|(?i)${landingExcludePattern}`; | |
| } else { | |
| manualSelectConfig["exclude-filter"] = `(?i)${landingExcludePattern}`; | |
| } | |
| } | |
| const customGroupProxies = buildCustomGroupProxies(defaultSelector); | |
| // 构建地域前置代理组 | |
| const regionalFrontProxyGroups = buildRegionalFrontProxyGroups( | |
| countryGroupNames, | |
| frontProxySelector | |
| ); | |
| // 构建分地区的落地节点组 | |
| const landingCountryGroups = []; | |
| if (landingNodesByCountry && typeof landingNodesByCountry === 'object') { | |
| for (const [country, nodes] of Object.entries(landingNodesByCountry)) { | |
| if (nodes && nodes.length > 0 && countriesMeta[country]) { | |
| landingCountryGroups.push({ | |
| "name": `${country}落地`, | |
| "icon": countriesMeta[country].icon, | |
| "type": "select", | |
| "proxies": nodes | |
| }); | |
| } | |
| } | |
| } | |
| return [ | |
| { | |
| "name": "选择节点", | |
| "icon": "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Proxy.png", | |
| "type": "select", | |
| "proxies": defaultSelector | |
| }, | |
| { | |
| "name": CUSTOM_PROXIED_NAME, | |
| "icon": "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Proxy.png", | |
| "type": "select", | |
| "proxies": customGroupProxies | |
| }, | |
| { | |
| "name": CUSTOM_DIRECT_NAME, | |
| "icon": "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Proxy.png", | |
| "type": "select", | |
| "proxies": customGroupProxies | |
| }, | |
| manualSelectConfig, | |
| ...regionalFrontProxyGroups, | |
| { | |
| "name": "前置代理", | |
| "icon": "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Area.png", | |
| "type": "select", | |
| "exclude-filter": `(?i)Fam|${buildLandingExcludePattern()}`, | |
| "proxies": frontProxySelector | |
| }, | |
| ...landingCountryGroups, | |
| { | |
| "name": "落地节点", | |
| "icon": "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Airport.png", | |
| "type": "select", | |
| "include-all": true, | |
| "filter": `(?i)${buildLandingExcludePattern()}`, | |
| }, | |
| { | |
| "name": "故障转移", | |
| "icon": "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Bypass.png", | |
| "type": "fallback", | |
| "url": "https://cp.cloudflare.com/generate_204", | |
| "proxies": defaultFallback, | |
| "interval": 180, | |
| "tolerance": 20, | |
| "lazy": false | |
| }, | |
| { | |
| "name": "AI", | |
| "icon": "https://cdn.jsdelivr.net/gh/powerfullz/override-rules@master/icons/chatgpt.png", | |
| "type": "select", | |
| "proxies": defaultProxies | |
| }, | |
| { | |
| "name": "Google", | |
| "icon": "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Google_Search.png", | |
| "type": "select", | |
| "proxies": defaultProxies | |
| }, | |
| { | |
| "name": "Telegram", | |
| "icon": "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Telegram.png", | |
| "type": "select", | |
| "proxies": defaultProxies | |
| }, | |
| { | |
| "name": "YouTube", | |
| "icon": "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/YouTube.png", | |
| "type": "select", | |
| "proxies": defaultProxies | |
| }, | |
| { | |
| "name": "Bilibili", | |
| "icon": "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/bilibili.png", | |
| "type": "select", | |
| "proxies": (hasTW && hasHK) ? ["直连", "台湾节点", "香港节点"] : defaultProxiesDirect | |
| }, | |
| { | |
| "name": "Netflix", | |
| "icon": "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Netflix.png", | |
| "type": "select", | |
| "proxies": defaultProxies | |
| }, | |
| { | |
| "name": "Spotify", | |
| "icon": "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Spotify.png", | |
| "type": "select", | |
| "proxies": defaultProxies | |
| }, | |
| { | |
| "name": "TikTok", | |
| "icon": "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/TikTok.png", | |
| "type": "select", | |
| "proxies": defaultProxies | |
| }, | |
| { | |
| "name": "E-Hentai", | |
| "icon": "https://cdn.jsdelivr.net/gh/powerfullz/override-rules@master/icons/Ehentai.png", | |
| "type": "select", | |
| "proxies": defaultProxies | |
| }, | |
| { | |
| "name": "PikPak", | |
| "icon": "https://cdn.jsdelivr.net/gh/powerfullz/override-rules@master/icons/PikPak.png", | |
| "type": "select", | |
| "proxies": defaultProxies | |
| }, | |
| { | |
| "name": "Bahamut", | |
| "icon": "https://cdn.jsdmirror.com/gh/Koolson/Qure@master/IconSet/Color/Bahamut.png", | |
| "type": "select", | |
| "proxies": (hasTW) ? ["台湾节点", "选择节点", "手动选择", "直连"] : defaultProxies | |
| }, | |
| { | |
| "name": "Crypto", | |
| "icon": "https://cdn.jsdmirror.com/gh/Koolson/Qure@master/IconSet/Color/Cryptocurrency_3.png", | |
| "type": "select", | |
| "proxies": defaultProxies | |
| }, | |
| { | |
| "name": "SSH", | |
| "icon": "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Server.png", | |
| "type": "select", | |
| "proxies": defaultProxies | |
| }, | |
| { | |
| "name": "直连", | |
| "icon": "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Direct.png", | |
| "type": "select", | |
| "proxies": [ | |
| "DIRECT", "选择节点" | |
| ] | |
| }, | |
| { | |
| "name": "广告拦截", | |
| "icon": "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/AdBlack.png", | |
| "type": "select", | |
| "proxies": [ | |
| "REJECT", "直连" | |
| ] | |
| }, | |
| ...(lowCost ? [ | |
| { | |
| "name": LOW_COST_AUTO_GROUP_NAME, | |
| "icon": "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Lab.png", | |
| "type": "url-test", | |
| "url": "https://cp.cloudflare.com/generate_204", | |
| "include-all": true, | |
| "filter": `(?i)${LOW_COST_KEYWORDS}`, | |
| "hidden": false // 低倍率自动组保持可见,便于确认状态 | |
| }, | |
| { | |
| "name": LOW_COST_MANUAL_GROUP_NAME, | |
| "icon": "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Lab.png", | |
| "include-all": true, | |
| "filter": `(?i)${LOW_COST_KEYWORDS}`, | |
| "type": "select", | |
| "hidden": false // 低倍率手动组同样可见,方便手动挑选 | |
| } | |
| ] : []), | |
| ...countryProxyGroups, | |
| ...selfBuiltProxyGroups, | |
| ...famProxyGroups, | |
| ...manualProxyGroups, | |
| { | |
| "name": CUSTOM_MATCH_NAME, | |
| "icon": "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Proxy.png", | |
| "type": "select", | |
| "proxies": customGroupProxies | |
| } | |
| ].filter(Boolean); // 过滤掉 null 值 | |
| } | |
| // ==================== 主函数 ==================== | |
| function main(config) { | |
| config = { proxies: config.proxies }; | |
| // 解析地区、家宽、自建、手动组与低倍率信息 | |
| const { regular: countryInfo, fam: famInfo, selfBuilt: selfBuiltInfo, manual: manualInfo } = parseCountries(config); | |
| const lowCost = hasLowCost(config); | |
| // 解析落地节点,按地区分类(需要在buildBaseLists前进行,以便传入落地信息) | |
| const landingNodesByCountry = parseLandingNodesByCountry(config, allLandingRegions); | |
| // 构建基础数组 | |
| const { | |
| defaultProxies, | |
| defaultProxiesDirect, | |
| defaultSelector, | |
| defaultFallback, | |
| countryGroupNames: targetCountryList, | |
| landingCountryGroupNames: targetLandingCountryList, | |
| famGroupNames: targetFamList, | |
| selfBuiltGroupNames: targetSelfBuiltList, | |
| manualGroupNames: targetManualList | |
| } = buildBaseLists({ lowCost, countryInfo, famInfo, selfBuiltInfo, manualInfo, landingNodesByCountry }); | |
| // 为地区构建对应的 url-test / load-balance 组 | |
| const countryProxyGroups = buildCountryProxyGroups(targetCountryList.map(n => n.replace(/节点$/, ''))); | |
| // 为家宽节点构建地区分组 | |
| const famProxyGroups = buildFamProxyGroups(targetFamList.map(n => n.replace(/家宽$/, ''))); | |
| // 为自建节点构建地区分组 | |
| const selfBuiltProxyGroups = buildSelfBuiltProxyGroups(targetSelfBuiltList.map(n => n.replace(/自建$/, ''))); | |
| // 为手动组构建地区分组 | |
| const manualProxyGroups = buildManualProxyGroups(targetManualList.map(n => n.replace(/手动$/, ''))); | |
| // 生成代理组 | |
| const proxyGroups = buildProxyGroups({ | |
| countryList: targetCountryList.map(n => n.replace(/节点$/, '')), | |
| countryProxyGroups, | |
| famProxyGroups, | |
| selfBuiltProxyGroups, | |
| manualProxyGroups, | |
| lowCost, | |
| defaultProxies, | |
| defaultProxiesDirect, | |
| defaultSelector, | |
| defaultFallback, | |
| cleanManual: cleanManualEnabled, | |
| countryGroupNames: targetCountryList, | |
| famGroupNames: targetFamList, | |
| selfBuiltGroupNames: targetSelfBuiltList, | |
| landingNodesByCountry | |
| }); | |
| // 为中转节点添加 dialer-proxy 字段 | |
| identifyRelayNodes(config.proxies); | |
| const globalProxies = proxyGroups.map(item => item.name); | |
| proxyGroups.push( | |
| { | |
| "name": "GLOBAL", | |
| "icon": "https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Global.png", | |
| "include-all": true, | |
| "type": "select", | |
| "proxies": globalProxies | |
| } | |
| ); | |
| if (fullConfig) Object.assign(config, { | |
| "mixed-port": 7890, | |
| "redir-port": 7892, | |
| "tproxy-port": 7893, | |
| "routing-mark": 7894, | |
| "allow-lan": true, | |
| "ipv6": true, | |
| "mode": "rule", | |
| "unified-delay": true, | |
| "tcp-concurrent": true, | |
| "find-process-mode": "off", | |
| "log-level": "info", | |
| "geodata-loader": "standard", | |
| "external-controller": ":9999", | |
| "disable-keep-alive": !keepAliveEnabled, | |
| "profile": { | |
| "store-selected": true, | |
| } | |
| }); | |
| Object.assign(config, { | |
| "proxy-groups": proxyGroups, | |
| "rule-providers": ruleProviders, | |
| "rules": rules, | |
| "sniffer": snifferConfig, | |
| "dns": dnsConfig, | |
| "geodata-mode": true, | |
| "geox-url": geoxURL, | |
| }); | |
| return config; | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
哭 忘记fork了
希望powerfullz别介意