Files
ql-scripts/qqmusic/test_sign_vector.py
zhuhjay 89afcd1e60 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 * * * 双轮
2026-11-04 00:38:19 +08:00

65 lines
2.3 KiB
Python
Raw Permalink 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.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""签名对拍(文件交换版,规避 Windows 子进程控制台编码坑):
本文件 = LDP924/auto-checkin qmcommon.py 的 zzc/time33 参考实现,生成期望值 JSON;
qqmusic/test_sign_run.js = 被测 Node 模块,读取 JSON 逐条比对并给出 PASS/FAIL。
两个实现任何一处不一致都会 MISMATCH —— 这是协议调用可用性的硬门槛。"""
import json
import subprocess
import sys
import os
from base64 import b64encode
from hashlib import sha1
SCRAMBLE = (89, 39, 179, 150, 218, 82, 58, 252, 177, 52,
186, 123, 120, 64, 242, 133, 143, 161, 121, 179)
def time33(s):
h = 5381
for c in s:
h += (h << 5) + ord(c)
h &= 0xFFFFFFFF
return h & 0x7FFFFFFF
def zzc(payload):
h = sha1(payload.encode()).hexdigest().upper()
p1 = ''.join(h[i] for i in (23, 14, 6, 36, 16, 7, 19))
p2 = ''.join(h[i] for i in (16, 1, 32, 12, 19, 27, 8, 5))
p3 = bytes(v ^ int(h[i * 2:i * 2 + 2], 16) for i, v in enumerate(SCRAMBLE))
mid = b64encode(p3).decode().replace('\\', '').replace('/', '').replace('+', '').replace('=', '')
return ('zzc' + p1 + mid + p2).lower()
PAYLOADS = [
'{"comm":{"g_tk":962138355,"uin":123456789,"format":"json","inCharset":"utf-8","outCharset":"utf-8","notice":0,"platform":"h5","needNewCode":1,"ct":23,"cv":0},"req_0":{"module":"music.lvz.LevelConfigSvr","method":"GetState","param":{}}}',
'{"comm":{},"req_0":{"module":"m","method":"x","param":{}}}',
'x',
'a' * 10000,
'',
'unicode测试中文签名输入⏰',
]
def main():
expect = {
'time33': time33('Q_H_L_testkey1234567890'),
'cases': [{'payload': p, 'zzc': zzc(p), 'len': len(zzc(p))} for p in PAYLOADS],
}
here = os.path.dirname(os.path.abspath(__file__))
expect_path = os.path.join(here, 'test_sign_expect.json')
with open(expect_path, 'w', encoding='utf-8') as f:
json.dump(expect, f, ensure_ascii=False)
out = subprocess.run(['node', os.path.join(here, 'test_sign_run.js')],
capture_output=True, text=True, shell=False, cwd=here,
encoding='utf-8', errors='replace')
sys.stdout.write(out.stdout)
if out.stderr:
sys.stderr.write(out.stderr)
return out.returncode
if __name__ == '__main__':
sys.exit(main())