Last active
July 14, 2025 15:28
-
-
Save NHZEX/d32864d66a4c5bbcd273d669d271e2c8 to your computer and use it in GitHub Desktop.
clash 自定义配置
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
// Define main function (script entry) | |
// 规则 | |
const prependRules = [ | |
'DOMAIN-SUFFIX,test,DIRECT,no-resolve', | |
'DOMAIN-SUFFIX,local,DIRECT,no-resolve', | |
'DOMAIN,cn.download.nvidia.com,DIRECT', | |
'DOMAIN,docker.1panel.live,DIRECT', | |
'DOMAIN-SUFFIX,dockerhub.icu,DIRECT', | |
'DOMAIN-SUFFIX,cursor.sh,[R]Cursor', // DIRECT | |
'DOMAIN-SUFFIX,jetbrains.com,[R]Jetbrains', | |
'DOMAIN,download-cdn.jetbrains.com,DIRECT', | |
'DOMAIN,download.jetbrains.com,DIRECT', | |
]; | |
const appendRules = []; | |
const dns = { | |
'use-system-hosts': true, | |
'fake-ip-filter': [ | |
"+.lan", | |
"+.test", | |
"+.local", | |
], | |
} | |
const defaultGroupOpts = { | |
url: 'http://cp.cloudflare.com', | |
interval: 35, | |
tolerance: 100, | |
lazy: true | |
} | |
const autoGroupSet = [ | |
{ name: '[AUTO]香港', match: (name) => testStrMatch(name, ['香港', { not: '家宽' }], 'all'), type: 'url-test' }, | |
{ name: '[AUTO]香港中转', match: (name) => testStrMatch(name, ['香港', '中转', { not: '家宽' }], 'all'), type: 'url-test' }, | |
{ name: '[AUTO]台湾', match: (name) => testStrMatch(name, ['台湾', { not: '家宽' }, { not: 'IEPL' }], 'all'), type: 'url-test' }, | |
{ name: '[AUTO]台湾IEPL', match: (name) => testStrMatch(name, ['台湾', 'IEPL', { not: '家宽' }], 'all'), type: 'url-test' }, | |
{ name: '[AUTO]日本', match: (name) => testStrMatch(name, ['日本', { not: '家宽' }], 'all'), type: 'url-test' }, | |
{ name: '[AUTO]日本IEPL', match: (name) => testStrMatch(name, ['日本', 'IEPL', { not: '家宽' }], 'all'), type: 'url-test' }, | |
{ name: '[AUTO]韩国', match: (name) => testStrMatch(name, ['韩国', { not: '家宽' }], 'all'), type: 'url-test' }, | |
{ name: '[AUTO]新加坡', match: (name) => testStrMatch(name, ['新加坡', { not: '家宽' }], 'all'), type: 'url-test' }, | |
{ name: '[AUTO]美国', match: (name) => testStrMatch(name, ['美国', { not: '家宽' }], 'all'), type: 'url-test' }, | |
]; | |
const manualGroupSet = [ | |
{ name: '[R]Cursor', match: () => false, type: 'url-test', appendProxies: ['[AUTO]香港', '[AUTO]台湾', '[AUTO]日本', '[AUTO]韩国', '[AUTO]新加坡', '[AUTO]美国'] }, | |
{ name: '[R]Jetbrains', match: () => false, type: 'url-test', appendProxies: ['[AUTO]香港', '[AUTO]台湾', '[AUTO]日本', '[AUTO]韩国', '[AUTO]新加坡', '[AUTO]美国'] }, | |
]; | |
function buildGroups(proxies, buildSetRules) { | |
const addGroups = []; | |
for (const _g of buildSetRules) { | |
const groupProxies = [] | |
for (const proxie of proxies) { | |
if (_g.match(proxie.name)) { | |
groupProxies.push(proxie.name) | |
} | |
} | |
if (_g.appendProxies && Array.isArray(_g.appendProxies)) { | |
groupProxies.push(..._g.appendProxies) | |
} | |
const groupInfo = { | |
name: _g.name, | |
type: _g.type, | |
proxies: groupProxies, | |
...defaultGroupOpts, | |
}; | |
if (groupProxies.length > 0) { | |
addGroups.push(groupInfo) | |
} | |
} | |
return addGroups | |
} | |
function main(config, profileName) { | |
// 在数组末尾追加原本的配置 | |
config.rules.unshift(...prependRules); | |
config.rules.push(...appendRules); | |
const addProxieGroups = buildGroups(config.proxies, autoGroupSet); | |
let proxyGroups = config['proxy-groups'] ?? [] | |
if (addProxieGroups.length > 0) { | |
proxyGroups = insertSubArray(proxyGroups, 1, addProxieGroups) | |
const addGroupNames = addProxieGroups.map(v => v.name) | |
proxyGroups[0].proxies = insertSubArray(proxyGroups[0].proxies, 0, addGroupNames) | |
} | |
const addManualGroups = buildGroups(config.proxies, manualGroupSet); | |
if (addManualGroups.length > 0) { | |
proxyGroups.push(...addManualGroups); | |
} | |
// 覆盖配置 | |
config.dns = { | |
...config['dns'], | |
...dns, | |
} | |
config['proxy-groups'] = proxyGroups | |
return config; | |
} | |
/** | |
* 测试字符串是否匹配给定条件(支持肯定/否定匹配,字符串/正则,任一/全部模式) | |
* @param {string} str - 要测试的目标字符串 | |
* @param {string|RegExp|Object|Array<string|RegExp|Object>} patterns - 匹配模式 | |
* - 字符串: 要求包含该字符串 | |
* - 正则: 要求匹配该正则 | |
* - 对象 { not: string|RegExp }: 要求不包含/不匹配该模式 | |
* @param {string} [mode='any'] - 匹配模式: 'any'(任一匹配) 或 'all'(全部匹配) | |
* @returns {boolean} - 根据匹配模式返回测试结果 | |
* @throws {TypeError} 当模式参数无效或匹配项类型错误时抛出异常 | |
*/ | |
function testStrMatch(str, patterns, mode = 'any') { | |
// 验证模式参数 | |
const validModes = ['any', 'all']; | |
if (!validModes.includes(mode)) { | |
throw new Error(`无效的匹配模式: '${mode}'。请使用 'any' 或 'all'`); | |
} | |
// 处理无效输入 | |
if (typeof str !== 'string') return false; | |
if (patterns === null || patterns === undefined) return false; | |
// 统一处理为数组形式 | |
const testPatterns = Array.isArray(patterns) ? patterns : [patterns]; | |
// 空数组处理 | |
if (testPatterns.length === 0) { | |
return mode === 'all'; // 空数组时:all模式返回true,any模式返回false | |
} | |
// 根据模式进行测试 | |
return testPatterns[mode === 'any' ? 'some' : 'every'](item => { | |
// 处理否定匹配(要求不存在) | |
if (typeof item === 'object' && item !== null && 'not' in item) { | |
const exclusion = item.not; | |
if (typeof exclusion === 'string') { | |
return !str.includes(exclusion); | |
} | |
else if (exclusion instanceof RegExp) { | |
return !exclusion.test(str); | |
} | |
else { | |
throw new TypeError('否定匹配的值必须是字符串或正则表达式'); | |
} | |
} | |
// 处理肯定匹配(要求存在) | |
else if (typeof item === 'string') { | |
return str.includes(item); | |
} | |
else if (item instanceof RegExp) { | |
return item.test(str); | |
} | |
else { | |
throw new TypeError('匹配模式必须是字符串、正则表达式或包含"not"属性的对象'); | |
} | |
}); | |
} | |
/** | |
* 在数组的指定位置插入子数组 | |
* @param {Array} arr - 原始数组 | |
* @param {number} index - 插入位置的索引 | |
* @param {Array} subArray - 要插入的子数组 | |
* @returns {Array} - 插入后的新数组(不修改原数组) | |
*/ | |
function insertSubArray(arr, index, subArray) { | |
// 创建原数组的副本(避免直接修改) | |
const newArr = [...arr]; | |
// 使用 splice 在指定位置插入(扩展运算符展开子数组) | |
newArr.splice(index, 0, ...subArray); | |
return newArr; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment