From 30dd36efeecbdc4e44447050af6a6e78dc9a4ff8 Mon Sep 17 00:00:00 2001 From: CMLiussss <24787744+cmliu@users.noreply.github.com> Date: Fri, 12 Apr 2024 15:22:38 +0800 Subject: [PATCH] Update _worker.js --- _worker.js | 196 ++++++++++++++++++++++++++++------------------------- 1 file changed, 103 insertions(+), 93 deletions(-) diff --git a/_worker.js b/_worker.js index 7bd6515..33ea244 100644 --- a/_worker.js +++ b/_worker.js @@ -4,10 +4,11 @@ let mytoken = 'auto'; //可以随便取,或者uuid生成,https://1024tools.com/uuid let BotToken =''; //可以为空,或者@BotFather中输入/start,/newbot,并关注机器人 let ChatID =''; //可以为空,或者@userinfobot中获取,/start -let TG = 0; //1 为推送所有的访问信息,0 为不推送订阅转换后端的访问信息与异常访问 +let TG = 0; //小白勿动, 开发者专用,1 为推送所有的访问信息,0 为不推送订阅转换后端的访问信息与异常访问 +let FileName = 'CF-Workers-SUB'; let SUBUpdateTime = 6; //自定义订阅更新时间,单位小时 -//自建节点+机场订阅 +//节点链接 + 订阅链接 let MainData = ` vless://b7a392e2-4ef0-4496-90bc-1c37bb234904@cf.090227.xyz:443?encryption=none&security=tls&sni=edgetunnel-2z2.pages.dev&fp=random&type=ws&host=edgetunnel-2z2.pages.dev&path=%2F%3Fed%3D2048#%E5%8A%A0%E5%85%A5%E6%88%91%E7%9A%84%E9%A2%91%E9%81%93t.me%2FCMLiussss%E8%A7%A3%E9%94%81%E6%9B%B4%E5%A4%9A%E4%BC%98%E9%80%89%E8%8A%82%E7%82%B9 https://sub.xf.free.hr/auto @@ -15,11 +16,8 @@ https://hy2sub.pages.dev ` //请将机场订阅链接填入上方 -let urls = [ - //'https://sub.xf.free.hr/auto', - //'https://hy2sub.pages.dev', - // 添加更多订阅,支持base64 -]; +let urls = []; +let warp = "";// https://subs.zeabur.app/clash , https://neko-warp.nloli.xyz/neko_warp.yaml let subconverter = "apiurl.v1.mk"; //在线订阅转换后端,目前使用肥羊的订阅转换功能。支持自建psub 可自行搭建https://github.com/bulianglin/psub let subconfig = "https://raw.githubusercontent.com/cmliu/ACL4SSR/main/Clash/config/ACL4SSR_Online_MultiCountry.ini"; //订阅配置文件 @@ -36,12 +34,13 @@ export default { TG = env.TG || TG; subconverter = env.SUBAPI || subconverter; subconfig = env.SUBCONFIG || subconfig; - + FileName = env.SUBNAME || FileName; + warp = env.WARP || warp; MainData = env.LINK || MainData; if(env.LINKSUB) urls = await ADD(env.LINKSUB); let links = await ADD(MainData + '\n' + urls.join('\n')); - let link =""; + let link = ""; let linksub = ""; for (let x of links) { @@ -52,9 +51,9 @@ export default { } } MainData = link; - urls = await ADD(linksub) + urls = await ADD(linksub); let sublinks = request.url ; - if(env.WARP) sublinks += '|' + (await ADD(env.WARP)).join('|'); + if(warp && warp != "") sublinks += '|' + (await ADD(warp)).join('|'); //console.log(MainData,urls,sublinks); if ( !(token == mytoken || url.pathname == ("/"+ mytoken) || url.pathname.includes("/"+ mytoken + "?")) ) { @@ -95,91 +94,76 @@ export default { await sendMessage("#获取订阅", request.headers.get('CF-Connecting-IP'), `UA: ${userAgentHeader}\n域名: ${url.hostname}\n入口: ${url.pathname + url.search}`); } + let req_data = MainData; + // 创建一个AbortController对象,用于控制fetch请求的取消 + const controller = new AbortController(); + + const timeout = setTimeout(() => { + controller.abort(); // 取消所有请求 + }, 1618); // 1.618秒后触发 + + try { + const responses = await Promise.allSettled(urls.map(url => + fetch(url, { + method: 'get', + headers: { + 'Accept': 'text/html,application/xhtml+xml,application/xml;', + 'User-Agent': 'v2rayN/6.39 cmliu/CF-Workers-SUB' + }, + signal: controller.signal // 将AbortController的信号量添加到fetch请求中,以便于需要时可以取消请求 + }).then(response => { + if (response.ok) { + return response.text().then(content => { + // 这里可以顺便做内容检查 + if (content.includes('dns') && content.includes('proxies') && content.includes('proxy-groups') && content.includes('rules')) { + //console.log("clashsub: " + url); + sublinks += "|" + url; + } else if (content.includes('dns') && content.includes('outbounds') && content.includes('inbounds')){ + //console.log("singboxsub: " + url); + sublinks += "|" + url; + } else { + return content; // 保证链式调用中的下一个then可以接收到文本内容 + } + }); + } else { + return ""; // 如果response.ok为false,返回空字符串 + } + }) + )); + //console.log(responses); + for (const response of responses) { + if (response.status === 'fulfilled') { + const content = await response.value; + req_data += base64Decode(content) + '\n'; + } + } + } catch (error) { + //console.error(error); + } finally { + // 无论成功或失败,最后都清除设置的超时定时器 + clearTimeout(timeout); + } + //修复中文错误 + const utf8Encoder = new TextEncoder(); + const encodedData = utf8Encoder.encode(req_data); + const text = String.fromCharCode.apply(null, encodedData); + + //去重 + const uniqueLines = new Set(text.split('\n')); + const result = [...uniqueLines].join('\n'); + //console.log(result); + + const base64Data = btoa(result); + //console.log(base64Data); + + //console.log("自建节点: " + MainData,"订阅链接: " + urls,"转换链接: " + sublinks); + + let target = "v2ray"; if (userAgent.includes('clash') && !userAgent.includes('nekobox')) { - - const subconverterUrl = `https://${subconverter}/sub?target=clash&url=${encodeURIComponent(sublinks)}&insert=false&config=${encodeURIComponent(subconfig)}&emoji=true&list=false&tfo=false&scv=false&fdn=false&sort=false&new_name=true`; - - try { - const subconverterResponse = await fetch(subconverterUrl); - - if (!subconverterResponse.ok) { - throw new Error(`Error fetching subconverterUrl: ${subconverterResponse.status} ${subconverterResponse.statusText}`); - } - - const subconverterContent = await subconverterResponse.text(); - - return new Response(subconverterContent ,{ - headers: { - "content-type": "text/plain; charset=utf-8", - "Profile-Update-Interval": `${SUBUpdateTime}`, - } - }); - } catch (error) { - return new Response(`Error: ${error.message}`, { - status: 500, - headers: { 'content-type': 'text/plain; charset=utf-8' }, - }); - } + target = "clash"; } else if (userAgent.includes('sing-box') || userAgent.includes('singbox')) { - const subconverterUrl = `https://${subconverter}/sub?target=singbox&url=${encodeURIComponent(sublinks)}&insert=false&config=${encodeURIComponent(subconfig)}&emoji=true&list=false&tfo=false&scv=false&fdn=false&sort=false&new_name=true`; - - try { - const subconverterResponse = await fetch(subconverterUrl); - - if (!subconverterResponse.ok) { - throw new Error(`Error fetching subconverterUrl: ${subconverterResponse.status} ${subconverterResponse.statusText}`); - } - - const subconverterContent = await subconverterResponse.text(); - - return new Response(subconverterContent ,{ - headers: { - "content-type": "text/plain; charset=utf-8", - "Profile-Update-Interval": `${SUBUpdateTime}`, - } - }); - } catch (error) { - return new Response(`Error: ${error.message}`, { - status: 500, - headers: { 'content-type': 'text/plain; charset=utf-8' }, - }); - } + target = "singbox"; } else { - let req_data = ""; - req_data += MainData; - - try { - const responses = await Promise.allSettled(urls.map(url => - fetch(url, { - method: 'get', - headers: { - 'Accept': 'text/html,application/xhtml+xml,application/xml;', - 'User-Agent': 'v2rayN/6.39 cmliu/CF-Workers-SUB' - } - }).then(response => response.ok ? response.text() : Promise.reject()) - )); - - for (const response of responses) { - if (response.status === 'fulfilled') { - const content = await response.value; - req_data += base64Decode(content) + '\n'; - } - } - } catch (error) { - console.error(error); - } - //修复中文错误 - const utf8Encoder = new TextEncoder(); - const encodedData = utf8Encoder.encode(req_data); - const text = String.fromCharCode.apply(null, encodedData); - - //去重 - const uniqueLines = new Set(text.split('\n')); - const result = [...uniqueLines].join('\n'); - //console.log(result); - - const base64Data = btoa(result); - //console.log(base64Data); return new Response(base64Data ,{ headers: { "content-type": "text/plain; charset=utf-8", @@ -187,6 +171,32 @@ export default { } }); } + + const subconverterUrl = `https://${subconverter}/sub?target=${target}&url=${encodeURIComponent(sublinks)}&insert=false&config=${encodeURIComponent(subconfig)}&emoji=true&list=false&tfo=false&scv=true&fdn=false&sort=false&new_name=true`; + + try { + const subconverterResponse = await fetch(subconverterUrl); + + if (!subconverterResponse.ok) { + throw new Error(`Error fetching subconverterUrl: ${subconverterResponse.status} ${subconverterResponse.statusText}`); + } + + const subconverterContent = await subconverterResponse.text(); + + return new Response(subconverterContent ,{ + headers: { + "Content-Disposition": `attachment; filename*=utf-8''${encodeURIComponent(FileName)}; filename=${FileName}`, + "content-type": "text/plain; charset=utf-8", + "Profile-Update-Interval": `${SUBUpdateTime}`, + } + }); + } catch (error) { + return new Response(`Error: ${error.message}`, { + status: 500, + headers: { 'content-type': 'text/plain; charset=utf-8' }, + }); + } + } };