Files
QuantumultX/Scripts/resource-parser.js
2020-04-24 13:46:02 +08:00

299 lines
9.4 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 本资源解析器作者: Shawn (@XIAO_KOP) , 有问题请反馈:@Shawn_KOP_bot
* 功能: 将不同格式订阅转换成 Quantumult X并支持简单的过滤.
* 目前支持 V2RayN/SSR/Trojan/Quanx 格式写法的节点引用;
* 过滤参数为 in,out, 分别为保留与排除,多个参数间用+号连接, 可直接使用中文(如 in=香港+台湾)
* 示范,
0⃣ 在quantumult X 配置文件中[general] 部分,加入 resource_parser_url=https://raw.githubusercontent.com/KOP-XIAO/QuantumultX/master/Scripts/resource-parser.js
1⃣ 原始订阅连接为: https://raw.githubusercontent.com/crossutility/Quantumult-X/master/server-complete.txt ,
2⃣ 想要保留的参数为 in=tls+ss, 想要过滤的参数为 out=http+2, 请注意下面订阅链接后一定要加 ”#“ 符号
3⃣ 则填入 quanx 的总链接为 https://raw.githubusercontent.com/crossutility/Quantumult-X/master/server-complete.txt#in=tls+ss&out=http+2
4⃣ 填入上述链接并打开的资源解析器开关
*/
var content0=$resource.content;
var para=decodeURIComponent($resource.link);
var type0=Type_Check(content0);
if(type0=="Vmess"){
total=V2QX(content0);
flag=1;
}else if(type0=="QuanX"){
total=content0.split("\n");
flag=1;
}else if(type0=="SSR"){
total=SSR2QX(content0);
flag=1;
}else if(type0=="Trojan"){
total=TJ2QX(content0);
flag=1;
}else{
$notify("👻该解析器暂未支持您的订阅格式");
flag=0;
$done({content : content0});
}
if(flag==1){
$notify("🤖 您订阅类型为:"+type0,"☠️ 您的订阅连接为: 其中#后面的为自定义传入参数","👉"+ para);
var Pin0=para.indexOf("in=")!=-1? para.split("#")[1].split("in=")[1].split("&")[0].split("+"):null;
var Pout0=para.indexOf("out=")!=-1? para.split("#")[1].split("out=")[1].split("&")[0].split("+"):null;
if(Pin0||Pout0){
$notify("👥 开始转换并过滤节点","🐶 具体参数如下","👍️ 保留的关键字:"+Pin0+"\n👎 排除的关键字:"+Pout0);
total=filter(total,Pin0,Pout0)
} else {
$notify("🐷 未开启过滤节点","🐼️ 如需过滤节点请使用in/out参数具体操作参考此示范:","👉 https://t.me/QuanXNews/110");
}
//console.log(total)
$done({content : total.join("\n")});
}
//判断订阅类型
function Type_Check(subs){
var type=""
if (subs.indexOf("dm1lc3M6Ly")!= -1){
type="Vmess"
} else if (subs.indexOf("tag")!=-1){
type="QuanX"
} else if (subs.indexOf("c3NyOi8v")!= -1){
type="SSR"
} else if (subs.indexOf("dHJvamFu")!= -1){
type="Trojan"
}
return type
}
//V2RayN 订阅转换成 QUANX 格式
function V2QX(subs){
const $base64 = new Base64()
var list0=$base64.decode(subs).split("\n");
var QXList=[]
for(i in list0){
if(list0[i].trim()!=""){
var server=String($base64.decode(list0[i].replace("vmess://","")).trim()).split("\u0000")[0];
var nss=[];
if(server!=""){
ss=JSON.parse(server);
ip="vmess="+ss.add+":"+ss.port;
pwd="password="+ss.id;
mtd="method=aes-128-gcm"
tag="tag="+decodeURIComponent(ss.ps);
tfo="fast-open=false";
udp="udp-relay=false";
obfs=Pobfs(ss);
if(obfs==""){
nss.push(ip,mtd,pwd,tfo,udp,tag)
}else {
nss.push(ip,mtd,pwd,obfs,tfo,udp,tag);}
QX=nss.join(", ");
//$notify("Lists","check",QX)
QXList.push(QX)
}
}
}
return QXList
}
//节点过滤,使用+连接多个关键词:in 为保留out 为排除
function filter(Servers,Pin,Pout){
var NList=[];
for(i in Servers){
if(Servers[i].indexOf("tag")!=-1){
name=Servers[i].split("tag=")[1]
const include = (item) => name.indexOf(item) != -1;
const exclude = (item) => name.indexOf(item) != -1;
if(Pin){
if(Pin.some(include)&&Pout){
if(!Pout.some(exclude)){
NList.push(Servers[i])
}
} else if(Pin.some(include)&&!Pout) {NList.push(Servers[i])}
} else{
if(!Pout.some(exclude)){
NList.push(Servers[i])
}
}
}
}
return NList
}
// Vmess obfs 参数
function Pobfs(jsonl){
var obfsi=[]
if(jsonl.net=="ws" && jsonl.tls=="tls"){
obfs0="obfs=wss, ";
uri0=jsonl.path!=""? "obfs-uri="+jsonl.path:"obfs-uri=/";
host0= jsonl.host!=""? "obfs-host="+jsonl.host+",":"";
obfsi.push(obfs0+host0+uri0)
return obfsi.join(", ")
}else if(jsonl.net=="ws"){
obfs0="obfs=ws";
uri0=jsonl.path!=""? "obfs-uri="+jsonl.path:"obfs-uri=/";
obfsi.push(obfs0,uri0)
return obfsi.join(", ")
}else if(jsonl.tls=="tls"){
obfs0="obfs=over-tls";
uri0=jsonl.path!=""? "obfs-uri="+jsonl.path:"";
host0=jsonl.host!=""? "obfs-host="+jsonl.host:"";
obfsi.push(obfs0+host0)
return obfsi.join(", ")
}
}
//SSR 转换 quanx 格式
function SSR2QX(subs){
const $base64 = new Base64()
var list0=$base64.decode(subs).split("\n");
var QXList=[];
for(i in list0){
if(list0[i].indexOf("ssr://")!=-1){
var nssr=[]
var cnt=$base64.decode(list0[i].split("ssr://")[1].replace(/-/g,"+").replace(/_/g,"/"))
console.log(cnt)
type="shadowsocks=";
ip=cnt.split(":")[0]+":"+cnt.split(":")[1];
pwd="password="+cnt.split("/?")[0].split(":")[5];
mtd="method="+cnt.split(":")[3];
obfs="obfs="+cnt.split(":")[4]+", ";
ssrp="ssr-protocol="+cnt.split(":")[2];
if(cnt.indexOf("obfsparam=")!=-1){
obfshost=cnt.split("obfsparam=")[1].split("&")[0]!=""? "obfs-host="+$base64.decode(cnt.split("obfsparam=")[1].split("&")[0].replace(/-/g,"+").replace(/_/g,"/")).split(",")[0].split("\u0000")[0]+", ":""
}
if(cnt.indexOf("protoparam=")!=-1){
oparam=cnt.split("protoparam=")[1].split("&")[0]!=""? "ssr-protocol-param="+$base64.decode(cnt.split("protoparam=")[1].split("&")[0].replace(/-/g,"+").replace(/_/g,"/")).split(",")[0].split("\u0000")[0]+", ":""
}
tag="tag="+($base64.decode(cnt.split("remarks=")[1].split("&")[0].replace(/-/g,"+").replace(/_/g,"/"))).split("\u0000")[0]
console.log($base64.decode(cnt.split("remarks=")[1].split("&")[0].replace(/-/g,"+").replace(/_/g,"/")))
nssr.push(type+ip,pwd,mtd,obfs+obfshost+oparam+ssrp,tag)
QX=nssr.join(", ")
QXList.push(QX);
}
}
return QXList;
}
//Trojan 类型转换成 QX
function TJ2QX(subs){
const $base64 = new Base64()
var list0=$base64.decode(subs).split("\n");
var QXList=[];
for(i in list0){
if(list0[i].indexOf("trojan://")!=-1){
var ntrojan=[]
var cnt=list0[i].split("trojan://")[1]
type="trojan=";
ip=cnt.split("@")[1].split("?")[0];
pwd="password="+cnt.split("@")[0];
obfs="over-tls=true";
pcert= cnt.indexOf("allowInsecure=0")!= -1? "tls-verification=true":"tls-verification=false";
tag="tag="+decodeURIComponent(cnt.split("#")[1])
ntrojan.push(type+ip,pwd,obfs,pcert,tag)
QX=ntrojan.join(", ");
QXList.push(QX);
}
}
return QXList;
}
//来自 yichahucha 大佬的 Base64 编码/解码: https://github.com/yichahucha/surge/tree/master
function Base64() {
// private property
_keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
// public method for encoding
this.encode = function (input) {
var output = "";
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
var i = 0;
input = _utf8_encode(input);
while (i < input.length) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output +
_keyStr.charAt(enc1) + _keyStr.charAt(enc2) +
_keyStr.charAt(enc3) + _keyStr.charAt(enc4);
}
return output;
}
// public method for decoding
this.decode = function (input) {
var output = "";
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
while (i < input.length) {
enc1 = _keyStr.indexOf(input.charAt(i++));
enc2 = _keyStr.indexOf(input.charAt(i++));
enc3 = _keyStr.indexOf(input.charAt(i++));
enc4 = _keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 != 64) {
output = output + String.fromCharCode(chr2);
}
if (enc4 != 64) {
output = output + String.fromCharCode(chr3);
}
}
output = _utf8_decode(output);
return output;
}
// private method for UTF-8 encoding
_utf8_encode = function (string) {
string = string.replace(/\r\n/g, "\n");
var utftext = "";
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
} else if ((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
} else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
}
// private method for UTF-8 decoding
_utf8_decode = function (utftext) {
var string = "";
var i = 0;
var c = c1 = c2 = 0;
while (i < utftext.length) {
c = utftext.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
i++;
} else if ((c > 191) && (c < 224)) {
c2 = utftext.charCodeAt(i + 1);
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
i += 2;
} else {
c2 = utftext.charCodeAt(i + 1);
c3 = utftext.charCodeAt(i + 2);
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
i += 3;
}
}
return string;
}
}