Files
ql-scripts/qqmusic/README.md
zhuhjay 3531437898 fix(qqmusic): 修正青龙自动建任务的元数据,任务名与 cron 不再被误提取
真机故障(2026-11-04):青龙订阅勾「自动添加定时任务」后,任务被建成
  名称 = u.hostname,      (应为 QQ音乐自动签到)
  cron = 18 21 * * *      (应为 1 0,6 * * *)

根因是青龙从脚本正文正则提取元数据,两条正则都不锚定行首:
  1) 任务名 /name:\s*(.+)/ —— 全文第一个命中即采用。脚本里 https.request 的
     选项对象写了 hostname: u.hostname,其中的 name 段被当成任务名。
  2) cron /\bcron:\s*([^\r\n]+)/ —— 必须带冒号。原写法是注释里的
     「定时: cron 1 0,6 * * *」,冒号在「定时」后面,cron 后面没有冒号 → 匹配不到,
     落到随机 fallback(randomInt 生成 18 21 * * *)。

修法:
- 脚本第 3 行显式写 name 注解(独占一行,内容为「QQ音乐自动签到」)
- cron 注解改成「cron: 1 0,6 * * *」独占一行,注释挪到下一行
- https.request 选项 hostname -> host(Node 的别名,语义等价,实测 u6.y.qq.com
  返回 404 而非连接失败),彻底消除全文唯一的 name+冒号连写
- README 补「青龙自动建任务的元数据约定」小节,记录两条正则与兜底行为

验证:node --check 通过 / 签名对拍 6 组 PASS / 空 env 优雅跳过 /
复刻青龙两条正则做提取断言,name=QQ音乐自动签到、cron=1 0,6 * * *;
新版青龙(cli/src/internal/subscription/subscriptionRunner.ts 的 cronMetadata)
同样提取正确
2026-11-04 21:13:34 +08:00

78 lines
4.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# QQ音乐自动签到(scrip_qqmusic_checkin.js)
QQ音乐会员成长值任务 + 会员福利站 自动签到,青龙面板 Node 零依赖。
协议底座与 [LDP924/auto-checkin](https://github.com/LDP924/auto-checkin)(Python)逐字节同源:
`u6.y.qq.com/cgi-bin/musics.fcg` 网关 + `zzc` 签名(sha1 重组 + 置乱表 + b64 去尾)+ `qm_keyst` cookie。
> **文件名必须带 `scrip_` 前缀**:本仓库的青龙订阅规则白名单是 `scrip_`,
> 不带前缀的文件不会被订阅拉取(脚本、测试、文档同一约定)。
## 环境变量
| 变量 | 必填 | 说明 |
|---|---|---|
| `SH_QQMUSIC_KEY` | ✅ | 多账号:青龙同名 env 加多条(注入自动 `&` 连接)。**单条格式 `<uin>#<qm_keyst>`**,如 `123456789#Q_H_L_xxxx`。也接受整串 cookie(含 `qm_keyst=` 与 `uin=o...`) |
| `QM_KEY` / `QM_UIN` | 备选 | 单账号兼容形态(`SH_QQMUSIC_KEY` 优先) |
| `QM_CACHE_DIR` | 可选 | key 缓存目录,默认 `/ql/data/qqmusic_cache`(青龙)/ `qqmusic/.cache`(本地) |
| `QM_PLAY_REPORT` | 可选 | `on` 才启用任务20播放上报(本版未实现模板,挂了开关占位) |
## 凭证获取(web 抓一次,之后无限续)
1. 浏览器打开 [y.qq.com](https://y.qq.com) 登录(QQ/微信均可)
2. F12 → Application → Cookies → `https://y.qq.com` → 复制 `qm_keyst` 与 `uin`(`o123456789` 去掉 `o`)
3. 青龙新建环境变量 `SH_QQMUSIC_KEY`,值 `uin#qm_keyst`
**为什么抓一次就够**:签名/`g_tk` 全是本地算法(无盐、无设备绑定、无动态 token);
`qm_keyst` 名义 72h,但续期接口 `QQConnectLogin.LoginServer.QQLogin` 旧 key 不吊销——
脚本每次运行先续期,新 key 写缓存滚动,环境变量永远不用再动。
只有脚本断跑超 72h 且缓存丢失(推送出现 🔴 2000)才需要重新抓。
## 缓存与订阅安全
续期产物存 `/ql/data/qqmusic_cache/qm_<uin>.json`(**订阅仓库之外**)。
git 的 reset/clean 只动 tracked 文件,untracked 目录在 `git pull` 下天然安全;
且脚本读缓存优先、env 兜底,缓存丢失仅退化为"72h 内重新抓一次"。
## 定时
```
cron: 1 0,6 * * *
```
每天 00:01 + 06:02 双轮:任务20(收听节目)跨天滚动翻账本 + 福利站 0 点翻新兜底。
### 青龙自动建任务的元数据约定(踩坑记录 2026-11-04)
订阅勾了「自动添加定时任务」时,青龙从**脚本内容**里正则提取任务名与 cron,两个坑:
| 项 | 青龙的提取规则 | 必须怎么写 |
|---|---|---|
| **任务名** | `/name:\s*(.+)/`(**不锚定行首**),取**全文第一个**命中 | 脚本第 3 行写 `* name: QQ音乐自动签到`。**全文任何位置都不能再出现「name+冒号」的连写**——`https.request({ hostname: u.hostname })` 会被抓成任务名 `u.hostname,`(真机已复现) |
| **cron** | `/\bcron:\s*([^\r\n]+)/`(**必须带冒号**) | 写 `* cron: 1 0,6 * * *`,且**独占一行、后面不跟注释**(同一行剩余文字会被一起吞进 schedule) |
两个都抓不到时的兜底:任务名 = 文件名 `scrip_qqmusic_checkin.js`;cron = 随机 `M H * * *`。
所以脚本里:
- `https.request` 的选项用 `host:`(Node 的 `hostname` 别名)而不是 `hostname:`
- cron 注解独占一行
## 任务覆盖
| 层 | 内容 | 风险 |
|---|---|---|
| 任务中心 | 签到(15) / 挂件(5) / 装扮(5) / 听书(5) / 节目StartTask | 低(等价 App 点击) |
| 会员福利站 | 每日签到(15) / 礼券(+10心愿值) / 旅程激励 / 月里程碑 / 月度好礼 / 臻享抽奖 | 低(先探后做,无硬编码 ID) |
| 播放上报 | 任务20 完整 +10 需 App 正常收听(伪造统计默认关) | 中(默认关闭) |
| 支付流水任务 | 4/5/6/12/14/18/21 | 不可伪造,不碰 |
状态三态机:`Y`=已完成零请求(防风控)/ `W`=进行中直接领 / `N`=执行动作。
错误码处置:`20020` 冷却3s重领 · `30005` 只读探测后补领 · `10006` 写锁即停次日恢复 · `2000` 登录态失效推送提示。
## 本地测试
```bash
node --check scrip_qqmusic_checkin.js # 语法
node scrip_qqmusic_checkin.js # 无 env 时优雅跳过
SH_QQMUSIC_KEY='123#Q_H_L_x' node -e "console.log(require('./scrip_qqmusic_checkin').parseAccounts())"
```