├── README.md ├── workers ├── wetest-vip.js ├── sspanel.js ├── dockerhub.js └── glados.js ├── sspanel.md └── glados.md /README.md: -------------------------------------------------------------------------------- 1 | # 🚀 CF worker 工具集合 2 | 3 | ## 📋 功能模块 4 | 5 |
8 | 🛡️ GLaDOS 签到9 | |
10 |
11 | 🌐 SSPanel 通用签到12 | |
13 |
|
16 | 自动完成 GLaDOS 的每日签到任务 17 |💡 多账户 | 🔔 tg通知 | 📊 签到统计 18 | |
19 |
20 | 自动完成 SSPanel 面板每日签到任务 21 |💡 多账户 | 🔔 tg通知 22 | |
23 |
|
26 |
27 | |
30 |
31 |
32 | |
35 |
${result.email}\n`;
204 | message += `📝 ${result.message}\n`;
205 | message += `⏰ ${result.time}\n\n`;
206 |
207 | if (result.success) {
208 | successCount++;
209 | } else {
210 | failureCount++;
211 | }
212 | });
213 |
214 | // 添加统计信息
215 | message += `📊 签到统计\n`;
216 | message += `✅ 成功: ${successCount} 个账号\n`;
217 | message += `❌ 失败: ${failureCount} 个账号\n`;
218 | message += `🔢 总计: ${results.length} 个账号`;
219 |
220 | const url = `https://api.telegram.org/bot${botToken}/sendMessage`;
221 | const payload = {
222 | chat_id: chatId,
223 | text: message,
224 | parse_mode: 'HTML'
225 | };
226 |
227 | const response = await fetch(url, {
228 | method: 'POST',
229 | headers: {
230 | 'Content-Type': 'application/json',
231 | 'User-Agent': 'Mozilla/5.0 (compatible; SSPanel-Checkin/1.0)'
232 | },
233 | body: JSON.stringify(payload)
234 | });
235 |
236 | if (response.ok) {
237 | console.log('Telegram 消息发送成功');
238 | return { sent: true };
239 | } else {
240 | const errorData = await response.text();
241 | console.error('Telegram 消息发送失败:', errorData);
242 | return { sent: false, error: `发送失败: ${response.status}` };
243 | }
244 | } catch (error) {
245 | console.error('Telegram 通知异常:', error.message);
246 | return { sent: false, error: error.message };
247 | }
248 | }
249 |
250 | // 执行所有机场签到
251 | async function handleRequest() {
252 | const results = [];
253 | for (const config of AIRPORTS) {
254 | try {
255 | const checkin = new AirportCheckin(config);
256 | const result = await checkin.run();
257 | results.push(result);
258 | } catch (error) {
259 | // 如果某个机场签到出错,记录错误但继续处理其他机场
260 | results.push({
261 | airport: config.name,
262 | email: config.email,
263 | success: false,
264 | message: `处理异常: ${error.message}`,
265 | time: new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' })
266 | });
267 | }
268 | }
269 | return { success: true, timestamp: new Date().toISOString(), results };
270 | }
271 |
272 | export default {
273 | async fetch(request, env) {
274 | try {
275 | // 初始化环境变量
276 | initializeVariables(env);
277 |
278 | const url = new URL(request.url);
279 |
280 | // 路由处理
281 | switch (url.pathname) {
282 | case "/tg":
283 | // 检查 Telegram 配置
284 | if (!botToken || !chatId) {
285 | return new Response(JSON.stringify({
286 | success: false,
287 | error: "Telegram 配置未完成",
288 | message: "请在 Cloudflare Workers 环境变量中设置 TGTOKEN 和 TGID",
289 | help: {
290 | "TGTOKEN": "从 @BotFather 获取的 Bot Token",
291 | "TGID": "你的 Telegram Chat ID (可从 @userinfobot 获取)"
292 | }
293 | }, null, 2), {
294 | status: 400,
295 | headers: { 'Content-Type': 'application/json' }
296 | });
297 | }
298 |
299 | // 执行签到并发送 Telegram 通知
300 | const tgResult = await handleRequest();
301 | const telegramResult = await sendTelegramMessage(tgResult.results);
302 |
303 | return new Response(JSON.stringify({
304 | ...tgResult,
305 | telegram_sent: telegramResult.sent,
306 | telegram_error: telegramResult.error || null,
307 | message: telegramResult.sent
308 | ? "签到完成,已发送 Telegram 通知"
309 | : `签到完成,但 Telegram 通知发送失败: ${telegramResult.error}`
310 | }, null, 2), {
311 | status: telegramResult.sent ? 200 : 206, // 206 表示部分成功
312 | headers: { 'Content-Type': 'application/json' }
313 | });
314 |
315 | case "/status":
316 | // 仅显示配置状态
317 | return new Response(JSON.stringify({
318 | airports_configured: AIRPORTS.length,
319 | telegram_configured: !!(botToken && chatId),
320 | endpoints: [
321 | "/ - 显示帮助信息",
322 | "/checkin - 执行签到(不发送通知)",
323 | "/tg - 执行签到并发送 Telegram 通知",
324 | "/status - 显示配置状态"
325 | ]
326 | }, null, 2), {
327 | headers: { 'Content-Type': 'application/json' }
328 | });
329 |
330 | case "/checkin":
331 | // 仅执行签到,不发送通知
332 | const checkinResult = await handleRequest();
333 | return new Response(JSON.stringify(checkinResult, null, 2), {
334 | headers: { 'Content-Type': 'application/json' }
335 | });
336 |
337 | default:
338 | // 默认帮助页面
339 | const helpMessage = `
340 | SSPanel 机场自动签到服务
341 |
342 | 🔧 环境变量配置:
343 | - TGTOKEN: Telegram Bot Token (可选)
344 | - TGID: Telegram Chat ID (可选)
345 |
346 | 📡 可用端点:
347 | - GET / - 显示此帮助信息
348 | - POST /checkin - 执行机场签到
349 | - POST /tg - 执行签到并发送 Telegram 通知
350 | - GET /status - 查看配置状态
351 |
352 | 📊 当前状态:
353 | - 已配置机场: ${AIRPORTS.length} 个
354 | - Telegram 通知: ${botToken && chatId ? '✅ 已配置' : '❌ 未配置'}
355 |
356 | ⏰ 支持 Cloudflare Workers 定时任务
357 | `;
358 |
359 | return new Response(helpMessage, {
360 | headers: { 'Content-Type': 'text/plain; charset=utf-8' }
361 | });
362 | }
363 | } catch (error) {
364 | return new Response(JSON.stringify({
365 | success: false,
366 | error: error.message,
367 | timestamp: new Date().toISOString()
368 | }), {
369 | status: 500,
370 | headers: { 'Content-Type': 'application/json' }
371 | });
372 | }
373 | },
374 |
375 | // 定时任务处理函数
376 | async scheduled(event, env, ctx) {
377 | console.log('SSPanel 机场签到定时任务开始');
378 | try {
379 | // 初始化环境变量
380 | initializeVariables(env);
381 |
382 | // 执行签到
383 | const result = await handleRequest();
384 |
385 | // 尝试发送 Telegram 通知
386 | const telegramResult = await sendTelegramMessage(result.results);
387 |
388 | console.log('SSPanel 机场签到定时任务完成');
389 | return new Response(JSON.stringify({
390 | ...result,
391 | telegram_sent: telegramResult.sent,
392 | telegram_error: telegramResult.error || null,
393 | scheduled: true,
394 | message: telegramResult.sent
395 | ? "定时任务完成,已发送 Telegram 通知"
396 | : `定时任务完成,Telegram 通知: ${telegramResult.error || '未配置'}`
397 | }));
398 | } catch (error) {
399 | console.error('定时任务失败:', error);
400 |
401 | // 即使出错也尝试发送错误通知(如果配置了 Telegram)
402 | if (botToken && chatId) {
403 | await sendTelegramMessage([{
404 | airport: "系统",
405 | email: "定时任务",
406 | success: false,
407 | message: `定时任务执行失败: ${error.message}`,
408 | time: new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' })
409 | }]);
410 | }
411 |
412 | return new Response(JSON.stringify({
413 | success: false,
414 | error: error.message,
415 | timestamp: new Date().toISOString()
416 | }), { status: 500 });
417 | }
418 | }
419 | };
420 |
--------------------------------------------------------------------------------
/workers/dockerhub.js:
--------------------------------------------------------------------------------
1 | // _worker.js
2 |
3 | // Docker镜像仓库主机地址
4 | let hub_host = 'registry-1.docker.io';
5 | // Docker认证服务器地址
6 | const auth_url = 'https://auth.docker.io';
7 | // 自定义的工作服务器地址
8 | let workers_url = '';
9 |
10 | let 屏蔽爬虫UA = ['netcraft'];
11 |
12 | // 根据主机名选择对应的上游地址
13 | function routeByHosts(host) {
14 | // 定义路由表
15 | const routes = {
16 | // 生产环境
17 | "quay": "quay.io",
18 | "gcr": "gcr.io",
19 | "k8s-gcr": "k8s.gcr.io",
20 | "k8s": "registry.k8s.io",
21 | "ghcr": "ghcr.io",
22 | "cloudsmith": "docker.cloudsmith.io",
23 | "nvcr": "nvcr.io",
24 |
25 | // 测试环境
26 | "test": "registry-1.docker.io",
27 | };
28 |
29 | if (host in routes) return [ routes[host], false ];
30 | else return [ hub_host, true ];
31 | }
32 |
33 | /** @type {RequestInit} */
34 | const PREFLIGHT_INIT = {
35 | // 预检请求配置
36 | headers: new Headers({
37 | 'access-control-allow-origin': '*', // 允许所有来源
38 | 'access-control-allow-methods': 'GET,POST,PUT,PATCH,TRACE,DELETE,HEAD,OPTIONS', // 允许的HTTP方法
39 | 'access-control-max-age': '1728000', // 预检请求的缓存时间
40 | }),
41 | }
42 |
43 | /**
44 | * 构造响应
45 | * @param {any} body 响应体
46 | * @param {number} status 响应状态码
47 | * @param {ObjectIf you see this page, the nginx web server is successfully installed and 91 | working. Further configuration is required.
92 | 93 |For online documentation and support please refer to
94 | nginx.org.
95 | Commercial support is available at
96 | nginx.com.
Thank you for using nginx.
99 | 100 | 101 | ` 102 | return text; 103 | } 104 | 105 | async function searchInterface() { 106 | const text = ` 107 | 108 | 109 | 110 |✅ 共完成 ${accounts.length} 个账号的签到任务`;
247 |
248 | // 添加图表链接,仅当request参数存在时
249 | // 获取 Worker URL
250 | const baseUrl = request ? getWorkerUrl(request) : workerUrl;
251 | const chartUrl = baseUrl + "/checkinChart";
252 | message += `\n\n📊 点击查看积分历史图表`;
253 |
254 | const url = `https://api.telegram.org/bot${botToken}/sendMessage?chat_id=${chatId}&parse_mode=HTML&text=${encodeURIComponent(message)}`;
255 | return fetch(url, {
256 | method: 'get',
257 | headers: {
258 | 'Accept': 'text/html,application/xhtml+xml,application/xml;',
259 | 'Accept-Encoding': 'gzip, deflate, br',
260 | 'User-Agent': 'Mozilla/5.0 Chrome/90.0.4430.72'
261 | }
262 | });
263 | }
264 |
265 | // 执行所有账号的签到
266 | async function performAllCheckins() {
267 | checkinResults = [];
268 |
269 | if (accounts.length === 0) {
270 | checkinResults.push("⚠️ 未配置任何账号信息");
271 | return;
272 | }
273 |
274 | for (const account of accounts) {
275 | try {
276 | const result = await performCheckin(account.email, account.cookie);
277 | checkinResults.push(result);
278 | } catch (error) {
279 | console.error(`账号 ${account.email} 签到错误:`, error);
280 | checkinResults.push(`${account.email}: 签到过程发生错误: ${error.message} ❌`);
281 | }
282 | }
283 |
284 | return checkinResults;
285 | }
286 |
287 | // 检查所有账号的状态
288 | async function checkAllAccountStatus() {
289 | accountStatus = [];
290 |
291 | if (accounts.length === 0) {
292 | accountStatus.push("⚠️ 未配置任何账号信息");
293 | return;
294 | }
295 |
296 | for (const account of accounts) {
297 | try {
298 | const result = await checkAccountStatus(account.email, account.cookie);
299 | accountStatus.push(result);
300 | } catch (error) {
301 | console.error(`账号 ${account.email} 状态查询错误:`, error);
302 | accountStatus.push(`${account.email}: 获取状态失败 - ${error.message} ❌`);
303 | }
304 | }
305 |
306 | return accountStatus;
307 | }
308 |
309 | // 执行单个账号签到
310 | async function performCheckin(email, cookie) {
311 | try {
312 | const data = { token: "glados.one" };
313 | const responseData = await makeApiRequest(API_ENDPOINTS.CHECKIN, 'POST', cookie, data);
314 | const translatedMessage = translateMessage(responseData);
315 |
316 | const result = `${email}: ${translatedMessage}`;
317 | return result;
318 | } catch (error) {
319 | throw new Error(`签到失败: ${error.message}`);
320 | }
321 | }
322 |
323 | // 检查单个账号状态
324 | async function checkAccountStatus(email, cookie) {
325 | try {
326 | const data = await makeApiRequest(API_ENDPOINTS.STATUS, 'GET', cookie);
327 |
328 | if (!data.data || !data.data.leftDays) {
329 | throw new Error('响应数据格式不正确');
330 | }
331 |
332 | const leftDays = formatDays(data.data.leftDays);
333 | return `${email}: 剩余 ${leftDays} 天`;
334 | } catch (error) {
335 | throw new Error(`获取状态失败: ${error.message}`);
336 | }
337 | }
338 |
339 | // 获取积分历史数据
340 | async function fetchPointsHistory() {
341 | pointsHistory = [];
342 |
343 | if (accounts.length === 0) {
344 | return;
345 | }
346 |
347 | for (const account of accounts) {
348 | try {
349 | // 获取积分历史
350 | const data = { token: "glados.one" };
351 | const responseData = await makeApiRequest(API_ENDPOINTS.CHECKIN, 'POST', account.cookie, data);
352 |
353 | // 获取账号状态(剩余天数)
354 | const statusData = await makeApiRequest(API_ENDPOINTS.STATUS, 'GET', account.cookie);
355 | const leftDays = statusData.data && statusData.data.leftDays ? formatDays(statusData.data.leftDays) : "未知";
356 |
357 | if (responseData.code === 1 && Array.isArray(responseData.list)) {
358 | // 处理积分历史数据
359 | const accountData = {
360 | email: account.email,
361 | leftDays: leftDays, // 添加剩余天数信息
362 | history: responseData.list.map(item => ({
363 | time: new Date(parseInt(item.time)),
364 | balance: parseFloat(item.balance),
365 | change: parseFloat(item.change),
366 | business: item.business
367 | })).sort((a, b) => a.time - b.time) // 按时间排序
368 | };
369 | pointsHistory.push(accountData);
370 | }
371 | } catch (error) {
372 | console.error(`获取账号 ${account.email} 积分历史错误:`, error);
373 | }
374 | }
375 | }
376 |
377 | // 生成图表响应
378 | function generateChartResponse() {
379 | // 如果没有数据,返回提示信息
380 | if (pointsHistory.length === 0) {
381 | return createResponse("未获取到任何积分历史数据,请确保账号配置正确。");
382 | }
383 |
384 | // 生成HTML页面,包含Chart.js图表
385 | const html = generateChartHtml();
386 | return new Response(html, {
387 | status: 200,
388 | headers: CONTENT_TYPE_HTML
389 | });
390 | }
391 |
392 | // 生成图表HTML
393 | function generateChartHtml() {
394 | return `
395 |
396 |
397 |
398 |
399 |
400 |