koishi-plugin-cfmrmod 1.0.3 → 1.0.5

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 (3) hide show
  1. package/README.md +29 -1
  2. package/dist/notify.js +114 -23
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -13,14 +13,42 @@ Koishi 插件:搜索 CurseForge / Modrinth / MCMod,并渲染图片卡片。
13
13
  - `cnmc.mod/.data/.pack/.tutorial/.author/.user <关键词>`
14
14
  - `cf.help` / `mr.help` / `cnmc.help`
15
15
 
16
+ #### 更新通知(notify)
17
+ - `notify.add <platform> <projectId>` 添加订阅
18
+ - `notify.remove <platform> <projectId>` 删除订阅
19
+ - `notify.list` 列出订阅
20
+ - `notify.enable <onoff>` 启用/禁用本群通知
21
+ - `notify.check [arg] [-b]` 手动检查更新(arg 为序号或 projectId;-b 强制发送最新卡片)
22
+ - `notify.helpme` 查看完整参数说明
23
+
24
+ 参数说明:
25
+ - `<platform>`:平台代码,`mr`=Modrinth,`cf`=CurseForge
26
+ - `<projectId>`:平台项目 ID(不是名称)
27
+ - `<onoff>`:`on/off` 或 `true/false`
28
+ - `[arg]`:`notify.check` 的参数,可填订阅序号或 `projectId`
29
+ - `-b`:强制发送最新卡片(忽略是否更新)
30
+
16
31
  列表交互:输入序号查看,`n` 下一页,`p` 上一页,`q` 退出。
17
32
 
18
33
  ### 配置要点
34
+ #### 通用
19
35
  - `prefixes`: 设置 `cf` / `mr` / `cnmc` 指令前缀
20
- - `fontPath`: 中文字体路径
21
36
  - `timeouts`: 搜索会话超时(毫秒)
22
37
  - `debug`: 调试日志开关
23
38
 
39
+ #### 更新通知(notify)
40
+ - `notify.enabled`: 是否开启更新通知
41
+ - `notify.interval`: 全局轮询间隔(毫秒)
42
+ - `notify.adminAuthority`: 权限等级(1=全部,2=管理员+群主,3=仅群主)
43
+ - `notify.stateFile`: 状态文件路径(JSON)
44
+ - `notify.groups`: 通知群组列表
45
+ - `channelId`: 群/频道 ID
46
+ - `enabled`: 是否启用本群通知
47
+ - `subs`: 订阅列表
48
+ - `platform`: `mr` 或 `cf`
49
+ - `projectId`: 项目 ID
50
+ - `interval`: 单独轮询间隔(毫秒),<=0 禁用
51
+
24
52
  ## 项目特点
25
53
  - 支持 CurseForge / Modrinth / MCMod 多平台搜索
26
54
  - 结果以图片卡片形式展示
package/dist/notify.js CHANGED
@@ -244,7 +244,37 @@ function apply(ctx, config, options) {
244
244
  stateCache.set(key, { lastVersion });
245
245
  await saveStateToFile();
246
246
  };
247
- const getConfigGroups = () => Array.isArray(config.groups) ? config.groups : [];
247
+ const getConfigGroups = () => {
248
+ if (!Array.isArray(config.groups))
249
+ config.groups = [];
250
+ return config.groups;
251
+ };
252
+ const getGroup = (channelId) => {
253
+ return getConfigGroups().find((g) => String(g === null || g === void 0 ? void 0 : g.channelId) === String(channelId));
254
+ };
255
+ const ensureGroup = (channelId) => {
256
+ const groups = getConfigGroups();
257
+ let group = groups.find((g) => String(g === null || g === void 0 ? void 0 : g.channelId) === String(channelId));
258
+ if (!group) {
259
+ group = { channelId: String(channelId), enabled: true, subs: [] };
260
+ groups.push(group);
261
+ }
262
+ if (typeof group.enabled !== 'boolean')
263
+ group.enabled = true;
264
+ if (!Array.isArray(group.subs))
265
+ group.subs = [];
266
+ return group;
267
+ };
268
+ const parseOnOff = (value) => {
269
+ if (typeof value !== 'string')
270
+ return null;
271
+ const v = value.trim().toLowerCase();
272
+ if (['1', 'on', 'true', 'yes', 'y'].includes(v))
273
+ return true;
274
+ if (['0', 'off', 'false', 'no', 'n'].includes(v))
275
+ return false;
276
+ return null;
277
+ };
248
278
  const getConfigSubs = (channelId) => {
249
279
  const groups = getConfigGroups();
250
280
  const subs = [];
@@ -442,48 +472,109 @@ function apply(ctx, config, options) {
442
472
  const tick = Math.max(60 * 1000, Number(config.interval) || 30 * 60 * 1000);
443
473
  ctx.setInterval(() => checkOnce().catch(() => null), tick);
444
474
  }
445
- ctx.command('notify.add <platform> <projectId> [channelId]', '添加更新订阅')
446
- .action(async ({ session }, platform, projectId, channelId) => {
475
+ ctx.command('notify.add <platform> <projectId>', '添加更新订阅')
476
+ .action(async ({ session }, platform, projectId) => {
447
477
  if (!platform || !projectId)
448
478
  return '参数不足。';
449
- const targetChannel = channelId || session.channelId;
479
+ const platformKey = normalizePlatform(platform);
480
+ if (!platformKey)
481
+ return '平台参数错误,请使用 mr 或 cf。';
482
+ const targetChannel = session.channelId;
450
483
  if (!targetChannel)
451
484
  return '只能在群聊使用或指定 channelId。';
452
- if (!await requireManage(session, channelId))
485
+ if (!await requireManage(session))
453
486
  return '权限不足。';
454
- return '请在配置页面的 notify.groups 中编辑订阅列表。';
487
+ const pid = String(projectId).trim();
488
+ if (!pid)
489
+ return '项目 ID 不能为空。';
490
+ const group = ensureGroup(targetChannel);
491
+ const list = Array.isArray(group.subs) ? group.subs : [];
492
+ const exists = list.some((s) => normalizePlatform(s === null || s === void 0 ? void 0 : s.platform) === platformKey && String((s === null || s === void 0 ? void 0 : s.projectId) || '').trim() === pid);
493
+ if (exists)
494
+ return `已存在订阅:${platformKey}:${pid}`;
495
+ const interval = Math.max(60 * 1000, Number(config.interval) || 30 * 60 * 1000);
496
+ list.push({ platform: platformKey, projectId: pid, interval });
497
+ group.subs = list;
498
+ return `已添加订阅:${platformKey}:${pid}`;
455
499
  });
456
- ctx.command('notify.remove <platform> <projectId> [channelId]', '删除更新订阅')
457
- .action(async ({ session }, platform, projectId, channelId) => {
500
+ ctx.command('notify.remove <platform> <projectId>', '删除更新订阅')
501
+ .action(async ({ session }, platform, projectId) => {
458
502
  if (!platform || !projectId)
459
503
  return '参数不足。';
460
- const targetChannel = channelId || session.channelId;
504
+ const platformKey = normalizePlatform(platform);
505
+ if (!platformKey)
506
+ return '平台参数错误,请使用 mr 或 cf。';
507
+ const targetChannel = session.channelId;
461
508
  if (!targetChannel)
462
509
  return '只能在群聊使用或指定 channelId。';
463
- if (!await requireManage(session, channelId))
510
+ if (!await requireManage(session))
464
511
  return '权限不足。';
465
- return '请在配置页面的 notify.groups 中编辑订阅列表。';
512
+ const pid = String(projectId).trim();
513
+ if (!pid)
514
+ return '项目 ID 不能为空。';
515
+ const group = getGroup(targetChannel);
516
+ if (!group || !Array.isArray(group.subs) || !group.subs.length)
517
+ return '未找到订阅。';
518
+ const before = group.subs.length;
519
+ group.subs = group.subs.filter((s) => !(normalizePlatform(s === null || s === void 0 ? void 0 : s.platform) === platformKey && String((s === null || s === void 0 ? void 0 : s.projectId) || '').trim() === pid));
520
+ if (group.subs.length === before)
521
+ return '未找到订阅。';
522
+ return `已删除订阅:${platformKey}:${pid}`;
466
523
  });
467
- ctx.command('notify.list [channelId]', '列出订阅')
468
- .action(async ({ session }, channelId) => {
469
- const targetChannel = channelId || session.channelId;
524
+ ctx.command('notify.list', '列出订阅')
525
+ .action(async ({ session }) => {
526
+ const targetChannel = session.channelId;
470
527
  if (!targetChannel)
471
528
  return '只能在群聊使用或指定 channelId。';
472
- if (!await requireManage(session, channelId))
529
+ if (!await requireManage(session))
473
530
  return '权限不足。';
474
- const subs = getConfigSubs(targetChannel);
475
- if (!subs.length)
531
+ const group = getGroup(targetChannel);
532
+ if (!group)
476
533
  return '暂无订阅。';
477
- return subs.map(s => `- ${s.platform}:${s.projectId} (${Math.round(s.interval / 60000)} 分钟)`).join('\n');
534
+ const list = Array.isArray(group.subs) ? group.subs : [];
535
+ if (!list.length)
536
+ return group.enabled === false ? '本群通知已禁用,暂无订阅。' : '暂无订阅。';
537
+ const status = group.enabled === false ? '禁用' : '启用';
538
+ const lines = list.map((s, i) => {
539
+ const platformKey = normalizePlatform(s === null || s === void 0 ? void 0 : s.platform) || String((s === null || s === void 0 ? void 0 : s.platform) || '').trim();
540
+ const pid = String((s === null || s === void 0 ? void 0 : s.projectId) || '').trim();
541
+ const rawInterval = Number(s === null || s === void 0 ? void 0 : s.interval);
542
+ const interval = Math.max(60 * 1000, rawInterval || Number(config.interval) || 30 * 60 * 1000);
543
+ return `${i + 1}. ${platformKey}:${pid} (${Math.round(interval / 60000)} 分钟)`;
544
+ });
545
+ return [`本群通知:${status}`, ...lines].join('\n');
478
546
  });
479
- ctx.command('notify.enable <onoff> [channelId]', '启用/禁用本群通知')
480
- .action(async ({ session }, onoff, channelId) => {
481
- const targetChannel = channelId || session.channelId;
547
+ ctx.command('notify.enable <onoff>', '启用/禁用本群通知')
548
+ .action(async ({ session }, onoff) => {
549
+ const targetChannel = session.channelId;
482
550
  if (!targetChannel)
483
551
  return '只能在群聊使用或指定 channelId。';
484
- if (!await requireManage(session, channelId))
552
+ if (!await requireManage(session))
485
553
  return '权限不足。';
486
- return '请在配置页面的 notify.groups 中编辑 enabled。';
554
+ const flag = parseOnOff(onoff);
555
+ if (flag === null)
556
+ return 'onoff 参数错误,请使用 on/off 或 true/false。';
557
+ const group = ensureGroup(targetChannel);
558
+ group.enabled = flag;
559
+ return flag ? '已启用本群通知。' : '已禁用本群通知。';
560
+ });
561
+ ctx.command('notify.helpme', '查看通知系统帮助')
562
+ .action(() => {
563
+ return [
564
+ 'notify 使用说明:',
565
+ '1) notify.add [platform] [projectId] 添加订阅',
566
+ '2) notify.remove [platform] [projectId] 删除订阅',
567
+ '3) notify.list 列出订阅',
568
+ '4) notify.enable [onoff] 启用/禁用',
569
+ '5) notify.check [arg] [-b] 手动检查更新(arg 为序号或 projectId)',
570
+ '平台:mr=Modrinth,cf=CurseForge',
571
+ '参数说明:',
572
+ '- [platform]:平台代码,填写 mr 或 cf',
573
+ '- [projectId]:平台项目ID(Modrinth/CurseForge 的项目ID,不是名称)',
574
+ '- [onoff]:启用开关,填写 on/off 或 true/false',
575
+ '- [arg]:notify.check 的参数,可填订阅序号或 projectId',
576
+ '- -b:强制发送最新卡片(忽略是否更新)',
577
+ ].join('\n');
487
578
  });
488
579
  ctx.command('notify.check [arg]', '手动检查更新')
489
580
  .option('broadcast', '-b 直接发送最新版卡片(忽略是否更新)')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "koishi-plugin-cfmrmod",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "Koishi 插件:搜索 CurseForge/Modrinth/MCMod 并渲染图片卡片",
5
5
  "main": "dist/index.js",
6
6
  "files": [