-
-
Save vfarid/7a725ccba10da1fc21f55037873727f6 to your computer and use it in GitHub Desktop.
// Version 1.0.3 | |
const maxConfigItems = 500 | |
const maxPerType = 200 | |
const includeOriginalConfigs = true | |
const subLinks = [ | |
"https://raw.githubusercontent.com/freefq/free/master/v2", | |
"https://raw.githubusercontent.com/Pawdroid/Free-servers/main/sub", | |
"https://raw.githubusercontent.com/aiboboxx/v2rayfree/main/v2", | |
"https://raw.githubusercontent.com/AzadNetCH/Clash/main/V2Ray.txt" | |
] | |
const cnfLinks = [ | |
"https://raw.githubusercontent.com/mahdibland/ShadowsocksAggregator/master/sub/sub_merge.txt", | |
"https://raw.githubusercontent.com/awesome-vpn/awesome-vpn/master/all" | |
] | |
const cleanIPLink = "http://bot.sudoer.net/best.cf.iran.all" | |
const operatorList = ["AST", "HWB", "IRC", "MBT", "MCI", "MKB", "PRS", "RTL", "SHT", "ZTL"] | |
const addressList = ["discord.com", "cloudflare.com", "nginx.com", "cdnjs.com", "vimeo.com", "networksolutions.com", "spotify.com"] | |
const fpList = ["chrome", "chrome", "chrome", "firefox", "safari", "edge", "ios", "android", "random", "random"] | |
const alpnList = ["http/1.1", "h2,http/1.1", "h2,http/1.1"] | |
var cleanIPs = [] | |
export default { | |
async fetch(request) { | |
var url = new URL(request.url) | |
var pathParts = url.pathname.replace(/^\/|\/$/g, "").split("/") | |
var type = pathParts[0].toLowerCase() | |
if (["sub", "clash"].includes(type)) { | |
if (pathParts[1] !== undefined) { | |
var operator = pathParts[1].toUpperCase() | |
if (operatorList.includes(operator)) { | |
cleanIPs = await fetch(cleanIPLink).then(r => r.text()).then(t => t.split("\n")) | |
cleanIPs = cleanIPs.filter(line => (line.search(operator) > 0)) | |
cleanIPs = cleanIPs.map(line => line.split(" ")[0].trim()) | |
} else { | |
cleanIPs = [operator.toLowerCase()] | |
} | |
} | |
var configList = [] | |
for (var subLink of subLinks) { | |
try { | |
configList = configList.concat(await fetch(subLink).then(r => r.text()).then(a => atob(a)).then(t => t.split("\n"))) | |
} catch (e) { } | |
} | |
for (var cnfLink of cnfLinks) { | |
try { | |
configList = configList.concat(await fetch(cnfLink).then(r => r.text()).then(t => t.split("\n"))) | |
} catch (e) { } | |
} | |
var vmessConfigList = configList.filter(cnf => (cnf.search("vmess://") == 0)) | |
var trojanConfigList = configList.filter(cnf => (cnf.search("trojan://") == 0)) | |
var ssConfigList = configList.filter(cnf => (cnf.search("ss://") == 0)) | |
var mergedConfigList = [] | |
if (type == "sub") { | |
if (includeOriginalConfigs) { | |
mergedConfigList = mergedConfigList.concat(getMultipleRandomElements(vmessConfigList, maxPerType)) | |
} | |
mergedConfigList = mergedConfigList.concat( | |
getMultipleRandomElements( | |
vmessConfigList.map(decodeVmess).map(cnf => mixConfig(cnf, url, "vmess")).filter(cnf => (!!cnf && cnf.id)).map(encodeVmess).filter(cnf => !!cnf), | |
maxPerType | |
) | |
) | |
if (includeOriginalConfigs) { | |
mergedConfigList = mergedConfigList.concat(getMultipleRandomElements(trojanConfigList, maxPerType)) | |
mergedConfigList = mergedConfigList.concat(getMultipleRandomElements(ssConfigList, maxPerType)) | |
} | |
return new Response(btoa(getMultipleRandomElements(mergedConfigList, maxConfigItems).join("\n"))); | |
} else { // clash | |
if (includeOriginalConfigs) { | |
mergedConfigList = mergedConfigList.concat( | |
getMultipleRandomElements( | |
vmessConfigList.map(decodeVmess).filter(cnf => (cnf && cnf.id)).map(cnf => toClash(cnf, "vmess")).filter(cnf => (cnf && cnf.uuid)), | |
maxPerType | |
) | |
) | |
} | |
mergedConfigList = mergedConfigList.concat( | |
getMultipleRandomElements( | |
vmessConfigList.map(decodeVmess).map(cnf => mixConfig(cnf, url, "vmess")).filter(cnf => (cnf && cnf.id)).map(cnf => toClash(cnf, "vmess")), | |
maxPerType | |
) | |
) | |
return new Response(toYaml(mergedConfigList)); | |
} | |
} else { | |
var url = new URL(request.url) | |
var newUrl = new URL("https://" + url.pathname.replace(/^\/|\/$/g, "")) | |
return fetch(new Request(newUrl, request)); | |
} | |
} | |
} | |
function encodeVmess(conf) { | |
try { | |
return "vmess://" + btoa(JSON.stringify(conf)) | |
} catch { | |
return null | |
} | |
} | |
function decodeVmess(conf) { | |
try { | |
return JSON.parse(atob(conf.substr(8))) | |
} catch { | |
return {} | |
} | |
} | |
function mixConfig(conf, url, protocol) { | |
try { | |
if (conf.tls != "tls") { | |
return {} | |
} | |
var addr = conf.sni | |
if (!addr) { | |
if (conf.add && !isIp(conf.add)) { | |
addr = conf.add | |
} else if (conf.host && !isIp(conf.host)) { | |
addr = conf.host | |
} | |
} | |
if (!addr) { | |
return conf | |
} | |
conf.name = (conf.name ? conf.name : conf.ps) + '-Worker' | |
conf.sni = url.hostname | |
if (cleanIPs.length) { | |
conf.add = cleanIPs[Math.floor(Math.random() * cleanIPs.length)] | |
} else { | |
conf.add = addressList[Math.floor(Math.random() * addressList.length)] | |
} | |
if (protocol == "vmess") { | |
conf.sni = url.hostname | |
conf.host = url.hostname | |
if (conf.path == undefined) { | |
conf.path = "" | |
} | |
conf.path = "/" + addr + ":" + conf.port + "/" + conf.path.replace(/^\//g, "") | |
conf.fp = fpList[Math.floor(Math.random() * fpList.length)] | |
conf.alpn = alpnList[Math.floor(Math.random() * alpnList.length)] | |
conf.port = 443 | |
} | |
return conf | |
} catch (e) { | |
return {} | |
} | |
} | |
function getMultipleRandomElements(arr, num) { | |
var shuffled = arr //[...arr].sort(() => 0.5 - Math.random()) | |
return shuffled.slice(0, num) | |
} | |
function isIp(str) { | |
try { | |
if (str == "" || str == undefined) return false | |
if (!/^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])(\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])){2}\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-4])$/.test(str)) { | |
return false | |
} | |
var ls = str.split('.') | |
if (ls == null || ls.length != 4 || ls[3] == "0" || parseInt(ls[3]) === 0) { | |
return false | |
} | |
return true | |
} catch (e) { } | |
return false | |
} | |
function toClash(conf, protocol) { | |
const regexUUID = /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/gi | |
var config = {} | |
try { | |
config = { | |
name: conf.name ? conf.name : conf.ps, | |
type: protocol, | |
server: conf.add, | |
port: conf.port, | |
uuid: conf.id, | |
alterId: 0, | |
tls: true, | |
cipher: conf.cipher ? conf.cipher : "auto", | |
"skip-cert-verify": true, | |
servername: conf.sni, | |
network: conf.net, | |
"ws-opts": { | |
path: conf.path, | |
headers: { | |
host: conf.host | |
} | |
} | |
} | |
config.name = config.name.replace(/[^\x20-\x7E]/g, "").replace(/[\s\/:|\[\]@\(\)\.]/g, "") + "-" + Math.floor(Math.random() * 10000) | |
if (!regexUUID.test(config.uuid)) { | |
return {} | |
} | |
return config | |
} catch (e) { | |
return {} | |
} | |
} | |
function toYaml(configList) { | |
var yaml = | |
` | |
mixed-port: 7890 | |
allow-lan: true | |
log-level: info | |
external-controller: 0.0.0.0:9090 | |
dns: | |
enabled: true | |
nameserver: | |
- 1.1.1.1 | |
- 4.2.2.4 | |
- 119.29.29.29 | |
- 223.5.5.5 | |
fallback: | |
- 8.8.8.8 | |
- 8.8.4.4 | |
- tls://1.0.0.1:853 | |
- tls://dns.google:853 | |
proxies: | |
${configList.map(cnf => " - " + JSON.stringify(cnf)).join("\n")} | |
proxy-groups: | |
- name: maingroup | |
type: url-test | |
tolerance: 300 | |
url: 'https://www.google.com/generate_204' | |
interval: 30 | |
lazy: false | |
proxies: | |
${configList.map(cnf => " - " + cnf.name.trim()).join("\n")} | |
rules: | |
- GEOIP,IR,DIRECT | |
- MATCH,maingroup | |
` | |
return yaml; | |
} |
GREATTTT. thanks a lot
مرسیییی وحید🙏🏻
❤️❤️❤️❤️❤️🙏🙏🙏🙏🙏
ممنون وحید جان
دمت گرم
درود بر شما عزیزان
اگر میتونستید کدی بنویسید که پروتکل Shadowsocks رو هم بشه انداخت پشت کلودفلر همچون Vmess عالی میشد
سپاس از شما
سلام
میشه طریقه استفاده از این کد رو بگید ؟
سلام اموزشش توی کانال شون هست
دمت گرم خیلی خوبه، برا خودم یکم دستکاریش کردم (کلش فقط) که سایت های داخلی رو بدون پروکسی باز کنه و دوتا گروه ساختم یکی اتوماتیک یکی هم دستی، گفتم اینجا بزارم شاید بدرد کسی خورد: https://gist.github.com/nasiriscript/169ad75493d04c43e4649b146f756f8a اول که واردش می کنید رو حالت Direct (بدون پروکسی) هست ابتدا یه لتنسی بگیرید تا چند تا سرور با قابلیت اتصال پیدا کنه و بعد یا پروکسی مورد نظرتون رو انتخاب کنید یا بزارید رو اتوماتیک که سریعترین سرور رو طی زمان، خودش پیدا و انتخاب کنه.
سپاس از محبت شما
برای url-test
من از این لینک استفاده میکنم و تقریبا تمام سرورهایی که بدست میاد علاوه بر پینک سرعت اتصالشون هم درسته
https://speed.cloudflare.com/__down?bytes=100
اگه خواستید میتونید بایتهاشو هم تغییر بدید
تو کدتون تست کنید
سلام وحید جان . کدت یه مشکلی که داره .
وقتی domain ست میکنم واسش . sni و هاست رو جایگزین نمیکنه .
وقتی ip ست میکنم . تفاوتی با اصلش نداره . ip اصلی سرورا باقی میمونه .
بعد اگه ابزاری برای اتوماتیک گرفتن تمام کانفیگ ها و پاک کردن تکراری ها میشناسی معرفی کن . ی حجم خیلی زیادی منبع برای سرور دارم :)
وحید جان این آخرین ویرایشه؟
سلام
اگه بخوام (همه کانفیگای اوریجینال) + (همه ی کانفیگا با ایپی تمیز) برگردونه باید کجا رو تغیر بدم ؟ کلا المان راندوم رو بردارم یعنی...
((تعداد ایپی ها زیاد نمیشه... فقط یکی از لینک ها رو فعال کردم))
میشه لطفا ساپورت سابسکریپشن لینک مرزبان هم اضافه کنی؟
متشکر وحید عزیز
یکی راهنمایی کنه لطفا چطور استفاده کنیم ایا رو ورکر اضافش کنیم و کد رو از گت فری نو بگیرم انجام میشه
.
بله