Skip to content

Instantly share code, notes, and snippets.

@AnYiEE
Last active July 26, 2024 08:00
Show Gist options
  • Save AnYiEE/fdce3f476dbdc1a905c9255d71c131f7 to your computer and use it in GitHub Desktop.
Save AnYiEE/fdce3f476dbdc1a905c9255d71c131f7 to your computer and use it in GitHub Desktop.
Clash Verge Rev Script for generate configuration based on proxy server information
/**
* @description Clash Verge Rev Script for generate configuration based on proxy server information
* @author AnYiEE<https://gist.github.com/AnYiEE>
* @license GPL-3.0-or-later
*
* @see https://wiki.metacubex.one/config/
* @see https://clash-verge-rev.github.io/guide/script.html
*/
// 全局配置
const generalConfig = {
'allow-lan': true,
'bind-address': '*',
mode: 'rule',
'log-level': 'silent',
ipv6: true,
'tcp-concurrent': true,
'mixed-port': 1080,
};
// Android配置
const androidConfig = {
'append-system-dns': false,
};
// 实验性配置
const experimentalConfig = {
'sniff-tls-sni': true,
};
// 默认DNS(用于解析 其他DNS 的域名)
const defaultNameServers = ['223.5.5.5', '8.8.4.4'];
// 国内DNS
const domesticNameservers = [
'tls://223.5.5.5:853', // 阿里云公共DNS
...defaultNameServers,
];
// 国外DNS
const foreignNameservers = [
'tls://8.8.4.4', // Google
'tls://1.1.1.1', // Cloudflare
];
// DNS配置
const dnsConfig = {
enable: true,
'prefer-h3': true,
listen: '127.0.0.1:1053',
ipv6: true,
'enhanced-mode': 'fake-ip',
'fake-ip-range': '198.18.0.1/16',
'fake-ip-filter': [
'*.*.xboxlive.com',
'*.126.net',
'*.example',
'*.ff14.sdo.com',
'*.ffxiv.com',
'*.finalfantasyxiv.com',
'*.home.arpa',
'*.invalid',
'*.kuwo.cn',
'*.linksys.com',
'*.linksyssmartwifi.com',
'*.mcdn.bilivideo.cn',
'*.music.163.com',
'*.music.migu.cn',
'*.ntp.org.cn',
'*.router.asus.com',
'*.square-enix.com',
'*.test',
'*.time.edu.cn',
'*.xiami.com',
'*.y.qq.com',
'+.battlenet.com.cn',
'+.ipv6.microsoft.com',
'+.lan',
'+.local',
'+.localdomain',
'+.localhost',
'+.jjvip8.com',
'+.media.dssott.com',
'+.msftconnecttest.com',
'+.msftncsi.com',
'+.pool.ntp.org',
'+.pvp.net',
'+.srv.nintendo.net',
'+.stun.*.*',
'+.stun.*.*.*',
'+.stun.*.*.*.*',
'+.stun.playstation.net',
'+.wargaming.net',
'+.wggames.cn',
'+.wotgame.cn',
'+.wowsgame.cn',
'a.w.bilicdn1.com',
'activityapi.huya.com',
'activityapi.huya.com.w.cdngslb.com',
'amobile.music.tc.qq.com',
'api-jooxtt.sanook.com',
'api.bilibili.com',
'api.joox.com',
'aqqmusic.tc.qq.com',
'dl.stream.qqmusic.qq.com',
'ff.dorado.sdo.com',
'heartbeat.belkin.com',
'isure.stream.qqmusic.qq.com',
'joox.com',
'lens.l.google.com',
'localhost.ptlogin2.qq.com',
'localhost.sec.qq.com',
'localhost.work.weixin.qq.com',
'mesu.apple.com',
'mobileoc.music.tc.qq.com',
'msftconnecttest.com',
'msftncsi.com',
'music.163.com',
'music.migu.cn',
'music.taihe.com',
'musicapi.taihe.com',
'ntp.*.com',
'ntp1.*.com',
'ntp2.*.com',
'ntp3.*.com',
'ntp4.*.com',
'ntp5.*.com',
'ntp6.*.com',
'ntp7.*.com',
'proxy.golang.org',
'songsearch.kugou.com',
'streamoc.music.tc.qq.com',
'stun.*.*',
'stun.*.*.*',
'stun.l.google.com',
'swcdn.apple.com',
'swdist.apple.com',
'swdownload.apple.com',
'swquery.apple.com',
'swscan.apple.com',
'teredo.*.*',
'teredo.*.*.*',
'time.*.apple.com',
'time.*.com',
'time.*.edu.cn',
'time.*.gov',
'time1.*.com',
'time1.cloud.tencent.com',
'time2.*.com',
'time3.*.com',
'time4.*.com',
'time5.*.com',
'time6.*.com',
'time7.*.com',
'trackercdn.kugou.com',
'www.bilibili.com',
'www.douyu.com',
'xbox.*.*.microsoft.com',
'xbox.*.microsoft.com',
'xnotify.xboxlive.com',
'y.qq.com',
],
'use-hosts': true,
'use-system-hosts': true,
'default-nameserver': defaultNameServers,
'nameserver-policy': {
'geosite:private,cn,geolocation-cn': domesticNameservers,
},
nameserver: [...domesticNameservers, ...foreignNameservers],
fallback: foreignNameservers,
'fallback-filter': {
geoip: true,
'geoip-code': 'CN',
},
};
// 规则集通用选项
const ruleProviderCommon = {
type: 'http',
interval: 86400,
};
// 规则集配置
const ruleProviders = {
'local-area-network': {
...ruleProviderCommon,
behavior: 'classical',
url: 'https://cdn.jsdelivr.net/gh/ACL4SSR/ACL4SSR/Clash/Providers/LocalAreaNetwork.yaml',
},
'china-media': {
...ruleProviderCommon,
behavior: 'classical',
url: 'https://cdn.jsdelivr.net/gh/ACL4SSR/ACL4SSR/Clash/Providers/ChinaMedia.yaml',
},
'china-domain': {
...ruleProviderCommon,
behavior: 'classical',
url: 'https://cdn.jsdelivr.net/gh/ACL4SSR/ACL4SSR/Clash/Providers/ChinaDomain.yaml',
},
'china-ip': {
...ruleProviderCommon,
behavior: 'ipcidr',
url: 'https://cdn.jsdelivr.net/gh/ACL4SSR/ACL4SSR/Clash/Providers/ChinaIp.yaml',
},
'china-ip-v6': {
...ruleProviderCommon,
behavior: 'classical',
url: 'https://cdn.jsdelivr.net/gh/ACL4SSR/ACL4SSR/Clash/Providers/ChinaIpV6.yaml',
},
'china-company-ip': {
...ruleProviderCommon,
behavior: 'ipcidr',
url: 'https://cdn.jsdelivr.net/gh/ACL4SSR/ACL4SSR/Clash/Providers/ChinaCompanyIp.yaml',
},
'apple-acl': {
...ruleProviderCommon,
behavior: 'classical',
url: 'https://cdn.jsdelivr.net/gh/ACL4SSR/ACL4SSR/Clash/Providers/Apple.yaml',
},
'proxy-media': {
...ruleProviderCommon,
behavior: 'classical',
url: 'https://cdn.jsdelivr.net/gh/ACL4SSR/ACL4SSR/Clash/Providers/ProxyMedia.yaml',
},
'proxy-gfwlist': {
...ruleProviderCommon,
behavior: 'classical',
url: 'https://cdn.jsdelivr.net/gh/ACL4SSR/ACL4SSR/Clash/Providers/ProxyGFWlist.yaml',
},
copilot: {
...ruleProviderCommon,
behavior: 'classical',
url: 'https://cdn.jsdelivr.net/gh/blackmatrix7/ios_rule_script/rule/Clash/Copilot/Copilot.yaml',
},
'open-ai': {
...ruleProviderCommon,
behavior: 'classical',
url: 'https://cdn.jsdelivr.net/gh/blackmatrix7/ios_rule_script/rule/Clash/OpenAI/OpenAI.yaml',
},
ea: {
...ruleProviderCommon,
behavior: 'classical',
url: 'https://cdn.jsdelivr.net/gh/blackmatrix7/ios_rule_script/rule/Clash/EA/EA.yaml',
},
epic: {
...ruleProviderCommon,
behavior: 'classical',
url: 'https://cdn.jsdelivr.net/gh/blackmatrix7/ios_rule_script/rule/Clash/Epic/Epic.yaml',
},
origin: {
...ruleProviderCommon,
behavior: 'classical',
url: 'https://cdn.jsdelivr.net/gh/blackmatrix7/ios_rule_script/rule/Clash/Origin/Origin.yaml',
},
steam: {
...ruleProviderCommon,
behavior: 'classical',
url: 'https://cdn.jsdelivr.net/gh/blackmatrix7/ios_rule_script/rule/Clash/Steam/Steam.yaml',
},
'steam-cn': {
...ruleProviderCommon,
behavior: 'classical',
url: 'https://cdn.jsdelivr.net/gh/blackmatrix7/ios_rule_script/rule/Clash/SteamCN/SteamCN.yaml',
},
apple: {
...ruleProviderCommon,
behavior: 'domain',
url: 'https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/apple.txt',
},
'google-cn': {
...ruleProviderCommon,
behavior: 'domain',
url: 'https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/google.txt',
},
icloud: {
...ruleProviderCommon,
behavior: 'domain',
url: 'https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/icloud.txt',
},
direct: {
...ruleProviderCommon,
behavior: 'domain',
url: 'https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/direct.txt',
},
proxy: {
...ruleProviderCommon,
behavior: 'domain',
url: 'https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/proxy.txt',
},
};
// 规则
const rules = [
'RULE-SET,local-area-network,DIRECT',
'DOMAIN-SUFFIX,downloadmirror.intel.com,国内网站',
'DOMAIN-SUFFIX,openai-sb.com,国外网站',
'RULE-SET,apple-acl,Apple',
'RULE-SET,copilot,Copilot',
'RULE-SET,open-ai,OpenAI',
'RULE-SET,ea,EA',
'RULE-SET,epic,Epic',
'RULE-SET,origin,Origin',
'RULE-SET,steam-cn,SteamCN',
'RULE-SET,steam,Steam',
'RULE-SET,apple,Apple',
'RULE-SET,google-cn,GoogleCN',
'RULE-SET,icloud,iCloud',
'RULE-SET,proxy-media,国外媒体',
'RULE-SET,proxy-gfwlist,国外网站',
'RULE-SET,proxy,国外网站',
'RULE-SET,china-media,国内媒体',
'RULE-SET,china-domain,国内网站',
'RULE-SET,china-ip,国内网站',
'RULE-SET,china-ip-v6,国内网站',
'RULE-SET,china-company-ip,国内网站',
'RULE-SET,direct,国内网站',
'GEOIP,CN,国内网站,no-resolve',
'GEOIP,PRIVATE,DIRECT,no-resolve',
'MATCH,规则之外',
];
// 生成伪UUID
function generateFakeUUID() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
const r = Math.trunc(Math.random() * 16);
const v = c === 'x' ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
}
function getProxies(config) {
return config.proxies
.filter(
(proxy) =>
!(proxy.name?.includes('剩余') || proxy.name?.includes('Expire') || proxy.name?.includes('Traffic'))
)
.sort((a, b) => {
let nameA = a.name?.match(/^\S+\s(.*)$/);
let nameB = b.name?.match(/^\S+\s(.*)$/);
nameA = nameA ? nameA[1] : a.name;
nameB = nameB ? nameB[1] : b.name;
return nameA.localeCompare(nameB);
});
}
function getProxyName(proxy) {
return proxy.name ?? generateFakeUUID();
}
function generateProxyConfig(config) {
const allProxies = getProxies(config);
const hk = allProxies.filter((proxy) => proxy.name?.includes('🇭🇰') || proxy.name?.includes('Hong Kong'));
const tw = allProxies.filter(
(proxy) => proxy.name?.includes('🇨🇳') || proxy.name?.includes('🇹🇼') || proxy.name?.includes('Taiwan')
);
const sg = allProxies.filter((proxy) => proxy.name?.includes('🇸🇬') || proxy.name?.includes('Singapore'));
const jp = allProxies.filter((proxy) => proxy.name?.includes('🇯🇵') || proxy.name?.includes('Japan'));
const us = allProxies.filter((proxy) => proxy.name?.includes('🇺🇸') || proxy.name?.includes('United States'));
const uk = allProxies.filter((proxy) => proxy.name?.includes('🇬🇧') || proxy.name?.includes('United Kingdom'));
const de = allProxies.filter((proxy) => proxy.name?.includes('🇩🇪') || proxy.name?.includes('Germany'));
const nl = allProxies.filter((proxy) => proxy.name?.includes('🇳🇱') || proxy.name?.includes('Netherlands'));
const others = allProxies.filter(
(proxy) => ![...hk, ...tw, ...sg, ...jp, ...us, ...uk, ...de, ...nl].includes(proxy)
);
const namedGroups = [];
if (hk.length) namedGroups.push('🇭🇰 香港节点');
if (tw.length) namedGroups.push('🇨🇳 台湾节点');
if (sg.length) namedGroups.push('🇸🇬 新加坡节点');
if (jp.length) namedGroups.push('🇯🇵 日本节点');
if (us.length) namedGroups.push('🇺🇸 美国节点');
if (uk.length) namedGroups.push('🇬🇧 英国节点');
if (de.length) namedGroups.push('🇩🇪 德国节点');
if (nl.length) namedGroups.push('🇳🇱 新西兰节点');
const commonProxies = [
'🚀 节点选择',
...namedGroups,
...others.map(getProxyName),
'✈️ 手动切换',
'♻️ 自动选择',
'DIRECT',
];
const aiProxies = namedGroups.filter(
(group) => group.includes('🇨🇳') || group.includes('🇸🇬') || group.includes('🇯🇵') || group.includes('🇺🇸')
);
const proxyGroups = [
{
name: '🚀 节点选择',
type: 'select',
proxies: [...namedGroups, ...others.map(getProxyName), '✈️ 手动切换', '♻️ 自动选择'],
},
{
name: '✈️ 手动切换',
type: 'select',
proxies: ['♻️ 自动选择', ...allProxies.map(getProxyName)],
},
{
name: '国内网站',
type: 'select',
proxies: commonProxies,
},
{
name: '国内媒体',
type: 'select',
proxies: commonProxies,
},
{
name: 'Copilot',
type: 'select',
proxies: aiProxies,
},
{
name: 'OpenAI',
type: 'select',
proxies: aiProxies,
},
{
name: 'Apple',
type: 'select',
proxies: commonProxies,
},
{
name: 'iCloud',
type: 'select',
proxies: commonProxies,
},
{
name: 'GoogleCN',
type: 'select',
proxies: commonProxies,
},
{
name: 'EA',
type: 'select',
proxies: commonProxies,
},
{
name: 'Epic',
type: 'select',
proxies: commonProxies,
},
{
name: 'Origin',
type: 'select',
proxies: commonProxies,
},
{
name: 'Steam',
type: 'select',
proxies: commonProxies,
},
{
name: 'SteamCN',
type: 'select',
proxies: commonProxies,
},
{
name: '国外网站',
type: 'select',
proxies: commonProxies,
},
{
name: '国外媒体',
type: 'select',
proxies: commonProxies,
},
{
name: '规则之外',
type: 'select',
proxies: commonProxies,
},
];
const urlTestOptions = {
type: 'url-test',
url: 'http://www.gstatic.com/generate_204',
interval: '300',
};
proxyGroups.push({
...urlTestOptions,
name: '♻️ 自动选择',
proxies: allProxies.map(getProxyName),
});
if (hk.length) {
proxyGroups.push({
...urlTestOptions,
name: '🇭🇰 香港节点',
proxies: hk.map(getProxyName),
});
}
if (tw.length) {
proxyGroups.push({
...urlTestOptions,
name: '🇨🇳 台湾节点',
proxies: tw.map(getProxyName),
});
}
if (sg.length) {
proxyGroups.push({
...urlTestOptions,
name: '🇸🇬 新加坡节点',
proxies: sg.map(getProxyName),
});
}
if (jp.length) {
proxyGroups.push({
...urlTestOptions,
name: '🇯🇵 日本节点',
proxies: jp.map(getProxyName),
});
}
if (us.length) {
proxyGroups.push({
...urlTestOptions,
name: '🇺🇸 美国节点',
proxies: us.map(getProxyName),
});
}
if (uk.length) {
proxyGroups.push({
...urlTestOptions,
name: '🇬🇧 英国节点',
proxies: uk.map(getProxyName),
});
}
if (de.length) {
proxyGroups.push({
...urlTestOptions,
name: '🇩🇪 德国节点',
proxies: de.map(getProxyName),
});
}
if (nl.length) {
proxyGroups.push({
...urlTestOptions,
name: '🇳🇱 新西兰节点',
proxies: nl.map(getProxyName),
});
}
return [allProxies, proxyGroups];
}
function main(config) {
const proxyCount = config?.proxies?.length ?? 0;
const proxyProviderCount =
typeof config?.['proxy-providers'] === 'object' ? Object.keys(config['proxy-providers']).length : 0;
if (proxyCount === 0 && proxyProviderCount === 0) {
throw new Error('配置文件中未找到任何代理');
}
const [allProxies, proxyGroups] = generateProxyConfig(config);
const customConfig = {
...generalConfig,
'clash-for-android': androidConfig,
experimental: experimentalConfig,
dns: dnsConfig,
proxies: allProxies,
'proxy-groups': proxyGroups,
'rule-providers': ruleProviders,
rules,
};
console.log(customConfig);
return customConfig;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment