mirror of
https://github.com/KOP-XIAO/QuantumultX.git
synced 2026-03-24 16:15:08 +00:00
Compare commits
6 Commits
7b9a72e547
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6da56e2678 | ||
|
|
fca6933acb | ||
|
|
d2e11ad165 | ||
|
|
ab25d1ee1e | ||
|
|
53a7e425b8 | ||
|
|
dc56bc8440 |
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
☑️ 资源解析器 ©𝐒𝐡𝐚𝐰𝐧 ⟦2026-02-06 10:57⟧
|
||||
☑️ 资源解析器 ©𝐒𝐡𝐚𝐰𝐧 ⟦2026-02-27 10:27⟧
|
||||
----------------------------------------------------------
|
||||
🛠 发现 𝐁𝐔𝐆 请反馈: https://t.me/ShawnKOP_Parser_Bot
|
||||
⛳️ 关注 🆃🅶 相关频道: https://t.me/QuanX_API
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
🤖 主要功能:
|
||||
❶ 将其它格式的⟦服务器订阅⟧解析成 𝐐𝐮𝐚𝐧𝐭𝐮𝐦𝐮𝐥𝐭 𝐗 格式
|
||||
☑︎ 支持 𝐕2𝐫𝐚𝐲𝐍/𝗦𝗦(𝗥/𝗗)/𝗛𝗧𝗧𝗣(𝗦)/𝗧𝗿𝗼𝗷𝗮𝗻/𝐕𝐋𝗲𝐬𝐬/𝗤𝘂𝗮𝗻𝘁𝘂𝗺𝘂𝗹𝘁(𝗫)/𝗦𝘂𝗿𝗴𝗲/𝐂𝐥𝐚𝐬𝐡/𝐒𝐡𝐚𝐝𝐨𝐰𝐫𝐨𝐜𝐤𝐞𝐭/𝐋𝐨𝐨𝐧 格式
|
||||
☑︎ 支持 𝐕2𝐫𝐚𝐲𝐍/𝗦𝗦(𝗥/𝗗)/𝗧𝗿𝗼𝗷𝗮𝗻/𝐕𝐋𝗲𝐬𝐬/𝗛𝗧𝗧𝗣(𝗦)/𝗤𝘂𝗮𝗻𝘁𝘂𝗺𝘂𝗹𝘁(𝗫)/𝗦𝘂𝗿𝗴𝗲/𝐂𝐥𝐚𝐬𝐡/𝐒𝐡𝐚𝐝𝐨𝐰𝐫𝐨𝐜𝐤𝐞𝐭/𝐋𝐨𝐨𝐧 格式
|
||||
☑︎ 提供说明 1⃣️ 中的可选个性化参数(筛选、重命名 等)
|
||||
❷ 𝗿𝗲𝘄𝗿𝗶𝘁𝗲(重写) & 𝗳𝗶𝗹𝘁𝗲𝗿(分流) 的 转换 & 筛选
|
||||
☑︎ 用于禁用/修改远程引用中某(几)项 𝗿𝗲𝘄𝗿𝗶𝘁𝗲/𝗵𝗼𝘀𝘁𝗻𝗮𝗺𝗲/𝗳𝗶𝗹𝘁𝗲𝗿
|
||||
@@ -502,16 +502,21 @@ function ResourceParse() {
|
||||
if (PUOT==1) { total = total.split("\n").map(UOT).join("\n")}
|
||||
if (Pcnt == 1 && total!=undefined) {$notify("⟦" + subtag + "⟧"+"解析后最终返回内容" , "节点数量: " +total.split("\n").length, total)}
|
||||
total = PRelay==""? Base64.encode(total) : ServerRelay(total.split("\n"),PRelay) //强制节点类型 base64 加密后再导入 Quantumult X, 如果是relay,则转换成分流类型
|
||||
if (PNS !=0) {$notify("⚠️ 存在Quantumult X不支持的节点类型", "⚠️ 已忽略相关节点数,共计:"+PNS+" 条", "⚠️ 当前版本不支持 Hysteria2,Anytls 等类型"+"\n"+"⚠️ 也不支持“http-upgrade/xhttp/grpc/mkcp/h2” 等类型vless")}
|
||||
if (PNS !=0) {
|
||||
$notify("⚠️ 存在Quantumult X不支持的节点类型", "⚠️ 已忽略相关节点数,共计:"+PNS+" 条", "⚠️ 当前版本不支持 Hysteria2,Anytls 等类型"+"\n"+"⚠️ 也不支持“http-upgrade/xhttp/grpc/mkcp/h2” 等类型vless")
|
||||
}
|
||||
if(Pflow==1) {
|
||||
//$notify("添加流量信息","xxx","xxxx")
|
||||
$done({ content: total, info: {bytes_used: 3073741824, bytes_remaining: 2147483648, expire_date: 1854193966}});
|
||||
//$notify("done?","strange")
|
||||
} else { $done({ content: total });}
|
||||
} else {
|
||||
} else { // total length = 0
|
||||
if(Perror == 0) {
|
||||
if (PNS !=0) {$notify("⚠️ 存在Quantumult X不支持的节点类型", "⚠️ 已忽略相关节点数,共计:"+PNS+" 条", "⚠️ 当前版本不支持 Hysteria2,Anytls 等类型"+"\n"+"⚠️ 也不支持“http-upgrade/xhttp/grpc/mkcp/h2” 等类型vless")}
|
||||
$notify("❓❓ 友情提示 ➟ "+ "⟦" + subtag + "⟧", "⚠️⚠️ 解析后无有效内容", "🚥🚥 请自行检查相关参数, 或者点击通知跳转并发送链接反馈", bug_link)
|
||||
if (PNS !=0) { // 全部为不支持类型节点
|
||||
$notify("⚠️ Quantumult-X 不支持该订阅内的节点类型", "⚠️ 已忽略共计:"+PNS+" 条不支持节点,剩余 0️⃣ 条", "⚠️ 当前版本不支持 Hysteria2,Anytls 等类型"+"\n"+"⚠️ 也不支持“http-upgrade/xhttp/grpc/mkcp/h2” 等类型vless")
|
||||
} else { // 其它原因
|
||||
$notify("❓❓ 该订阅 ➟ "+ "⟦" + subtag + "⟧ 解析后无有效节点", "⚠️⚠️ 解析后 Quantumult-X 支持节点数为 0️⃣ 条", "🚥🚥 请自行检查相关参数、确认节点类型, 或者点击通知跳转并发送链接反馈", bug_link)
|
||||
}
|
||||
}
|
||||
total = errornode
|
||||
$done({ content: errornode })
|
||||
@@ -586,7 +591,7 @@ function Type_Check(subs) {
|
||||
var DomainK = ["domain-set,"]
|
||||
var QuanXK = ["shadowsocks=", "trojan=", "vmess=", "http=", "socks5=", "vless="];
|
||||
var SurgeK = ["=ss,", "=vmess,", "=trojan,", "=http,", "=custom,", "=https,", "=shadowsocks", "=shadowsocksr", "=sock5", "=sock5-tls"];
|
||||
var ClashK = ["proxies:"]
|
||||
var ClashK = ["proxies:","\"proxies\":"]
|
||||
var SubK = ["dm1lc3M", "c3NyOi8v", "CnNzOi8", "dHJvamFu", "c3M6Ly", "c3NkOi8v", "c2hhZG93", "aHR0cDovLw", "aHR0cHM6L", "CnRyb2phbjo", "aHR0cD0", "aHR0cCA","U1RBVFVT","dmxlc3M6"];
|
||||
var RewriteK = [" url 302", " url 307", " url reject", " url script", " url req", " url res", " url echo", " url-and-header 302", " url-and-header 307", " url-and-header reject", " url-and-header script", " url-and-header req", " url-and-header res", " url-and-header echo", " url jsonjq"] // quantumult X 类型 rewrite
|
||||
var SubK2 = ["ss://", "vmess://", "ssr://", "trojan://", "ssd://", "\nhttps://", "\nhttp://","socks://","ssocks://","vless://"];
|
||||
@@ -3047,10 +3052,10 @@ function LoonVL2QX(cnt) {
|
||||
////////////////////
|
||||
|
||||
function YAMLFix(cnt){
|
||||
cnt = cnt.replace(/\[/g,"yaml@bug1").replace(/\\r/g,"").replace(/\*/g,"yaml@bug2")
|
||||
cnt = cnt.replace(/\[/g,"yaml@bug𝟙").replace(/\\r/g,"").replace(/\*/g,"yaml@bug𝟚")
|
||||
//2022-08-08 增加 .replace(/\*/g,"🌟@bug2") 以解决名字以 * 开始时引起的部分问题
|
||||
if (cnt.indexOf("{") != -1 && /\{\s*\"*(name|type|server)/.test(cnt)){ // - { } 类型 yaml
|
||||
cnt = cnt.replace(/\s+/g," ").replace(/\s\-\s\{/g," - {") // 2026-02-06 部分空格解析错误
|
||||
cnt = cleanYamlSpaces(cnt) // 2026-02-06 部分空格解析错误
|
||||
cnt = cnt.replace(/(^|\n)- /g, "$1 - ").replace(/ - /g," - ").replace(/:(?!\s)/g,": ").replace(/\,\"/g,", \"").replace(/: {\s{0,1}/g, ": {, ").replace(/, (Host|host|path|mux)/g,", $1")
|
||||
//2022-04-11 remove tls|skip from replace(/, (Host|host|path|mux)/g,", $1")
|
||||
console.log("1st:\n"+cnt)
|
||||
@@ -3082,6 +3087,7 @@ function YAMLFix(cnt){
|
||||
//console.log("part-fix:\n"+cnt.split("proxies:")[1])
|
||||
cnt = cnt.indexOf("proxies:") == -1? "proxies:\n" + cnt :"proxies:"+cnt.split("proxies:")[1]
|
||||
cnt = cnt.replace(/>/g,"⟩") // 2026-02-02 部分奇葩问题
|
||||
//cnt=cnt.replace(/yaml@bug𝟙/g,"[").replace(/冒号/gmi,":").replace(/yaml@bug𝟚/g,"*")
|
||||
console.log("after-fix\n"+cnt)
|
||||
if(Pdbg == 1) {
|
||||
$notify("After-Fix","this is", "After-fix:\n"+cnt)}
|
||||
@@ -3090,6 +3096,15 @@ function YAMLFix(cnt){
|
||||
return cnt
|
||||
}
|
||||
|
||||
// 2026-02-06 {} yaml 空格问题修复
|
||||
function cleanYamlSpaces(yamlText) {
|
||||
return yamlText.split('\n').map(line => {
|
||||
if (line.includes('{') && line.includes('}')) {
|
||||
return ' ' + line.trim().replace(/ {2,}/g, ' ');
|
||||
}
|
||||
return line;
|
||||
}).join('\n');
|
||||
}
|
||||
|
||||
function yamlcheck(cnt){
|
||||
if (cnt.indexOf("name") !=-1){ //名字以某些数字结尾时,解析有 bug
|
||||
@@ -3264,13 +3279,22 @@ function decodeUnicodeEscapes(str) {
|
||||
});
|
||||
}
|
||||
|
||||
// 完整的json
|
||||
function JCheck(cnt) {
|
||||
if (/^{/.test(cnt) &&/}$/.test(cnt)) {
|
||||
return 1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Clash parser
|
||||
function Clash2QX(cnt) {
|
||||
const yaml = new YAML()
|
||||
if (Pdbg==1) { $notify(" Before YAML Parse", "content", cnt)}
|
||||
var aa = JSON.stringify(yaml.parse(reorderYamlByNesting(YAMLFix(cnt)))).replace(/yaml@bug𝟙/g,"[").replace(/冒号/gmi,":").replace(/yaml@bug𝟚/g,"*")
|
||||
//if (Pdbg==1) { $notify(" Before YAML Parse", "content", cnt)}
|
||||
// 如果本身为json则无需解析
|
||||
aa = JCheck(cnt)==0 ? JSON.stringify(yaml.parse(reorderYamlByNesting(YAMLFix(cnt)))).replace(/yaml@bug𝟙/g,"[").replace(/冒号/gmi,":").replace(/yaml@bug𝟚/g,"*") : cnt
|
||||
for (var i=0;i<10;i++) {
|
||||
aa = aa.replace(new RegExp(patn[4][i], "gmi"),patn[0][i])
|
||||
}
|
||||
@@ -3300,13 +3324,19 @@ function Clash2QX(cnt) {
|
||||
node = CVL2QX(node)
|
||||
} else { // not support type
|
||||
PNS = PNS+1
|
||||
if (Pdbg==1) { // 通知提示
|
||||
$notify("不支持该类型节点,已忽略",typecc,JSON.stringify(node))
|
||||
}
|
||||
typecc="NS"
|
||||
}
|
||||
node = Pudp0 != 0 ? XUDP(node,Pudp0) : node
|
||||
node = Ptfo0 != 0 ? XTFO(node,Ptfo0) : node
|
||||
if (typecc!="NS") {
|
||||
node=node.replace(/^([^,]*)\s+/g, (match, p1) => { // 某些ipv6节点空格问题
|
||||
return p1.replace(/\s+/g, '');
|
||||
});
|
||||
nodelist.push(node)
|
||||
}
|
||||
}catch (e) {
|
||||
$notify(`⚠️该节点解析错误, 暂时已忽略处理`,`可点击通知并发送链接反馈至 bot`,JSON.stringify(node),bug_link )
|
||||
$notify(`⚠️错误内容如下`,`可复制错误内容到反馈 bot`,JSON.stringify(node)+"\n\n"+e)
|
||||
@@ -3507,6 +3537,11 @@ function CVL2QX(cnt){
|
||||
ohost = phost ? "obfs-host="+phost : ohost
|
||||
//ohost= cnt["ws-opts"]? "obfs-host=" + cnt["ws-opts"]["headers"]["Host"] : ohost
|
||||
ohost = cnt["servername"]? "obfs-host=" + cnt["servername"] : ohost
|
||||
ohost=ohost.toLowerCase()
|
||||
|
||||
const ppath = getValue(()=>cnt["ws-opts"]["path"])
|
||||
puri = ppath ? "obfs-uri="+ppath : ""
|
||||
|
||||
cert = cnt["skip-cert-verify"] && cnt.tls ? "tls-verification=false" : ""
|
||||
//$notify(cert)
|
||||
if (Pcert0 == 1 && cnt.tls) {
|
||||
@@ -3519,7 +3554,7 @@ function CVL2QX(cnt){
|
||||
PNS = PNS +1
|
||||
node=""
|
||||
} else {
|
||||
node = "vless="+[ipt, pwd, mtd, udp, tfo, obfs, ohost, vfl, pbk, sid, cert, tag].filter(Boolean).join(", ")
|
||||
node = "vless="+[ipt, pwd, mtd, udp, tfo, obfs, ohost, puri, vfl, pbk, sid, cert, tag].filter(Boolean).join(", ")
|
||||
}
|
||||
//console.log(node)
|
||||
return node
|
||||
|
||||
Reference in New Issue
Block a user