mirror of
https://github.com/KOP-XIAO/QuantumultX.git
synced 2026-03-24 16:15:08 +00:00
Update resource-parser.js
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
☑️ 资源解析器 ©𝐒𝐡𝐚𝐰𝐧 ⟦2026-01-29 18:09⟧
|
☑️ 资源解析器 ©𝐒𝐡𝐚𝐰𝐧 ⟦2026-02-02 22:49⟧
|
||||||
----------------------------------------------------------
|
----------------------------------------------------------
|
||||||
🛠 发现 𝐁𝐔𝐆 请反馈: https://t.me/ShawnKOP_Parser_Bot
|
🛠 发现 𝐁𝐔𝐆 请反馈: https://t.me/ShawnKOP_Parser_Bot
|
||||||
⛳️ 关注 🆃🅶 相关频道: https://t.me/QuanX_API
|
⛳️ 关注 🆃🅶 相关频道: https://t.me/QuanX_API
|
||||||
@@ -502,7 +502,7 @@ function ResourceParse() {
|
|||||||
if (PUOT==1) { total = total.split("\n").map(UOT).join("\n")}
|
if (PUOT==1) { total = total.split("\n").map(UOT).join("\n")}
|
||||||
if (Pcnt == 1 && total!=undefined) {$notify("⟦" + subtag + "⟧"+"解析后最终返回内容" , "节点数量: " +total.split("\n").length, total)}
|
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,则转换成分流类型
|
total = PRelay==""? Base64.encode(total) : ServerRelay(total.split("\n"),PRelay) //强制节点类型 base64 加密后再导入 Quantumult X, 如果是relay,则转换成分流类型
|
||||||
if (PNS !=0) {$notify("⚠️ 存在Quantumult X不支持的节点类型", "⚠️ 已忽略相关节点数,共计:"+PNS+" 条", "⚠️ 当前版本不支持 HY2,Anytls 等类型")}
|
if (PNS !=0) {$notify("⚠️ 存在Quantumult X不支持的节点类型", "⚠️ 已忽略相关节点数,共计:"+PNS+" 条", "⚠️ 当前版本不支持 Hysteria2,Anytls 等类型"+"\n"+"⚠️ 也不支持“v2ray-http-upgrade” 类型vless")}
|
||||||
if(Pflow==1) {
|
if(Pflow==1) {
|
||||||
//$notify("添加流量信息","xxx","xxxx")
|
//$notify("添加流量信息","xxx","xxxx")
|
||||||
$done({ content: total, info: {bytes_used: 3073741824, bytes_remaining: 2147483648, expire_date: 1854193966}});
|
$done({ content: total, info: {bytes_used: 3073741824, bytes_remaining: 2147483648, expire_date: 1854193966}});
|
||||||
@@ -3079,6 +3079,7 @@ function YAMLFix(cnt){
|
|||||||
cnt = cnt.indexOf("proxies:") != -1 && /\n\s{4}server/.test(cnt) ? cnt.replace(/\n\s{4}(headers|path)/g,"\n $1").replace(/\n\s{6}Host/g,"\n Host").replace(/\t/g,""):cnt
|
cnt = cnt.indexOf("proxies:") != -1 && /\n\s{4}server/.test(cnt) ? cnt.replace(/\n\s{4}(headers|path)/g,"\n $1").replace(/\n\s{6}Host/g,"\n Host").replace(/\t/g,""):cnt
|
||||||
//console.log("part-fix:\n"+cnt.split("proxies:")[1])
|
//console.log("part-fix:\n"+cnt.split("proxies:")[1])
|
||||||
cnt = cnt.indexOf("proxies:") == -1? "proxies:\n" + cnt :"proxies:"+cnt.split("proxies:")[1]
|
cnt = cnt.indexOf("proxies:") == -1? "proxies:\n" + cnt :"proxies:"+cnt.split("proxies:")[1]
|
||||||
|
cnt = cnt.replace(/>/g,"⟩") // 2026-02-02 部分奇葩问题
|
||||||
console.log("after-fix\n"+cnt)
|
console.log("after-fix\n"+cnt)
|
||||||
if(Pdbg == 1) {
|
if(Pdbg == 1) {
|
||||||
$notify("After-Fix","this is", "After-fix:\n"+cnt)}
|
$notify("After-Fix","this is", "After-fix:\n"+cnt)}
|
||||||
@@ -3157,12 +3158,117 @@ function YJSON(cnt) {
|
|||||||
return cnt
|
return cnt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function reorderYamlByNesting(yamlString, decodeUnicode = true) {
|
||||||
|
// 如果需要,先解码 Unicode
|
||||||
|
if (decodeUnicode) {
|
||||||
|
yamlString = decodeUnicodeEscapes(yamlString);
|
||||||
|
}
|
||||||
|
|
||||||
|
const lines = yamlString.split('\n');
|
||||||
|
const result = [];
|
||||||
|
let i = 0;
|
||||||
|
// 收集字段块(包括所有子级)
|
||||||
|
function collectFieldBlock(startIdx, parentIndent) {
|
||||||
|
const block = [lines[startIdx]];
|
||||||
|
let idx = startIdx + 1;
|
||||||
|
while (idx < lines.length) {
|
||||||
|
const line = lines[idx];
|
||||||
|
const indent = line.search(/\S/);
|
||||||
|
const trimmed = line.trim();
|
||||||
|
if (!trimmed) {
|
||||||
|
idx++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (indent <= parentIndent) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
block.push(line);
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
return { block, nextIdx: idx };
|
||||||
|
}
|
||||||
|
// 判断是否有子级
|
||||||
|
function hasChildren(block, parentIndent) {
|
||||||
|
return block.slice(1).some(line => {
|
||||||
|
const trimmed = line.trim();
|
||||||
|
return trimmed && line.search(/\S/) > parentIndent;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 处理单个列表项
|
||||||
|
function processListItem(startIdx, listIndent) {
|
||||||
|
const simpleFields = [];
|
||||||
|
const nestedFields = [];
|
||||||
|
const fieldIndent = listIndent + 2;
|
||||||
|
let idx = startIdx;
|
||||||
|
while (idx < lines.length) {
|
||||||
|
const line = lines[idx];
|
||||||
|
const indent = line.search(/\S/);
|
||||||
|
const trimmed = line.trim();
|
||||||
|
if (!trimmed) {
|
||||||
|
idx++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (indent <= listIndent) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (indent === fieldIndent && trimmed.includes(':')) {
|
||||||
|
const { block, nextIdx } = collectFieldBlock(idx, fieldIndent);
|
||||||
|
|
||||||
|
if (hasChildren(block, fieldIndent)) {
|
||||||
|
nestedFields.push(...block);
|
||||||
|
} else {
|
||||||
|
simpleFields.push(block[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
idx = nextIdx;
|
||||||
|
} else {
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { simpleFields, nestedFields, endIdx: idx };
|
||||||
|
}
|
||||||
|
// 主循环
|
||||||
|
while (i < lines.length) {
|
||||||
|
const line = lines[i];
|
||||||
|
const trimmed = line.trim();
|
||||||
|
if (trimmed.startsWith('- ')) {
|
||||||
|
const listIndent = line.search(/\S/);
|
||||||
|
result.push(line);
|
||||||
|
|
||||||
|
const { simpleFields, nestedFields, endIdx } = processListItem(i + 1, listIndent);
|
||||||
|
result.push(...simpleFields, ...nestedFields);
|
||||||
|
|
||||||
|
i = endIdx;
|
||||||
|
} else {
|
||||||
|
result.push(line);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result.join('\n');
|
||||||
|
}
|
||||||
|
function decodeUnicodeEscapes(str) {
|
||||||
|
return str
|
||||||
|
.replace(/\\U([0-9A-Fa-f]{8})/g, (match, hex) => {
|
||||||
|
return String.fromCodePoint(parseInt(hex, 16));
|
||||||
|
})
|
||||||
|
.replace(/\\u\{([0-9A-Fa-f]+)\}/g, (match, hex) => {
|
||||||
|
return String.fromCodePoint(parseInt(hex, 16));
|
||||||
|
})
|
||||||
|
.replace(/\\u([0-9A-Fa-f]{4})/g, (match, hex) => {
|
||||||
|
return String.fromCodePoint(parseInt(hex, 16));
|
||||||
|
})
|
||||||
|
.replace(/\\x([0-9A-Fa-f]{2})/g, (match, hex) => {
|
||||||
|
return String.fromCharCode(parseInt(hex, 16));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Clash parser
|
// Clash parser
|
||||||
function Clash2QX(cnt) {
|
function Clash2QX(cnt) {
|
||||||
const yaml = new YAML()
|
const yaml = new YAML()
|
||||||
if (Pdbg==1) { $notify(" Before YAML Parse", "content", cnt)}
|
if (Pdbg==1) { $notify(" Before YAML Parse", "content", cnt)}
|
||||||
var aa = JSON.stringify(yaml.parse(YAMLFix(cnt))).replace(/yaml@bug𝟙/g,"[").replace(/冒号/gmi,":").replace(/yaml@bug𝟚/g,"*")
|
var aa = JSON.stringify(yaml.parse(reorderYamlByNesting(YAMLFix(cnt)))).replace(/yaml@bug𝟙/g,"[").replace(/冒号/gmi,":").replace(/yaml@bug𝟚/g,"*")
|
||||||
for (var i=0;i<10;i++) {
|
for (var i=0;i<10;i++) {
|
||||||
aa = aa.replace(new RegExp(patn[4][i], "gmi"),patn[0][i])
|
aa = aa.replace(new RegExp(patn[4][i], "gmi"),patn[0][i])
|
||||||
}
|
}
|
||||||
@@ -3190,6 +3296,8 @@ function Clash2QX(cnt) {
|
|||||||
node = CS52QX(node)
|
node = CS52QX(node)
|
||||||
} else if (typecc == "vless"){
|
} else if (typecc == "vless"){
|
||||||
node = CVL2QX(node)
|
node = CVL2QX(node)
|
||||||
|
} else { // not support type
|
||||||
|
PNS = PNS+1
|
||||||
}
|
}
|
||||||
node = Pudp0 != 0 ? XUDP(node,Pudp0) : node
|
node = Pudp0 != 0 ? XUDP(node,Pudp0) : node
|
||||||
node = Ptfo0 != 0 ? XTFO(node,Ptfo0) : node
|
node = Ptfo0 != 0 ? XTFO(node,Ptfo0) : node
|
||||||
@@ -3401,7 +3509,13 @@ function CVL2QX(cnt){
|
|||||||
} else if (Pcert0 != 1 && cnt.tls) {
|
} else if (Pcert0 != 1 && cnt.tls) {
|
||||||
cert = "tls-verification=false"
|
cert = "tls-verification=false"
|
||||||
}
|
}
|
||||||
node = "vless="+[ipt, pwd, mtd, udp, tfo, obfs, ohost, vfl, pbk, sid, cert, tag].filter(Boolean).join(", ")
|
const pspt = getValue(()=>cnt["ws-opts"]["v2ray-http-upgrade"])
|
||||||
|
if (pspt==true) {
|
||||||
|
PNS = PNS +1
|
||||||
|
node=""
|
||||||
|
} else {
|
||||||
|
node = "vless="+[ipt, pwd, mtd, udp, tfo, obfs, ohost, vfl, pbk, sid, cert, tag].filter(Boolean).join(", ")
|
||||||
|
}
|
||||||
//console.log(node)
|
//console.log(node)
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user