GLaDOS 自动签到部署指南

GLaDOS 自动签到部署指南

hutao

🚀 GLaDOS 自动签到部署指南

Cloudflare Workers + Telegram Bot + 定时任务

本教程用于将 GLaDOS 自动签到部署到 Cloudflare Workers,实现每天自动签到,并通过 Telegram Bot 推送签到结果。


✨ 功能特性

  • ✅ 每日自动签到 GLaDOS
  • ✅ Cloudflare Workers 定时执行
  • ✅ Telegram Bot 推送通知
  • ✅ 支持多个 GLaDOS 账号
  • ✅ 不需要服务器
  • ✅ 不需要 GitHub Actions
  • ✅ 不需要电脑保持开机
  • ✅ 使用 Cloudflare API Token 登录 Wrangler

🧱 项目结构

最终项目结构如下:

1
2
3
4
5
6
7
8
9
glados-checkin-worker

├── package.json
├── tsconfig.json
├── wrangler.toml
├── .dev.vars
├── .gitignore
└── src
└── index.ts

一、准备环境

1. 安装 Node.js

建议安装 Node.js 18 或更高版本。

检查版本:

1
2
node -v
npm -v

二、创建 Cloudflare API Token

由于 wrangler login 浏览器授权可能超时,本教程使用 API Token 模式

进入 Cloudflare:

1
2
3
4
Cloudflare Dashboard
→ My Profile
→ API Tokens
→ Create Token

选择模板:

1
Edit Cloudflare Workers

创建后复制生成的 API Token。


三、配置 Wrangler 登录

1. 当前 PowerShell 临时配置

1
$env:CLOUDFLARE_API_TOKEN="你的Cloudflare_API_Token"

验证:

1
npx wrangler whoami

如果能看到 Cloudflare 账号信息,说明成功。


2. 永久配置

1
setx CLOUDFLARE_API_TOKEN "你的Cloudflare_API_Token"

执行后关闭 PowerShell,重新打开生效。


四、创建项目

1
2
3
4
5
6
7
8
mkdir glados-checkin-worker
cd glados-checkin-worker

npm init -y

npm install -D wrangler typescript @cloudflare/workers-types

mkdir src

五、项目文件内容

1. package.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"name": "glados-checkin-worker",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "wrangler dev --test-scheduled",
"deploy": "wrangler deploy",
"tail": "wrangler tail"
},
"devDependencies": {
"@cloudflare/workers-types": "^4.20250601.0",
"typescript": "^5.5.4",
"wrangler": "^4.98.0"
}
}

2. tsconfig.json

1
2
3
4
5
6
7
8
9
10
11
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2022"],
"module": "ESNext",
"moduleResolution": "Bundler",
"strict": true,
"types": ["@cloudflare/workers-types"],
"skipLibCheck": true
}
}

3. wrangler.toml

1
2
3
4
5
6
name = "glados-checkin-worker"
main = "src/index.ts"
compatibility_date = "2026-06-05"

[triggers]
crons = ["0 23 * * *"]

4. .dev.vars

.dev.vars 只用于本地开发,不会部署到 Cloudflare。

1
2
3
GLADOS_COOKIE=koa:sess=你的sess; koa:sess.sig=你的sig
TELEGRAM_BOT_TOKEN=你的Telegram_Bot_Token
TELEGRAM_CHAT_ID=你的Telegram_Chat_ID

多个账号写法:

1
2
3
4
5
GLADOS_COOKIE=koa:sess=账号1sess; koa:sess.sig=账号1sig
koa:sess=账号2sess; koa:sess.sig=账号2sig
koa:sess=账号3sess; koa:sess.sig=账号3sig
TELEGRAM_BOT_TOKEN=你的Telegram_Bot_Token
TELEGRAM_CHAT_ID=你的Telegram_Chat_ID

注意:如果多账号换行写法在本地 .dev.vars 中读取异常,建议本地测试使用 & 分隔,线上 Secret 可直接粘贴多行。

推荐多账号写法:

1
2
3
GLADOS_COOKIE=koa:sess=账号1sess; koa:sess.sig=账号1sig&koa:sess=账号2sess; koa:sess.sig=账号2sig&koa:sess=账号3sess; koa:sess.sig=账号3sig
TELEGRAM_BOT_TOKEN=你的Telegram_Bot_Token
TELEGRAM_CHAT_ID=你的Telegram_Chat_ID

5. .gitignore

1
2
3
node_modules
.wrangler
.dev.vars

6. src/index.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
export interface Env {
GLADOS_COOKIE: string;
TELEGRAM_BOT_TOKEN?: string;
TELEGRAM_CHAT_ID?: string;
GLADOS_EXCHANGE_PLAN?: "plan100" | "plan200" | "plan500" | "";
}

type GladosJson = Record<string, any>;

const GLADOS_DOMAINS = [
"https://glados.cloud",
"https://railgun.info",
"https://glados.rocks",
"https://glados.network"
];

const EXCHANGE_PLANS: Record<string, { points: number; days: number }> = {
plan100: { points: 100, days: 7 },
plan200: { points: 200, days: 15 },
plan500: { points: 500, days: 40 }
};

export default {
async fetch(_request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
ctx.waitUntil(run(env));

return new Response("GLaDOS check-in started. Check Telegram or Worker logs.", {
headers: {
"content-type": "text/plain;charset=UTF-8"
}
});
},

async scheduled(_controller: ScheduledController, env: Env, ctx: ExecutionContext): Promise<void> {
ctx.waitUntil(run(env));
}
};

async function run(env: Env): Promise<void> {
const cookies = parseCookies(env.GLADOS_COOKIE);

if (cookies.length === 0) {
await notifyTelegram(env, "❌ GLaDOS 签到失败:未配置 GLADOS_COOKIE");
return;
}

const reports: string[] = [];
let successCount = 0;

for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i];
const accountNo = i + 1;

try {
const report = await checkOneAccount(
cookie,
accountNo,
env.GLADOS_EXCHANGE_PLAN || ""
);

reports.push(report.text);

if (report.success) {
successCount++;
}

console.log(report.text);
} catch (error) {
reports.push(
`👤 账号 ${accountNo}\n` +
`状态:❌ 异常\n` +
`错误:${safeError(error)}`
);
}
}

const title = `🎉 GLaDOS 签到完成:${successCount}/${cookies.length}`;

const message =
`<b>${escapeHtml(title)}</b>\n\n` +
reports.map(escapeHtml).join("\n\n");

console.log(stripHtml(message));

await notifyTelegram(env, message);
}

async function checkOneAccount(
cookie: string,
accountNo: number,
exchangePlan: string
): Promise<{ success: boolean; text: string }> {
const beforeStatus = await gladosRequest(cookie, "GET", "/api/user/status");
const beforePoints = await gladosRequest(cookie, "GET", "/api/user/points");

const checkin = await gladosRequest(cookie, "POST", "/api/user/checkin", {
token: "glados.cloud"
});

const afterStatus = await gladosRequest(cookie, "GET", "/api/user/status");
const afterPoints = await gladosRequest(cookie, "GET", "/api/user/points");

const email =
getString(afterStatus, ["data", "email"]) ||
getString(beforeStatus, ["data", "email"]) ||
"未知";

const leftDays = getNumber(afterStatus, ["data", "leftDays"]);
const checkinMessage = getString(checkin, ["message"]) || JSON.stringify(checkin);

const beforePoint = extractPoints(beforePoints);
const afterPoint = extractPoints(afterPoints);

const diff =
beforePoint !== null && afterPoint !== null
? afterPoint - beforePoint
: null;

const success = isCheckinSuccess(checkinMessage);

let exchangeText = "";

if (exchangePlan && EXCHANGE_PLANS[exchangePlan]) {
exchangeText = await tryExchange(cookie, exchangePlan, afterPoint);
}

const lines = [
`👤 账号 ${accountNo}`,
`📧 邮箱:${email}`,
`📝 签到:${success ? "✅" : "⚠️"} ${checkinMessage}`,
`📅 剩余天数:${leftDays === null ? "未知" : leftDays.toFixed(2)}`,
`💎 积分:${afterPoint === null ? "未知" : afterPoint}`,
`📈 今日积分变化:${diff === null ? "未知" : diff >= 0 ? `+${diff}` : `${diff}`}`
];

if (exchangeText) {
lines.push(exchangeText);
}

return {
success,
text: lines.join("\n")
};
}

async function gladosRequest(
cookie: string,
method: "GET" | "POST",
path: string,
body?: unknown
): Promise<GladosJson | null> {
let lastError = "";

for (const domain of GLADOS_DOMAINS) {
try {
const response = await fetch(domain + path, {
method,
headers: {
"User-Agent": "Mozilla/5.0",
"Accept": "application/json, text/plain, */*",
"Content-Type": "application/json;charset=UTF-8",
"Cookie": cookie,
"Origin": domain,
"Referer": `${domain}/console/checkin`
},
body: body === undefined ? undefined : JSON.stringify(body)
});

const text = await response.text();

if (!response.ok) {
lastError = `${domain} HTTP ${response.status}: ${text.slice(0, 200)}`;
continue;
}

try {
return JSON.parse(text);
} catch {
return {
raw: text
};
}
} catch (error) {
lastError = `${domain}: ${safeError(error)}`;
}
}

return {
message: `Network Error: ${lastError || "all domains failed"}`
};
}

async function tryExchange(
cookie: string,
plan: string,
currentPoints: number | null
): Promise<string> {
const config = EXCHANGE_PLANS[plan];

if (!config) {
return "";
}

if (currentPoints === null) {
return "🎁 自动兑换:跳过,无法读取积分";
}

if (currentPoints < config.points) {
return `🎁 自动兑换:积分不足,${currentPoints}/${config.points}`;
}

const result = await gladosRequest(cookie, "POST", "/api/user/points", {
action: "exchange",
point: config.points
});

const message = getString(result, ["message"]) || JSON.stringify(result);

return `🎁 自动兑换:${plan}${message}`;
}

async function notifyTelegram(env: Env, html: string): Promise<void> {
const token = env.TELEGRAM_BOT_TOKEN;
const chatId = env.TELEGRAM_CHAT_ID;

if (!token || !chatId) {
console.log(stripHtml(html));
return;
}

const response = await fetch(`https://api.telegram.org/bot${token}/sendMessage`, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
chat_id: chatId,
text: html,
parse_mode: "HTML",
disable_web_page_preview: true
})
});

if (!response.ok) {
const text = await response.text();
console.log(`Telegram send failed: ${response.status} ${text}`);
}
}

function parseCookies(raw: string | undefined): string[] {
if (!raw) {
return [];
}

return raw
.split(/\n|&/)
.map((item) => item.trim())
.filter(Boolean);
}

function isCheckinSuccess(message: string): boolean {
const normalized = message.toLowerCase();

return (
normalized.includes("checkin") ||
normalized.includes("checked") ||
normalized.includes("already") ||
normalized.includes("observation") ||
message.includes("签到") ||
message.includes("已签到")
);
}

function extractPoints(json: GladosJson | null): number | null {
if (!json) {
return null;
}

const candidates = [
json.points,
json.point,
json.data?.points,
json.data?.point,
json.data?.balance,
json.data?.credit
];

for (const value of candidates) {
const num = Number(value);

if (Number.isFinite(num)) {
return num;
}
}

return null;
}

function getString(obj: any, path: string[]): string | null {
let cur = obj;

for (const key of path) {
cur = cur?.[key];
}

return typeof cur === "string" ? cur : null;
}

function getNumber(obj: any, path: string[]): number | null {
let cur = obj;

for (const key of path) {
cur = cur?.[key];
}

const num = Number(cur);

return Number.isFinite(num) ? num : null;
}

function safeError(error: unknown): string {
if (error instanceof Error) {
return error.message;
}

return String(error);
}

function escapeHtml(input: string): string {
return input
.replaceAll("&", "&amp;")
.replaceAll("<", "&lt;")
.replaceAll(">", "&gt;");
}

function stripHtml(input: string): string {
return input.replace(/<[^>]*>/g, "");
}

六、获取 GLaDOS Cookie

1. 登录 GLaDOS

打开 GLaDOS 当前可用域名,例如:

1
https://glados.rocks

2. 打开开发者工具

按:

1
F12

进入:

1
2
3
4
Application
→ Storage
→ Cookies
→ 当前 GLaDOS 域名

找到:

1
2
koa:sess
koa:sess.sig

格式:

1
koa:sess=xxxxx; koa:sess.sig=yyyyy

七、创建 Telegram Bot

1. 创建机器人

Telegram 搜索:

1
@BotFather

发送:

1
/newbot

根据提示创建机器人。


2. 获取 Bot Token

BotFather 会返回类似:

1
1234567890:AAxxxxxxxxxxxxxxxxxxxxxxxx

这个就是:

1
TELEGRAM_BOT_TOKEN

八、获取 Telegram Chat ID

先给你的机器人发送一条消息,例如:

1
hello

然后浏览器访问:

1
https://api.telegram.org/bot你的BotToken/getUpdates

返回内容中找到:

1
2
3
"chat": {
"id": 123456789
}

其中:

1
123456789

就是:

1
TELEGRAM_CHAT_ID

九、本地测试

启动本地开发环境:

1
npm run dev

看到:

1
Ready on http://127.0.0.1:8787

访问:

1
http://127.0.0.1:8787

成功日志示例:

1
2
3
4
5
6
7
8
🎉 GLaDOS 签到完成:1/1

👤 账号 1
📧 邮箱:user@gmail.com
📝 签到:✅ Checkin! Got 7 Points
📅 剩余天数:14.00
💎 积分:7
📈 今日积分变化:+7

十、配置 Cloudflare Secrets

Cloudflare 线上环境不会读取 .dev.vars

必须使用 Wrangler Secrets。


1
npx wrangler secret put GLADOS_COOKIE

输入:

1
koa:sess=xxxxx; koa:sess.sig=yyyyy

2. 配置 Telegram Bot Token

1
npx wrangler secret put TELEGRAM_BOT_TOKEN

输入:

1
1234567890:AAxxxxxxxxxxxxxxxxxxxxxxxx

3. 配置 Telegram Chat ID

1
npx wrangler secret put TELEGRAM_CHAT_ID

输入:

1
123456789

4. 查看 Secret

1
npx wrangler secret list

正常结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[
{
"name": "GLADOS_COOKIE",
"type": "secret_text"
},
{
"name": "TELEGRAM_BOT_TOKEN",
"type": "secret_text"
},
{
"name": "TELEGRAM_CHAT_ID",
"type": "secret_text"
}
]

十一、配置多个账号

重新写入 GLADOS_COOKIE

1
npx wrangler secret put GLADOS_COOKIE

输入多个账号,每行一个:

1
2
3
koa:sess=账号1sess; koa:sess.sig=账号1sig
koa:sess=账号2sess; koa:sess.sig=账号2sig
koa:sess=账号3sess; koa:sess.sig=账号3sig

也可以使用 & 分隔:

1
koa:sess=账号1sess; koa:sess.sig=账号1sig&koa:sess=账号2sess; koa:sess.sig=账号2sig&koa:sess=账号3sess; koa:sess.sig=账号3sig

十二、部署到 Cloudflare Workers

执行:

1
npx wrangler deploy

成功示例:

1
2
3
4
5
6
Uploaded glados-checkin-worker
Deployed glados-checkin-worker triggers

https://glados-checkin-worker.xxx.workers.dev

schedule: 0 23 * * *

十三、查看线上日志

执行:

1
npx wrangler tail

然后访问 Worker 地址:

1
https://你的worker.workers.dev

日志示例:

1
2
3
4
5
6
7
8
🎉 GLaDOS 签到完成:1/1

👤 账号 1
📧 邮箱:user@gmail.com
📝 签到:✅ Today's observation logged. Return tomorrow for more points.
📅 剩余天数:14.00
💎 积分:7
📈 今日积分变化:+0

十四、定时任务说明

wrangler.toml 中配置:

1
2
[triggers]
crons = ["0 23 * * *"]

表示:

1
UTC 每天 23:00

换算为:

1
2
北京时间每天 07:00
新加坡时间每天 07:00

十五、常见问题

检查 .dev.vars 是否在项目根目录。

正确位置:

1
glados-checkin-worker/.dev.vars

2. Telegram 返回 404

通常是 Bot Token 错误。

重新配置:

1
2
npx wrangler secret put TELEGRAM_BOT_TOKEN
npx wrangler deploy

3. Telegram 收不到消息

检查:

1
npx wrangler tail

确认是否有:

1
Telegram send failed

同时确认:

  • Bot Token 正确
  • Chat ID 正确
  • 已经给机器人发送过消息

4. Secret 配错了怎么办

重新执行即可覆盖:

1
npx wrangler secret put 变量名

例如:

1
npx wrangler secret put GLADOS_COOKIE

5. 删除错误 Secret

1
npx wrangler secret delete 错误的Secret名称

十六、安全建议

不要上传 .dev.vars

.gitignore 中必须包含:

1
2
3
.dev.vars
node_modules
.wrangler

如果 Telegram Bot Token 泄露,应立即在 BotFather 中重新生成。


十七、最终运行流程

1
2
3
4
5
6
7
8
9
10
11
12
13
⏰ Cloudflare Cron


☁️ Cloudflare Worker

├── 🍪 读取 GLaDOS Cookie
├── ✅ 执行 GLaDOS 签到
├── 💎 查询积分
├── 📅 查询剩余天数
└── 🤖 发送 Telegram 通知


📱 手机接收消息

十八、完成

完成以上配置后,Cloudflare Workers 会每天自动执行。

默认执行时间:

1
每天 北京时间 / 新加坡时间 07:00

你也可以手动访问 Worker 地址立即执行一次:

1
https://你的worker.workers.dev

至此,GLaDOS 自动签到系统部署完成。

  • 标题: GLaDOS 自动签到部署指南
  • 作者: hutao
  • 创建于 : 2020-08-08 18:20:00
  • 更新于 : 2026-06-06 16:01:51
  • 链接: https://blog.hutaoint.de5.net/GLaDOS 自动签到/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。