qqmusic-api-enhanced 1.0.8 → 1.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,12 +1,18 @@
1
1
  # qqmusic-api-enhanced
2
2
 
3
+ [![npm](https://img.shields.io/npm/v/qqmusic-api-enhanced.svg)](https://www.npmjs.com/package/qqmusic-api-enhanced)
4
+ [![CI](https://github.com/Cosmosuperbaka/qqmusic-api-enhanced/actions/workflows/ci.yml/badge.svg)](https://github.com/Cosmosuperbaka/qqmusic-api-enhanced/actions/workflows/ci.yml)
5
+ [![License: MIT AND Apache-2.0](https://img.shields.io/badge/license-MIT%20AND%20Apache--2.0-blue.svg)](LICENSE)
6
+
3
7
  QQ 音乐增强版 Node.js / Bun API 客户端,基于 QQ 音乐逆向协议与签名机制实现。项目架构与设计风格严格对齐 `@neteasecloudmusicapienhanced/api`,旨在为音乐播放器、猜歌游戏(如 SonGuessr)、数据分析等应用提供开箱即用、零外部生产依赖的纯 TypeScript 解决方案。
4
8
 
9
+ 运行时:Node.js >= 20 或 Bun 1.x;生产依赖为零。
10
+
5
11
  ---
6
12
 
7
13
  ## 特性亮点
8
14
 
9
- - **零外部生产依赖**:纯 TypeScript 编写,直接利用 Node.js / Bun 原生 `crypto`、`zlib`、`fetch`,无需安装 heavy C++ 插件或额外加密包。
15
+ - **零生产依赖**:纯 TypeScript 编写,直接利用 Node.js / Bun 原生 `crypto`、`zlib`、`fetch`;`devDependencies` 只用于构建与测试。
10
16
  - **全平台扫码登录**:支持手机 QQ 快捷扫码、微信网页扫码、QQ 音乐移动端 App 扫码,玩家可自主完成身份凭据提取与长效刷新。
11
17
  - **VKey 播放直链提取**:基于 `UrlGetVkey` 逆向调度,支持 128kbps (mp3)、320kbps (高品质 mp3)、FLAC (无损)、M4A 以及试听片段直链解析。
12
18
  - **QRC 逐字歌词解密**:内置原生定制版 Triple-DES(支持 QQ 音乐特定 PC-2 偏移置换)及 zlib 解压算法,自动将加密 QRC 转换为带时间戳的明文逐字歌词。
@@ -16,6 +22,8 @@ QQ 音乐增强版 Node.js / Bun API 客户端,基于 QQ 音乐逆向协议与
16
22
 
17
23
  ## 安装
18
24
 
25
+ 主包发布在 npmjs:
26
+
19
27
  ```bash
20
28
  # npm
21
29
  npm install qqmusic-api-enhanced
@@ -27,6 +35,9 @@ pnpm add qqmusic-api-enhanced
27
35
  bun add qqmusic-api-enhanced
28
36
  ```
29
37
 
38
+ GitHub 仓库的 Packages 页另外提供 scoped 镜像 `@cosmosuperbaka/qqmusic-api-enhanced`;
39
+ GitHub Packages 的 npm 安装需要带 GitHub token,日常使用请优先用上面的 npmjs 包。
40
+
30
41
  ---
31
42
 
32
43
  ## 快速上手
@@ -132,6 +143,21 @@ import {
132
143
 
133
144
  ---
134
145
 
146
+ ## 开发
147
+
148
+ ```bash
149
+ bun install --frozen-lockfile
150
+ bun run build
151
+ bun test
152
+ ```
153
+
154
+ 构建会生成并覆盖仓库里的 `.js` / `.d.ts` 产物,提交 TypeScript 改动时请一并提交生成文件。
155
+ 贡献规范见 [CONTRIBUTING.md](CONTRIBUTING.md),安全问题见 [SECURITY.md](SECURITY.md)。
156
+
157
+ 不要在日志、issue、测试或代码提交里放真实 Cookie、`qm_keyst`、`refresh_token` 或 AppSecret;如果凭据可能泄露,请先在 QQ 音乐侧退出登录/轮换。
158
+
159
+ ---
160
+
135
161
  ## 发布
136
162
 
137
163
  版本号在 `package.json`;发布由 GitHub Actions 自动完成:
@@ -1,13 +1,59 @@
1
- import { request, type ApiResponse } from "../util/request.js";
1
+ import { request, requestCgi, type ApiResponse } from "../util/request.js";
2
+ import { type MobileQrDeps } from "../util/mobile_qr_session.js";
2
3
  /**
3
4
  * 轮询检查二维码登录状态.
4
5
  *
6
+ * 返回 `body.code` 约定:
7
+ * - 200 登录成功(保证带有 musickey,调用方可以直接落库)
8
+ * - 801 等待扫码 / 802 已扫码待确认
9
+ * - 800 二维码过期
10
+ * - 803 用户在手机上取消或拒绝授权
11
+ * - 500 上游协议失败:带 `reason`(见 {@link LoginFailureReason})、`stage`、`upstreamCode`,
12
+ * 与“二维码过期 / 用户取消”区分开,调用方不应继续轮询同一个二维码
13
+ *
5
14
  * @param query.type 登录类型: 'qq' | 'wx' | 'mobile'
6
15
  * @param query.qrsig QQ 二维码凭证标识 (type=qq 时必填)
7
16
  * @param query.ptqrtoken QQ 二维码校验 token (type=qq 时必填)
8
17
  * @param query.uuid 微信登录会话 uuid (type=wx 时必填)
9
18
  * @param query.qrcodeID QQ 音乐 App 扫码 qrcodeID (type=mobile 时必填)
10
19
  */
20
+ export type LoginFailureReason = "auth_invalid" | "rate_limited" | "device_limit" | "account_restricted" | "protocol";
21
+ /** 测试注入点:真实调用不需要传。 */
22
+ export interface LoginQrCheckDeps {
23
+ fetch?: typeof fetch;
24
+ cgi?: typeof requestCgi;
25
+ mobile?: MobileQrDeps;
26
+ }
27
+ /** 业务码 → 失败原因。码表来自各登录入口的公开实现与实测(无效授权码返回 104400)。 */
28
+ export declare function classifyLoginCode(code: number | undefined): {
29
+ reason: LoginFailureReason;
30
+ message: string;
31
+ };
32
+ /**
33
+ * 按域名隔离的 Cookie 罐,行为对齐浏览器。
34
+ *
35
+ * 登录网关会在同一次响应里给 `graph.qq.com` 下发 p_skey,再把 `qq.com` 的同名项清掉;
36
+ * 不分域名合并时,清除指令会连真票据一起删掉,后面的 OAuth 就没有 g_tk 可算。
37
+ */
38
+ export declare class CookieJar {
39
+ private readonly entries;
40
+ constructor(initial?: Record<string, string>);
41
+ apply(setCookies: string[], requestHost?: string): void;
42
+ /** 目标主机能看到的 Cookie;同名时取域最具体的一项。 */
43
+ private visible;
44
+ get(name: string, host?: string): string;
45
+ toObject(host?: string): Record<string, string>;
46
+ header(host?: string): string;
47
+ }
48
+ /** 解析 ptqrlogin 的 `ptuiCB('码','…','URL','…','提示','昵称')` 回调。 */
49
+ export declare function parsePtqrloginText(text: string): {
50
+ status: "expired" | "waiting" | "scanned" | "refused" | "success" | "unknown";
51
+ url?: string;
52
+ };
53
+ /** 从授权跳转里取 code;Location 之外也兜底扫描响应体里的跳转脚本。 */
54
+ export declare function extractAuthCode(location: string, body?: string): string;
55
+ /** 把 Location 概括成可安全进日志的形态:只留主机、路径和 error 类参数,不含 code/token。 */
56
+ export declare function describeLocation(location: string): Record<string, string>;
11
57
  export default function login_qr_check(query?: {
12
58
  type?: "qq" | "wx" | "mobile";
13
59
  qrsig?: string;
@@ -16,4 +62,4 @@ export default function login_qr_check(query?: {
16
62
  qrcodeID?: string;
17
63
  key?: string;
18
64
  guid?: string;
19
- }, req?: typeof request): Promise<ApiResponse>;
65
+ }, _req?: typeof request, deps?: LoginQrCheckDeps): Promise<ApiResponse>;