diff --git a/Scripts/resource-parser.js b/Scripts/resource-parser.js index f4789b6..82ad962 100644 --- a/Scripts/resource-parser.js +++ b/Scripts/resource-parser.js @@ -73,245 +73,249 @@ PS. 隐藏参数 ntf=0/1, 用于关闭/打开资源解析器的提示通知 ------------------------------ */ -var content0=$resource.content; -var link0=$resource.link; +var content0 = $resource.content; +var link0 = $resource.link; //debug -//const $notify=console.log //const $resource={} //const $done=function(snt){return snt} //parameters -var para=(link0.indexOf("http")!=-1 && link0.indexOf("://")!=-1)? link0:link0+content0.split("\n")[0]; -var para1=para.slice(para.indexOf("#")+1) //防止参数中其它位置也存在"#" -var mark0=para.indexOf("#")!=-1? true:false; -const subinfo=$resource.info; -const subtag=$resource.tag!=undefined? $resource.tag:""; -var Pinfo=mark0 && para1.indexOf("info=")!=-1? para1.split("info=")[1].split("&")[0]:0; -var ntf_flow=0; +var para = (link0.indexOf("http") != -1 && link0.indexOf("://") != -1) ? link0 : link0 + content0.split("\n")[0]; +var para1 = para.slice(para.indexOf("#") + 1) //防止参数中其它位置也存在"#" +var mark0 = para.indexOf("#") != -1 ? true : false; +const subinfo = $resource.info; +const subtag = $resource.tag != undefined ? $resource.tag : ""; +var Pinfo = mark0 && para1.indexOf("info=") != -1 ? para1.split("info=")[1].split("&")[0] : 0; +var ntf_flow = 0; //常用量 -const Base64=new Base64Code(); +const Base64 = new Base64Code(); const escapeRegExp = str => str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); //处理特殊符号以便正则匹配使用 -var link1=link0.split("#")[0] -const qxpng="https://raw.githubusercontent.com/crossutility/Quantumult-X/master/quantumult-x.png" // server sub-info link -const subinfo_link = {"open-url": "https://t.me/QuanX_API", "media-url" :"https://shrtm.nu/ebAr"}; -const subinfo_link1={"open-url":link1, "media-url": "https://shrtm.nu/uo13"} // server sub-info link(fake-nodes) -const rwrite_link = {"open-url":link1, "media-url": "https://shrtm.nu/x3o2"} // rewrite filter link -const rwhost_link = {"open-url":link1, "media-url": "https://shrtm.nu/0n5J"} // hostname filter link -const rule_link={"open-url":link1, "media-url": "https://shrtm.nu/cpHD"} // rule filter link -const nan_link={"open-url":link1, "media-url": qxpng} // nan error link -const bug_link={"open-url":"https://t.me/Shawn_KOP_bot", "media-url": "https://shrtm.nu/obcB"} // bug link -const sub_link={"open-url":link1, "media-url": "https://shrtm.nu/ebAr"} // server link +var link1 = link0.split("#")[0] +const qxpng = "https://raw.githubusercontent.com/crossutility/Quantumult-X/master/quantumult-x.png" // server sub-info link +const subinfo_link = { "open-url": "https://t.me/QuanX_API", "media-url": "https://shrtm.nu/ebAr" }; +const subinfo_link1 = { "open-url": link1, "media-url": "https://shrtm.nu/uo13" } // server sub-info link(fake-nodes) +const rwrite_link = { "open-url": link1, "media-url": "https://shrtm.nu/x3o2" } // rewrite filter link +const rwhost_link = { "open-url": link1, "media-url": "https://shrtm.nu/0n5J" } // hostname filter link +const rule_link = { "open-url": link1, "media-url": "https://shrtm.nu/cpHD" } // rule filter link +const nan_link = { "open-url": link1, "media-url": qxpng } // nan error link +const bug_link = { "open-url": "https://t.me/Shawn_KOP_bot", "media-url": "https://shrtm.nu/obcB" } // bug link +const sub_link = { "open-url": link1, "media-url": "https://shrtm.nu/ebAr" } // server link SubFlow() //流量通知 -var type0=Type_Check(content0); // 类型 -var Pin0=mark0 && para1.indexOf("in=")!=-1? (para1.split("in=")[1].split("&")[0].split("+")).map(decodeURIComponent):null; -var Pout0=mark0 && para1.indexOf("out=")!=-1? (para1.split("out=")[1].split("&")[0].split("+")).map(decodeURIComponent):null; -var Preg=mark0 && para1.indexOf("regex=")!=-1? decodeURIComponent(para1.split("regex=")[1].split("&")[0]):null; //server正则过滤参数 -var Pregdel=mark0 && para1.indexOf("delreg=")!=-1? decodeURIComponent(para1.split("delreg=")[1].split("&")[0]):null; // 正则删除参数 -var Phin0=mark0 && para1.indexOf("inhn=")!=-1? (para1.split("inhn=")[1].split("&")[0].split("+")).map(decodeURIComponent):null; //hostname -var Phout0=mark0 && para1.indexOf("outhn=")!=-1? (para1.split("outhn=")[1].split("&")[0].split("+")).map(decodeURIComponent):null; //hostname -var Preplace=mark0 && para1.indexOf("replace=")!=-1? decodeURIComponent(para1.split("replace=")[1].split("&")[0]):null; //filter/rewrite 正则替换 -var Pemoji=mark0 && para1.indexOf("emoji=")!=-1? para1.split("emoji=")[1].split("&")[0]:null; -var Pudp0=mark0 && para1.indexOf("udp=")!=-1? para1.split("udp=")[1].split("&")[0]:0; -var Ptfo0=mark0 && para1.indexOf("tfo=")!=-1? para1.split("tfo=")[1].split("&")[0]:0; -var Prname=mark0 && para1.indexOf("rename=")!=-1? para1.split("rename=")[1].split("&")[0].split("+"):null; -var Prrname=mark0 && para1.indexOf("rrname=")!=-1? para1.split("rrname=")[1].split("&")[0].split("+"):null; -var Ppolicy=mark0 && para1.indexOf("policy=")!=-1? decodeURIComponent(para1.split("policy=")[1].split("&")[0]):"Shawn"; -var Pcert0=mark0 && para1.indexOf("cert=")!=-1? para1.split("cert=")[1].split("&")[0]:1; -var Psort0=mark0 && para1.indexOf("sort=")!=-1? para1.split("sort=")[1].split("&")[0]:0; -var PTls13=mark0 && para1.indexOf("tls13=")!=-1? para1.split("tls13=")[1].split("&")[0]:0; -var Pntf0= mark0 && para1.indexOf("ntf=")!=-1? para1.split("ntf=")[1].split("&")[0]:2; -var Pb64= mark0 && para1.indexOf("b64=")!=-1? para1.split("b64=")[1].split("&")[0]:0; -var emojino=[" 0️⃣ "," 1⃣️ "," 2⃣️ "," 3⃣️ "," 4⃣️ "," 5⃣️ "," 6⃣️ "," 7⃣️ "," 8⃣️ "," 9⃣️ "," 🔟 "] -var pfi=Pin0? "in="+Pin0.join(", ")+", ":"" -var pfo=Pout0? "out="+Pout0.join(", "):"" -var pfihn=Phin0? "inhn="+Phin0.join(", ")+", ":"" -var pfohn=Phout0? "outhn="+Phout0.join(", "):"" -var flow=""; -var exptime=""; +var type0 = Type_Check(content0); // 类型 +var Pin0 = mark0 && para1.indexOf("in=") != -1 ? (para1.split("in=")[1].split("&")[0].split("+")).map(decodeURIComponent) : null; +var Pout0 = mark0 && para1.indexOf("out=") != -1 ? (para1.split("out=")[1].split("&")[0].split("+")).map(decodeURIComponent) : null; +var Psfilter = mark0 && para1.indexOf("sfilter=") != -1 ? Base64.decode(para1.split("sfilter=")[1].split("&")[0]) : null; // script filter +var Preg = mark0 && para1.indexOf("regex=") != -1 ? decodeURIComponent(para1.split("regex=")[1].split("&")[0]) : null; //server正则过滤参数 +var Pregdel = mark0 && para1.indexOf("delreg=") != -1 ? decodeURIComponent(para1.split("delreg=")[1].split("&")[0]) : null; // 正则删除参数 +var Phin0 = mark0 && para1.indexOf("inhn=") != -1 ? (para1.split("inhn=")[1].split("&")[0].split("+")).map(decodeURIComponent) : null; //hostname +var Phout0 = mark0 && para1.indexOf("outhn=") != -1 ? (para1.split("outhn=")[1].split("&")[0].split("+")).map(decodeURIComponent) : null; //hostname +var Preplace = mark0 && para1.indexOf("replace=") != -1 ? decodeURIComponent(para1.split("replace=")[1].split("&")[0]) : null; //filter/rewrite 正则替换 +var Pemoji = mark0 && para1.indexOf("emoji=") != -1 ? para1.split("emoji=")[1].split("&")[0] : null; +var Pudp0 = mark0 && para1.indexOf("udp=") != -1 ? para1.split("udp=")[1].split("&")[0] : 0; +var Ptfo0 = mark0 && para1.indexOf("tfo=") != -1 ? para1.split("tfo=")[1].split("&")[0] : 0; +var Prname = mark0 && para1.indexOf("rename=") != -1 ? para1.split("rename=")[1].split("&")[0].split("+") : null; +var Psrename = mark0 && para1.indexOf("srename=") != -1 ? Base64.decode(para1.split("srename=")[1].split("&")[0]) : null; // script rename +var Prrname = mark0 && para1.indexOf("rrname=") != -1 ? para1.split("rrname=")[1].split("&")[0].split("+") : null; +var Ppolicy = mark0 && para1.indexOf("policy=") != -1 ? decodeURIComponent(para1.split("policy=")[1].split("&")[0]) : "Shawn"; +var Pcert0 = mark0 && para1.indexOf("cert=") != -1 ? para1.split("cert=")[1].split("&")[0] : 1; +var Psort0 = mark0 && para1.indexOf("sort=") != -1 ? para1.split("sort=")[1].split("&")[0] : 0; +var PTls13 = mark0 && para1.indexOf("tls13=") != -1 ? para1.split("tls13=")[1].split("&")[0] : 0; +var Pntf0 = mark0 && para1.indexOf("ntf=") != -1 ? para1.split("ntf=")[1].split("&")[0] : 2; +var Pb64 = mark0 && para1.indexOf("b64=") != -1 ? para1.split("b64=")[1].split("&")[0] : 0; +var emojino = [" 0️⃣ ", " 1⃣️ ", " 2⃣️ ", " 3⃣️ ", " 4⃣️ ", " 5⃣️ ", " 6⃣️ ", " 7⃣️ ", " 8⃣️ ", " 9⃣️ ", " 🔟 "] +var pfi = Pin0 ? "in=" + Pin0.join(", ") + ", " : "" +var pfo = Pout0 ? "out=" + Pout0.join(", ") : "" +var pfihn = Phin0 ? "inhn=" + Phin0.join(", ") + ", " : "" +var pfohn = Phout0 ? "outhn=" + Phout0.join(", ") : "" +var flow = ""; +var exptime = ""; //$notify(type0) //响应头流量处理部分 -function SubFlow(){ - if(Pinfo==1 && subinfo){ - var sinfo=subinfo.replace(/ /g,"").toLowerCase(); - var total="总流量: "+(parseFloat(sinfo.split("total=")[1].split(",")[0])/(1024**3)).toFixed(2)+"GB"; - var usd="已用流量: "+((parseFloat(sinfo.split("upload=")[1].split(",")[0])+parseFloat(sinfo.split("download=")[1].split(",")[0]))/(1024**3)).toFixed(2)+"GB" - var left="剩余流量: "+((parseFloat(sinfo.split("total=")[1].split(",")[0])/(1024**3))-((parseFloat(sinfo.split("upload=")[1].split(",")[0])+parseFloat(sinfo.split("download=")[1].split(",")[0]))/(1024**3))).toFixed(2)+"GB" - if(sinfo.indexOf("expire=")!=-1){ - var epr= new Date(parseFloat(sinfo.split("expire=")[1].split(",")[0])*1000); - var year=epr.getFullYear(); // 获取完整的年份(4位,1970) - var mth=epr.getMonth()+1 < 10 ? '0'+(epr.getMonth()+1):(epr.getMonth()+1); // 获取月份(0-11,0代表1月,用的时候记得加上1) - var day=epr.getDate()<10 ? "0"+(epr.getDate()):epr.getDate(); - epr="过期时间: "+year+"-"+mth+"-"+day - } else{ - epr=""; //"过期时间: ✈️ 未提供該信息" //没过期时间的显示订阅链接 - } - var message=total+"\n"+usd+", "+left; - ntf_flow=1; - $notify("流量信息: ⟦"+subtag+"⟧", epr, message,subinfo_link) +function SubFlow() { + if (Pinfo == 1 && subinfo) { + var sinfo = subinfo.replace(/ /g, "").toLowerCase(); + var total = "总流量: " + (parseFloat(sinfo.split("total=")[1].split(",")[0]) / (1024 ** 3)).toFixed(2) + "GB"; + var usd = "已用流量: " + ((parseFloat(sinfo.split("upload=")[1].split(",")[0]) + parseFloat(sinfo.split("download=")[1].split(",")[0])) / (1024 ** 3)).toFixed(2) + "GB" + var left = "剩余流量: " + ((parseFloat(sinfo.split("total=")[1].split(",")[0]) / (1024 ** 3)) - ((parseFloat(sinfo.split("upload=")[1].split(",")[0]) + parseFloat(sinfo.split("download=")[1].split(",")[0])) / (1024 ** 3))).toFixed(2) + "GB" + if (sinfo.indexOf("expire=") != -1) { + var epr = new Date(parseFloat(sinfo.split("expire=")[1].split(",")[0]) * 1000); + var year = epr.getFullYear(); // 获取完整的年份(4位,1970) + var mth = epr.getMonth() + 1 < 10 ? '0' + (epr.getMonth() + 1) : (epr.getMonth() + 1); // 获取月份(0-11,0代表1月,用的时候记得加上1) + var day = epr.getDate() < 10 ? "0" + (epr.getDate()) : epr.getDate(); + epr = "过期时间: " + year + "-" + mth + "-" + day + } else { + epr = ""; //"过期时间: ✈️ 未提供該信息" //没过期时间的显示订阅链接 + } + var message = total + "\n" + usd + ", " + left; + ntf_flow = 1; + $notify("流量信息: ⟦" + subtag + "⟧", epr, message, subinfo_link) } } //flag=1,2,3分别为 server、rewrite、rule 类型 -if(type0=="Subs-B64Encode"){ - total=SubsEd2QX(content0,Pudp0,Ptfo0,Pcert0,PTls13); - flag=1; -}else if(type0=="Subs"){ - total=Subs2QX(content0,Pudp0,Ptfo0,Pcert0,PTls13); - flag=1; -}else if(type0=="QuanX"){ - total=isQuanX(content0); - flag=1; -}else if(type0=="Surge"){ - total=Surge2QX(content0); - flag=1; -}else if(type0=="sgmodule"){ - flag=2 - if(para1.indexOf("dst=regex")!=-1){ - total=URX2QX(content0) - }else if(para1.indexOf("dst=script")!=-1){ - total=SCP2QX(content0) - }else { - total=SGMD2QX(content0) - } - total=Rewrite_Filter(total,Pin0,Pout0); -}else if(type0=="rewrite"){ - flag=2; - content0=content0.split("\n"); - total=Rewrite_Filter(content0,Pin0,Pout0); -}else if(type0=="Rule"){ - flag=3; - total=content0.split("\n"); - total=Rule_Handle(total,Pout0,Pin0); -}else if(content0.trim()==""){ - $notify("‼️ 引用"+"⟦"+subtag+"⟧"+" 返回內容为空","⁉️ 点通知跳转以确认链接是否失效",para.split("#")[0],nan_link); - flag=0; - $done({content : ""}) -}else if(type0=="unknown"){ - $notify("😭 未能解析, 可能是 bug ⁉️ "+"⟦"+subtag+"⟧", "👻 本解析器 暂未支持/未能识别 该订阅格式", "⚠️ 将直接导入Quantumult X \n 如认为是 BUG, 请点通知跳转反馈",bug_link); - $done({content : content0}); - flag=-1; -}else { flag=0 } +if (type0 == "Subs-B64Encode") { + total = SubsEd2QX(content0, Pudp0, Ptfo0, Pcert0, PTls13); + flag = 1; +} else if (type0 == "Subs") { + total = Subs2QX(content0, Pudp0, Ptfo0, Pcert0, PTls13); + flag = 1; +} else if (type0 == "QuanX") { + total = isQuanX(content0); + flag = 1; +} else if (type0 == "Surge") { + total = Surge2QX(content0); + flag = 1; +} else if (type0 == "sgmodule") { + flag = 2 + if (para1.indexOf("dst=regex") != -1) { + total = URX2QX(content0) + } else if (para1.indexOf("dst=script") != -1) { + total = SCP2QX(content0) + } else { + total = SGMD2QX(content0) + } + total = Rewrite_Filter(total, Pin0, Pout0); +} else if (type0 == "rewrite") { + flag = 2; + content0 = content0.split("\n"); + total = Rewrite_Filter(content0, Pin0, Pout0); +} else if (type0 == "Rule") { + flag = 3; + total = content0.split("\n"); + total = Rule_Handle(total, Pout0, Pin0); +} else if (content0.trim() == "") { + $notify("‼️ 引用" + "⟦" + subtag + "⟧" + " 返回內容为空", "⁉️ 点通知跳转以确认链接是否失效", para.split("#")[0], nan_link); + flag = 0; + $done({ content: "" }) +} else if (type0 == "unknown") { + $notify("😭 未能解析, 可能是 bug ⁉️ " + "⟦" + subtag + "⟧", "👻 本解析器 暂未支持/未能识别 该订阅格式", "⚠️ 将直接导入Quantumult X \n 如认为是 BUG, 请点通知跳转反馈", bug_link); + $done({ content: content0 }); + flag = -1; +} else { flag = 0 } -if(flag==3){ // rule 类型 - $done({content : total.join("\n")}); -}else if(flag==2){ // rewrite 类型 - if(Preplace){total=ReplaceReg(total, Preplace)} - $done({content:total.join("\n")}); -}else if(flag==1){ //server 类型 - if(Pinfo==1&&ntf_flow==0){ //假节点类型的流量通知 - flowcheck(total)} - if(Pin0||Pout0){ total=Filter(total,Pin0,Pout0) } - if(Preg){ total=total.map(Regex).filter(Boolean) } - if(Prrname){ - var Prn=Prrname; - total=total.map(Rename); +if (flag == 3) { // rule 类型 + $done({ content: total.join("\n") }); +} else if (flag == 2) { // rewrite 类型 + if (Preplace) { total = ReplaceReg(total, Preplace) } + $done({ content: total.join("\n") }); +} else if (flag == 1) { //server 类型 + if (Pinfo == 1 && ntf_flow == 0) { //假节点类型的流量通知 + flowcheck(total) } - if(Pemoji){ total=emoji_handle(total,Pemoji); } - if(Prname){ - var Prn=Prname; - total=total.map(Rename); + if (Pin0 || Pout0) { total = Filter(total, Pin0, Pout0) } + if (Preg) { total = total.map(Regex).filter(Boolean) } + if (Psfilter) { total = FilterScript(total, Psfilter) } + if (Prrname) { + var Prn = Prrname; + total = total.map(Rename); } - if(Pregdel){ - var delreg=Pregdel - total=total.map(DelReg) + if (Pemoji) { total = emoji_handle(total, Pemoji); } + if (Prname) { + var Prn = Prname; + total = total.map(Rename); } - if(Preplace){ // server 类型也可用 replace 参数进行重命名操作 - total=ReplaceReg(total, Preplace) + if (Pregdel) { + var delreg = Pregdel + total = total.map(DelReg) } - if(Psort0==1 || Psort0==-1){ - total=QXSort(total,Psort0); - }else if(Psort0=="x"){ - total=shuffle(total) + if (Preplace) { // server 类型也可用 replace 参数进行重命名操作 + total = ReplaceReg(total, Preplace) } - total=TagCheck_QX(total) - total=total.join("\n"); -//$notify("Final","test",total) - if(flag==1){ total=Base64.encode(total) } //强制节点类型的 base64 - $done({content : total}); + if (Psrename) { total = RenameScript(total, Psrename) } + if (Psort0 == 1 || Psort0 == -1) { + total = QXSort(total, Psort0); + } else if (Psort0 == "x") { + total = shuffle(total) + } + total = TagCheck_QX(total) + total = total.join("\n"); + //$notify("Final","test",total) + if (flag == 1) { total = Base64.encode(total) } //强制节点类型的 base64 + $done({ content: total }); } //flowcheck-fake-server -function flowcheck(cnt){ - for(var i=0;i=0; i--) { - var randomIndex = Math.floor(Math.random()*(i+1)); - var itemAtIndex = input[randomIndex]; - input[randomIndex] = input[i]; - input[i] = itemAtIndex; - } - return input; - } +function shuffle(arr) { + var input = arr; + for (var i = input.length - 1; i >= 0; i--) { + var randomIndex = Math.floor(Math.random() * (i + 1)); + var itemAtIndex = input[randomIndex]; + input[randomIndex] = input[i]; + input[i] = itemAtIndex; + } + return input; +} //判断订阅类型 -function Type_Check(subs){ - var type="unknown" - var RuleK=["host","domain","ip-cidr","geoip","user-agent","ip6-cidr"]; - var QuanXK=["shadowsocks=","trojan=","vmess=","http="]; - var SurgeK=["=ss,","=vmess,","=trojan,","=http,","=custom,","=https,","=shadowsocks","=shadowsocksr"]; - var SubK=["dm1lc3M","c3NyOi8v","dHJvamFu","c3M6Ly","c3NkOi8v"]; - var RewriteK=[" url "] - var SubK2=["ss://","vmess://","ssr://","trojan://","ssd://"]; - var html="DOCTYPE html" - var subi=subs.replace(/ /g,"") - const RuleCheck = (item) => subs.toLowerCase().indexOf(item)!=-1; - const QuanXCheck = (item) => subi.toLowerCase().indexOf(item)!=-1; - const SurgeCheck = (item) => subi.toLowerCase().indexOf(item)!=-1; - const SubCheck = (item) => subs.indexOf(item)!=-1; - const RewriteCheck = (item) => subs.indexOf(item)!=-1; - var subsn=subs.split("\n") - if(subs.indexOf(html)!=-1){ - $notify("‼️ 该链接返回内容有误","⁉️ 点通知跳转以确认链接是否失效",link0,nan_link); - type="web"; - } else if(subsn.length>=1 && SubK2.some(SubCheck)){ //未b64加密的多行URI 组合订阅 - type="Subs" - }else if(SubK.some(SubCheck)){ //b64加密的订阅类型 - type="Subs-B64Encode" - } else if(subi.indexOf("tag=")!=-1 && QuanXK.some(QuanXCheck)){ - type="Subs" // QuanX list - } else if(subs.indexOf("[Proxy]")!=-1){ - type="Surge"; // Surge Profiles - } else if(SurgeK.some(SurgeCheck)){ - type="Subs" // Surge proxy list - } else if(subi.indexOf("[Script]")!=-1 || subi.indexOf("[Rule]")!=-1 || subi.indexOf("[URL Rewrite]")!=-1 || para1.indexOf("dst=regex")!=-1){ // Surge module /rule-set(url-regex) 类型 - type="sgmodule" - }else if(subi.indexOf("hostname=")!=-1 || RewriteK.some(RewriteCheck)){ - type="rewrite" - } else if(RuleK.some(RuleCheck) && subs.indexOf(html)==-1){ - type="Rule"; +function Type_Check(subs) { + var type = "unknown" + var RuleK = ["host", "domain", "ip-cidr", "geoip", "user-agent", "ip6-cidr"]; + var QuanXK = ["shadowsocks=", "trojan=", "vmess=", "http="]; + var SurgeK = ["=ss,", "=vmess,", "=trojan,", "=http,", "=custom,", "=https,", "=shadowsocks", "=shadowsocksr"]; + var SubK = ["dm1lc3M", "c3NyOi8v", "dHJvamFu", "c3M6Ly", "c3NkOi8v"]; + var RewriteK = [" url "] + var SubK2 = ["ss://", "vmess://", "ssr://", "trojan://", "ssd://"]; + var html = "DOCTYPE html" + var subi = subs.replace(/ /g, "") + const RuleCheck = (item) => subs.toLowerCase().indexOf(item) != -1; + const QuanXCheck = (item) => subi.toLowerCase().indexOf(item) != -1; + const SurgeCheck = (item) => subi.toLowerCase().indexOf(item) != -1; + const SubCheck = (item) => subs.indexOf(item) != -1; + const RewriteCheck = (item) => subs.indexOf(item) != -1; + var subsn = subs.split("\n") + if (subs.indexOf(html) != -1) { + $notify("‼️ 该链接返回内容有误", "⁉️ 点通知跳转以确认链接是否失效", link0, nan_link); + type = "web"; + } else if (subsn.length >= 1 && SubK2.some(SubCheck)) { //未b64加密的多行URI 组合订阅 + type = "Subs" + } else if (SubK.some(SubCheck)) { //b64加密的订阅类型 + type = "Subs-B64Encode" + } else if (subi.indexOf("tag=") != -1 && QuanXK.some(QuanXCheck)) { + type = "Subs" // QuanX list + } else if (subs.indexOf("[Proxy]") != -1) { + type = "Surge"; // Surge Profiles + } else if (SurgeK.some(SurgeCheck)) { + type = "Subs" // Surge proxy list + } else if (subi.indexOf("[Script]") != -1 || subi.indexOf("[Rule]") != -1 || subi.indexOf("[URL Rewrite]") != -1 || para1.indexOf("dst=regex") != -1) { // Surge module /rule-set(url-regex) 类型 + type = "sgmodule" + } else if (subi.indexOf("hostname=") != -1 || RewriteK.some(RewriteCheck)) { + type = "rewrite" + } else if (RuleK.some(RuleCheck) && subs.indexOf(html) == -1) { + type = "Rule"; } return type } -function Trim(item){ +function Trim(item) { return item.trim() - } +} //url-regex 转换成 Quantumult X -function URX2QX(subs){ - var nrw=[] - var rw="" - subs=subs.split("\n") - for(var i=0;i subs[i].indexOf(item)!=-1 - if(SC.every(sccheck)){ // surge js 新格式 - ptn=subs[i].split("pattern=")[1].split(",")[0] - js=subs[i].split("script-path=")[1].split(",")[0] - type=subs[i].split("type=")[1].split(",")[0].trim() - if(type=="http-response" && subs[i].indexOf("requires-body=1")!=-1){ - type="script-response-body " - }else if(type=="http-response" && subs[i].indexOf("requires-body=1")==-1){ - type="script-response-header " - }else if(type=="http-request" && subs[i].indexOf("requires-body=1")!=-1){ - type="script-request-body " - }else if(type=="http-request" && subs[i].indexOf("requires-body=1")==-1){ - type="script-request-header " + var SC = ["type=", ".js", "pattern=", "script-path="] + const sccheck = (item) => subs[i].indexOf(item) != -1 + if (SC.every(sccheck)) { // surge js 新格式 + ptn = subs[i].split("pattern=")[1].split(",")[0] + js = subs[i].split("script-path=")[1].split(",")[0] + type = subs[i].split("type=")[1].split(",")[0].trim() + if (type == "http-response" && subs[i].indexOf("requires-body=1") != -1) { + type = "script-response-body " + } else if (type == "http-response" && subs[i].indexOf("requires-body=1") == -1) { + type = "script-response-header " + } else if (type == "http-request" && subs[i].indexOf("requires-body=1") != -1) { + type = "script-request-body " + } else if (type == "http-request" && subs[i].indexOf("requires-body=1") == -1) { + type = "script-request-header " } - rw=ptn+" url "+type+js + rw = ptn + " url " + type + js nrw.push(rw) - }else if(subs[i].indexOf(" 302")!=-1 || subs[i].indexOf(" 307")!=-1){ //rewrite 复写 - rw=subs[i].split(" ")[0]+" url "+subs[i].split(" ")[2]+" "+subs[i].split(" ")[1] + } else if (subs[i].indexOf(" 302") != -1 || subs[i].indexOf(" 307") != -1) { //rewrite 复写 + rw = subs[i].split(" ")[0] + " url " + subs[i].split(" ")[2] + " " + subs[i].split(" ")[1] nrw.push(rw) - }else if(subs[i].indexOf("script-path")!=-1){ //surge js 旧写法 - type=subs[i].split(" ")[0] - js=subs[i].split("script-path")[1].split("=")[1].split(",")[0] - ptn=subs[i].split(" ")[1] - if(type=="http-response" && subs[i].indexOf("requires-body=1")!=-1){ - type="script-response-body " - }else if(type=="http-response" && subs[i].indexOf("requires-body=1")==-1){ - type="script-response-header " - }else if(type=="http-request" && subs[i].indexOf("requires-body=1")!=-1){ - type="script-request-body " - }else if(type=="http-request" && subs[i].indexOf("requires-body=1")==-1){ - type="script-request-header " + } else if (subs[i].indexOf("script-path") != -1) { //surge js 旧写法 + type = subs[i].split(" ")[0] + js = subs[i].split("script-path")[1].split("=")[1].split(",")[0] + ptn = subs[i].split(" ")[1] + if (type == "http-response" && subs[i].indexOf("requires-body=1") != -1) { + type = "script-response-body " + } else if (type == "http-response" && subs[i].indexOf("requires-body=1") == -1) { + type = "script-response-header " + } else if (type == "http-request" && subs[i].indexOf("requires-body=1") != -1) { + type = "script-request-body " + } else if (type == "http-request" && subs[i].indexOf("requires-body=1") == -1) { + type = "script-request-header " } - rw=ptn+" url "+type+js + rw = ptn + " url " + type + js nrw.push(rw) } } return nrw } // 如果 URL-Regex 跟 rewrite/script 都需要 -function SGMD2QX(subs){ - var nrw0=URX2QX(subs) - var nrw1=SCP2QX(subs) - var nrwt=[...nrw0, ...nrw1] +function SGMD2QX(subs) { + var nrw0 = URX2QX(subs) + var nrw1 = SCP2QX(subs) + var nrwt = [...nrw0, ...nrw1] return nrwt } //Rewrite过滤,使用+连接多个关键词(逻辑"或"):in 为保留,out 为排除 -function Rewrite_Filter(subs,Pin,Pout){ - var Nlist=[]; - var noteK=["//","#",";"]; - var hnc=0; - var dwrite=[] - var hostname="" - for(var i=0;i subi.indexOf(item)==0 - if(noteK.some(notecheck)){ // 注释项跳过 - continue; - }else if(hnc==0 && subii.indexOf("hostname=")==0){ //host name 部分 - hostname=(Phin0||Phout0)? HostNamecheck(subi,Phin0,Phout0):subi;//hostname 部分 - }else if(subii.indexOf("hostname=")!=0){ //rewrite 部分 - var inflag=Rcheck(subi,Pin); - var outflag=Rcheck(subi,Pout); - if(outflag==1 || inflag==0){ - dwrite.push(subi); //out 命中 - }else if(outflag==0 && inflag!=0){ //out 未命中 && in 未排除 - Nlist.push(subi); - }else if(outflag==2 && inflag!=0){ //无 out 参数 && in 未排除 - Nlist.push(subi); - } - } +function Rewrite_Filter(subs, Pin, Pout) { + var Nlist = []; + var noteK = ["//", "#", ";"]; + var hnc = 0; + var dwrite = [] + var hostname = "" + for (var i = 0; i < subs.length; i++) { + subi = subs[i].trim(); + var subii = subi.replace(/ /g, "") + if (subi != "") { + const notecheck = (item) => subi.indexOf(item) == 0 + if (noteK.some(notecheck)) { // 注释项跳过 + continue; + } else if (hnc == 0 && subii.indexOf("hostname=") == 0) { //host name 部分 + hostname = (Phin0 || Phout0) ? HostNamecheck(subi, Phin0, Phout0) : subi;//hostname 部分 + } else if (subii.indexOf("hostname=") != 0) { //rewrite 部分 + var inflag = Rcheck(subi, Pin); + var outflag = Rcheck(subi, Pout); + if (outflag == 1 || inflag == 0) { + dwrite.push(subi); //out 命中 + } else if (outflag == 0 && inflag != 0) { //out 未命中 && in 未排除 + Nlist.push(subi); + } else if (outflag == 2 && inflag != 0) { //无 out 参数 && in 未排除 + Nlist.push(subi); + } + } } } - if(Pntf0!=0){ - nowrite=dwrite.length<=10?emojino[dwrite.length]:dwrite.length - no1write=Nlist.length<=10?emojino[Nlist.length]:Nlist.length - if(Pin0 && no1write!=" 0️⃣ "){ //有 in 参数就通知保留项目 - $notify("🤖 "+"重写引用 ➟ "+"⟦"+subtag+"⟧","⛔️ 筛选参数: "+pfi+pfo,"☠️ 重写 rewrite 中保留以下"+no1write+"个匹配项:"+"\n ⨷ "+Nlist.join("\n ⨷ "),rwrite_link ) - } else if(dwrite.length>0 ){ - $notify("🤖 "+"重写引用 ➟ "+"⟦"+subtag+"⟧","⛔️ 筛选参数: "+pfi+pfo,"☠️ 重写 rewrite 中已禁用以下"+nowrite+"个匹配项:"+"\n ⨷ "+dwrite.join("\n ⨷ "),rwrite_link )} + if (Pntf0 != 0) { + nowrite = dwrite.length <= 10 ? emojino[dwrite.length] : dwrite.length + no1write = Nlist.length <= 10 ? emojino[Nlist.length] : Nlist.length + if (Pin0 && no1write != " 0️⃣ ") { //有 in 参数就通知保留项目 + $notify("🤖 " + "重写引用 ➟ " + "⟦" + subtag + "⟧", "⛔️ 筛选参数: " + pfi + pfo, "☠️ 重写 rewrite 中保留以下" + no1write + "个匹配项:" + "\n ⨷ " + Nlist.join("\n ⨷ "), rwrite_link) + } else if (dwrite.length > 0) { + $notify("🤖 " + "重写引用 ➟ " + "⟦" + subtag + "⟧", "⛔️ 筛选参数: " + pfi + pfo, "☠️ 重写 rewrite 中已禁用以下" + nowrite + "个匹配项:" + "\n ⨷ " + dwrite.join("\n ⨷ "), rwrite_link) + } } - if(Nlist.length==0){$notify("🤖 "+"重写引用 ➟ "+"⟦"+subtag+"⟧","⛔️ 筛选参数: "+pfi+pfo,"⚠️ 筛选后剩余rewrite规则数为 0️⃣ 条, 请检查参数及原始链接",nan_link)} - if(hostname!=""){Nlist.push(hostname)} + if (Nlist.length == 0) { $notify("🤖 " + "重写引用 ➟ " + "⟦" + subtag + "⟧", "⛔️ 筛选参数: " + pfi + pfo, "⚠️ 筛选后剩余rewrite规则数为 0️⃣ 条, 请检查参数及原始链接", nan_link) } + if (hostname != "") { Nlist.push(hostname) } return Nlist } // 主机名处理 -function HostNamecheck(content,parain,paraout){ - var hname=content.replace(/ /g,"").split("=")[1].split(","); - var nname=[]; - var dname=[]; //删除项 - for(var i=0;i dd.indexOf(item)!=-1; - if(paraout && paraout!=""){ //存在 out 参数时 - if(!paraout.some(excludehn)){ //out 未命中🎯️ - if(parain && parain!=""){ - if(parain.some(excludehn)){ //Pin 命中🎯️ - nname.push(hname[i]) - } else{$notify("..xx") - dname.push(hname[i])} //Pin 未命中🎯️的记录 - }else{nname.push(hname[i])} //无in 参数 - }else{dname.push(hname[i])} //out 参数命中 - }else if(parain && parain!=""){ //不存在 out,但有 in 参数时 - if(parain.some(excludehn)){ //Pin 命中🎯️ - nname.push(hname[i]) - }else{dname.push(hname[i])} - }else { +function HostNamecheck(content, parain, paraout) { + var hname = content.replace(/ /g, "").split("=")[1].split(","); + var nname = []; + var dname = []; //删除项 + for (var i = 0; i < hname.length; i++) { + dd = hname[i] + const excludehn = (item) => dd.indexOf(item) != -1; + if (paraout && paraout != "") { //存在 out 参数时 + if (!paraout.some(excludehn)) { //out 未命中🎯️ + if (parain && parain != "") { + if (parain.some(excludehn)) { //Pin 命中🎯️ + nname.push(hname[i]) + } else { + $notify("..xx") + dname.push(hname[i]) + } //Pin 未命中🎯️的记录 + } else { nname.push(hname[i]) } //无in 参数 + } else { dname.push(hname[i]) } //out 参数命中 + } else if (parain && parain != "") { //不存在 out,但有 in 参数时 + if (parain.some(excludehn)) { //Pin 命中🎯️ nname.push(hname[i]) - } + } else { dname.push(hname[i]) } + } else { + nname.push(hname[i]) + } } //for j - hname="hostname="+nname.join(", "); - if(Pntf0!=0){ - if(paraout || parain){ - var noname=dname.length<=10?emojino[dname.length]:dname.length - var no1name=nname.length<=10?emojino[nname.length]:nname.length - if(parain && no1name!=" 0️⃣ "){ - $notify("🤖 "+"重写引用 ➟ "+"⟦"+subtag+"⟧","⛔️ 筛选参数: "+pfihn+pfohn,"☠️ 主机名 hostname 中已保留以下"+no1name+"个匹配项:"+"\n ⨷ "+nname.join(","),rwhost_link ) - } else if(dname.length>0){ - $notify("🤖 "+"重写引用 ➟ "+"⟦"+subtag+"⟧","⛔️ 筛选参数: "+pfihn+pfohn,"☠️ 主机名 hostname 中已删除以下"+noname+"个匹配项:"+"\n ⨷ "+dname.join(","),rwhost_link )} + hname = "hostname=" + nname.join(", "); + if (Pntf0 != 0) { + if (paraout || parain) { + var noname = dname.length <= 10 ? emojino[dname.length] : dname.length + var no1name = nname.length <= 10 ? emojino[nname.length] : nname.length + if (parain && no1name != " 0️⃣ ") { + $notify("🤖 " + "重写引用 ➟ " + "⟦" + subtag + "⟧", "⛔️ 筛选参数: " + pfihn + pfohn, "☠️ 主机名 hostname 中已保留以下" + no1name + "个匹配项:" + "\n ⨷ " + nname.join(","), rwhost_link) + } else if (dname.length > 0) { + $notify("🤖 " + "重写引用 ➟ " + "⟦" + subtag + "⟧", "⛔️ 筛选参数: " + pfihn + pfohn, "☠️ 主机名 hostname 中已删除以下" + noname + "个匹配项:" + "\n ⨷ " + dname.join(","), rwhost_link) + } } } - if(nname.length==0){ - $notify("🤖 "+"重写引用 ➟ "+"⟦"+subtag+"⟧","⛔️ 筛选参数: "+pfihn+pfohn,"⚠️ 主机名 hostname 中剩余 0️⃣ 项, 请检查参数及原始链接",nan_link ) + if (nname.length == 0) { + $notify("🤖 " + "重写引用 ➟ " + "⟦" + subtag + "⟧", "⛔️ 筛选参数: " + pfihn + pfohn, "⚠️ 主机名 hostname 中剩余 0️⃣ 项, 请检查参数及原始链接", nan_link) } return hname } //Rewrite 筛选的函数 -function Rcheck(content,param){ - name=content.toUpperCase() - if(param){ - var flag=0; //没命中 - const checkpara= (item) => name.indexOf(item.toUpperCase()) !=-1; - if(param.some(checkpara)){ - flag=1 //命中 +function Rcheck(content, param) { + name = content.toUpperCase() + if (param) { + var flag = 0; //没命中 + const checkpara = (item) => name.indexOf(item.toUpperCase()) != -1; + if (param.some(checkpara)) { + flag = 1 //命中 } - return flag - }else { //if param - return 2} //无参数 + return flag + } else { //if param + return 2 + } //无参数 } //分流规则转换及过滤,可用于 surge 及 quanx 的 rule-list -function Rule_Handle(subs,Pout,Pin){ - cnt=subs //.split("\n"); - Tin=Pin; //保留参数 - Tout=Pout; //过滤参数 - ply=Ppolicy; //策略组 - var nlist=[] - var RuleK=["//","#",";"]; - if(Tout!="" && Tout!=null){ // 有 out 参数时 - var dlist=[]; - for(var i=0;icc.indexOf(item)!=-1; // 删除项 - const RuleCheck = (item) => cc.indexOf(item)!=-1; //无视注释行 - if(Tout.some(exclude) && !RuleK.some(RuleCheck)){ - dlist.push(Rule_Policy("-"+cnt[i])) - } else if(!RuleK.some(RuleCheck) && cc ){ //if Pout.some, 不操作注释项 - dd=Rule_Policy(cc); - if(Tin!="" && Tin!=null){ - const include = (item) =>dd.indexOf(item)!=-1; // 保留项 - if(Tin.some(include)){ - nlist.push(dd); - } - }else{nlist.push(dd); - } - } //else if cc +function Rule_Handle(subs, Pout, Pin) { + cnt = subs //.split("\n"); + Tin = Pin; //保留参数 + Tout = Pout; //过滤参数 + ply = Ppolicy; //策略组 + var nlist = [] + var RuleK = ["//", "#", ";"]; + if (Tout != "" && Tout != null) { // 有 out 参数时 + var dlist = []; + for (var i = 0; i < cnt.length; i++) { + cc = cnt[i] + const exclude = (item) => cc.indexOf(item) != -1; // 删除项 + const RuleCheck = (item) => cc.indexOf(item) != -1; //无视注释行 + if (Tout.some(exclude) && !RuleK.some(RuleCheck)) { + dlist.push(Rule_Policy("-" + cnt[i])) + } else if (!RuleK.some(RuleCheck) && cc) { //if Pout.some, 不操作注释项 + dd = Rule_Policy(cc); + if (Tin != "" && Tin != null) { + const include = (item) => dd.indexOf(item) != -1; // 保留项 + if (Tin.some(include)) { + nlist.push(dd); + } + } else { + nlist.push(dd); + } + } //else if cc }//for cnt - var no=dlist.length<=10?emojino[dlist.length]:dlist.length - if(dlist.length>0 ){ if(Pntf0!=0){$notify("🤖 "+"分流引用 ➟ "+"⟦"+subtag+"⟧","⛔️ 禁用: "+ Tout,"☠️ 已禁用以下"+no+"条匹配规则:"+"\n ⨷ "+dlist.join("\n ⨷ "),rule_link)} - }else{$notify("🤖 "+"分流引用 ➟ "+"⟦"+subtag+"⟧","⛔️ 禁用: "+Tout,"⚠️ 未发现任何匹配项, 请检查参数或原始链接",nan_link)} - if(Tin!="" && Tin!=null){ //有 in 跟 out 参数时 - if(nlist.length>0 ){ - var noin0=nlist.length<=10?emojino[nlist.length]:nlist.length - if(Pntf0!=0){ - $notify("🤖 "+"分流引用 ➟ "+"⟦"+subtag+"⟧","✅ 保留:"+Tin,"🎯 已保留以下 "+noin0+"条匹配规则:"+"\n ⨁ "+nlist.join("\n ⨁ "),rule_link)} - } else{$notify("🤖 "+"分流引用 ➟ "+"⟦"+subtag+"⟧","✅ 保留:"+Tin+",⛔️ 禁用: "+Tout,"⚠️ 筛选后剩余规则数为 0️⃣ 条, 请检查参数及原始链接",nan_link) - } - } else {// if Tin (No Tin) - if(nlist.length==0 ){ - $notify("🤖 "+"分流引用 ➟ "+"⟦"+subtag+"⟧","⛔️ 禁用: "+Tout,"⚠️ 筛选后剩余规则数为 0️⃣ 条, 请检查参数及原始链接",nan_link) - } - } - return [...dlist,...nlist]; - } else if(Tin!="" && Tin!=null){ //if Tout - var dlist=[]; - for(var i=0;i cc.indexOf(item)!=-1; //无视注释行 - if(!RuleK.some(RuleCheck) && cc ){ //if Pout.some, 不操作注释项 - dd=Rule_Policy(cc); - const include = (item) =>dd.indexOf(item)!=-1; // 保留项 - if(Tin.some(include)){ - nlist.push(dd); - }else{dlist.push("-"+dd)} + var no = dlist.length <= 10 ? emojino[dlist.length] : dlist.length + if (dlist.length > 0) { + if (Pntf0 != 0) { $notify("🤖 " + "分流引用 ➟ " + "⟦" + subtag + "⟧", "⛔️ 禁用: " + Tout, "☠️ 已禁用以下" + no + "条匹配规则:" + "\n ⨷ " + dlist.join("\n ⨷ "), rule_link) } + } else { $notify("🤖 " + "分流引用 ➟ " + "⟦" + subtag + "⟧", "⛔️ 禁用: " + Tout, "⚠️ 未发现任何匹配项, 请检查参数或原始链接", nan_link) } + if (Tin != "" && Tin != null) { //有 in 跟 out 参数时 + if (nlist.length > 0) { + var noin0 = nlist.length <= 10 ? emojino[nlist.length] : nlist.length + if (Pntf0 != 0) { + $notify("🤖 " + "分流引用 ➟ " + "⟦" + subtag + "⟧", "✅ 保留:" + Tin, "🎯 已保留以下 " + noin0 + "条匹配规则:" + "\n ⨁ " + nlist.join("\n ⨁ "), rule_link) + } + } else { + $notify("🤖 " + "分流引用 ➟ " + "⟦" + subtag + "⟧", "✅ 保留:" + Tin + ",⛔️ 禁用: " + Tout, "⚠️ 筛选后剩余规则数为 0️⃣ 条, 请检查参数及原始链接", nan_link) + } + } else {// if Tin (No Tin) + if (nlist.length == 0) { + $notify("🤖 " + "分流引用 ➟ " + "⟦" + subtag + "⟧", "⛔️ 禁用: " + Tout, "⚠️ 筛选后剩余规则数为 0️⃣ 条, 请检查参数及原始链接", nan_link) + } } - } // for cnt - if(nlist.length>0){ - var noin=nlist.length<=10?emojino[nlist.length]:nlist.length - if(Pntf0!=0){ - $notify("🤖 "+"分流引用 ➟ "+"⟦"+subtag+"⟧","✅ 保留:"+Tin,"🎯 已保留以下 "+noin+"条匹配规则:"+"\n ⨁ "+nlist.join("\n ⨁ "),rule_link)} -} else{$notify("🤖 "+"分流引用 ➟ "+"⟦"+subtag+"⟧","✅ 保留:"+Tin,"⚠️ 筛选后剩余规则数为 0️⃣ 条, 请检查参数及原始链接",nan_link)} - return [...dlist,...nlist]; + return [...dlist, ...nlist]; + } else if (Tin != "" && Tin != null) { //if Tout + var dlist = []; + for (var i = 0; i < cnt.length; i++) { + cc = cnt[i] + const RuleCheck = (item) => cc.indexOf(item) != -1; //无视注释行 + if (!RuleK.some(RuleCheck) && cc) { //if Pout.some, 不操作注释项 + dd = Rule_Policy(cc); + const include = (item) => dd.indexOf(item) != -1; // 保留项 + if (Tin.some(include)) { + nlist.push(dd); + } else { dlist.push("-" + dd) } + } + } // for cnt + if (nlist.length > 0) { + var noin = nlist.length <= 10 ? emojino[nlist.length] : nlist.length + if (Pntf0 != 0) { + $notify("🤖 " + "分流引用 ➟ " + "⟦" + subtag + "⟧", "✅ 保留:" + Tin, "🎯 已保留以下 " + noin + "条匹配规则:" + "\n ⨁ " + nlist.join("\n ⨁ "), rule_link) + } + } else { $notify("🤖 " + "分流引用 ➟ " + "⟦" + subtag + "⟧", "✅ 保留:" + Tin, "⚠️ 筛选后剩余规则数为 0️⃣ 条, 请检查参数及原始链接", nan_link) } + return [...dlist, ...nlist]; } else { //if Tin - return cnt.map(Rule_Policy) -} + return cnt.map(Rule_Policy) + } } -function Rule_Policy(content){ //增加、替换 policy - var cnt=content.split(","); - var RuleK=["//","#",";"]; - var RuleK1=["host","domain","ip-cidr","geoip","user-agent","ip6-cidr"]; - const RuleCheck = (item) => cnt[0].toLowerCase().indexOf(item)!=-1; //无视注释行 - const RuleCheck1 = (item) => cnt[0].toLowerCase().indexOf(item)!=-1; //无视 quanx 不支持的规则类别 - if(RuleK1.some(RuleCheck1)){ - if(cnt.length==3 && cnt.indexOf("no-resolve")==-1){ - ply0 = Ppolicy!="Shawn"? Ppolicy:cnt[2] - nn=cnt[0]+", "+cnt[1]+", "+ply0 - } else if(cnt.length==2){ //Surge rule-set - ply0 = Ppolicy!="Shawn"? Ppolicy:"Shawn" - nn=cnt[0]+", "+cnt[1]+", "+ply0 - }else if(cnt.length==3 && cnt[2].indexOf("no-resolve")!=-1){ - ply0 = Ppolicy!="Shawn"? Ppolicy:"Shawn" - nn=cnt[0]+", "+cnt[1]+", "+ply0+", "+cnt[2] - }else if(cnt.length==4 && cnt[3].indexOf("no-resolve")!=-1){ - ply0 = Ppolicy!="Shawn"? Ppolicy:cnt[2] - nn=cnt[0]+", "+cnt[1]+", "+ply0+", "+cnt[3] - }else if(!RuleK.some(RuleCheck)&& content){ - $notify("未能解析"+"⟦"+subtag+"⟧"+"其中部分规则:",content,nan_link); - return "" - }else{return ""} - if(cnt[0].indexOf("URL-REGEX")!=-1 || cnt[0].indexOf("PROCESS")!=-1){ - nn="" - } else {nn=nn.replace("IP-CIDR6","ip6-cidr")} - return nn - } else{return ""}//if RuleK1 check +function Rule_Policy(content) { //增加、替换 policy + var cnt = content.split(","); + var RuleK = ["//", "#", ";"]; + var RuleK1 = ["host", "domain", "ip-cidr", "geoip", "user-agent", "ip6-cidr"]; + const RuleCheck = (item) => cnt[0].toLowerCase().indexOf(item) != -1; //无视注释行 + const RuleCheck1 = (item) => cnt[0].toLowerCase().indexOf(item) != -1; //无视 quanx 不支持的规则类别 + if (RuleK1.some(RuleCheck1)) { + if (cnt.length == 3 && cnt.indexOf("no-resolve") == -1) { + ply0 = Ppolicy != "Shawn" ? Ppolicy : cnt[2] + nn = cnt[0] + ", " + cnt[1] + ", " + ply0 + } else if (cnt.length == 2) { //Surge rule-set + ply0 = Ppolicy != "Shawn" ? Ppolicy : "Shawn" + nn = cnt[0] + ", " + cnt[1] + ", " + ply0 + } else if (cnt.length == 3 && cnt[2].indexOf("no-resolve") != -1) { + ply0 = Ppolicy != "Shawn" ? Ppolicy : "Shawn" + nn = cnt[0] + ", " + cnt[1] + ", " + ply0 + ", " + cnt[2] + } else if (cnt.length == 4 && cnt[3].indexOf("no-resolve") != -1) { + ply0 = Ppolicy != "Shawn" ? Ppolicy : cnt[2] + nn = cnt[0] + ", " + cnt[1] + ", " + ply0 + ", " + cnt[3] + } else if (!RuleK.some(RuleCheck) && content) { + $notify("未能解析" + "⟦" + subtag + "⟧" + "其中部分规则:", content, nan_link); + return "" + } else { return "" } + if (cnt[0].indexOf("URL-REGEX") != -1 || cnt[0].indexOf("PROCESS") != -1) { + nn = "" + } else { nn = nn.replace("IP-CIDR6", "ip6-cidr") } + return nn + } else { return "" }//if RuleK1 check } // 正则替换 filter/rewrite 的部分 // 用途:如 tiktok 换区: JP -> KR ,如淘宝比价脚本 -> lite 横幅通知版本 -function ReplaceReg(cnt,para){ - var cnt0=cnt.join("\n") - var pp=para.split("+") - for(var i=0;i3){ - var type=list0[i].split("://")[0].trim() - var listi=list0[i].replace(/ /g,"") - const QuanXCheck = (item) => listi.toLowerCase().indexOf(item)!=-1; - const SurgeCheck = (item) => listi.toLowerCase().indexOf(item)!=-1; - const LoonCheck = (item) => listi.toLowerCase().indexOf(item)!=-1; - if(type=="vmess" && list0[i].indexOf("remarks=")==-1){ - var bnode=Base64.decode(list0[i].split("vmess://")[1]) - if(bnode.indexOf("over-tls=")==-1){ //v2rayN - node= V2QX(list0[i],Pudp,Ptfo,Pcert,Ptls13) - }else{ //quantumult 类型 - node= VQ2QX(list0[i],Pudp,Ptfo,Pcert,Ptls13)} - }else if(type=="vmess" && list0[i].indexOf("remarks=")!=-1){ //shadowrocket 类型 - node= VR2QX(list0[i],Pudp,Ptfo,Pcert,Ptls13) - }else if(type=="ssr"){ - node= SSR2QX(list0[i],Pudp,Ptfo) - }else if(type=="ss"){ - node = SS2QX(list0[i],Pudp,Ptfo) - }else if(type=="trojan"){ - node = TJ2QX(list0[i],Pudp,Ptfo,Pcert,Ptls13) - }else if(type=="https"&&listi.indexOf("@")!=-1){ //subs,Ptfo,Pcert,Ptls13 - node = HPS2QX(list0[i],Ptfo,Pcert,Ptls13) - }else if(QuanXK.some(QuanXCheck)){ - node = list0[i] - }else if(SurgeK.some(SurgeCheck)){ - node = Surge2QX(list0[i]) - }else if(LoonK.some(LoonCheck)){ - node = Loon2QX(list0[i]) +function SubsEd2QX(subs, Pudp, Ptfo, Pcert, Ptls13) { + var list0 = Base64.decode(subs).split("\n"); + var QuanXK = ["shadowsocks=", "trojan=", "vmess=", "http="]; + var SurgeK = ["=ss", "=vmess", "=trojan", "=http", "=custom"]; + var LoonK = ["=shadowsocks", "=shadowsocksr"] + var QXlist = []; + for (var i = 0; i < list0.length; i++) { + var node = "" + if (list0[i].trim().length > 3) { + var type = list0[i].split("://")[0].trim() + var listi = list0[i].replace(/ /g, "") + const QuanXCheck = (item) => listi.toLowerCase().indexOf(item) != -1; + const SurgeCheck = (item) => listi.toLowerCase().indexOf(item) != -1; + const LoonCheck = (item) => listi.toLowerCase().indexOf(item) != -1; + if (type == "vmess" && list0[i].indexOf("remarks=") == -1) { + var bnode = Base64.decode(list0[i].split("vmess://")[1]) + if (bnode.indexOf("over-tls=") == -1) { //v2rayN + node = V2QX(list0[i], Pudp, Ptfo, Pcert, Ptls13) + } else { //quantumult 类型 + node = VQ2QX(list0[i], Pudp, Ptfo, Pcert, Ptls13) + } + } else if (type == "vmess" && list0[i].indexOf("remarks=") != -1) { //shadowrocket 类型 + node = VR2QX(list0[i], Pudp, Ptfo, Pcert, Ptls13) + } else if (type == "ssr") { + node = SSR2QX(list0[i], Pudp, Ptfo) + } else if (type == "ss") { + node = SS2QX(list0[i], Pudp, Ptfo) + } else if (type == "trojan") { + node = TJ2QX(list0[i], Pudp, Ptfo, Pcert, Ptls13) + } else if (type == "https" && listi.indexOf("@") != -1) { //subs,Ptfo,Pcert,Ptls13 + node = HPS2QX(list0[i], Ptfo, Pcert, Ptls13) + } else if (QuanXK.some(QuanXCheck)) { + node = list0[i] + } else if (SurgeK.some(SurgeCheck)) { + node = Surge2QX(list0[i]) + } else if (LoonK.some(LoonCheck)) { + node = Loon2QX(list0[i]) + } + if (node != "") { + QXlist.push(node) + } } - if(node!=""){ - QXlist.push(node)} - } } return QXlist } //混合订阅类型,用于未整体进行 base64 encode 的类型 -function Subs2QX(subs,Pudp,Ptfo,Pcert,Ptls13){ - var list0=subs.split("\n"); - var QuanXK=["shadowsocks=","trojan=","vmess=","http="]; - var SurgeK=["=ss","=vmess","=trojan","=http"]; - var LoonK=["=shadowsocks","=shadowsocksr"] - var QXlist=[]; - for(var i=0;i3){ - var type=list0[i].split("://")[0].trim() - var listi=list0[i].replace(/ /g,"") - const QuanXCheck = (item) => listi.toLowerCase().indexOf(item)!=-1; - const SurgeCheck = (item) => listi.toLowerCase().indexOf(item)!=-1; - const LoonCheck = (item) => listi.toLowerCase().indexOf(item)!=-1; - if(type=="vmess" && list0[i].indexOf("remarks=")==-1){ - var bnode=Base64.decode(list0[i].split("vmess://")[1]) - if(bnode.indexOf("over-tls=")==-1){ //v2rayN - node= V2QX(list0[i],Pudp,Ptfo,Pcert,Ptls13) - }else{ //quantumult 类型 - node= VQ2QX(list0[i],Pudp,Ptfo,Pcert,Ptls13)} - }else if(type=="vmess" && list0[i].indexOf("remarks=")!=-1){ //shadowrocket 类型 - node= VR2QX(list0[i],Pudp,Ptfo,Pcert,Ptls13) - }else if(type=="ssr"){ - node= SSR2QX(list0[i],Pudp,Ptfo) - }else if(type=="ss"){ - node = SS2QX(list0[i],Pudp,Ptfo) - }else if(type=="ssd"){ - node = SSD2QX(list0[i],Pudp,Ptfo) - }else if(type=="trojan"){ - node = TJ2QX(list0[i],Pudp,Ptfo,Pcert,Ptls13) - }else if(type=="https"&&listi.indexOf("@")!=-1){ - node = HPS2QX(list0[i],Ptfo,Pcert,Ptls13) - }else if(QuanXK.some(QuanXCheck)){ - node = list0[i] - }else if(SurgeK.some(SurgeCheck)){ - node = Surge2QX(list0[i]) - }else if(LoonK.some(LoonCheck)){ - node = Loon2QX(list0[i]) +function Subs2QX(subs, Pudp, Ptfo, Pcert, Ptls13) { + var list0 = subs.split("\n"); + var QuanXK = ["shadowsocks=", "trojan=", "vmess=", "http="]; + var SurgeK = ["=ss", "=vmess", "=trojan", "=http"]; + var LoonK = ["=shadowsocks", "=shadowsocksr"] + var QXlist = []; + for (var i = 0; i < list0.length; i++) { + var node = "" + if (list0[i].trim().length > 3) { + var type = list0[i].split("://")[0].trim() + var listi = list0[i].replace(/ /g, "") + const QuanXCheck = (item) => listi.toLowerCase().indexOf(item) != -1; + const SurgeCheck = (item) => listi.toLowerCase().indexOf(item) != -1; + const LoonCheck = (item) => listi.toLowerCase().indexOf(item) != -1; + if (type == "vmess" && list0[i].indexOf("remarks=") == -1) { + var bnode = Base64.decode(list0[i].split("vmess://")[1]) + if (bnode.indexOf("over-tls=") == -1) { //v2rayN + node = V2QX(list0[i], Pudp, Ptfo, Pcert, Ptls13) + } else { //quantumult 类型 + node = VQ2QX(list0[i], Pudp, Ptfo, Pcert, Ptls13) + } + } else if (type == "vmess" && list0[i].indexOf("remarks=") != -1) { //shadowrocket 类型 + node = VR2QX(list0[i], Pudp, Ptfo, Pcert, Ptls13) + } else if (type == "ssr") { + node = SSR2QX(list0[i], Pudp, Ptfo) + } else if (type == "ss") { + node = SS2QX(list0[i], Pudp, Ptfo) + } else if (type == "ssd") { + node = SSD2QX(list0[i], Pudp, Ptfo) + } else if (type == "trojan") { + node = TJ2QX(list0[i], Pudp, Ptfo, Pcert, Ptls13) + } else if (type == "https" && listi.indexOf("@") != -1) { + node = HPS2QX(list0[i], Ptfo, Pcert, Ptls13) + } else if (QuanXK.some(QuanXCheck)) { + node = list0[i] + } else if (SurgeK.some(SurgeCheck)) { + node = Surge2QX(list0[i]) + } else if (LoonK.some(LoonCheck)) { + node = Loon2QX(list0[i]) + } + if (node instanceof Array) { + for (var j in node) { + QXlist.push(node[j]) + } + } else if (node != "") { + QXlist.push(node) + } } - if (node instanceof Array){ - for (var j in node) { - QXlist.push(node[j]) - } - }else if(node!=""){ - QXlist.push(node) - } - } } return QXlist } // 检查节点名字(重复以及空名)等QuanX 不允许的情形 -function TagCheck_QX(content){ - var Olist=content - var Nlist=[] - var nmlist=[] - var nulllist=[]; //记录空名字节点 - var duplist=[]; //记录重名节点 - var no=0; - for(var i=0;i=1){ - no= duplist.length<=10? emojino[duplist.length]:duplist.length ; - $notify("⚠️ 引用"+"⟦"+subtag+"⟧"+" 内有"+no+"个重复节点名 ", "✅ 已添加⌘符号作为区分:", " ⨁ "+duplist.join("\n ⨁ "),nan_link)} + if (nulllist.length >= 1) { + no = nulllist.length <= 10 ? emojino[nulllist.length] : nulllist.length; + $notify("⚠️ 引用" + "⟦" + subtag + "⟧" + " 内有" + no + "个空节点名 ", "✅ 已将节点“类型+IP”设为节点名", " ⨁ " + nulllist.join("\n ⨁ "), nan_link) + } + if (duplist.length >= 1) { + no = duplist.length <= 10 ? emojino[duplist.length] : duplist.length; + $notify("⚠️ 引用" + "⟦" + subtag + "⟧" + " 内有" + no + "个重复节点名 ", "✅ 已添加⌘符号作为区分:", " ⨁ " + duplist.join("\n ⨁ "), nan_link) + } return Nlist } //http=example.com:443, username=name, password=pwd, over-tls=true, tls-host=example.com, tls-verification=true, tls13=true, fast-open=false, udp-relay=false, tag=http-tls-02 //HTTPS 类型 URI 转换成 QUANX 格式 -function HPS2QX(subs,Ptfo,Pcert,Ptls13){ - var server=Base64.decode(subs.replace("https://","")).trim().split("\u0000")[0]; - var nss=[] - if(server!=""){ - var ipport="http="+server.split("@")[1].split("#")[0].split("/")[0]; - var uname="username="+server.split(":")[0]; - var pwd="password="+server.split("@")[0].split(":")[1]; - var tag="tag="+server.split("#")[1]; - var tls="over-tls=true"; - var cert=Pcert!=0? "tls-verification=true":"tls-verification=false"; - var tfo=Ptfo==1? "fast-open=true":"fast-open=false"; - var tls13=Ptls13==1? "tls13=true":"tls13=false"; - nss.push(ipport,uname,pwd,tls,cert,tfo,tls13,tag) +function HPS2QX(subs, Ptfo, Pcert, Ptls13) { + var server = Base64.decode(subs.replace("https://", "")).trim().split("\u0000")[0]; + var nss = [] + if (server != "") { + var ipport = "http=" + server.split("@")[1].split("#")[0].split("/")[0]; + var uname = "username=" + server.split(":")[0]; + var pwd = "password=" + server.split("@")[0].split(":")[1]; + var tag = "tag=" + server.split("#")[1]; + var tls = "over-tls=true"; + var cert = Pcert != 0 ? "tls-verification=true" : "tls-verification=false"; + var tfo = Ptfo == 1 ? "fast-open=true" : "fast-open=false"; + var tls13 = Ptls13 == 1 ? "tls13=true" : "tls13=false"; + nss.push(ipport, uname, pwd, tls, cert, tfo, tls13, tag) } - var QX=nss.join(","); + var QX = nss.join(","); return QX -} +} //quantumult 格式的 vmess URI 转换 -function VQ2QX(subs,Pudp,Ptfo,Pcert,Ptls13){ - var server=String(Base64.decode(subs.replace("vmess://","").trim()).split("\u0000")[0]) - var node="" - var ip="vmess="+server.split(",")[1].trim()+":"+server.split(",")[2].trim()+", "+"method=aes-128-gcm, "+"password="+server.split(",")[4].split("\"")[1]+", " - var tag="tag="+server.split("=")[0] - var tfo=subs.indexOf("tfo=1")!=-1? "fast-open=true, ":"fast-open=false, " - var udp= Pudp==1? "udp-relay=true, ":"udp-relay=false, "; - node=ip+tfo+udp - var obfs="" - if(server.indexOf("obfs=")==-1){ // 非 ws 类型 - obfs=server.indexOf("over-tls=true")!=-1? "obfs=over-tls, ":"" //over-tls - var host=server.indexOf("tls-host")!=-1? "obfs-host="+server.split("tls-host=")[1].split(",")[0]+", ":"" - obfs=obfs+host - }else if(server.indexOf("obfs=ws")!=-1){ - obfs=server.indexOf("over-tls=true")!=-1? "obfs=wss, ":"obfs=ws, " //ws,wss 类型 - var uri=server.indexOf("obfs-path=")!=-1? "obfs-uri="+server.split("obfs-path=")[1].split("\"")[1]+", ":"obfs-uri=/, " - obfs=obfs+uri - var host=server.indexOf("obfs-header=")!=-1? "obfs-host="+server.split("obfs-header=\"Host:")[1].split("[")[0].trim()+", ":"" - obfs=obfs+host +function VQ2QX(subs, Pudp, Ptfo, Pcert, Ptls13) { + var server = String(Base64.decode(subs.replace("vmess://", "").trim()).split("\u0000")[0]) + var node = "" + var ip = "vmess=" + server.split(",")[1].trim() + ":" + server.split(",")[2].trim() + ", " + "method=aes-128-gcm, " + "password=" + server.split(",")[4].split("\"")[1] + ", " + var tag = "tag=" + server.split("=")[0] + var tfo = subs.indexOf("tfo=1") != -1 ? "fast-open=true, " : "fast-open=false, " + var udp = Pudp == 1 ? "udp-relay=true, " : "udp-relay=false, "; + node = ip + tfo + udp + var obfs = "" + if (server.indexOf("obfs=") == -1) { // 非 ws 类型 + obfs = server.indexOf("over-tls=true") != -1 ? "obfs=over-tls, " : "" //over-tls + var host = server.indexOf("tls-host") != -1 ? "obfs-host=" + server.split("tls-host=")[1].split(",")[0] + ", " : "" + obfs = obfs + host + } else if (server.indexOf("obfs=ws") != -1) { + obfs = server.indexOf("over-tls=true") != -1 ? "obfs=wss, " : "obfs=ws, " //ws,wss 类型 + var uri = server.indexOf("obfs-path=") != -1 ? "obfs-uri=" + server.split("obfs-path=")[1].split("\"")[1] + ", " : "obfs-uri=/, " + obfs = obfs + uri + var host = server.indexOf("obfs-header=") != -1 ? "obfs-host=" + server.split("obfs-header=\"Host:")[1].split("[")[0].trim() + ", " : "" + obfs = obfs + host } - if(obfs.indexOf("obfs=over-tls")!=-1||obfs.indexOf("obfs=wss")!=-1 ){ - var cert= Pcert!=0 || subs.indexOf("allowInsecure=1")!=-1 ? "tls-verification=false, ":"tls-verification=true, " - var tls13=Ptls13==1? "tls13=true, ":"" - obfs=obfs+cert+tls13 + if (obfs.indexOf("obfs=over-tls") != -1 || obfs.indexOf("obfs=wss") != -1) { + var cert = Pcert != 0 || subs.indexOf("allowInsecure=1") != -1 ? "tls-verification=false, " : "tls-verification=true, " + var tls13 = Ptls13 == 1 ? "tls13=true, " : "" + obfs = obfs + cert + tls13 } - node=node+obfs+tag + node = node + obfs + tag return node } //Shadowrocket 格式的 vmess URI 转换 -function VR2QX(subs,Pudp,Ptfo,Pcert,Ptls13){ - var server=String(Base64.decode(subs.replace("vmess://","").split("?remarks")[0]).trim()).split("\u0000")[0] - var node="" - var ip="vmess="+server.split("@")[1]+", "+"method=aes-128-gcm, "+"password="+server.split("@")[0].split(":")[1]+", " - var tag="tag="+decodeURIComponent(subs.split("remarks=")[1].split("&")[0]) - var tfo=subs.indexOf("tfo=1")!=-1? "fast-open=true, ":"fast-open=false, " - var udp= Pudp==1? "udp-relay=true, ":"udp-relay=false, "; - node=ip+tfo+udp - var obfs=subs.split("obfs=")[1].split("&")[0] - if(obfs=="none"){ // - obfs=subs.indexOf("tls=1")!=-1? "obfs=over-tls, ":"" //over-tls - }else if(obfs=="websocket"){ - obfs=subs.indexOf("tls=1")!=-1? "obfs=wss, ":"obfs=ws," //ws,wss 类型 - obfs=obfs+"obfs-uri="+subs.split("&path=")[1].split("&")[0]+", " - var host=subs.indexOf("&obfsParam=")!=-1? "obfs-host="+subs.split("&obfsParam=")[1].split("&")[0]+", ":"" - obfs=obfs+host +function VR2QX(subs, Pudp, Ptfo, Pcert, Ptls13) { + var server = String(Base64.decode(subs.replace("vmess://", "").split("?remarks")[0]).trim()).split("\u0000")[0] + var node = "" + var ip = "vmess=" + server.split("@")[1] + ", " + "method=aes-128-gcm, " + "password=" + server.split("@")[0].split(":")[1] + ", " + var tag = "tag=" + decodeURIComponent(subs.split("remarks=")[1].split("&")[0]) + var tfo = subs.indexOf("tfo=1") != -1 ? "fast-open=true, " : "fast-open=false, " + var udp = Pudp == 1 ? "udp-relay=true, " : "udp-relay=false, "; + node = ip + tfo + udp + var obfs = subs.split("obfs=")[1].split("&")[0] + if (obfs == "none") { // + obfs = subs.indexOf("tls=1") != -1 ? "obfs=over-tls, " : "" //over-tls + } else if (obfs == "websocket") { + obfs = subs.indexOf("tls=1") != -1 ? "obfs=wss, " : "obfs=ws," //ws,wss 类型 + obfs = obfs + "obfs-uri=" + subs.split("&path=")[1].split("&")[0] + ", " + var host = subs.indexOf("&obfsParam=") != -1 ? "obfs-host=" + subs.split("&obfsParam=")[1].split("&")[0] + ", " : "" + obfs = obfs + host } - if(obfs.indexOf("obfs=over-tls")!=-1||obfs.indexOf("obfs=wss")!=-1 ){ - var cert= Pcert!=0 || subs.indexOf("allowInsecure=1")!=-1 ? "tls-verification=false, ":"tls-verification=true, " - var tls13=Ptls13==1? "tls13=true, ":"" - obfs=obfs+cert+tls13 + if (obfs.indexOf("obfs=over-tls") != -1 || obfs.indexOf("obfs=wss") != -1) { + var cert = Pcert != 0 || subs.indexOf("allowInsecure=1") != -1 ? "tls-verification=false, " : "tls-verification=true, " + var tls13 = Ptls13 == 1 ? "tls13=true, " : "" + obfs = obfs + cert + tls13 } - node=node+obfs+tag + node = node + obfs + tag return node } //V2RayN uri转换成 QUANX 格式 -function V2QX(subs,Pudp,Ptfo,Pcert,Ptls13){ - var cert=Pcert - var tls13=Ptls13 - var server=String(Base64.decode(subs.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); - udp= Pudp==1? "udp-relay=true":"udp-relay=false"; - tfo= Ptfo==1? "fast-open=true":"fast-open=false"; - obfs=Pobfs(ss,cert,tls13); - if(obfs=="" || obfs==undefined){ - nss.push(ip,mtd,pwd,tfo,udp,tag) - }else { - nss.push(ip,mtd,pwd,obfs,tfo,udp,tag);} - QX=nss.join(", "); +function V2QX(subs, Pudp, Ptfo, Pcert, Ptls13) { + var cert = Pcert + var tls13 = Ptls13 + var server = String(Base64.decode(subs.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); + udp = Pudp == 1 ? "udp-relay=true" : "udp-relay=false"; + tfo = Ptfo == 1 ? "fast-open=true" : "fast-open=false"; + obfs = Pobfs(ss, cert, tls13); + if (obfs == "" || obfs == undefined) { + nss.push(ip, mtd, pwd, tfo, udp, tag) + } else { + nss.push(ip, mtd, pwd, obfs, tfo, udp, tag); + } + QX = nss.join(", "); } return QX } // Vmess obfs 参数 -function Pobfs(jsonl,Pcert,Ptls13){ - var obfsi=[]; - var cert=Pcert; - tcert= cert==0? "tls-verification=false":"tls-verification=true"; - tls13= Ptls13==1? "tls13=true":"tls13=false" - if(jsonl.net=="ws" && jsonl.tls=="tls"){ - obfs0="obfs=wss, "+tcert+", "+tls13+", "; - uri0= jsonl.path && jsonl.path!=""? "obfs-uri="+jsonl.path:"obfs-uri=/"; - host0= jsonl.host && jsonl.host!=""? "obfs-host="+jsonl.host+",":""; - obfsi.push(obfs0+host0+uri0) +function Pobfs(jsonl, Pcert, Ptls13) { + var obfsi = []; + var cert = Pcert; + tcert = cert == 0 ? "tls-verification=false" : "tls-verification=true"; + tls13 = Ptls13 == 1 ? "tls13=true" : "tls13=false" + if (jsonl.net == "ws" && jsonl.tls == "tls") { + obfs0 = "obfs=wss, " + tcert + ", " + tls13 + ", "; + uri0 = jsonl.path && jsonl.path != "" ? "obfs-uri=" + jsonl.path : "obfs-uri=/"; + host0 = jsonl.host && 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 && jsonl.path!=""? "obfs-uri="+jsonl.path:"obfs-uri=/"; - host0= jsonl.host && jsonl.host!=""? "obfs-host="+jsonl.host+",":""; - obfsi.push(obfs0,host0+uri0); + } else if (jsonl.net == "ws") { + obfs0 = "obfs=ws"; + uri0 = jsonl.path && jsonl.path != "" ? "obfs-uri=" + jsonl.path : "obfs-uri=/"; + host0 = jsonl.host && jsonl.host != "" ? "obfs-host=" + jsonl.host + "," : ""; + obfsi.push(obfs0, host0 + uri0); return obfsi.join(", ") - }else if(jsonl.tls=="tls"){ - obfs0="obfs=over-tls, "+tcert+", "+tls13; - uri0=jsonl.path && jsonl.path!=""? "obfs-uri="+jsonl.path:""; - host0=jsonl.host && jsonl.host!=""? ", obfs-host="+jsonl.host:""; - obfsi.push(obfs0+host0) + } else if (jsonl.tls == "tls") { + obfs0 = "obfs=over-tls, " + tcert + ", " + tls13; + uri0 = jsonl.path && jsonl.path != "" ? "obfs-uri=" + jsonl.path : ""; + host0 = jsonl.host && jsonl.host != "" ? ", obfs-host=" + jsonl.host : ""; + obfsi.push(obfs0 + host0) return obfsi.join(", ") } } //对.的特殊处理(in/out & rename中) function Dot2(cnt) { - cnt=cnt? cnt.replace(/\\\./g,"这是个点"):"" + cnt = cnt ? cnt.replace(/\\\./g, "这是个点") : "" return cnt } function ToDot(cnt) { - cnt=cnt? cnt.replace(/这是个点/g,"."):"" + cnt = cnt ? cnt.replace(/这是个点/g, ".") : "" return cnt } //正则筛选, 完整内容匹配 -function Regex(content){ - Preg=RegExp(Preg,"i") - cnt=content //.split("tag=")[1] - if(Preg.test(cnt)){ +function Regex(content) { + Preg = RegExp(Preg, "i") + cnt = content //.split("tag=")[1] + if (Preg.test(cnt)) { return content } } // 判断节点过滤的函数 -function Scheck(content,param){ - name=content.split("tag=")[1].toUpperCase() - param=param? param.map(Dot2):param // 对符号.的特殊处理 - if(param){ - var flag=0; - for(var i=0;i name.indexOf(item.toUpperCase()) !=-1; - if(params.every(checkpara)){ - flag=1 - } - }//for - return flag - }else { //if param - return 2} +function Scheck(content, param) { + name = content.split("tag=")[1].toUpperCase() + param = param ? param.map(Dot2) : param // 对符号.的特殊处理 + if (param) { + var flag = 0; + for (var i = 0; i < param.length; i++) { + var params = param[i].split(".").map(ToDot); + const checkpara = (item) => name.indexOf(item.toUpperCase()) != -1; + if (params.every(checkpara)) { + flag = 1 + } + }//for + return flag + } else { //if param + return 2 + } } //节点过滤,使用+连接多个关键词(逻辑"或"):in 为保留,out 为排除, "与"逻辑请用符号"."连接 -function Filter(servers,Pin,Pout){ - var Nlist=[]; - var Delist=[]; - var Nname=[]; - for(var i=0;i0){ - $notify("👥 引用"+"⟦"+subtag+"⟧"+" 开始节点筛选","🕹 筛选关键字: "+pfi+pfo, "☠️ 已删除以下 "+no+"个节点\n"+Delist.join(", "),sub_link); + var no = Delist.length <= 10 ? emojino[Delist.length] : Delist.length; + var no1 = Nlist.length <= 10 ? emojino[Nlist.length] : Nlist.length; + if (Pntf0 == 1 && Delist.length >= 1) {//通知部分 + if (Pin && no1 > 0) { //有 in 参数就通知保留部分 + $notify("👥 引用" + "⟦" + subtag + "⟧" + " 开始节点筛选", "🕹 筛选关键字: " + pfi + pfo, "☠️ 已保留以下 " + no1 + "个节点\n" + Nname.join(", "), sub_link); + } else if (Pout && no > 0) { + $notify("👥 引用" + "⟦" + subtag + "⟧" + " 开始节点筛选", "🕹 筛选关键字: " + pfi + pfo, "☠️ 已删除以下 " + no + "个节点\n" + Delist.join(", "), sub_link); + } + } else if (no1 == 0 || no1 == null) { //无剩余节点时强制通知 + $notify("‼️ ⟦" + subtag + "⟧" + "筛选后节点数为0️⃣", "⚠️ 请自行检查原始链接以及筛选参数", link0, sub_link); } - }else if(no1==0 || no1==null){ //无剩余节点时强制通知 - $notify("‼️ ⟦"+subtag+"⟧"+"筛选后节点数为0️⃣","⚠️ 请自行检查原始链接以及筛选参数", link0, sub_link);} return Nlist } +function FilterScript(servers, script) { + const $ = Tools(); + eval(script); + // extract server tags + const nodes = { + names: servers.map(s => s.split("tag=")[1]) + }; + const IN = filter(nodes); + const res = servers.filter((_, i) => IN[i]); + if (res.length === 0) { + $notify("‼️ ⟦" + subtag + "⟧" + "筛选后节点数为0️⃣", "⚠️ 请自行检查原始链接以及筛选参数", link0, sub_link); + } + return res; +} + //SSR 类型 URI 转换 quanx 格式 -function SSR2QX(subs,Pudp,Ptfo){ - var nssr=[] - var cnt=Base64.decode(subs.split("ssr://")[1].replace(/-/g,"+").replace(/_/g,"/")).split("\u0000")[0] +function SSR2QX(subs, Pudp, Ptfo) { + var nssr = [] + var cnt = Base64.decode(subs.split("ssr://")[1].replace(/-/g, "+").replace(/_/g, "/")).split("\u0000")[0] var obfshost = ''; var oparam = ''; - if(cnt.split(":").length<=6) { //排除难搞的 ipv6 节点 - type="shadowsocks="; - ip=cnt.split(":")[0]+":"+cnt.split(":")[1]; - pwd="password="+Base64.decode(cnt.split("/?")[0].split(":")[5].replace(/-/g,"+").replace(/_/g,"/")).split("\u0000")[0]; - 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] - pudp= Pudp==1? "udp-relay=true":"udp-relay=false"; - ptfo= Ptfo==1? "fast-open=true":"fast-open=false"; - nssr.push(type+ip,pwd,mtd,obfs+obfshost+oparam+ssrp,pudp,ptfo,tag) - QX=nssr.join(", ") -}else {QX=""} + if (cnt.split(":").length <= 6) { //排除难搞的 ipv6 节点 + type = "shadowsocks="; + ip = cnt.split(":")[0] + ":" + cnt.split(":")[1]; + pwd = "password=" + Base64.decode(cnt.split("/?")[0].split(":")[5].replace(/-/g, "+").replace(/_/g, "/")).split("\u0000")[0]; + 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] + pudp = Pudp == 1 ? "udp-relay=true" : "udp-relay=false"; + ptfo = Ptfo == 1 ? "fast-open=true" : "fast-open=false"; + nssr.push(type + ip, pwd, mtd, obfs + obfshost + oparam + ssrp, pudp, ptfo, tag) + QX = nssr.join(", ") + } else { QX = "" } return QX; } //Trojan 类型 URI 转换成 QX -function TJ2QX(subs,Pudp,Ptfo,Pcert,Ptls13){ - var ntrojan=[] - var cnt=subs.split("trojan://")[1] - type="trojan="; - if(cnt.indexOf(":443")!=-1){ - ip=cnt.split("@")[1].split(":443")[0]+":443"; - }else{ - ip=cnt.split("@")[1].split("?")[0].split("\n")[0].trim(); //非 443 端口的奇葩机场? +function TJ2QX(subs, Pudp, Ptfo, Pcert, Ptls13) { + var ntrojan = [] + var cnt = subs.split("trojan://")[1] + type = "trojan="; + if (cnt.indexOf(":443") != -1) { + ip = cnt.split("@")[1].split(":443")[0] + ":443"; + } else { + ip = cnt.split("@")[1].split("?")[0].split("\n")[0].trim(); //非 443 端口的奇葩机场? } - pwd="password="+cnt.split("@")[0]; - obfs="over-tls=true"; - pcert= cnt.indexOf("allowInsecure=0")!= -1? "tls-verification=true":"tls-verification=false"; - ptls13= Ptls13==1?"tls13=true":"tls13=false" - if(Pcert==0){pcert="tls-verification=false"} - pudp= Pudp==1? "udp-relay=true":"udp-relay=false"; - ptfo= Ptfo==1? "fast-open=true":"fast-open=false"; - tag=cnt.indexOf("#")!=-1? "tag="+decodeURIComponent(cnt.split("#")[1]):"tag= [trojan]"+ip - ntrojan.push(type+ip,pwd,obfs,pcert,ptls13,pudp,ptfo,tag) - QX=ntrojan.join(", "); + pwd = "password=" + cnt.split("@")[0]; + obfs = "over-tls=true"; + pcert = cnt.indexOf("allowInsecure=0") != -1 ? "tls-verification=true" : "tls-verification=false"; + ptls13 = Ptls13 == 1 ? "tls13=true" : "tls13=false" + if (Pcert == 0) { pcert = "tls-verification=false" } + pudp = Pudp == 1 ? "udp-relay=true" : "udp-relay=false"; + ptfo = Ptfo == 1 ? "fast-open=true" : "fast-open=false"; + tag = cnt.indexOf("#") != -1 ? "tag=" + decodeURIComponent(cnt.split("#")[1]) : "tag= [trojan]" + ip + ntrojan.push(type + ip, pwd, obfs, pcert, ptls13, pudp, ptfo, tag) + QX = ntrojan.join(", "); return QX; } //SS 类型 URI 转换 quanx 格式 -function SS2QX(subs,Pudp,Ptfo){ - var nssr=[] - var cnt=subs.split("ss://")[1] - if(cnt.split(":").length<=6) { //排除难搞的 ipv6 节点 - type="shadowsocks="; - if(cnt.indexOf("@")!=-1){ - ip=cnt.split("@")[1].split("#")[0].split("/")[0]; - pwdmtd=Base64.decode(cnt.split("@")[0].replace(/-/g,"+").replace(/_/g,"/")).split("\u0000")[0].split(":") - }else{ - var cnt0=Base64.decode(cnt.split("#")[0].replace(/-/g,"+").replace(/_/g,"/").split("\u0000")[0]); - ip=cnt0.split("@")[1].split("#")[0].split("/")[0]; - pwdmtd=cnt0.split("@")[0].split(":") +function SS2QX(subs, Pudp, Ptfo) { + var nssr = [] + var cnt = subs.split("ss://")[1] + if (cnt.split(":").length <= 6) { //排除难搞的 ipv6 节点 + type = "shadowsocks="; + if (cnt.indexOf("@") != -1) { + ip = cnt.split("@")[1].split("#")[0].split("/")[0]; + pwdmtd = Base64.decode(cnt.split("@")[0].replace(/-/g, "+").replace(/_/g, "/")).split("\u0000")[0].split(":") + } else { + var cnt0 = Base64.decode(cnt.split("#")[0].replace(/-/g, "+").replace(/_/g, "/").split("\u0000")[0]); + ip = cnt0.split("@")[1].split("#")[0].split("/")[0]; + pwdmtd = cnt0.split("@")[0].split(":") + } + pwd = "password=" + pwdmtd[1]; + mtd = "method=" + pwdmtd[0]; + obfs = cnt.split("obfs%3D")[1] != null ? ", obfs=" + cnt.split("obfs%3D")[1].split("%3B")[0] : ""; + obfshost = cnt.split("obfs-host%3D")[1] != null ? ", obfs-host=" + cnt.split("obfs-host%3D")[1].split("&")[0].split("#")[0] : ""; + tag = "tag=" + decodeURIComponent(cnt.split("#")[1]) + pudp = Pudp == 1 ? "udp-relay=true" : "udp-relay=false"; + ptfo = Ptfo == 1 ? "fast-open=true" : "fast-open=false"; + nssr.push(type + ip, pwd, mtd + obfs + obfshost, pudp, ptfo, tag) + QX = nssr.join(", ") + return QX; } - pwd="password="+pwdmtd[1]; - mtd="method="+pwdmtd[0]; - obfs= cnt.split("obfs%3D")[1]!=null ? ", obfs="+cnt.split("obfs%3D")[1].split("%3B")[0]: ""; - obfshost=cnt.split("obfs-host%3D")[1]!=null ? ", obfs-host="+cnt.split("obfs-host%3D")[1].split("&")[0].split("#")[0]:""; - tag="tag="+decodeURIComponent(cnt.split("#")[1]) - pudp= Pudp==1? "udp-relay=true":"udp-relay=false"; - ptfo= Ptfo==1? "fast-open=true":"fast-open=false"; - nssr.push(type+ip,pwd,mtd+obfs+obfshost,pudp,ptfo,tag) - QX=nssr.join(", ") - return QX; -} } //SSD 类型 URI 转换 quanx 格式 -function SSD2QX(subs,Pudp,Ptfo){ - var j=0 - var QX=[] - var cnt=JSON.parse(Base64.decode(subs.split("ssd://")[1])) - var type="shadowsocks="; - var pwd="password="+cnt.password; - var mtd="method="+cnt.encryption; - var obfs="" - var obfshost="" - var port=cnt.port? ":"+cnt.port:"" - if(cnt.plugin_options){ - obfs=cnt.plugin_options.split(";")[0]!=null ? ", "+cnt.plugin_options.split(";")[0]: ""; - obfshost=cnt.plugin_options.split(";")[1]!=null ? ", "+cnt.plugin_options.split(";")[1]: ""; +function SSD2QX(subs, Pudp, Ptfo) { + var j = 0 + var QX = [] + var cnt = JSON.parse(Base64.decode(subs.split("ssd://")[1])) + var type = "shadowsocks="; + var pwd = "password=" + cnt.password; + var mtd = "method=" + cnt.encryption; + var obfs = "" + var obfshost = "" + var port = cnt.port ? ":" + cnt.port : "" + if (cnt.plugin_options) { + obfs = cnt.plugin_options.split(";")[0] != null ? ", " + cnt.plugin_options.split(";")[0] : ""; + obfshost = cnt.plugin_options.split(";")[1] != null ? ", " + cnt.plugin_options.split(";")[1] : ""; } - pudp= Pudp==1? "udp-relay=true":"udp-relay=false"; - ptfo= Ptfo==1? "fast-open=true":"fast-open=false"; + pudp = Pudp == 1 ? "udp-relay=true" : "udp-relay=false"; + ptfo = Ptfo == 1 ? "fast-open=true" : "fast-open=false"; for (var i in cnt.servers) { - ip=cnt.servers[i].server; - if(cnt.servers[i].plugin_options){ - obfs=cnt.servers[i].plugin_options.split(";")[0]!=null ? ", "+cnt.servers[i].plugin_options.split(";")[0]: ""; - obfshost=cnt.servers[i].plugin_options.split(";")[1]!=null ? ", "+cnt.servers[i].plugin_options.split(";")[1]: ""; + ip = cnt.servers[i].server; + if (cnt.servers[i].plugin_options) { + obfs = cnt.servers[i].plugin_options.split(";")[0] != null ? ", " + cnt.servers[i].plugin_options.split(";")[0] : ""; + obfshost = cnt.servers[i].plugin_options.split(";")[1] != null ? ", " + cnt.servers[i].plugin_options.split(";")[1] : ""; } - if(cnt.servers[i].encryption){ //独立的加密方式 - mtd="method="+cnt.servers[i].encryption + if (cnt.servers[i].encryption) { //独立的加密方式 + mtd = "method=" + cnt.servers[i].encryption } - if(cnt.servers[i].password){ //独立的密码 - pwd="password="+cnt.servers[i].password + if (cnt.servers[i].password) { //独立的密码 + pwd = "password=" + cnt.servers[i].password } - if(ip.indexOf(".")>0){ //排除难搞的 ipv6 节点 - port=cnt.servers[i].port?":"+cnt.servers[i].port:port; - tag="tag="+cnt.servers[i].remarks; - QX[j]=type+ip+port+", "+pwd+", "+mtd+obfs+obfshost+", "+pudp+", "+ptfo+", "+tag; - var j=j+1; - } - } + if (ip.indexOf(".") > 0) { //排除难搞的 ipv6 节点 + port = cnt.servers[i].port ? ":" + cnt.servers[i].port : port; + tag = "tag=" + cnt.servers[i].remarks; + QX[j] = type + ip + port + ", " + pwd + ", " + mtd + obfs + obfshost + ", " + pudp + ", " + ptfo + ", " + tag; + var j = j + 1; + } + } return QX; } // 用于过滤非节点部分(比如整份配置中其它内容) -function isQuanX(content){ - var cnts=content.split("\n"); - var nlist=[] - for(var i=0;itag2? 1:-1 +function ToTag(elem1, elem2) { + var tag1 = emoji_del(elem1.split("tag")[1].split("=")[1].trim()) + var tag2 = emoji_del(elem2.split("tag")[1].split("=")[1].trim()) + res = tag1 > tag2 ? 1 : -1 return res } //逆序 -function ToTagR(elem1,elem2){ - var tag1=emoji_del(elem1.split("tag")[1].split("=")[1].trim()) - var tag2=emoji_del(elem2.split("tag")[1].split("=")[1].trim()) - res = tag1>tag2? -1:1 +function ToTagR(elem1, elem2) { + var tag1 = emoji_del(elem1.split("tag")[1].split("=")[1].trim()) + var tag2 = emoji_del(elem2.split("tag")[1].split("=")[1].trim()) + res = tag1 > tag2 ? -1 : 1 return res } //正则删除节点名内的字符 -function DelReg(content){ - delreg=RegExp(delreg,"gmi") - cnt0=content.split("tag=")[0] - cnt1=content.split("tag=")[1] - cnt=cnt0+"tag="+cnt1.replace(delreg,"") - return cnt +function DelReg(content) { + delreg = RegExp(delreg, "gmi") + cnt0 = content.split("tag=")[0] + cnt1 = content.split("tag=")[1] + cnt = cnt0 + "tag=" + cnt1.replace(delreg, "") + return cnt } //节点重命名 -function Rename(str){ - var server=str; - if(server.indexOf("tag=")!=-1){ - hd=server.split("tag=")[0] - name=server.split("tag=")[1].trim() - for(var i=0;i>> 6)) - + fromCharCode(0x80 | (cc & 0x3f))) - : (fromCharCode(0xe0 | ((cc >>> 12) & 0x0f)) - + fromCharCode(0x80 | ((cc >>> 6) & 0x3f)) - + fromCharCode(0x80 | ( cc & 0x3f))); + + fromCharCode(0x80 | (cc & 0x3f))) + : (fromCharCode(0xe0 | ((cc >>> 12) & 0x0f)) + + fromCharCode(0x80 | ((cc >>> 6) & 0x3f)) + + fromCharCode(0x80 | (cc & 0x3f))); } else { var cc = 0x10000 + (c.charCodeAt(0) - 0xD800) * 0x400 + (c.charCodeAt(1) - 0xDC00); return (fromCharCode(0xf0 | ((cc >>> 18) & 0x07)) - + fromCharCode(0x80 | ((cc >>> 12) & 0x3f)) - + fromCharCode(0x80 | ((cc >>> 6) & 0x3f)) - + fromCharCode(0x80 | ( cc & 0x3f))); + + fromCharCode(0x80 | ((cc >>> 12) & 0x3f)) + + fromCharCode(0x80 | ((cc >>> 6) & 0x3f)) + + fromCharCode(0x80 | (cc & 0x3f))); } }; var re_utob = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g; - var utob = function(u) { + var utob = function (u) { return u.replace(re_utob, cb_utob); }; - var cb_encode = function(ccc) { + var cb_encode = function (ccc) { var padlen = [0, 2, 1][ccc.length % 3], - ord = ccc.charCodeAt(0) << 16 - | ((ccc.length > 1 ? ccc.charCodeAt(1) : 0) << 8) - | ((ccc.length > 2 ? ccc.charCodeAt(2) : 0)), - chars = [ - b64chars.charAt( ord >>> 18), - b64chars.charAt((ord >>> 12) & 63), - padlen >= 2 ? '=' : b64chars.charAt((ord >>> 6) & 63), - padlen >= 1 ? '=' : b64chars.charAt(ord & 63) - ]; + ord = ccc.charCodeAt(0) << 16 + | ((ccc.length > 1 ? ccc.charCodeAt(1) : 0) << 8) + | ((ccc.length > 2 ? ccc.charCodeAt(2) : 0)), + chars = [ + b64chars.charAt(ord >>> 18), + b64chars.charAt((ord >>> 12) & 63), + padlen >= 2 ? '=' : b64chars.charAt((ord >>> 6) & 63), + padlen >= 1 ? '=' : b64chars.charAt(ord & 63) + ]; return chars.join(''); }; - var btoa = function(b) { + var btoa = function (b) { return b.replace(/[\s\S]{1,3}/g, cb_encode); }; // var _encode = function(u) { @@ -1409,66 +1459,66 @@ function Base64Code(){ // return isUint8Array ? u.toString('base64') // : btoa(utob(String(u))); // } - this.encode=function(u){ - var isUint8Array = Object.prototype.toString.call(u) === '[object Uint8Array]'; - return isUint8Array ? u.toString('base64') - : btoa(utob(String(u))); - } - var uriencode = function(u, urisafe) { + this.encode = function (u) { + var isUint8Array = Object.prototype.toString.call(u) === '[object Uint8Array]'; + return isUint8Array ? u.toString('base64') + : btoa(utob(String(u))); + } + var uriencode = function (u, urisafe) { return !urisafe ? _encode(u) - : _encode(String(u)).replace(/[+\/]/g, function(m0) { + : _encode(String(u)).replace(/[+\/]/g, function (m0) { return m0 == '+' ? '-' : '_'; }).replace(/=/g, ''); }; - var encodeURI = function(u) { return uriencode(u, true) }; + var encodeURI = function (u) { return uriencode(u, true) }; // decoder stuff var re_btou = /[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3}/g; - var cb_btou = function(cccc) { - switch(cccc.length) { - case 4: - var cp = ((0x07 & cccc.charCodeAt(0)) << 18) - | ((0x3f & cccc.charCodeAt(1)) << 12) - | ((0x3f & cccc.charCodeAt(2)) << 6) - | (0x3f & cccc.charCodeAt(3)), - offset = cp - 0x10000; - return (fromCharCode((offset >>> 10) + 0xD800) + var cb_btou = function (cccc) { + switch (cccc.length) { + case 4: + var cp = ((0x07 & cccc.charCodeAt(0)) << 18) + | ((0x3f & cccc.charCodeAt(1)) << 12) + | ((0x3f & cccc.charCodeAt(2)) << 6) + | (0x3f & cccc.charCodeAt(3)), + offset = cp - 0x10000; + return (fromCharCode((offset >>> 10) + 0xD800) + fromCharCode((offset & 0x3FF) + 0xDC00)); - case 3: - return fromCharCode( - ((0x0f & cccc.charCodeAt(0)) << 12) + case 3: + return fromCharCode( + ((0x0f & cccc.charCodeAt(0)) << 12) | ((0x3f & cccc.charCodeAt(1)) << 6) - | (0x3f & cccc.charCodeAt(2)) - ); - default: - return fromCharCode( - ((0x1f & cccc.charCodeAt(0)) << 6) - | (0x3f & cccc.charCodeAt(1)) - ); + | (0x3f & cccc.charCodeAt(2)) + ); + default: + return fromCharCode( + ((0x1f & cccc.charCodeAt(0)) << 6) + | (0x3f & cccc.charCodeAt(1)) + ); } }; - var btou = function(b) { + var btou = function (b) { return b.replace(re_btou, cb_btou); }; - var cb_decode = function(cccc) { + var cb_decode = function (cccc) { var len = cccc.length, - padlen = len % 4, - n = (len > 0 ? b64tab[cccc.charAt(0)] << 18 : 0) - | (len > 1 ? b64tab[cccc.charAt(1)] << 12 : 0) - | (len > 2 ? b64tab[cccc.charAt(2)] << 6 : 0) - | (len > 3 ? b64tab[cccc.charAt(3)] : 0), - chars = [ - fromCharCode( n >>> 16), - fromCharCode((n >>> 8) & 0xff), - fromCharCode( n & 0xff) - ]; + padlen = len % 4, + n = (len > 0 ? b64tab[cccc.charAt(0)] << 18 : 0) + | (len > 1 ? b64tab[cccc.charAt(1)] << 12 : 0) + | (len > 2 ? b64tab[cccc.charAt(2)] << 6 : 0) + | (len > 3 ? b64tab[cccc.charAt(3)] : 0), + chars = [ + fromCharCode(n >>> 16), + fromCharCode((n >>> 8) & 0xff), + fromCharCode(n & 0xff) + ]; chars.length -= [0, 0, 2, 1][padlen]; return chars.join(''); }; - var _atob = function(a){ + var _atob = function (a) { return a.replace(/\S{1,4}/g, cb_decode); }; - var atob = function(a) { + var atob = function (a) { return _atob(String(a).replace(/[^A-Za-z0-9\+\/]/g, '')); }; // var _decode = buffer ? @@ -1482,13 +1532,52 @@ function Base64Code(){ // ? a : new buffer(a, 'base64')).toString(); // } // : function(a) { return btou(_atob(a)) }; - var _decode=function(u){ + var _decode = function (u) { return btou(_atob(u)) } - this.decode = function(a){ + this.decode = function (a) { return _decode( - String(a).replace(/[-_]/g, function(m0) { return m0 == '-' ? '+' : '/' }) + String(a).replace(/[-_]/g, function (m0) { return m0 == '-' ? '+' : '/' }) .replace(/[^A-Za-z0-9\+\/]/g, '') - ); + ).replace(/>/g, ">").replace(/</g, "<"); }; +} + + +/***********************************************************************************************/ +function Tools() { + const filter = (src, ...regex) => { + const initial = [...Array(src.length).keys()].map(() => false); + return regex.reduce((a, expr) => OR(a, src.map(item => expr.test(item))), initial) + } + + const rename = { + replace: (src, old, now) => { + return src.map(item => item.replace(old, now)); + }, + + delete: (src, ...args) => { + return src.map(item => args.reduce((now, expr) => now.replace(expr, ''), item)); + }, + + trim: (src) => { + return src.map(item => item.trim().replace(/[^\S\r\n]{2,}/g, ' ')); + } + } + + return { + filter, rename + } +} + +function AND(...args) { + return args.reduce((a, b) => a.map((c, i) => b[i] && c)); +} + +function OR(...args) { + return args.reduce((a, b) => a.map((c, i) => b[i] || c)) +} + +function NOT(array) { + return array.map(c => !c); } \ No newline at end of file