feat(qqmusic): QQ音乐会员成长值+福利站自动签到(zzc签名对拍验证)

- u6.y.qq.com 协议底座: zzc/time33 与 LDP924/auto-checkin qmcommon.py 逐字节对拍 PASS(6向量)
- 续期闭环: QQLogin 换新 key + openid/access_token 二级救活, 缓存存 /ql/data/qqmusic_cache(订阅git免疫)
- 任务中心三态机: 签到/挂件/装扮/听书/节目, Y零请求/W直领/N动作, 10006写锁即停
- 福利站全量: 每日签到/礼券/旅程激励/月里程碑/月度好礼/臻享抽奖, 先探后做
- env: SH_QQMUSIC_KEY 多账号(uin#key / cookie串 / 混排), code 1000/2000 归一失效语义
- 播放上报(任务20完整+10)默认关闭, 定时 1 0,6 * * * 双轮
This commit is contained in:
2026-11-04 00:38:19 +08:00
parent 21f4d40a0c
commit 89afcd1e60
5 changed files with 722 additions and 0 deletions

27
qqmusic/test_sign_run.js Normal file
View File

@@ -0,0 +1,27 @@
#!/usr/bin/env node
// 被测模块 vs Python 参考实现的逐字节比对(输入: test_sign_expect.json)
'use strict'
const fs = require('fs')
const path = require('path')
const { zzc, time33 } = require(path.join(__dirname, 'qqmusic_checkin.js'))
const expect = JSON.parse(fs.readFileSync(path.join(__dirname, 'test_sign_expect.json'), 'utf8'))
let fails = 0
const t33js = time33('Q_H_L_testkey1234567890')
const t33ok = t33js === expect.time33
console.log(`time33 py=${expect.time33} js=${t33js} -> ${t33ok ? 'OK' : 'MISMATCH'}`)
if (!t33ok) fails++
for (const c of expect.cases) {
const got = zzc(c.payload)
const ok = got === c.zzc
if (!ok) {
fails++
console.log(`zzc MISMATCH payload[:40]=${JSON.stringify(c.payload.slice(0, 40))}\n py=${c.zzc}\n js=${got}`)
} else {
console.log(`zzc OK len=${c.len} payload[:28]=${JSON.stringify(c.payload.slice(0, 28))}`)
}
}
console.log('RESULT:', fails === 0 ? 'PASS' : `FAIL(${fails})`)
process.exit(fails === 0 ? 0 : 1)