@zhin.js/plugin-music 1.1.0 → 1.1.3

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.
Files changed (73) hide show
  1. package/README.md +27 -27
  2. package/commands/cookie/delete/{[source].js → [source]/index.js} +4 -4
  3. package/commands/cookie/delete/{[source].ts → [source]/index.ts} +5 -5
  4. package/commands/cookie/get/{[source].js → [source]/index.js} +4 -4
  5. package/commands/cookie/get/{[source].ts → [source]/index.ts} +5 -5
  6. package/commands/cookie/set/{[source].js → [source]/index.js} +4 -4
  7. package/commands/cookie/set/{[source].ts → [source]/index.ts} +5 -5
  8. package/commands/cookie/{status.js → status/index.js} +4 -4
  9. package/commands/cookie/{status.ts → status/index.ts} +5 -5
  10. package/commands/login/{[platform].js → [platform]/index.js} +10 -8
  11. package/commands/login/{[platform].ts → [platform]/index.ts} +10 -12
  12. package/commands//347/202/271/346/255/214/{[keyword].js → [keyword]/index.js} +7 -6
  13. package/commands//347/202/271/346/255/214/{[keyword].ts → [keyword]/index.ts} +8 -7
  14. package/components/{share-music.js → share-music/index.js} +4 -4
  15. package/components/{share-music.ts → share-music/index.ts} +5 -5
  16. package/lib/credential-store.d.ts +10 -7
  17. package/lib/credential-store.d.ts.map +1 -1
  18. package/lib/credential-store.js +44 -70
  19. package/lib/credential-store.js.map +1 -1
  20. package/lib/index.d.ts +5 -4
  21. package/lib/index.d.ts.map +1 -1
  22. package/lib/index.js +5 -4
  23. package/lib/index.js.map +1 -1
  24. package/lib/login/index.d.ts +18 -11
  25. package/lib/login/index.d.ts.map +1 -1
  26. package/lib/login/index.js +103 -79
  27. package/lib/login/index.js.map +1 -1
  28. package/lib/music-lib.d.ts +3 -2
  29. package/lib/music-lib.d.ts.map +1 -1
  30. package/lib/music-lib.js +4 -5
  31. package/lib/music-lib.js.map +1 -1
  32. package/lib/runtime.d.ts +12 -0
  33. package/lib/runtime.d.ts.map +1 -0
  34. package/lib/runtime.js +3 -0
  35. package/lib/runtime.js.map +1 -0
  36. package/lib/session.d.ts +10 -4
  37. package/lib/session.d.ts.map +1 -1
  38. package/lib/session.js +33 -21
  39. package/lib/session.js.map +1 -1
  40. package/lib/sources/index.d.ts +2 -1
  41. package/lib/sources/index.d.ts.map +1 -1
  42. package/lib/sources/index.js +8 -6
  43. package/lib/sources/index.js.map +1 -1
  44. package/lib/sources/kugou.d.ts.map +1 -1
  45. package/lib/sources/kugou.js +16 -1
  46. package/lib/sources/kugou.js.map +1 -1
  47. package/lib/sources/netease.d.ts +3 -0
  48. package/lib/sources/netease.d.ts.map +1 -1
  49. package/lib/sources/netease.js +5 -2
  50. package/lib/sources/netease.js.map +1 -1
  51. package/lib/sources/qq.d.ts +3 -0
  52. package/lib/sources/qq.d.ts.map +1 -1
  53. package/lib/sources/qq.js +6 -3
  54. package/lib/sources/qq.js.map +1 -1
  55. package/middlewares/{music-selection.js → music-selection/index.js} +9 -7
  56. package/middlewares/{music-selection.ts → music-selection/index.ts} +13 -7
  57. package/package.json +16 -11
  58. package/plugin.js +23 -9
  59. package/{agent/skills/music.md → skills/music/SKILL.md} +2 -2
  60. package/{tools/music-search.js → skills/music/tools/music-search/index.js} +4 -3
  61. package/{tools/music-search.ts → skills/music/tools/music-search/index.ts} +11 -5
  62. package/{tools/music-share.js → skills/music/tools/music-share/index.js} +4 -3
  63. package/{tools/music-share.ts → skills/music/tools/music-share/index.ts} +6 -4
  64. package/src/credential-store.ts +43 -87
  65. package/src/index.ts +8 -16
  66. package/src/login/index.ts +111 -92
  67. package/src/music-lib.ts +5 -4
  68. package/src/runtime.ts +17 -0
  69. package/src/session.ts +38 -21
  70. package/src/sources/index.ts +9 -6
  71. package/src/sources/kugou.ts +15 -1
  72. package/src/sources/netease.ts +8 -2
  73. package/src/sources/qq.ts +9 -3
package/README.md CHANGED
@@ -17,21 +17,23 @@
17
17
  ## 📦 安装
18
18
 
19
19
  ```bash
20
- pnpm add @zhin.js/plugin-music
20
+ zhin install @zhin.js/plugin-music
21
21
  ```
22
22
 
23
23
  ## 🚀 使用
24
24
 
25
- ### 配置
25
+ ### 挂载插件
26
26
 
27
- 在 `zhin.config.ts` 中添加插件:
27
+ `zhin install` 会安装依赖,并把插件实例写入 `package.json#zhin.plugins`。手工挂载时使用同一份拓扑契约:
28
28
 
29
- ```typescript
30
- export default defineConfig({
31
- plugins: [
32
- 'music' // 添加音乐插件
33
- ]
34
- })
29
+ ```json
30
+ {
31
+ "zhin": {
32
+ "plugins": [
33
+ { "package": "@zhin.js/plugin-music", "instanceKey": "music" }
34
+ ]
35
+ }
36
+ }
35
37
  ```
36
38
 
37
39
  ### 命令列表
@@ -200,22 +202,18 @@ interface ShareContent {
200
202
  }
201
203
  ```
202
204
 
203
- ### 导出的服务
205
+ ### 运行时代码中使用服务
204
206
 
205
207
  ```typescript
206
- import { musicServices } from '@zhin.js/plugin-music'
207
-
208
- // 使用音乐搜索服务
209
- const qqMusic = musicServices.qq
210
- const results = await qqMusic.search('周杰伦', 10)
211
- const cover = await qqMusic.getCover('音乐ID')
212
- const detail = await qqMusic.getDetail('音乐ID')
213
-
214
- // 获取音频直链(需要 Meting API)
215
- const audioUrl = await qqMusic.getAudioUrl?.('音乐ID')
216
-
217
- // 获取歌词
218
- const lyric = await qqMusic.getLyric?.('音乐ID')
208
+ import { defineCommand } from 'zhin.js/command'
209
+ import { musicRuntimeToken } from '@zhin.js/plugin-music'
210
+
211
+ export default defineCommand({
212
+ async execute({ use }) {
213
+ const qqMusic = use(musicRuntimeToken).services.qq
214
+ return qqMusic.search('周杰伦', 10)
215
+ },
216
+ })
219
217
  ```
220
218
 
221
219
  ### 配置工具
@@ -266,10 +264,12 @@ export class MyMusicService implements MusicSearchService {
266
264
  // src/sources/index.ts
267
265
  import { MyMusicService } from './my-music.js'
268
266
 
269
- export const musicServices = {
270
- qq: new QQMusicService(),
271
- netease: new NeteaseMusicService(),
272
- mymusic: new MyMusicService(), // 添加新服务
267
+ export function createMusicServices(credentials: CredentialStore) {
268
+ return {
269
+ qq: new QQMusicService(credentials),
270
+ netease: new NeteaseMusicService(credentials),
271
+ mymusic: new MyMusicService(),
272
+ }
273
273
  }
274
274
  ```
275
275
 
@@ -1,14 +1,14 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
2
  import { defineCommand } from 'zhin.js/command';
3
- import { deleteCredential } from "../../../lib/credential-store.js";
4
- import { SOURCE_DISPLAY_NAME } from "../../../lib/config.js";
3
+ import { musicRuntimeToken } from "../../../../lib/runtime.js";
4
+ import { SOURCE_DISPLAY_NAME } from "../../../../lib/config.js";
5
5
  const VALID_SOURCES = new Set(['qq', 'netease', 'kuwo', 'kugou']);
6
6
  export default defineCommand({
7
7
  description: '删除音乐平台凭证',
8
8
  alias: ['删除'],
9
9
  params: { source: { type: 'string', description: '音乐源(qq/netease/kuwo/kugou)' } },
10
10
  permit: ['role(master)'],
11
- async execute({ params, args }) {
11
+ async execute({ params, args, use }) {
12
12
  const source = String(params.source ?? '').trim();
13
13
  const key = String(args[0] ?? '').trim();
14
14
  if (!VALID_SOURCES.has(source)) {
@@ -17,7 +17,7 @@ export default defineCommand({
17
17
  if (!key) {
18
18
  return `格式:cookie delete ${source} <key>`;
19
19
  }
20
- await deleteCredential(source, key);
20
+ await use(musicRuntimeToken).credentials.delete(source, key);
21
21
  return `[${SOURCE_DISPLAY_NAME[source]}] 凭证 ${key} 已删除`;
22
22
  },
23
23
  });
@@ -1,7 +1,7 @@
1
1
  import { defineCommand } from 'zhin.js/command';
2
- import { deleteCredential } from '../../../src/credential-store.js';
3
- import { SOURCE_DISPLAY_NAME } from '../../../src/config.js';
4
- import type { MusicSource } from '../../../src/types.js';
2
+ import { musicRuntimeToken } from '../../../../src/runtime.js';
3
+ import { SOURCE_DISPLAY_NAME } from '../../../../src/config.js';
4
+ import type { MusicSource } from '../../../../src/types.js';
5
5
 
6
6
  const VALID_SOURCES = new Set<string>(['qq', 'netease', 'kuwo', 'kugou']);
7
7
 
@@ -10,7 +10,7 @@ export default defineCommand({
10
10
  alias: ['删除'],
11
11
  params: { source: { type: 'string', description: '音乐源(qq/netease/kuwo/kugou)' } },
12
12
  permit: ['role(master)'],
13
- async execute({ params, args }) {
13
+ async execute({ params, args, use }) {
14
14
  const source = String(params.source ?? '').trim();
15
15
  const key = String(args[0] ?? '').trim();
16
16
 
@@ -21,7 +21,7 @@ export default defineCommand({
21
21
  return `格式:cookie delete ${source} <key>`;
22
22
  }
23
23
 
24
- await deleteCredential(source as MusicSource, key);
24
+ await use(musicRuntimeToken).credentials.delete(source as MusicSource, key);
25
25
  return `[${SOURCE_DISPLAY_NAME[source as MusicSource]}] 凭证 ${key} 已删除`;
26
26
  },
27
27
  });
@@ -1,14 +1,14 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
2
  import { defineCommand } from 'zhin.js/command';
3
- import { getCredential } from "../../../lib/credential-store.js";
4
- import { SOURCE_DISPLAY_NAME } from "../../../lib/config.js";
3
+ import { musicRuntimeToken } from "../../../../lib/runtime.js";
4
+ import { SOURCE_DISPLAY_NAME } from "../../../../lib/config.js";
5
5
  const VALID_SOURCES = new Set(['qq', 'netease', 'kuwo', 'kugou']);
6
6
  export default defineCommand({
7
7
  description: '查看音乐平台凭证(脱敏)',
8
8
  alias: ['查看'],
9
9
  params: { source: { type: 'string', description: '音乐源(qq/netease/kuwo/kugou)' } },
10
10
  permit: ['role(master)'],
11
- async execute({ params, args }) {
11
+ async execute({ params, args, use }) {
12
12
  const source = String(params.source ?? '').trim();
13
13
  const key = String(args[0] ?? '').trim();
14
14
  if (!VALID_SOURCES.has(source)) {
@@ -18,7 +18,7 @@ export default defineCommand({
18
18
  return `格式:cookie get ${source} <key>`;
19
19
  }
20
20
  const sourceName = SOURCE_DISPLAY_NAME[source];
21
- const value = await getCredential(source, key);
21
+ const value = await use(musicRuntimeToken).credentials.get(source, key);
22
22
  if (!value)
23
23
  return `[${sourceName}] 凭证 ${key} 未设置`;
24
24
  const masked = value.length > 10
@@ -1,7 +1,7 @@
1
1
  import { defineCommand } from 'zhin.js/command';
2
- import { getCredential } from '../../../src/credential-store.js';
3
- import { SOURCE_DISPLAY_NAME } from '../../../src/config.js';
4
- import type { MusicSource } from '../../../src/types.js';
2
+ import { musicRuntimeToken } from '../../../../src/runtime.js';
3
+ import { SOURCE_DISPLAY_NAME } from '../../../../src/config.js';
4
+ import type { MusicSource } from '../../../../src/types.js';
5
5
 
6
6
  const VALID_SOURCES = new Set<string>(['qq', 'netease', 'kuwo', 'kugou']);
7
7
 
@@ -10,7 +10,7 @@ export default defineCommand({
10
10
  alias: ['查看'],
11
11
  params: { source: { type: 'string', description: '音乐源(qq/netease/kuwo/kugou)' } },
12
12
  permit: ['role(master)'],
13
- async execute({ params, args }) {
13
+ async execute({ params, args, use }) {
14
14
  const source = String(params.source ?? '').trim();
15
15
  const key = String(args[0] ?? '').trim();
16
16
 
@@ -22,7 +22,7 @@ export default defineCommand({
22
22
  }
23
23
 
24
24
  const sourceName = SOURCE_DISPLAY_NAME[source as MusicSource];
25
- const value = await getCredential(source as MusicSource, key);
25
+ const value = await use(musicRuntimeToken).credentials.get(source as MusicSource, key);
26
26
  if (!value) return `[${sourceName}] 凭证 ${key} 未设置`;
27
27
 
28
28
  const masked = value.length > 10
@@ -1,14 +1,14 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
2
  import { defineCommand } from 'zhin.js/command';
3
- import { setCredential } from "../../../lib/credential-store.js";
4
- import { SOURCE_DISPLAY_NAME } from "../../../lib/config.js";
3
+ import { musicRuntimeToken } from "../../../../lib/runtime.js";
4
+ import { SOURCE_DISPLAY_NAME } from "../../../../lib/config.js";
5
5
  const VALID_SOURCES = new Set(['qq', 'netease', 'kuwo', 'kugou']);
6
6
  export default defineCommand({
7
7
  description: '保存音乐平台凭证',
8
8
  alias: ['设置'],
9
9
  params: { source: { type: 'string', description: '音乐源(qq/netease/kuwo/kugou)' } },
10
10
  permit: ['role(master)'],
11
- async execute({ params, args }) {
11
+ async execute({ params, args, use }) {
12
12
  const source = String(params.source ?? '').trim();
13
13
  const [key, ...valueParts] = args.map(String);
14
14
  if (!VALID_SOURCES.has(source)) {
@@ -17,7 +17,7 @@ export default defineCommand({
17
17
  if (!key || valueParts.length === 0) {
18
18
  return `格式:cookie set ${source} <key> <value>\n示例:cookie set netease cookie MUSIC_U=xxx`;
19
19
  }
20
- await setCredential(source, key, valueParts.join(' '));
20
+ await use(musicRuntimeToken).credentials.set(source, key, valueParts.join(' '));
21
21
  return `[${SOURCE_DISPLAY_NAME[source]}] 凭证 ${key} 已保存`;
22
22
  },
23
23
  });
@@ -1,7 +1,7 @@
1
1
  import { defineCommand } from 'zhin.js/command';
2
- import { setCredential } from '../../../src/credential-store.js';
3
- import { SOURCE_DISPLAY_NAME } from '../../../src/config.js';
4
- import type { MusicSource } from '../../../src/types.js';
2
+ import { musicRuntimeToken } from '../../../../src/runtime.js';
3
+ import { SOURCE_DISPLAY_NAME } from '../../../../src/config.js';
4
+ import type { MusicSource } from '../../../../src/types.js';
5
5
 
6
6
  const VALID_SOURCES = new Set<string>(['qq', 'netease', 'kuwo', 'kugou']);
7
7
 
@@ -10,7 +10,7 @@ export default defineCommand({
10
10
  alias: ['设置'],
11
11
  params: { source: { type: 'string', description: '音乐源(qq/netease/kuwo/kugou)' } },
12
12
  permit: ['role(master)'],
13
- async execute({ params, args }) {
13
+ async execute({ params, args, use }) {
14
14
  const source = String(params.source ?? '').trim();
15
15
  const [key, ...valueParts] = args.map(String);
16
16
 
@@ -21,7 +21,7 @@ export default defineCommand({
21
21
  return `格式:cookie set ${source} <key> <value>\n示例:cookie set netease cookie MUSIC_U=xxx`;
22
22
  }
23
23
 
24
- await setCredential(source as MusicSource, key, valueParts.join(' '));
24
+ await use(musicRuntimeToken).credentials.set(source as MusicSource, key, valueParts.join(' '));
25
25
  return `[${SOURCE_DISPLAY_NAME[source as MusicSource]}] 凭证 ${key} 已保存`;
26
26
  },
27
27
  });
@@ -1,13 +1,13 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
2
  import { defineCommand } from 'zhin.js/command';
3
- import { listCredentials } from "../../lib/credential-store.js";
4
- import { SOURCE_DISPLAY_NAME } from "../../lib/config.js";
3
+ import { musicRuntimeToken } from "../../../lib/runtime.js";
4
+ import { SOURCE_DISPLAY_NAME } from "../../../lib/config.js";
5
5
  export default defineCommand({
6
6
  description: '查看各平台凭证配置状态',
7
7
  alias: ['状态'],
8
8
  permit: ['role(master)'],
9
- async execute() {
10
- const allCreds = await listCredentials();
9
+ async execute({ use }) {
10
+ const allCreds = await use(musicRuntimeToken).credentials.list();
11
11
  const lines = ['--- 音乐凭证状态 ---'];
12
12
  for (const source of ['qq', 'netease', 'kuwo', 'kugou']) {
13
13
  const name = SOURCE_DISPLAY_NAME[source];
@@ -1,14 +1,14 @@
1
1
  import { defineCommand } from 'zhin.js/command';
2
- import { listCredentials } from '../../src/credential-store.js';
3
- import { SOURCE_DISPLAY_NAME } from '../../src/config.js';
4
- import type { MusicSource } from '../../src/types.js';
2
+ import { musicRuntimeToken } from '../../../src/runtime.js';
3
+ import { SOURCE_DISPLAY_NAME } from '../../../src/config.js';
4
+ import type { MusicSource } from '../../../src/types.js';
5
5
 
6
6
  export default defineCommand({
7
7
  description: '查看各平台凭证配置状态',
8
8
  alias: ['状态'],
9
9
  permit: ['role(master)'],
10
- async execute() {
11
- const allCreds = await listCredentials();
10
+ async execute({ use }) {
11
+ const allCreds = await use(musicRuntimeToken).credentials.list();
12
12
  const lines: string[] = ['--- 音乐凭证状态 ---'];
13
13
  for (const source of ['qq', 'netease', 'kuwo', 'kugou'] as MusicSource[]) {
14
14
  const name = SOURCE_DISPLAY_NAME[source];
@@ -1,8 +1,9 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
2
  import { defineCommand } from 'zhin.js/command';
3
- import { startLogin, pollLogin, cancelLogin, getActiveLogin, loginSessionKey, } from "../../lib/login/index.js";
4
- import { resolveMessageIds } from "../../lib/session.js";
5
- import { SOURCE_DISPLAY_NAME } from "../../lib/config.js";
3
+ import { loginSessionKey, } from "../../../lib/login/index.js";
4
+ import { resolveMessageIds } from "../../../lib/session.js";
5
+ import { SOURCE_DISPLAY_NAME } from "../../../lib/config.js";
6
+ import { musicRuntimeToken } from "../../../lib/runtime.js";
6
7
  const QR_LOGIN_SOURCES = {
7
8
  qq: 'qq',
8
9
  netease: 'netease',
@@ -13,27 +14,28 @@ export default defineCommand({
13
14
  platform: { type: 'string', description: '音乐平台(qq / netease / 取消)' },
14
15
  },
15
16
  permit: ['role(master)'],
16
- async execute({ params, input }) {
17
+ async execute({ params, input, use }) {
17
18
  const platform = String(params.platform ?? '').trim();
18
19
  const ids = resolveMessageIds(input);
19
20
  if (!ids)
20
21
  return '无法识别会话信息,请在群聊或私聊中使用';
21
22
  const key = loginSessionKey(ids.endpointId, ids.conversationId, ids.senderId);
23
+ const runtime = use(musicRuntimeToken);
22
24
  if (platform === '取消' || platform === 'cancel') {
23
- return cancelLogin(key) ? '已取消登录' : '没有进行中的登录会话';
25
+ return runtime.logins.cancel(key) ? '已取消登录' : '没有进行中的登录会话';
24
26
  }
25
27
  const source = QR_LOGIN_SOURCES[platform];
26
28
  if (!source) {
27
29
  return `不支持的平台:${platform || '(空)'}\n支持:qq, netease`;
28
30
  }
29
- const existing = getActiveLogin(key);
31
+ const existing = runtime.logins.get(key);
30
32
  if (existing) {
31
33
  return `正在进行 ${SOURCE_DISPLAY_NAME[existing.source]} 登录,请先完成或发送"音乐登录 取消"`;
32
34
  }
33
35
  const sourceName = SOURCE_DISPLAY_NAME[source];
34
36
  let qrResult;
35
37
  try {
36
- qrResult = await startLogin(source, key);
38
+ qrResult = await runtime.logins.start(source, key);
37
39
  }
38
40
  catch (err) {
39
41
  return `[${sourceName}] 获取二维码失败:${err instanceof Error ? err.message : String(err)}`;
@@ -46,7 +48,7 @@ export default defineCommand({
46
48
  qrResult.imageSegment,
47
49
  `\n二维码有效期 2 分钟,发送"音乐登录 取消"可中止`,
48
50
  ]);
49
- const finalResult = await pollLogin(key, async (result) => {
51
+ const finalResult = await runtime.logins.poll(key, async (result) => {
50
52
  if (result.status === 'scanned') {
51
53
  await replyFn(`[${sourceName}] ${result.message}`);
52
54
  }
@@ -1,15 +1,12 @@
1
1
  import { defineCommand } from 'zhin.js/command';
2
2
  import type { Message } from '@zhin.js/core/runtime';
3
3
  import {
4
- startLogin,
5
- pollLogin,
6
- cancelLogin,
7
- getActiveLogin,
8
4
  loginSessionKey,
9
5
  type QrLoginSource,
10
- } from '../../src/login/index.js';
11
- import { resolveMessageIds } from '../../src/session.js';
12
- import { SOURCE_DISPLAY_NAME } from '../../src/config.js';
6
+ } from '../../../src/login/index.js';
7
+ import { resolveMessageIds } from '../../../src/session.js';
8
+ import { SOURCE_DISPLAY_NAME } from '../../../src/config.js';
9
+ import { musicRuntimeToken } from '../../../src/runtime.js';
13
10
 
14
11
  const QR_LOGIN_SOURCES: Record<string, QrLoginSource> = {
15
12
  qq: 'qq',
@@ -22,15 +19,16 @@ export default defineCommand<unknown, string, Message>({
22
19
  platform: { type: 'string', description: '音乐平台(qq / netease / 取消)' },
23
20
  },
24
21
  permit: ['role(master)'],
25
- async execute({ params, input }) {
22
+ async execute({ params, input, use }) {
26
23
  const platform = String(params.platform ?? '').trim();
27
24
 
28
25
  const ids = resolveMessageIds(input!);
29
26
  if (!ids) return '无法识别会话信息,请在群聊或私聊中使用';
30
27
  const key = loginSessionKey(ids.endpointId, ids.conversationId, ids.senderId);
28
+ const runtime = use(musicRuntimeToken);
31
29
 
32
30
  if (platform === '取消' || platform === 'cancel') {
33
- return cancelLogin(key) ? '已取消登录' : '没有进行中的登录会话';
31
+ return runtime.logins.cancel(key) ? '已取消登录' : '没有进行中的登录会话';
34
32
  }
35
33
 
36
34
  const source = QR_LOGIN_SOURCES[platform];
@@ -38,7 +36,7 @@ export default defineCommand<unknown, string, Message>({
38
36
  return `不支持的平台:${platform || '(空)'}\n支持:qq, netease`;
39
37
  }
40
38
 
41
- const existing = getActiveLogin(key);
39
+ const existing = runtime.logins.get(key);
42
40
  if (existing) {
43
41
  return `正在进行 ${SOURCE_DISPLAY_NAME[existing.source]} 登录,请先完成或发送"音乐登录 取消"`;
44
42
  }
@@ -46,7 +44,7 @@ export default defineCommand<unknown, string, Message>({
46
44
  const sourceName = SOURCE_DISPLAY_NAME[source];
47
45
  let qrResult;
48
46
  try {
49
- qrResult = await startLogin(source, key);
47
+ qrResult = await runtime.logins.start(source, key);
50
48
  } catch (err) {
51
49
  return `[${sourceName}] 获取二维码失败:${err instanceof Error ? err.message : String(err)}`;
52
50
  }
@@ -60,7 +58,7 @@ export default defineCommand<unknown, string, Message>({
60
58
  `\n二维码有效期 2 分钟,发送"音乐登录 取消"可中止`,
61
59
  ]);
62
60
 
63
- const finalResult = await pollLogin(key, async (result) => {
61
+ const finalResult = await runtime.logins.poll(key, async (result) => {
64
62
  if (result.status === 'scanned') {
65
63
  await replyFn(`[${sourceName}] ${result.message}`);
66
64
  } else if (result.status === 'confirmed') {
@@ -1,8 +1,9 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
2
  import { defineCommand } from 'zhin.js/command';
3
- import { searchMusic, formatSearchResults } from "../../lib/music-lib.js";
4
- import { resolveSourceAlias, SOURCE_DISPLAY_NAME } from "../../lib/config.js";
5
- import { sessionKey, resolveMessageIds, setPending } from "../../lib/session.js";
3
+ import { searchMusic, formatSearchResults } from "../../../lib/music-lib.js";
4
+ import { resolveSourceAlias, SOURCE_DISPLAY_NAME } from "../../../lib/config.js";
5
+ import { sessionKey, resolveMessageIds } from "../../../lib/session.js";
6
+ import { musicRuntimeToken } from "../../../lib/runtime.js";
6
7
  export default defineCommand({
7
8
  description: '搜索音乐并点歌(支持QQ/网易云/酷我/酷狗)',
8
9
  params: { keyword: { type: 'string' } },
@@ -13,7 +14,7 @@ export default defineCommand({
13
14
  '酷我点歌': { keyword: '' },
14
15
  '酷狗点歌': { keyword: '' },
15
16
  },
16
- async execute({ params, config, input }) {
17
+ async execute({ params, config, input, use }) {
17
18
  const rawKeyword = String(params.keyword ?? '').trim();
18
19
  if (!rawKeyword) {
19
20
  const sources = Object.values(SOURCE_DISPLAY_NAME).join('/');
@@ -43,14 +44,14 @@ export default defineCommand({
43
44
  return '请输入歌曲名称';
44
45
  }
45
46
  const pageSize = config?.pageSize ?? 5;
46
- const result = await searchMusic(keyword, source, pageSize);
47
+ const result = await searchMusic(use(musicRuntimeToken), keyword, source, pageSize);
47
48
  if (result.total === 0) {
48
49
  return `[${SOURCE_DISPLAY_NAME[source]}] 未找到"${keyword}"相关歌曲`;
49
50
  }
50
51
  const ids = input ? resolveMessageIds(input) : null;
51
52
  if (ids) {
52
53
  const key = sessionKey(ids.endpointId, ids.conversationId, ids.senderId);
53
- setPending(key, {
54
+ use(musicRuntimeToken).sessions.set(key, {
54
55
  results: result.results,
55
56
  source: result.source,
56
57
  keyword,
@@ -1,9 +1,10 @@
1
1
  import { defineCommand } from 'zhin.js/command';
2
2
  import type { Message } from '@zhin.js/core/runtime';
3
- import { searchMusic, formatSearchResults } from '../../src/music-lib.js';
4
- import { resolveSourceAlias, SOURCE_DISPLAY_NAME } from '../../src/config.js';
5
- import { sessionKey, resolveMessageIds, setPending } from '../../src/session.js';
6
- import type { MusicSource } from '../../src/types.js';
3
+ import { searchMusic, formatSearchResults } from '../../../src/music-lib.js';
4
+ import { resolveSourceAlias, SOURCE_DISPLAY_NAME } from '../../../src/config.js';
5
+ import { sessionKey, resolveMessageIds } from '../../../src/session.js';
6
+ import type { MusicSource } from '../../../src/types.js';
7
+ import { musicRuntimeToken } from '../../../src/runtime.js';
7
8
 
8
9
  interface MusicConfig {
9
10
  defaultSource?: MusicSource;
@@ -20,7 +21,7 @@ export default defineCommand<MusicConfig, string, Message>({
20
21
  '酷我点歌': { keyword: '' },
21
22
  '酷狗点歌': { keyword: '' },
22
23
  },
23
- async execute({ params, config, input }) {
24
+ async execute({ params, config, input, use }) {
24
25
  const rawKeyword = String(params.keyword ?? '').trim();
25
26
  if (!rawKeyword) {
26
27
  const sources = Object.values(SOURCE_DISPLAY_NAME).join('/');
@@ -53,7 +54,7 @@ export default defineCommand<MusicConfig, string, Message>({
53
54
  }
54
55
 
55
56
  const pageSize = (config as MusicConfig | undefined)?.pageSize ?? 5;
56
- const result = await searchMusic(keyword, source, pageSize);
57
+ const result = await searchMusic(use(musicRuntimeToken), keyword, source, pageSize);
57
58
  if (result.total === 0) {
58
59
  return `[${SOURCE_DISPLAY_NAME[source]}] 未找到"${keyword}"相关歌曲`;
59
60
  }
@@ -61,7 +62,7 @@ export default defineCommand<MusicConfig, string, Message>({
61
62
  const ids = input ? resolveMessageIds(input) : null;
62
63
  if (ids) {
63
64
  const key = sessionKey(ids.endpointId, ids.conversationId, ids.senderId);
64
- setPending(key, {
65
+ use(musicRuntimeToken).sessions.set(key, {
65
66
  results: result.results,
66
67
  source: result.source,
67
68
  keyword,
@@ -1,10 +1,10 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
2
  import { defineComponent } from 'zhin.js/component';
3
- import { musicServices } from "../lib/sources/index.js";
4
- import { sourceConfigMap } from "../lib/config.js";
3
+ import { sourceConfigMap } from "../../lib/config.js";
4
+ import { musicRuntimeToken } from "../../lib/runtime.js";
5
5
  export default defineComponent({
6
- async render({ platform, musicId }) {
7
- const service = musicServices[platform];
6
+ async render({ platform, musicId }, context) {
7
+ const service = context.use(musicRuntimeToken).services[platform];
8
8
  if (!service)
9
9
  return 'unsupported music source';
10
10
  const detail = await service.getDetail(musicId);
@@ -1,7 +1,7 @@
1
1
  import { defineComponent } from 'zhin.js/component';
2
- import { musicServices } from '../src/sources/index.js';
3
- import { sourceConfigMap } from '../src/config.js';
4
- import type { MusicSource } from '../src/types.js';
2
+ import { sourceConfigMap } from '../../src/config.js';
3
+ import type { MusicSource } from '../../src/types.js';
4
+ import { musicRuntimeToken } from '../../src/runtime.js';
5
5
 
6
6
  interface ShareMusicProps {
7
7
  readonly platform: MusicSource;
@@ -9,8 +9,8 @@ interface ShareMusicProps {
9
9
  }
10
10
 
11
11
  export default defineComponent<ShareMusicProps>({
12
- async render({ platform, musicId }) {
13
- const service = musicServices[platform];
12
+ async render({ platform, musicId }, context) {
13
+ const service = context.use(musicRuntimeToken).services[platform];
14
14
  if (!service) return 'unsupported music source';
15
15
  const detail = await service.getDetail(musicId);
16
16
  return {
@@ -1,4 +1,3 @@
1
- import { type Dispose, type GenerationStoreContext } from 'zhin.js';
2
1
  import type { MusicSource } from './types.js';
3
2
  export declare const MUSIC_CREDENTIALS_TABLE = "music_credentials";
4
3
  export interface CredentialRow {
@@ -25,10 +24,14 @@ export interface CredentialDb {
25
24
  get(name: string): CredentialModel | undefined;
26
25
  };
27
26
  }
28
- export declare function provideCredentialDb(context: GenerationStoreContext, db: CredentialDb): Dispose;
29
- export declare function getCredential(source: MusicSource, key: string): Promise<string | null>;
30
- export declare function setCredential(source: MusicSource, key: string, value: string): Promise<void>;
31
- export declare function deleteCredential(source: MusicSource, key: string): Promise<void>;
32
- export declare function listCredentials(source?: MusicSource): Promise<CredentialRow[]>;
33
- export declare function resetCredentialDb(): void;
27
+ export declare function createInMemoryCredentialDb(): CredentialDb;
28
+ export declare class CredentialStore {
29
+ #private;
30
+ constructor(db: CredentialDb);
31
+ private get model();
32
+ get(source: MusicSource, key: string): Promise<string | null>;
33
+ set(source: MusicSource, key: string, value: string): Promise<void>;
34
+ delete(source: MusicSource, key: string): Promise<void>;
35
+ list(source?: MusicSource): Promise<CredentialRow[]>;
36
+ }
34
37
  //# sourceMappingURL=credential-store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"credential-store.d.ts","sourceRoot":"","sources":["../src/credential-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,OAAO,EACZ,KAAK,sBAAsB,EAC5B,MAAM,SAAS,CAAC;AACjB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,eAAO,MAAM,uBAAuB,sBAAsB,CAAC;AAE3D,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,WAAW,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,GAAG,MAAM,EAAE,MAAM,EAAE,GAAG;QAC3B,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;QAC9E,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAAE,QAAQ,GAAG,KAAK,EACzD,WAAW,CAAC,EACR,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,GACxE,IAAI,EACR,UAAU,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,OAAO,KAAK,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI,GAC1E,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC,CAAC;KACjC,CAAC;IACF,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACvD,MAAM,IAAI;QAAE,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;KAAE,CAAC;IACtE,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;QACtC,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;KACzD,CAAC;CACH;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE;QAAE,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAAA;KAAE,CAAC;CAC5D;AA6CD,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,sBAAsB,EAC/B,EAAE,EAAE,YAAY,GACf,OAAO,CAET;AAsBD,wBAAsB,aAAa,CACjC,MAAM,EAAE,WAAW,EACnB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAMxB;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,WAAW,EACnB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC,CAgBf;AAED,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,WAAW,EACnB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,IAAI,CAAC,CAIf;AAED,wBAAsB,eAAe,CACnC,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,aAAa,EAAE,CAAC,CAY1B;AAED,wBAAgB,iBAAiB,IAAI,IAAI,CAGxC"}
1
+ {"version":3,"file":"credential-store.d.ts","sourceRoot":"","sources":["../src/credential-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,eAAO,MAAM,uBAAuB,sBAAsB,CAAC;AAE3D,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,WAAW,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,GAAG,MAAM,EAAE,MAAM,EAAE,GAAG;QAC3B,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;QAC9E,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAAE,QAAQ,GAAG,KAAK,EACzD,WAAW,CAAC,EACR,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,GACxE,IAAI,EACR,UAAU,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,OAAO,KAAK,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI,GAC1E,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC,CAAC;KACjC,CAAC;IACF,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACvD,MAAM,IAAI;QAAE,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;KAAE,CAAC;IACtE,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;QACtC,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;KACzD,CAAC;CACH;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE;QAAE,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAAA;KAAE,CAAC;CAC5D;AA0CD,wBAAgB,0BAA0B,IAAI,YAAY,CAOzD;AAED,qBAAa,eAAe;;gBAGd,EAAE,EAAE,YAAY;IAI5B,OAAO,KAAK,KAAK,GAEhB;IAEK,GAAG,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAM7D,GAAG,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWnE,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvD,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;CAW3D"}