@zhin.js/plugin-music 1.0.26 → 1.1.2
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 +28 -27
- package/commands/cookie/delete/[source]/index.js +23 -0
- package/commands/cookie/delete/[source]/index.ts +27 -0
- package/commands/cookie/get/[source]/index.js +29 -0
- package/commands/cookie/get/[source]/index.ts +33 -0
- package/commands/cookie/set/[source]/index.js +23 -0
- package/commands/cookie/set/[source]/index.ts +27 -0
- package/commands/cookie/status/index.js +25 -0
- package/commands/cookie/status/index.ts +25 -0
- package/commands/login/[platform]/index.js +66 -0
- package/commands/login/[platform]/index.ts +74 -0
- package/commands//347/202/271/346/255/214/[keyword]/index.js +63 -0
- package/commands//347/202/271/346/255/214/[keyword]/index.ts +75 -0
- package/components/share-music/index.js +24 -0
- package/components/share-music/index.ts +29 -0
- package/lib/config.d.ts +3 -3
- package/lib/config.d.ts.map +1 -1
- package/lib/config.js +36 -7
- package/lib/config.js.map +1 -1
- package/lib/credential-store.d.ts +37 -0
- package/lib/credential-store.d.ts.map +1 -0
- package/lib/credential-store.js +85 -0
- package/lib/credential-store.js.map +1 -0
- package/lib/index.d.ts +8 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +7 -112
- package/lib/index.js.map +1 -1
- package/lib/login/index.d.ts +27 -0
- package/lib/login/index.d.ts.map +1 -0
- package/lib/login/index.js +124 -0
- package/lib/login/index.js.map +1 -0
- package/lib/login/netease.d.ts +6 -0
- package/lib/login/netease.d.ts.map +1 -0
- package/lib/login/netease.js +58 -0
- package/lib/login/netease.js.map +1 -0
- package/lib/login/qq.d.ts +7 -0
- package/lib/login/qq.d.ts.map +1 -0
- package/lib/login/qq.js +139 -0
- package/lib/login/qq.js.map +1 -0
- package/lib/login/types.d.ts +19 -0
- package/lib/login/types.d.ts.map +1 -0
- package/lib/login/types.js +11 -0
- package/lib/login/types.js.map +1 -0
- package/lib/music-lib.d.ts +32 -0
- package/lib/music-lib.d.ts.map +1 -0
- package/lib/music-lib.js +58 -0
- package/lib/music-lib.js.map +1 -0
- package/lib/runtime.d.ts +12 -0
- package/lib/runtime.d.ts.map +1 -0
- package/lib/runtime.js +3 -0
- package/lib/runtime.js.map +1 -0
- package/lib/session.d.ts +35 -0
- package/lib/session.d.ts.map +1 -0
- package/lib/session.js +51 -0
- package/lib/session.js.map +1 -0
- package/lib/sources/index.d.ts +4 -2
- package/lib/sources/index.d.ts.map +1 -1
- package/lib/sources/index.js +12 -6
- package/lib/sources/index.js.map +1 -1
- package/lib/sources/kugou.d.ts +6 -0
- package/lib/sources/kugou.d.ts.map +1 -0
- package/lib/sources/kugou.js +69 -0
- package/lib/sources/kugou.js.map +1 -0
- package/lib/sources/kuwo.d.ts +7 -0
- package/lib/sources/kuwo.d.ts.map +1 -0
- package/lib/sources/kuwo.js +69 -0
- package/lib/sources/kuwo.js.map +1 -0
- package/lib/sources/netease.d.ts +4 -1
- package/lib/sources/netease.d.ts.map +1 -1
- package/lib/sources/netease.js +25 -6
- package/lib/sources/netease.js.map +1 -1
- package/lib/sources/qq.d.ts +4 -14
- package/lib/sources/qq.d.ts.map +1 -1
- package/lib/sources/qq.js +117 -82
- package/lib/sources/qq.js.map +1 -1
- package/lib/types.d.ts +4 -24
- package/lib/types.d.ts.map +1 -1
- package/lib/types.js +0 -1
- package/lib/types.js.map +1 -1
- package/middlewares/music-selection/index.js +48 -0
- package/middlewares/music-selection/index.ts +62 -0
- package/package.json +66 -12
- package/plugin.js +45 -0
- package/schema.json +6 -0
- package/skills/music/SKILL.md +2 -2
- package/skills/music/tools/music-search/index.js +22 -0
- package/skills/music/tools/music-search/index.ts +33 -0
- package/skills/music/tools/music-share/index.js +21 -0
- package/skills/music/tools/music-share/index.ts +26 -0
- package/src/config.ts +54 -30
- package/src/credential-store.ts +125 -0
- package/src/index.ts +37 -0
- package/src/login/index.ts +154 -0
- package/src/login/netease.ts +69 -0
- package/src/login/qq.ts +154 -0
- package/src/login/types.ts +27 -0
- package/src/music-lib.ts +71 -0
- package/src/runtime.ts +17 -0
- package/src/session.ts +77 -0
- package/src/sources/index.ts +17 -10
- package/src/sources/kugou.ts +92 -0
- package/src/sources/kuwo.ts +94 -0
- package/src/sources/netease.ts +35 -11
- package/src/sources/qq.ts +164 -126
- package/src/types.ts +6 -28
- package/lib/async-jsx.d.ts +0 -19
- package/lib/async-jsx.d.ts.map +0 -1
- package/lib/async-jsx.js +0 -48
- package/lib/async-jsx.js.map +0 -1
- package/src/async-jsx.ts +0 -54
- package/src/index.tsx +0 -130
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kuwo.js","sourceRoot":"","sources":["../../src/sources/kuwo.ts"],"names":[],"mappings":"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"}
|
package/lib/sources/netease.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { MusicSearchService, MusicDetail, MusicInfo } from '../types.js';
|
|
2
|
+
import type { CredentialStore } from '../credential-store.js';
|
|
2
3
|
/** 网易云音乐搜索服务 */
|
|
3
4
|
export declare class NeteaseMusicService implements MusicSearchService {
|
|
5
|
+
#private;
|
|
6
|
+
constructor(credentials: CredentialStore);
|
|
4
7
|
search(keyword: string, limit?: number): Promise<MusicInfo[]>;
|
|
5
8
|
getCover(id: string): Promise<string | null>;
|
|
6
9
|
getDetail(id: string): Promise<MusicDetail>;
|
|
@@ -10,6 +13,6 @@ export declare class NeteaseMusicService implements MusicSearchService {
|
|
|
10
13
|
* @param metingAPI Meting API 地址(可选)
|
|
11
14
|
* @returns 音频直链 URL
|
|
12
15
|
*/
|
|
13
|
-
getAudioUrl(id: string
|
|
16
|
+
getAudioUrl(id: string): Promise<string>;
|
|
14
17
|
}
|
|
15
18
|
//# sourceMappingURL=netease.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"netease.d.ts","sourceRoot":"","sources":["../../src/sources/netease.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"netease.d.ts","sourceRoot":"","sources":["../../src/sources/netease.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,SAAS,EAAY,MAAM,aAAa,CAAC;AACxF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D,gBAAgB;AAChB,qBAAa,mBAAoB,YAAW,kBAAkB;;gBAGhD,WAAW,EAAE,eAAe;IAIlC,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAwBzD,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAiB5C,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAoBjD;;;;;OAKG;IACG,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CA4B/C"}
|
package/lib/sources/netease.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
/** 网易云音乐搜索服务 */
|
|
2
2
|
export class NeteaseMusicService {
|
|
3
|
+
#credentials;
|
|
4
|
+
constructor(credentials) {
|
|
5
|
+
this.#credentials = credentials;
|
|
6
|
+
}
|
|
3
7
|
async search(keyword, limit = 10) {
|
|
4
8
|
try {
|
|
5
9
|
const searchUrl = `http://music.163.com/api/search/get/web?csrf_token=hlpretag=&hlposttag=&s=${encodeURIComponent(keyword)}&type=1&offset=0&total=true&limit=${limit}`;
|
|
@@ -60,16 +64,31 @@ export class NeteaseMusicService {
|
|
|
60
64
|
* @param metingAPI Meting API 地址(可选)
|
|
61
65
|
* @returns 音频直链 URL
|
|
62
66
|
*/
|
|
63
|
-
async getAudioUrl(id
|
|
64
|
-
|
|
65
|
-
|
|
67
|
+
async getAudioUrl(id) {
|
|
68
|
+
const cookie = await this.#credentials.get('netease', 'cookie');
|
|
69
|
+
if (cookie) {
|
|
70
|
+
try {
|
|
71
|
+
const response = await fetch(`https://music.163.com/api/song/enhance/player/url?ids=[${id}]&br=320000`, {
|
|
72
|
+
method: 'GET',
|
|
73
|
+
headers: { Cookie: cookie },
|
|
74
|
+
});
|
|
75
|
+
const result = await response.json();
|
|
76
|
+
const audioUrl = result.data?.[0]?.url;
|
|
77
|
+
if (audioUrl)
|
|
78
|
+
return audioUrl;
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
// cookie-based fetch failed, fall through to public API
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const apiUrl = 'https://api.injahow.cn/meting/';
|
|
66
85
|
const url = `${apiUrl}?type=url&id=${id}`;
|
|
67
86
|
const response = await fetch(url, { method: 'GET' });
|
|
68
87
|
const data = await response.json();
|
|
69
|
-
|
|
88
|
+
const audioUrl = data.url ?? data.data?.url;
|
|
89
|
+
if (!audioUrl)
|
|
70
90
|
throw new Error('Audio URL not found');
|
|
71
|
-
|
|
72
|
-
return data.url || data.data?.url;
|
|
91
|
+
return audioUrl;
|
|
73
92
|
}
|
|
74
93
|
}
|
|
75
94
|
//# sourceMappingURL=netease.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"netease.js","sourceRoot":"","sources":["../../src/sources/netease.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"netease.js","sourceRoot":"","sources":["../../src/sources/netease.ts"],"names":[],"mappings":"AAIA,gBAAgB;AAChB,MAAM,OAAO,mBAAmB;IACrB,YAAY,CAAkB;IAEvC,YAAY,WAA4B;QACtC,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,OAAe,EAAE,KAAK,GAAG,EAAE;QACtC,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,6EAA6E,kBAAkB,CAAC,OAAO,CAAC,qCAAqC,KAAK,EAAE,CAAA;YAEtK,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAA;YAC1D,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAuC,CAAA;YACvE,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE,CAAA;YAEtC,OAAO,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;gBACzB,EAAE,EAAE,KAAK,CAAC,EAAE;gBACZ,MAAM,EAAE,SAAkB;gBAC1B,KAAK,EAAE,KAAK,CAAC,IAAI;gBACjB,MAAM,EAAE,KAAK,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;gBACjD,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI;gBACvB,GAAG,EAAE,mCAAmC,KAAK,CAAC,EAAE,EAAE;gBAClD,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,SAAS;gBAClD,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;aACzE,CAAC,CAAC,CAAA;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,KAAK,CAAC,CAAA;YACpD,OAAO,EAAE,CAAA;QACX,CAAC;IACH,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,EAAU;QACvB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,+CAA+C,EAAE,GAAG,CAAC,CAAA;YAEzE,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAA;YACpD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAA2B,CAAA;YAE3D,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAA;YAC5B,IAAI,CAAC,IAAI;gBAAE,OAAO,IAAI,CAAA;YAEtB,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,IAAI,IAAI,CAAA;QAC1D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,iCAAiC,EAAE,KAAK,CAAC,CAAA;YACvD,OAAO,IAAI,CAAA;QACb,CAAC;IACH,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,EAAU;QACxB,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,+CAA+C,EAAE,GAAG,CAAC,CAAA;QAEvE,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAA;QACpD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAA2B,CAAA;QAE3D,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAA;QAC5B,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAA;QAE7C,OAAO;YACL,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,MAAM,EAAE,SAAS;YACjB,KAAK,EAAE,IAAI,CAAC,IAAI;YAChB,GAAG,EAAE,mCAAmC,IAAI,CAAC,EAAE,EAAE;YACjD,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS;YAChD,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;YACtE,KAAK,EAAE,MAAM,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;SAClC,CAAA;IACL,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,WAAW,CAAC,EAAU;QAC1B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAChE,IAAI,MAAM,EAAE,CAAC;YACX,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAC1B,0DAA0D,EAAE,aAAa,EACzE;oBACE,MAAM,EAAE,KAAK;oBACb,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE;iBAC5B,CACF,CAAC;gBACF,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAEjC,CAAC;gBACF,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC;gBACvC,IAAI,QAAQ;oBAAE,OAAO,QAAQ,CAAC;YAChC,CAAC;YAAC,MAAM,CAAC;gBACP,wDAAwD;YAC1D,CAAC;QACH,CAAC;QACD,MAAM,MAAM,GAAG,gCAAgC,CAAC;QAChD,MAAM,GAAG,GAAG,GAAG,MAAM,gBAAgB,EAAE,EAAE,CAAC;QAC1C,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QACrD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAA+C,CAAC;QAChF,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC;QAC5C,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;QACtD,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF"}
|
package/lib/sources/qq.d.ts
CHANGED
|
@@ -1,21 +1,11 @@
|
|
|
1
1
|
import type { MusicSearchService, MusicDetail, MusicInfo } from '../types.js';
|
|
2
|
-
|
|
2
|
+
import type { CredentialStore } from '../credential-store.js';
|
|
3
3
|
export declare class QQMusicService implements MusicSearchService {
|
|
4
|
+
#private;
|
|
5
|
+
constructor(credentials: CredentialStore);
|
|
4
6
|
search(keyword: string, limit?: number): Promise<MusicInfo[]>;
|
|
5
|
-
getCover(id: string): Promise<string | null>;
|
|
6
7
|
getDetail(id: string): Promise<MusicDetail>;
|
|
7
|
-
|
|
8
|
-
* 获取音频直链(需要第三方 API)
|
|
9
|
-
* @param id 音乐 ID
|
|
10
|
-
* @param metingAPI Meting API 地址(可选)
|
|
11
|
-
* @returns 音频直链 URL
|
|
12
|
-
*/
|
|
13
|
-
getAudioUrl(id: string, metingAPI?: string): Promise<string>;
|
|
14
|
-
/**
|
|
15
|
-
* 获取歌词
|
|
16
|
-
* @param id 音乐 ID
|
|
17
|
-
* @returns 歌词文本
|
|
18
|
-
*/
|
|
8
|
+
getAudioUrl(id: string, mid?: string, mediaMid?: string): Promise<string>;
|
|
19
9
|
getLyric(id: string): Promise<string | null>;
|
|
20
10
|
}
|
|
21
11
|
//# sourceMappingURL=qq.d.ts.map
|
package/lib/sources/qq.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qq.d.ts","sourceRoot":"","sources":["../../src/sources/qq.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"qq.d.ts","sourceRoot":"","sources":["../../src/sources/qq.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAc9D,qBAAa,cAAe,YAAW,kBAAkB;;gBAG3C,WAAW,EAAE,eAAe;IAIlC,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IA0DzD,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAkC3C,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAiDzE,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAqBnD"}
|
package/lib/sources/qq.js
CHANGED
|
@@ -1,64 +1,83 @@
|
|
|
1
|
-
|
|
1
|
+
import * as crypto from 'node:crypto';
|
|
2
|
+
const md5 = (text) => crypto.createHash('md5').update(text).digest('hex');
|
|
3
|
+
const MUSICU_API = 'https://u.y.qq.com/cgi-bin/musicu.fcg';
|
|
4
|
+
function getHeaders(cookie) {
|
|
5
|
+
return {
|
|
6
|
+
Referer: 'https://y.qq.com',
|
|
7
|
+
Cookie: cookie ?? '',
|
|
8
|
+
'Content-Type': 'application/json; charset=UTF-8',
|
|
9
|
+
};
|
|
10
|
+
}
|
|
2
11
|
export class QQMusicService {
|
|
12
|
+
#credentials;
|
|
13
|
+
constructor(credentials) {
|
|
14
|
+
this.#credentials = credentials;
|
|
15
|
+
}
|
|
3
16
|
async search(keyword, limit = 10) {
|
|
4
17
|
try {
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
const cookie = await this.#credentials.get('qq', 'cookie');
|
|
19
|
+
const response = await fetch(MUSICU_API, {
|
|
20
|
+
method: 'POST',
|
|
21
|
+
headers: getHeaders(cookie),
|
|
22
|
+
body: JSON.stringify({
|
|
23
|
+
comm: { uin: '0', authst: '', ct: 29 },
|
|
24
|
+
search: {
|
|
25
|
+
method: 'DoSearchForQQMusicMobile',
|
|
26
|
+
module: 'music.search.SearchCgiService',
|
|
27
|
+
param: {
|
|
28
|
+
query: keyword,
|
|
29
|
+
grp: 1,
|
|
30
|
+
num_per_page: limit,
|
|
31
|
+
page_num: 1,
|
|
32
|
+
search_type: 0,
|
|
33
|
+
searchid: String(Date.now()),
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
}),
|
|
37
|
+
});
|
|
38
|
+
const data = (await response.json());
|
|
39
|
+
if (data.code !== undefined && +data.code !== 0)
|
|
40
|
+
return [];
|
|
41
|
+
const body = data.search?.data?.body ?? {};
|
|
42
|
+
const list = (body.song?.list ?? body.item_song ?? []);
|
|
43
|
+
return list.slice(0, limit).map((e) => {
|
|
44
|
+
const mid = e?.mid ?? '';
|
|
45
|
+
const albumMid = e?.album?.pmid ?? e?.album?.mid ?? '';
|
|
46
|
+
const singerMid = e?.singer?.[0]?.pmid ?? e?.singer?.[0]?.mid ?? '';
|
|
47
|
+
const cover = albumMid
|
|
48
|
+
? `https://y.gtimg.cn/music/photo_new/T002R300x300M000${albumMid}.jpg`
|
|
49
|
+
: singerMid
|
|
50
|
+
? `https://y.qq.com/music/photo_new/T001R300x300M000${singerMid}.jpg`
|
|
51
|
+
: '';
|
|
52
|
+
return {
|
|
53
|
+
id: String(e.id),
|
|
54
|
+
source: 'qq',
|
|
55
|
+
title: e.name,
|
|
56
|
+
artist: (e.singer ?? []).map((s) => s.name).join('/'),
|
|
57
|
+
album: e.album?.name,
|
|
58
|
+
url: `https://y.qq.com/n/ryqq/songDetail/${mid}`,
|
|
59
|
+
image: cover,
|
|
60
|
+
duration: e.interval,
|
|
61
|
+
_mid: mid,
|
|
62
|
+
_mediaMid: e.file?.media_mid,
|
|
63
|
+
};
|
|
64
|
+
});
|
|
17
65
|
}
|
|
18
66
|
catch (error) {
|
|
19
67
|
console.error('QQ Music search failed:', error);
|
|
20
68
|
return [];
|
|
21
69
|
}
|
|
22
70
|
}
|
|
23
|
-
async getCover(id) {
|
|
24
|
-
try {
|
|
25
|
-
const url = new URL('https://u.y.qq.com/cgi-bin/musicu.fcg');
|
|
26
|
-
url.searchParams.set('format', 'json');
|
|
27
|
-
url.searchParams.set('inCharset', 'utf8');
|
|
28
|
-
url.searchParams.set('outCharset', 'utf-8');
|
|
29
|
-
url.searchParams.set('notice', '0');
|
|
30
|
-
url.searchParams.set('platform', 'yqq.json');
|
|
31
|
-
url.searchParams.set('needNewCode', '0');
|
|
32
|
-
url.searchParams.set('data', JSON.stringify({
|
|
33
|
-
comm: { ct: 24, cv: 0 },
|
|
34
|
-
songinfo: {
|
|
35
|
-
method: 'get_song_detail_yqq',
|
|
36
|
-
param: { song_type: 0, song_mid: '', song_id: parseInt(id) },
|
|
37
|
-
module: 'music.pf_song_detail_svr'
|
|
38
|
-
}
|
|
39
|
-
}));
|
|
40
|
-
const response = await fetch(url, { method: 'GET' });
|
|
41
|
-
const result = await response.json();
|
|
42
|
-
const albumMid = result?.songinfo?.data?.track_info?.album?.mid;
|
|
43
|
-
if (!albumMid)
|
|
44
|
-
return null;
|
|
45
|
-
return `https://y.gtimg.cn/music/photo_new/T002R300x300M000${albumMid}.jpg`;
|
|
46
|
-
}
|
|
47
|
-
catch (error) {
|
|
48
|
-
console.error('QQ Music get cover failed:', error);
|
|
49
|
-
return null;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
71
|
async getDetail(id) {
|
|
53
|
-
const url = new URL(
|
|
72
|
+
const url = new URL(MUSICU_API);
|
|
54
73
|
url.searchParams.set('format', 'json');
|
|
55
74
|
url.searchParams.set('data', JSON.stringify({
|
|
56
75
|
comm: { ct: 24, cv: 0 },
|
|
57
76
|
songinfo: {
|
|
58
77
|
method: 'get_song_detail_yqq',
|
|
59
78
|
param: { song_type: 0, song_mid: '', song_id: parseInt(id) },
|
|
60
|
-
module: 'music.pf_song_detail_svr'
|
|
61
|
-
}
|
|
79
|
+
module: 'music.pf_song_detail_svr',
|
|
80
|
+
},
|
|
62
81
|
}));
|
|
63
82
|
const response = await fetch(url, { method: 'GET' });
|
|
64
83
|
const result = await response.json();
|
|
@@ -68,39 +87,65 @@ export class QQMusicService {
|
|
|
68
87
|
const albumMid = trackInfo.album?.mid;
|
|
69
88
|
const image = albumMid
|
|
70
89
|
? `https://y.gtimg.cn/music/photo_new/T002R300x300M000${albumMid}.jpg`
|
|
71
|
-
:
|
|
90
|
+
: '';
|
|
72
91
|
return {
|
|
73
92
|
id,
|
|
74
93
|
source: 'qq',
|
|
75
94
|
title: trackInfo.name,
|
|
76
|
-
url: `https://y.qq.com/n/
|
|
77
|
-
audio: await this.getAudioUrl(id),
|
|
78
|
-
image
|
|
95
|
+
url: `https://y.qq.com/n/ryqq/songDetail/${trackInfo.mid}`,
|
|
96
|
+
audio: await this.getAudioUrl(id, trackInfo.mid, trackInfo.file?.media_mid),
|
|
97
|
+
image,
|
|
79
98
|
duration: trackInfo.interval,
|
|
80
99
|
};
|
|
81
100
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
101
|
+
async getAudioUrl(id, mid, mediaMid) {
|
|
102
|
+
const cookie = await this.#credentials.get('qq', 'cookie');
|
|
103
|
+
if (cookie) {
|
|
104
|
+
try {
|
|
105
|
+
const uin = /uin=o?(\d+)/.exec(cookie)?.[1] ?? '0';
|
|
106
|
+
const songMid = mid ?? id;
|
|
107
|
+
const response = await fetch(MUSICU_API, {
|
|
108
|
+
method: 'POST',
|
|
109
|
+
headers: getHeaders(cookie),
|
|
110
|
+
body: JSON.stringify({
|
|
111
|
+
comm: {
|
|
112
|
+
ct: 19,
|
|
113
|
+
cv: '1891',
|
|
114
|
+
uin: '0',
|
|
115
|
+
guid: md5(`${uin}music`),
|
|
116
|
+
tmeAppID: 'qqmusic',
|
|
117
|
+
tmeLoginType: 2,
|
|
118
|
+
},
|
|
119
|
+
vkey: {
|
|
120
|
+
module: 'vkey.GetVkeyServer',
|
|
121
|
+
method: 'CgiGetVkey',
|
|
122
|
+
param: {
|
|
123
|
+
guid: md5(String(Date.now())),
|
|
124
|
+
songmid: [songMid],
|
|
125
|
+
songtype: [0],
|
|
126
|
+
uin: '0',
|
|
127
|
+
ctx: 1,
|
|
128
|
+
filename: [`C400${id}${mediaMid ?? songMid}.m4a`],
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
}),
|
|
132
|
+
});
|
|
133
|
+
const result = await response.json();
|
|
134
|
+
if (result.vkey && +result.vkey.code === 0) {
|
|
135
|
+
const purl = result.vkey.data?.midurlinfo?.[0]?.purl;
|
|
136
|
+
if (purl)
|
|
137
|
+
return `https://ws.stream.qqmusic.qq.com/${purl}`;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
// fall through to public fallback
|
|
142
|
+
}
|
|
96
143
|
}
|
|
97
|
-
|
|
144
|
+
// 无 cookie 的公开 fallback:md5 签名直链
|
|
145
|
+
const songMid = mid ?? id;
|
|
146
|
+
const code = md5(`${songMid}q;z(&l~sdf2!nK`).substring(0, 5).toUpperCase();
|
|
147
|
+
return `https://c6.y.qq.com/rsc/fcgi-bin/fcg_pyq_play.fcg?songmid=${songMid}&code=${code}`;
|
|
98
148
|
}
|
|
99
|
-
/**
|
|
100
|
-
* 获取歌词
|
|
101
|
-
* @param id 音乐 ID
|
|
102
|
-
* @returns 歌词文本
|
|
103
|
-
*/
|
|
104
149
|
async getLyric(id) {
|
|
105
150
|
try {
|
|
106
151
|
const url = new URL('https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_new.fcg');
|
|
@@ -112,20 +157,10 @@ export class QQMusicService {
|
|
|
112
157
|
url.searchParams.set('nobase64', '1');
|
|
113
158
|
const response = await fetch(url, {
|
|
114
159
|
method: 'GET',
|
|
115
|
-
headers: {
|
|
116
|
-
'Referer': 'https://y.qq.com'
|
|
117
|
-
}
|
|
160
|
+
headers: { Referer: 'https://y.qq.com' },
|
|
118
161
|
});
|
|
119
|
-
const data = await response.json();
|
|
120
|
-
|
|
121
|
-
return null;
|
|
122
|
-
// QQ 音乐返回的歌词需要 base64 解码
|
|
123
|
-
try {
|
|
124
|
-
return Buffer.from(data.lyric, 'base64').toString('utf-8');
|
|
125
|
-
}
|
|
126
|
-
catch {
|
|
127
|
-
return data.lyric;
|
|
128
|
-
}
|
|
162
|
+
const data = (await response.json());
|
|
163
|
+
return data.lyric ?? null;
|
|
129
164
|
}
|
|
130
165
|
catch (error) {
|
|
131
166
|
console.error('QQ Music get lyric failed:', error);
|
package/lib/sources/qq.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qq.js","sourceRoot":"","sources":["../../src/sources/qq.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"qq.js","sourceRoot":"","sources":["../../src/sources/qq.ts"],"names":[],"mappings":"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"}
|
package/lib/types.d.ts
CHANGED
|
@@ -1,20 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
export type MusicSource = "qq" | "netease";
|
|
3
|
-
/** 音乐分享内容 */
|
|
1
|
+
export type MusicSource = 'qq' | 'netease' | 'kuwo' | 'kugou';
|
|
4
2
|
export interface MusicInfo {
|
|
5
3
|
id: string;
|
|
6
4
|
source: MusicSource;
|
|
7
|
-
/** 跳转链接 */
|
|
8
5
|
url: string;
|
|
9
|
-
/** 音乐标题 */
|
|
10
6
|
title: string;
|
|
7
|
+
artist?: string;
|
|
8
|
+
album?: string;
|
|
9
|
+
duration?: number;
|
|
11
10
|
}
|
|
12
11
|
export interface MusicDetail extends MusicInfo {
|
|
13
12
|
image: string;
|
|
14
13
|
audio: string;
|
|
15
|
-
duration?: number;
|
|
16
14
|
}
|
|
17
|
-
/** 音乐源配置 */
|
|
18
15
|
export interface MusicSourceConfig {
|
|
19
16
|
appid: number;
|
|
20
17
|
package: string;
|
|
@@ -22,20 +19,6 @@ export interface MusicSourceConfig {
|
|
|
22
19
|
sign: string;
|
|
23
20
|
version: string;
|
|
24
21
|
}
|
|
25
|
-
/** QQ 音乐 API 响应 */
|
|
26
|
-
export interface MusicQQ {
|
|
27
|
-
id: string;
|
|
28
|
-
mid: string;
|
|
29
|
-
name: string;
|
|
30
|
-
docid: string;
|
|
31
|
-
singer: string;
|
|
32
|
-
album?: {
|
|
33
|
-
mid: string;
|
|
34
|
-
name: string;
|
|
35
|
-
};
|
|
36
|
-
interval?: number;
|
|
37
|
-
}
|
|
38
|
-
/** 网易云音乐 API 响应 */
|
|
39
22
|
export interface Music163 {
|
|
40
23
|
id: string;
|
|
41
24
|
name: string;
|
|
@@ -51,11 +34,8 @@ export interface Music163 {
|
|
|
51
34
|
img1v1Url: string;
|
|
52
35
|
};
|
|
53
36
|
}
|
|
54
|
-
/** 音乐搜索服务接口 */
|
|
55
37
|
export interface MusicSearchService {
|
|
56
|
-
/** 搜索音乐 */
|
|
57
38
|
search(keyword: string, limit?: number): Promise<MusicInfo[]>;
|
|
58
|
-
/** 获取音乐详情 */
|
|
59
39
|
getDetail(id: string): Promise<MusicDetail>;
|
|
60
40
|
}
|
|
61
41
|
//# sourceMappingURL=types.d.ts.map
|
package/lib/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;AAE9D,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,WAAW,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAY,SAAQ,SAAS;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,KAAK,CAAC;QACd,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;KACd,CAAC,CAAC;IACH,KAAK,EAAE;QACL,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IAC9D,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CAC7C"}
|
package/lib/types.js
CHANGED
package/lib/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { defineMiddleware } from 'zhin.js/middleware';
|
|
3
|
+
import { sessionKey, resolveMessageIds } from "../../lib/session.js";
|
|
4
|
+
import { shareMusicDetail, buildMusicShareSegment } from "../../lib/music-lib.js";
|
|
5
|
+
import { SOURCE_DISPLAY_NAME } from "../../lib/config.js";
|
|
6
|
+
import { musicRuntimeToken } from "../../lib/runtime.js";
|
|
7
|
+
export default defineMiddleware({
|
|
8
|
+
target: 'inbound',
|
|
9
|
+
async handle(context, next) {
|
|
10
|
+
const raw = context.input.content?.trim() ?? '';
|
|
11
|
+
if (!raw) {
|
|
12
|
+
await next();
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const ids = resolveMessageIds(context.input);
|
|
16
|
+
if (!ids) {
|
|
17
|
+
await next();
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const key = sessionKey(ids.endpointId, ids.conversationId, ids.senderId);
|
|
21
|
+
const runtime = context.use(musicRuntimeToken);
|
|
22
|
+
const pending = runtime.sessions.get(key);
|
|
23
|
+
if (!pending) {
|
|
24
|
+
await next();
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (raw === '取消') {
|
|
28
|
+
runtime.sessions.delete(key);
|
|
29
|
+
await context.input.$reply('已取消点歌');
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const num = parseInt(raw, 10);
|
|
33
|
+
if (isNaN(num) || num < 1 || num > pending.results.length) {
|
|
34
|
+
await next();
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
runtime.sessions.delete(key);
|
|
38
|
+
const selected = pending.results[num - 1];
|
|
39
|
+
const sourceName = SOURCE_DISPLAY_NAME[selected.source] ?? selected.source;
|
|
40
|
+
const detailResult = await shareMusicDetail(runtime, selected.id, selected.source);
|
|
41
|
+
if (!detailResult.success) {
|
|
42
|
+
await context.input.$reply(`[${sourceName}] 获取"${selected.title}"播放信息失败:${detailResult.error}`);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const segment = buildMusicShareSegment(detailResult.music);
|
|
46
|
+
await context.input.$reply(segment);
|
|
47
|
+
},
|
|
48
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { defineMiddleware } from 'zhin.js/middleware';
|
|
2
|
+
import type { Message } from '@zhin.js/core/runtime';
|
|
3
|
+
import { sessionKey, resolveMessageIds } from '../../src/session.js';
|
|
4
|
+
import { shareMusicDetail, buildMusicShareSegment } from '../../src/music-lib.js';
|
|
5
|
+
import { SOURCE_DISPLAY_NAME } from '../../src/config.js';
|
|
6
|
+
import { musicRuntimeToken } from '../../src/runtime.js';
|
|
7
|
+
|
|
8
|
+
export default defineMiddleware<Message>({
|
|
9
|
+
target: 'inbound',
|
|
10
|
+
async handle(context, next) {
|
|
11
|
+
const raw = context.input.content?.trim() ?? '';
|
|
12
|
+
if (!raw) {
|
|
13
|
+
await next();
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const ids = resolveMessageIds(context.input);
|
|
18
|
+
if (!ids) {
|
|
19
|
+
await next();
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const key = sessionKey(ids.endpointId, ids.conversationId, ids.senderId);
|
|
24
|
+
const runtime = context.use(musicRuntimeToken);
|
|
25
|
+
const pending = runtime.sessions.get(key);
|
|
26
|
+
if (!pending) {
|
|
27
|
+
await next();
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (raw === '取消') {
|
|
32
|
+
runtime.sessions.delete(key);
|
|
33
|
+
await context.input.$reply('已取消点歌');
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const num = parseInt(raw, 10);
|
|
38
|
+
if (isNaN(num) || num < 1 || num > pending.results.length) {
|
|
39
|
+
await next();
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
runtime.sessions.delete(key);
|
|
44
|
+
const selected = pending.results[num - 1]!;
|
|
45
|
+
const sourceName = SOURCE_DISPLAY_NAME[selected.source] ?? selected.source;
|
|
46
|
+
|
|
47
|
+
const detailResult = await shareMusicDetail(
|
|
48
|
+
runtime,
|
|
49
|
+
selected.id,
|
|
50
|
+
selected.source,
|
|
51
|
+
);
|
|
52
|
+
if (!detailResult.success) {
|
|
53
|
+
await context.input.$reply(
|
|
54
|
+
`[${sourceName}] 获取"${selected.title}"播放信息失败:${detailResult.error}`,
|
|
55
|
+
);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const segment = buildMusicShareSegment(detailResult.music);
|
|
60
|
+
await context.input.$reply(segment);
|
|
61
|
+
},
|
|
62
|
+
});
|