【开源】STAL 洛谷比赛订阅

· · 科技·工程

Good morning.

很多同学都遇到过错过比赛的情况——明明是一次既能提升自己、又能增加等级分和估值的大好机会,却因为忘记比赛开始时间而失之交臂。

为了解决这一问题,现推出 STAL 洛谷比赛订阅系统,让它成为您竞赛路上最准时的管家。想直接上手,请看下面的「快速开始」与「使用方法」;想自行配置、了解内部实现,可访问 GitHub 查看详情。

快速开始

1. 准备

需要 Node.js 18 或更高版本。

git clone https://github.com/stellalling/stal.git stal
cd stal
node server.js

打开 http://127.0.0.1:3000,第一个注册的账号自动成为管理员。

首次启动时如果没有 config.json,程序会自动用 config.example.json 加一个随机生成的 sessionSecret 创建一份。

2. 配置 SMTP

以 QQ 邮箱为例。

方式一:改 config.json

{
  "smtp": {
    "host": "smtp.qq.com",
    "port": 465,
    "user": "你的QQ号@qq.com",
    "pass": "你的QQ邮箱授权码",
    "fromName": "洛谷比赛订阅"
  }
}

方式二:网页——登录后进 /admin →「SMTP / 推送配置」→ 填地址与授权码 → 保存 → 点「测试 SMTP 登录」。

3. 常驻运行

程序自带定时任务,所以只需要让一个进程长驻,不需要额外的 cron。

# 先把 docker-compose.yml 的 STAL_SMTP_USER / STAL_SMTP_PASS 换成真值
docker compose up -d --build

对外服务建议套一层 Nginx 并启用 HTTPS。反代必须传 X-Forwarded-Proto,程序靠它判断这一跳是不是 HTTPS,才决定给会话 Cookie 加 Secure:

location / {
    proxy_pass http://127.0.0.1:3000;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

4. 验收

curl -s http://127.0.0.1:3000/api/health     # {"ok":true,...}
npm run crawl                                # 抓一次数据
npm run send:dry                             # 演练今晚会推给谁、推几场

再在主页点「发送测试邮件」确认自己能收到,就大功告成了。

使用方法

如果不想自己部署,直接访问 stal.luogu.best,用邮箱注册登录后:

  1. 在主页看比赛列表,按状态、类型、赛制、Rated 筛选;
  2. 在「我的订阅设置」勾选接收范围(官方 / Rated / 团队 / 个人等)、赛制和关键词,填好收件邮箱并保存;
  3. 点「发送测试邮件」确认能收到信;
  4. 右侧「明日预告」可以提前看到明天有哪些比赛会推给你;
  5. 每天 20:00 自动发送邮件提醒。

请注意,本服务为公益性质的便民服务,请勿对其可靠性提出过高要求。

实现原理

那么,STAL 是怎么拿到洛谷的比赛信息的?

首先,容易发现洛谷的比赛列表中包含所有比赛信息。访问 https://www.luogu.com.cn/contest/list 时,在请求头中带上 x-lentille-request: content-only,即可直接获得 JSON 响应,稍加处理即可使用。

列表按开赛时间倒序返回。若发现某一页中最早的比赛都已开始,便停止翻页。随后获取尚未开始的比赛 ID,再通过 contest/{id} 补齐报名人数、等级分阈值和比赛说明等内容。

为减轻洛谷服务器压力,已爬取过的内容会直接复用缓存。

之后按规则打标签:

  1. 出题团队为“洛谷官方团队”的比赛为官方比赛;
  2. visibility=2,4 分别对应团队公开赛和个人公开赛;
  3. method=1,4,2 分别对应 OI、IOI、ACM 赛制;
  4. rated !== 0 即为 Rated。

最后,通过 SMTP 向用户发送邮件。

技术特点

为了少给洛谷添麻烦。

结语

STAL 比赛订阅系统将不断更新,感谢各位的支持。

AI 使用情况披露:本项目使用 DeepSeek-V4.1-Flash 辅助完成,文章由 DeepSeek-V4.1-Flash 润色。

感谢“冬日绘板 - 麦乐送计划”为本项目提供的技术支持。