mirror of
https://github.com/lush2020/CF-Workers-SUB.git
synced 2026-03-21 02:52:38 +08:00
debug
This commit is contained in:
@@ -21,7 +21,7 @@ Telegram交流群:[@CMLiussss](https://t.me/CMLiussss),**感谢[Alice Networ
|
||||
- 添加 `TOKEN` 变量,快速订阅访问入口,默认值为: `auto` ,获取订阅器默认节点订阅地址即 `/auto` ,例如 `https://sub.fuck.cloudns.biz/auto`
|
||||
|
||||
### 4. 添加你的节点和订阅链接:
|
||||
1. 绑定名为`KV`的KV空间;
|
||||
1. 绑定**变量名称**为`KV`的**KV命名空间**;
|
||||
2. 访问 `https://sub.fuck.cloudns.biz/auto`,添加你的自建节点链接和机场订阅链接,确保每行一个链接,例如:
|
||||
```
|
||||
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
|
||||
@@ -53,7 +53,7 @@ Telegram交流群:[@CMLiussss](https://t.me/CMLiussss),**感谢[Alice Networ
|
||||
|
||||
|
||||
### 3. 添加你的节点或订阅链接:
|
||||
1. 绑定名为`KV`的KV空间;
|
||||
1. 绑定**变量名称**为`KV`的**KV命名空间**;
|
||||
2. 访问 `https://sub.cmliussss.workers.dev/auto`,添加你的自建节点链接和机场订阅链接,确保每行一个链接,例如:
|
||||
```
|
||||
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
|
||||
|
||||
154
_worker.js
154
_worker.js
@@ -2,8 +2,8 @@
|
||||
// 部署完成后在网址后面加上这个,获取自建节点和机场聚合节点,/?token=auto或/auto或
|
||||
|
||||
let mytoken = 'auto'; //可以随便取,或者uuid生成,https://1024tools.com/uuid
|
||||
let BotToken =''; //可以为空,或者@BotFather中输入/start,/newbot,并关注机器人
|
||||
let ChatID =''; //可以为空,或者@userinfobot中获取,/start
|
||||
let BotToken = ''; //可以为空,或者@BotFather中输入/start,/newbot,并关注机器人
|
||||
let ChatID = ''; //可以为空,或者@userinfobot中获取,/start
|
||||
let TG = 0; //小白勿动, 开发者专用,1 为推送所有的访问信息,0 为不推送订阅转换后端的访问信息与异常访问
|
||||
let FileName = 'CF-Workers-SUB';
|
||||
let SUBUpdateTime = 6; //自定义订阅更新时间,单位小时
|
||||
@@ -22,17 +22,17 @@ let subConfig = "https://raw.githubusercontent.com/cmliu/ACL4SSR/main/Clash/conf
|
||||
let subProtocol = 'https';
|
||||
|
||||
export default {
|
||||
async fetch (request,env) {
|
||||
async fetch(request, env) {
|
||||
const userAgentHeader = request.headers.get('User-Agent');
|
||||
const userAgent = userAgentHeader ? userAgentHeader.toLowerCase() : "null";
|
||||
const url = new URL(request.url);
|
||||
const token = url.searchParams.get('token');
|
||||
mytoken = env.TOKEN || mytoken;
|
||||
BotToken = env.TGTOKEN || BotToken;
|
||||
ChatID = env.TGID || ChatID;
|
||||
TG = env.TG || TG;
|
||||
ChatID = env.TGID || ChatID;
|
||||
TG = env.TG || TG;
|
||||
subConverter = env.SUBAPI || subConverter;
|
||||
if( subConverter.includes("http://") ){
|
||||
if (subConverter.includes("http://")) {
|
||||
subConverter = subConverter.split("//")[1];
|
||||
subProtocol = 'http';
|
||||
} else {
|
||||
@@ -42,22 +42,22 @@ export default {
|
||||
FileName = env.SUBNAME || FileName;
|
||||
|
||||
const currentDate = new Date();
|
||||
currentDate.setHours(0, 0, 0, 0);
|
||||
currentDate.setHours(0, 0, 0, 0);
|
||||
const timeTemp = Math.ceil(currentDate.getTime() / 1000);
|
||||
const fakeToken = await MD5MD5(`${mytoken}${timeTemp}`);
|
||||
//console.log(`${fakeUserID}\n${fakeHostName}`); // 打印fakeID
|
||||
|
||||
let UD = Math.floor(((timestamp - Date.now())/timestamp * total * 1099511627776 )/2);
|
||||
total = total * 1099511627776 ;
|
||||
let expire= Math.floor(timestamp / 1000) ;
|
||||
let UD = Math.floor(((timestamp - Date.now()) / timestamp * total * 1099511627776) / 2);
|
||||
total = total * 1099511627776;
|
||||
let expire = Math.floor(timestamp / 1000);
|
||||
SUBUpdateTime = env.SUBUPTIME || SUBUpdateTime;
|
||||
|
||||
if ( !(token == mytoken || token == fakeToken || url.pathname == ("/"+ mytoken) || url.pathname.includes("/"+ mytoken + "?")) ) {
|
||||
if ( TG == 1 && url.pathname !== "/" && url.pathname !== "/favicon.ico" ) await sendMessage(`#异常访问 ${FileName}`, request.headers.get('CF-Connecting-IP'), `UA: ${userAgent}</tg-spoiler>\n域名: ${url.hostname}\n<tg-spoiler>入口: ${url.pathname + url.search}</tg-spoiler>`);
|
||||
if (!(token == mytoken || token == fakeToken || url.pathname == ("/" + mytoken) || url.pathname.includes("/" + mytoken + "?"))) {
|
||||
if (TG == 1 && url.pathname !== "/" && url.pathname !== "/favicon.ico") await sendMessage(`#异常访问 ${FileName}`, request.headers.get('CF-Connecting-IP'), `UA: ${userAgent}</tg-spoiler>\n域名: ${url.hostname}\n<tg-spoiler>入口: ${url.pathname + url.search}</tg-spoiler>`);
|
||||
if (env.URL302) return Response.redirect(env.URL302, 302);
|
||||
else if (env.URL) return await proxyURL(env.URL, url);
|
||||
else return new Response(await nginx(), {
|
||||
status: 200 ,
|
||||
else return new Response(await nginx(), {
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': 'text/html; charset=UTF-8',
|
||||
},
|
||||
@@ -65,7 +65,7 @@ export default {
|
||||
} else {
|
||||
if (env.KV) {
|
||||
await 迁移地址列表(env, 'LINK.txt');
|
||||
if (userAgent.includes('mozilla') && !url.search){
|
||||
if (userAgent.includes('mozilla') && !url.search) {
|
||||
await sendMessage(`#编辑订阅 ${FileName}`, request.headers.get('CF-Connecting-IP'), `UA: ${userAgentHeader}</tg-spoiler>\n域名: ${url.hostname}\n<tg-spoiler>入口: ${url.pathname + url.search}</tg-spoiler>`);
|
||||
return await KV(request, env, 'LINK.txt');
|
||||
} else {
|
||||
@@ -76,8 +76,8 @@ export default {
|
||||
if (env.LINKSUB) urls = await ADD(env.LINKSUB);
|
||||
}
|
||||
let 重新汇总所有链接 = await ADD(MainData + '\n' + urls.join('\n'));
|
||||
let 自建节点 ="";
|
||||
let 订阅链接 ="";
|
||||
let 自建节点 = "";
|
||||
let 订阅链接 = "";
|
||||
for (let x of 重新汇总所有链接) {
|
||||
if (x.toLowerCase().startsWith('http')) {
|
||||
订阅链接 += x + '\n';
|
||||
@@ -90,38 +90,38 @@ export default {
|
||||
await sendMessage(`#获取订阅 ${FileName}`, request.headers.get('CF-Connecting-IP'), `UA: ${userAgentHeader}</tg-spoiler>\n域名: ${url.hostname}\n<tg-spoiler>入口: ${url.pathname + url.search}</tg-spoiler>`);
|
||||
|
||||
let 订阅格式 = 'base64';
|
||||
if (userAgent.includes('null') || userAgent.includes('subconverter') || userAgent.includes('nekobox') || userAgent.includes(('CF-Workers-SUB').toLowerCase())){
|
||||
if (userAgent.includes('null') || userAgent.includes('subconverter') || userAgent.includes('nekobox') || userAgent.includes(('CF-Workers-SUB').toLowerCase())) {
|
||||
订阅格式 = 'base64';
|
||||
} else if (userAgent.includes('clash') || ( url.searchParams.has('clash') && !userAgent.includes('subconverter'))){
|
||||
} else if (userAgent.includes('clash') || (url.searchParams.has('clash') && !userAgent.includes('subconverter'))) {
|
||||
订阅格式 = 'clash';
|
||||
} else if (userAgent.includes('sing-box') || userAgent.includes('singbox') || ( (url.searchParams.has('sb') || url.searchParams.has('singbox')) && !userAgent.includes('subconverter'))){
|
||||
} else if (userAgent.includes('sing-box') || userAgent.includes('singbox') || ((url.searchParams.has('sb') || url.searchParams.has('singbox')) && !userAgent.includes('subconverter'))) {
|
||||
订阅格式 = 'singbox';
|
||||
} else if (userAgent.includes('surge') || ( url.searchParams.has('surge') && !userAgent.includes('subconverter'))){
|
||||
} else if (userAgent.includes('surge') || (url.searchParams.has('surge') && !userAgent.includes('subconverter'))) {
|
||||
订阅格式 = 'surge';
|
||||
} else if (userAgent.includes('quantumult%20x') || (url.searchParams.has('quanx') && !userAgent.includes('subconverter'))){
|
||||
} else if (userAgent.includes('quantumult%20x') || (url.searchParams.has('quanx') && !userAgent.includes('subconverter'))) {
|
||||
订阅格式 = 'quanx';
|
||||
} else if (userAgent.includes('loon') || (url.searchParams.has('loon') && !userAgent.includes('subconverter'))){
|
||||
} else if (userAgent.includes('loon') || (url.searchParams.has('loon') && !userAgent.includes('subconverter'))) {
|
||||
订阅格式 = 'loon';
|
||||
}
|
||||
|
||||
let subConverterUrl ;
|
||||
let subConverterUrl;
|
||||
let 订阅转换URL = `${url.origin}/${await MD5MD5(fakeToken)}?token=${fakeToken}`;
|
||||
//console.log(订阅转换URL);
|
||||
let req_data = MainData;
|
||||
|
||||
let 追加UA = 'v2rayn';
|
||||
if (url.searchParams.has('clash')) 追加UA = 'clash';
|
||||
else if(url.searchParams.has('singbox')) 追加UA = 'singbox';
|
||||
else if(url.searchParams.has('surge')) 追加UA = 'surge';
|
||||
else if(url.searchParams.has('quanx')) 追加UA = 'Quantumult%20X';
|
||||
else if(url.searchParams.has('loon')) 追加UA = 'Loon';
|
||||
|
||||
const 请求订阅响应内容 = await getSUB(urls ,request ,追加UA, userAgentHeader);
|
||||
else if (url.searchParams.has('singbox')) 追加UA = 'singbox';
|
||||
else if (url.searchParams.has('surge')) 追加UA = 'surge';
|
||||
else if (url.searchParams.has('quanx')) 追加UA = 'Quantumult%20X';
|
||||
else if (url.searchParams.has('loon')) 追加UA = 'Loon';
|
||||
|
||||
const 请求订阅响应内容 = await getSUB(urls, request, 追加UA, userAgentHeader);
|
||||
console.log(请求订阅响应内容);
|
||||
req_data += 请求订阅响应内容[0].join('\n');
|
||||
订阅转换URL += "|" + 请求订阅响应内容[1];
|
||||
|
||||
if(env.WARP) 订阅转换URL += "|" + (await ADD(env.WARP)).join("|");
|
||||
if (env.WARP) 订阅转换URL += "|" + (await ADD(env.WARP)).join("|");
|
||||
//修复中文错误
|
||||
const utf8Encoder = new TextEncoder();
|
||||
const encodedData = utf8Encoder.encode(req_data);
|
||||
@@ -133,7 +133,7 @@ export default {
|
||||
const uniqueLines = new Set(text.split('\n'));
|
||||
const result = [...uniqueLines].join('\n');
|
||||
//console.log(result);
|
||||
|
||||
|
||||
let base64Data;
|
||||
try {
|
||||
base64Data = btoa(result);
|
||||
@@ -142,51 +142,51 @@ export default {
|
||||
const binary = new TextEncoder().encode(data);
|
||||
let base64 = '';
|
||||
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
||||
|
||||
|
||||
for (let i = 0; i < binary.length; i += 3) {
|
||||
const byte1 = binary[i];
|
||||
const byte2 = binary[i + 1] || 0;
|
||||
const byte3 = binary[i + 2] || 0;
|
||||
|
||||
|
||||
base64 += chars[byte1 >> 2];
|
||||
base64 += chars[((byte1 & 3) << 4) | (byte2 >> 4)];
|
||||
base64 += chars[((byte2 & 15) << 2) | (byte3 >> 6)];
|
||||
base64 += chars[byte3 & 63];
|
||||
}
|
||||
|
||||
|
||||
const padding = 3 - (binary.length % 3 || 3);
|
||||
return base64.slice(0, base64.length - padding) + '=='.slice(0, padding);
|
||||
}
|
||||
|
||||
|
||||
base64Data = encodeBase64(result);
|
||||
}
|
||||
|
||||
if (订阅格式 == 'base64' || token == fakeToken){
|
||||
return new Response(base64Data ,{
|
||||
headers: {
|
||||
if (订阅格式 == 'base64' || token == fakeToken) {
|
||||
return new Response(base64Data, {
|
||||
headers: {
|
||||
"content-type": "text/plain; charset=utf-8",
|
||||
"Profile-Update-Interval": `${SUBUpdateTime}`,
|
||||
"Subscription-Userinfo": `upload=${UD}; download=${UD}; total=${total}; expire=${expire}`,
|
||||
}
|
||||
});
|
||||
} else if (订阅格式 == 'clash'){
|
||||
} else if (订阅格式 == 'clash') {
|
||||
subConverterUrl = `${subProtocol}://${subConverter}/sub?target=clash&url=${encodeURIComponent(订阅转换URL)}&insert=false&config=${encodeURIComponent(subConfig)}&emoji=true&list=false&tfo=false&scv=true&fdn=false&sort=false&new_name=true`;
|
||||
} else if (订阅格式 == 'singbox'){
|
||||
} else if (订阅格式 == 'singbox') {
|
||||
subConverterUrl = `${subProtocol}://${subConverter}/sub?target=singbox&url=${encodeURIComponent(订阅转换URL)}&insert=false&config=${encodeURIComponent(subConfig)}&emoji=true&list=false&tfo=false&scv=true&fdn=false&sort=false&new_name=true`;
|
||||
} else if (订阅格式 == 'surge'){
|
||||
} else if (订阅格式 == 'surge') {
|
||||
subConverterUrl = `${subProtocol}://${subConverter}/sub?target=surge&url=${encodeURIComponent(订阅转换URL)}&insert=false&config=${encodeURIComponent(subConfig)}&emoji=true&list=false&tfo=false&scv=true&fdn=false&sort=false&new_name=true`;
|
||||
} else if (订阅格式 == 'quanx'){
|
||||
} else if (订阅格式 == 'quanx') {
|
||||
subConverterUrl = `${subProtocol}://${subConverter}/sub?target=quanx&url=${encodeURIComponent(订阅转换URL)}&insert=false&config=${encodeURIComponent(subConfig)}&emoji=true&list=false&tfo=false&scv=true&fdn=false&sort=false&udp=true`;
|
||||
} else if (订阅格式 == 'loon'){
|
||||
} else if (订阅格式 == 'loon') {
|
||||
subConverterUrl = `${subProtocol}://${subConverter}/sub?target=loon&url=${encodeURIComponent(订阅转换URL)}&insert=false&config=${encodeURIComponent(subConfig)}&emoji=true&list=false&tfo=false&scv=true&fdn=false&sort=false`;
|
||||
}
|
||||
//console.log(订阅转换URL);
|
||||
try {
|
||||
const subConverterResponse = await fetch(subConverterUrl);
|
||||
|
||||
|
||||
if (!subConverterResponse.ok) {
|
||||
return new Response(base64Data ,{
|
||||
headers: {
|
||||
return new Response(base64Data, {
|
||||
headers: {
|
||||
"content-type": "text/plain; charset=utf-8",
|
||||
"Profile-Update-Interval": `${SUBUpdateTime}`,
|
||||
"Subscription-Userinfo": `upload=${UD}; download=${UD}; total=${total}; expire=${expire}`,
|
||||
@@ -195,22 +195,22 @@ export default {
|
||||
//throw new Error(`Error fetching subConverterUrl: ${subConverterResponse.status} ${subConverterResponse.statusText}`);
|
||||
}
|
||||
let subConverterContent = await subConverterResponse.text();
|
||||
if (订阅格式 == 'clash') subConverterContent =await clashFix(subConverterContent);
|
||||
if (订阅格式 == 'clash') subConverterContent = await clashFix(subConverterContent);
|
||||
return new Response(subConverterContent, {
|
||||
headers: {
|
||||
headers: {
|
||||
"Content-Disposition": `attachment; filename*=utf-8''${encodeURIComponent(FileName)}; filename=${FileName}`,
|
||||
"content-type": "text/plain; charset=utf-8",
|
||||
"Profile-Update-Interval": `${SUBUpdateTime}`,
|
||||
"Subscription-Userinfo": `upload=${UD}; download=${UD}; total=${total}; expire=${expire}`,
|
||||
//"Subscription-Userinfo": `upload=${UD}; download=${UD}; total=${total}; expire=${expire}`,
|
||||
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
return new Response(base64Data ,{
|
||||
headers: {
|
||||
return new Response(base64Data, {
|
||||
headers: {
|
||||
"content-type": "text/plain; charset=utf-8",
|
||||
"Profile-Update-Interval": `${SUBUpdateTime}`,
|
||||
"Subscription-Userinfo": `upload=${UD}; download=${UD}; total=${total}; expire=${expire}`,
|
||||
//"Subscription-Userinfo": `upload=${UD}; download=${UD}; total=${total}; expire=${expire}`,
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -222,10 +222,10 @@ async function ADD(envadd) {
|
||||
var addtext = envadd.replace(/[ "'|\r\n]+/g, ',').replace(/,+/g, ','); // 将空格、双引号、单引号和换行符替换为逗号
|
||||
//console.log(addtext);
|
||||
if (addtext.charAt(0) == ',') addtext = addtext.slice(1);
|
||||
if (addtext.charAt(addtext.length -1) == ',') addtext = addtext.slice(0, addtext.length - 1);
|
||||
if (addtext.charAt(addtext.length - 1) == ',') addtext = addtext.slice(0, addtext.length - 1);
|
||||
const add = addtext.split(',');
|
||||
//console.log(add);
|
||||
return add ;
|
||||
return add;
|
||||
}
|
||||
|
||||
async function nginx() {
|
||||
@@ -256,11 +256,11 @@ async function nginx() {
|
||||
</body>
|
||||
</html>
|
||||
`
|
||||
return text ;
|
||||
return text;
|
||||
}
|
||||
|
||||
async function sendMessage(type, ip, add_data = "") {
|
||||
if ( BotToken !== '' && ChatID !== ''){
|
||||
if (BotToken !== '' && ChatID !== '') {
|
||||
let msg = "";
|
||||
const response = await fetch(`http://ip-api.com/json/${ip}?lang=zh-CN`);
|
||||
if (response.status == 200) {
|
||||
@@ -269,8 +269,8 @@ async function sendMessage(type, ip, add_data = "") {
|
||||
} else {
|
||||
msg = `${type}\nIP: ${ip}\n<tg-spoiler>${add_data}`;
|
||||
}
|
||||
|
||||
let url = "https://api.telegram.org/bot"+ BotToken +"/sendMessage?chat_id=" + ChatID + "&parse_mode=HTML&text=" + encodeURIComponent(msg);
|
||||
|
||||
let url = "https://api.telegram.org/bot" + BotToken + "/sendMessage?chat_id=" + ChatID + "&parse_mode=HTML&text=" + encodeURIComponent(msg);
|
||||
return fetch(url, {
|
||||
method: 'get',
|
||||
headers: {
|
||||
@@ -290,7 +290,7 @@ function base64Decode(str) {
|
||||
|
||||
async function MD5MD5(text) {
|
||||
const encoder = new TextEncoder();
|
||||
|
||||
|
||||
const firstPass = await crypto.subtle.digest('MD5', encoder.encode(text));
|
||||
const firstPassArray = Array.from(new Uint8Array(firstPass));
|
||||
const firstHex = firstPassArray.map(b => b.toString(16).padStart(2, '0')).join('');
|
||||
@@ -298,19 +298,19 @@ async function MD5MD5(text) {
|
||||
const secondPass = await crypto.subtle.digest('MD5', encoder.encode(firstHex.slice(7, 27)));
|
||||
const secondPassArray = Array.from(new Uint8Array(secondPass));
|
||||
const secondHex = secondPassArray.map(b => b.toString(16).padStart(2, '0')).join('');
|
||||
|
||||
|
||||
return secondHex.toLowerCase();
|
||||
}
|
||||
|
||||
function clashFix(content) {
|
||||
if(content.includes('wireguard') && !content.includes('remote-dns-resolve')){
|
||||
if (content.includes('wireguard') && !content.includes('remote-dns-resolve')) {
|
||||
let lines;
|
||||
if (content.includes('\r\n')){
|
||||
if (content.includes('\r\n')) {
|
||||
lines = content.split('\r\n');
|
||||
} else {
|
||||
lines = content.split('\n');
|
||||
}
|
||||
|
||||
|
||||
let result = "";
|
||||
for (let line of lines) {
|
||||
if (line.includes('type: wireguard')) {
|
||||
@@ -421,7 +421,7 @@ async function getSUB(api, request, 追加UA, userAgentHeader) {
|
||||
订阅转换URLs += "|" + response.apiUrl; // Singbox 配置
|
||||
} else if (content.includes('://')) {
|
||||
newapi += content + '\n'; // 追加内容
|
||||
} else if (isValidBase64(content)){
|
||||
} else if (isValidBase64(content)) {
|
||||
newapi += base64Decode(content) + '\n'; // 解码并追加内容
|
||||
} else {
|
||||
const 异常订阅LINK = `trojan://CMLiussss@127.0.0.1:8888?security=tls&allowInsecure=1&type=tcp&headerType=none#%E5%BC%82%E5%B8%B8%E8%AE%A2%E9%98%85%20${response.apiUrl.split('://')[1].split('/')[0]}`;
|
||||
@@ -472,7 +472,7 @@ function isValidBase64(str) {
|
||||
async function 迁移地址列表(env, txt = 'ADD.txt') {
|
||||
const 旧数据 = await env.KV.get(`/${txt}`);
|
||||
const 新数据 = await env.KV.get(txt);
|
||||
|
||||
|
||||
if (旧数据 && !新数据) {
|
||||
// 写入新位置
|
||||
await env.KV.put(txt, 旧数据);
|
||||
@@ -498,11 +498,11 @@ async function KV(request, env, txt = 'ADD.txt') {
|
||||
return new Response("保存失败: " + error.message, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// GET请求部分
|
||||
let content = '';
|
||||
let hasKV = !!env.KV;
|
||||
|
||||
|
||||
if (hasKV) {
|
||||
try {
|
||||
content = await env.KV.get(txt) || '';
|
||||
@@ -511,7 +511,7 @@ async function KV(request, env, txt = 'ADD.txt') {
|
||||
content = '读取数据时发生错误: ' + error.message;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const html = `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
@@ -577,10 +577,10 @@ async function KV(request, env, txt = 'ADD.txt') {
|
||||
</head>
|
||||
<body>
|
||||
################################################################<br>
|
||||
Subscribe / sub 订阅地址, 支持 Base64、clash-meta、sing-box 订阅格式<br>
|
||||
Subscribe / sub 订阅地址, 点击链接自动 <strong>复制订阅链接</strong> 并 <strong>生成订阅二维码</strong> <br>
|
||||
---------------------------------------------------------------<br>
|
||||
自适应订阅地址:<br>
|
||||
<a href="javascript:void(0)" onclick="copyToClipboard('https://${url.hostname}/${mytoken}','qrcode_0')" style="color:blue;text-decoration:underline;cursor:pointer;">https://${url.hostname}/${mytoken}</a><br>
|
||||
<a href="javascript:void(0)" onclick="copyToClipboard('https://${url.hostname}/${mytoken}?b64','qrcode_0')" style="color:blue;text-decoration:underline;cursor:pointer;">https://${url.hostname}/${mytoken}</a><br>
|
||||
<div id="qrcode_0" style="margin: 10px 10px 10px 10px;"></div>
|
||||
Base64订阅地址:<br>
|
||||
<a href="javascript:void(0)" onclick="copyToClipboard('https://${url.hostname}/${mytoken}?b64','qrcode_1')" style="color:blue;text-decoration:underline;cursor:pointer;">https://${url.hostname}/${mytoken}?b64</a><br>
|
||||
@@ -601,8 +601,8 @@ async function KV(request, env, txt = 'ADD.txt') {
|
||||
################################################################<br>
|
||||
订阅转换配置<br>
|
||||
---------------------------------------------------------------<br>
|
||||
SUBAPI(订阅转换后端): ${subProtocol}://${subConverter}<br>
|
||||
SUBCONFIG(订阅转换配置文件): ${subConfig}<br>
|
||||
SUBAPI(订阅转换后端): <strong>${subProtocol}://${subConverter}</strong><br>
|
||||
SUBCONFIG(订阅转换配置文件): <strong>${subConfig}</strong><br>
|
||||
---------------------------------------------------------------<br>
|
||||
################################################################<br>
|
||||
${FileName} 汇聚订阅编辑:
|
||||
@@ -615,12 +615,12 @@ async function KV(request, env, txt = 'ADD.txt') {
|
||||
<button class="save-btn" onclick="saveContent(this)">保存</button>
|
||||
<span class="save-status" id="saveStatus"></span>
|
||||
</div>
|
||||
` : '<p>未绑定KV空间</p>'}
|
||||
` : '<p>请绑定 <strong>变量名称</strong> 为 <strong>KV</strong> 的KV命名空间</p>'}
|
||||
</div>
|
||||
<br>
|
||||
################################################################<br>
|
||||
${decodeURIComponent(atob('dGVsZWdyYW0lMjAlRTQlQkElQTQlRTYlQjUlODElRTclQkUlQTQlMjAlRTYlOEElODAlRTYlOUMlQUYlRTUlQTQlQTclRTQlQkQlQUMlN0UlRTUlOUMlQTglRTclQkElQkYlRTUlOEYlOTElRTclODklOEMhJTNDYnIlM0UKJTNDYSUyMGhyZWYlM0QlMjdodHRwcyUzQSUyRiUyRnQubWUlMkZDTUxpdXNzc3MlMjclM0VodHRwcyUzQSUyRiUyRnQubWUlMkZDTUxpdXNzc3MlM0MlMkZhJTNFJTNDYnIlM0UKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tJTNDYnIlM0UKZ2l0aHViJTIwJUU5JUExJUI5JUU3JTlCJUFFJUU1JTlDJUIwJUU1JTlEJTgwJTIwU3RhciFTdGFyIVN0YXIhISElM0NiciUzRQolM0NhJTIwaHJlZiUzRCUyN2h0dHBzJTNBJTJGJTJGZ2l0aHViLmNvbSUyRmNtbGl1JTJGQ0YtV29ya2Vycy1TVUIlMjclM0VodHRwcyUzQSUyRiUyRmdpdGh1Yi5jb20lMkZjbWxpdSUyRkNGLVdvcmtlcnMtU1VCJTNDJTJGYSUzRSUzQ2JyJTNFCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSUzQ2JyJTNFCiUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMw=='))}
|
||||
<br><br>UA: ${request.headers.get('User-Agent')}
|
||||
<br><br>UA: <strong>${request.headers.get('User-Agent')}</strong>
|
||||
<script>
|
||||
function copyToClipboard(text, qrcode) {
|
||||
navigator.clipboard.writeText(text).then(() => {
|
||||
@@ -759,13 +759,13 @@ async function KV(request, env, txt = 'ADD.txt') {
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
|
||||
return new Response(html, {
|
||||
headers: { "Content-Type": "text/html;charset=utf-8" }
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('处理请求时发生错误:', error);
|
||||
return new Response("服务器错误: " + error.message, {
|
||||
return new Response("服务器错误: " + error.message, {
|
||||
status: 500,
|
||||
headers: { "Content-Type": "text/plain;charset=utf-8" }
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user