koishi-plugin-cocoyyy-console 1.2.0-alpha.1 → 1.2.0

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.
@@ -6,3 +6,4 @@ export * from './configs/redis_config';
6
6
  export * from './configs/ai_config';
7
7
  export * from './configs/wish_config';
8
8
  export * from './configs/sum_config';
9
+ export * from './configs/jm_config';
@@ -11,6 +11,7 @@ interface FunctionConfig {
11
11
  game_flag: boolean;
12
12
  kuro_flag: boolean;
13
13
  sum_flag: boolean;
14
+ jm_flag: boolean;
14
15
  }
15
16
  interface GroupFunctionLimitConfig {
16
17
  cofig_enable_flag: boolean;
@@ -0,0 +1,10 @@
1
+ import { Schema } from 'koishi';
2
+ interface JmConfig {
3
+ api_url?: string;
4
+ api_key?: string;
5
+ poll_interval_ms?: number;
6
+ poll_timeout_ms?: number;
7
+ max_concurrent_per_guild?: number;
8
+ }
9
+ declare const JmConfigSchema: Schema<JmConfig>;
10
+ export { JmConfig, JmConfigSchema, };
package/lib/index.d.ts CHANGED
@@ -16,6 +16,7 @@ export interface Config {
16
16
  repeat_config?: my_config.RepeatConfig;
17
17
  wish_config?: my_config.WishConfig;
18
18
  sum_config?: my_config.SumConfig;
19
+ jm_config?: my_config.JmConfig;
19
20
  test?: string;
20
21
  }
21
22
  export declare const Config: Schema<Config>;
package/lib/index.js CHANGED
@@ -39,7 +39,7 @@ __export(src_exports, {
39
39
  savePath: () => savePath
40
40
  });
41
41
  module.exports = __toCommonJS(src_exports);
42
- var import_koishi16 = require("koishi");
42
+ var import_koishi18 = require("koishi");
43
43
 
44
44
  // src/config/configs/function_config.ts
45
45
  var import_koishi = require("koishi");
@@ -54,7 +54,8 @@ var FunctionConfigSchema = import_koishi.Schema.object({
54
54
  wish_flag: import_koishi.Schema.boolean().default(true).description("许愿功能是否启用"),
55
55
  game_flag: import_koishi.Schema.boolean().default(true).description("游戏功能是否启用"),
56
56
  kuro_flag: import_koishi.Schema.boolean().default(true).description("鸣潮功能是否启用"),
57
- sum_flag: import_koishi.Schema.boolean().default(true).description("总结功能是否启用")
57
+ sum_flag: import_koishi.Schema.boolean().default(true).description("总结功能是否启用"),
58
+ jm_flag: import_koishi.Schema.boolean().default(false).description("禁漫下载功能是否启用")
58
59
  });
59
60
  var GroupFunctionLimitConfigSchema = import_koishi.Schema.object({
60
61
  cofig_enable_flag: import_koishi.Schema.boolean().default(true).description("功能限制是否启用"),
@@ -117,6 +118,16 @@ var SumConfigSchema = import_koishi8.Schema.object({
117
118
  api_model: import_koishi8.Schema.string().default("").description("AI模型")
118
119
  });
119
120
 
121
+ // src/config/configs/jm_config.ts
122
+ var import_koishi9 = require("koishi");
123
+ var JmConfigSchema = import_koishi9.Schema.object({
124
+ api_url: import_koishi9.Schema.string().default("http://127.0.0.1:6789").description("JM 下载服务地址"),
125
+ api_key: import_koishi9.Schema.string().default("").description("JM 下载服务 API Key(X-API-Key)"),
126
+ poll_interval_ms: import_koishi9.Schema.number().default(5e3).description("任务状态轮询间隔(毫秒)"),
127
+ poll_timeout_ms: import_koishi9.Schema.number().default(18e5).description("任务轮询超时(毫秒,默认 30 分钟)"),
128
+ max_concurrent_per_guild: import_koishi9.Schema.number().default(5).description("每个群聊同时进行的最大下载任务数")
129
+ });
130
+
120
131
  // src/infra/mysql_init.ts
121
132
  var import_sequelize = require("sequelize");
122
133
  var sequelize = null;
@@ -370,6 +381,27 @@ function loadGroupFunctionLimitConfig(config) {
370
381
  }
371
382
  }
372
383
  __name(loadGroupFunctionLimitConfig, "loadGroupFunctionLimitConfig");
384
+ function getCtxForFunction(ctx, menuNumber) {
385
+ if (!groupFunctionLimitConfig || groupFunctionLimitConfig.length === 0) {
386
+ return ctx;
387
+ }
388
+ const defaultEntry = groupFunctionLimitConfig.find((item) => String(item.group_id) === "#");
389
+ const defaultAllowed = defaultEntry ? defaultEntry.menu_list.includes(menuNumber) : false;
390
+ const explicitGroups = groupFunctionLimitConfig.filter((item) => String(item.group_id) !== "#");
391
+ if (defaultAllowed) {
392
+ const excludedIds = explicitGroups.filter((item) => !item.menu_list.includes(menuNumber)).map((item) => String(item.group_id));
393
+ if (excludedIds.length === 0) return ctx;
394
+ return ctx.exclude((session) => !!session.guildId && excludedIds.includes(session.guildId));
395
+ } else {
396
+ const includedIds = explicitGroups.filter((item) => item.menu_list.includes(menuNumber)).map((item) => String(item.group_id));
397
+ if (includedIds.length === 0) {
398
+ logger.info(`[getCtxForFunction Info]: 功能 ${menuNumber} 在所有群组中均未启用,跳过注册`);
399
+ return null;
400
+ }
401
+ return ctx.guild(...includedIds);
402
+ }
403
+ }
404
+ __name(getCtxForFunction, "getCtxForFunction");
373
405
  function getGroupFunctionLimitConfig() {
374
406
  return groupFunctionLimitConfig;
375
407
  }
@@ -477,6 +509,12 @@ function getMenuListByCommand(command = null, functionConfig, session) {
477
509
  if (!isCommandAllowedForGuild(9, guildId))
478
510
  return "当前群聊已限制总结功能";
479
511
  return buildFuncMenu("总结功能菜单", "总结功能", sumFuncMenuList);
512
+ case menuByNumber.get(10)?.name:
513
+ if (!functionConfig.jm_flag)
514
+ return "禁漫下载功能已关闭";
515
+ if (!isCommandAllowedForGuild(10, guildId))
516
+ return "当前群聊已限制禁漫下载功能";
517
+ return buildFuncMenu("禁漫下载功能菜单", "禁漫下载功能", jmFuncMenuList);
480
518
  default:
481
519
  const allowedMenuNumbers = getAllowedMenuNumbersForGuild(guildId);
482
520
  const finalMenuList = allowedMenuNumbers ? allMenus.filter((item) => allowedMenuNumbers.includes(item.number)) : allMenus;
@@ -618,6 +656,13 @@ var sumFuncMenuList = [
618
656
  command: "sum [时间范围(1-168小时)]"
619
657
  }
620
658
  ];
659
+ var jmFuncMenuList = [
660
+ {
661
+ name: "jm",
662
+ description: "提交禁漫本子下载任务",
663
+ command: "jm [comic_id]"
664
+ }
665
+ ];
621
666
  function registerMenuCommands(ctx, connected, functionConfig) {
622
667
  ctx.command("help <参数>", "帮助菜单").action(async ({ session }, ...args) => {
623
668
  if (!dev_mode) {
@@ -631,7 +676,7 @@ function registerMenuCommands(ctx, connected, functionConfig) {
631
676
  __name(registerMenuCommands, "registerMenuCommands");
632
677
 
633
678
  // src/services/tag_func/tag_commands.ts
634
- var import_koishi10 = require("koishi");
679
+ var import_koishi11 = require("koishi");
635
680
 
636
681
  // src/services/tag_func/tag_service.ts
637
682
  var import_sequelize4 = require("sequelize");
@@ -639,7 +684,7 @@ var import_fs3 = require("fs");
639
684
  var import_path3 = require("path");
640
685
 
641
686
  // src/services/tag_func/img_service.ts
642
- var import_koishi9 = require("koishi");
687
+ var import_koishi10 = require("koishi");
643
688
  var import_path2 = require("path");
644
689
  var import_fs2 = require("fs");
645
690
  async function loadImageFromUrl(ctx, url) {
@@ -714,7 +759,7 @@ async function randomImgByTag(tag_name, guild_id) {
714
759
  if (ImgList.length <= 0) {
715
760
  throw new Error("Don't have image!");
716
761
  }
717
- const random = new import_koishi9.Random(() => Math.random());
762
+ const random = new import_koishi10.Random(() => Math.random());
718
763
  let result = ImgList[random.int(0, ImgList.length)];
719
764
  const filePath = result.get("img_url");
720
765
  return filePath;
@@ -998,13 +1043,13 @@ function registerTagCommands(ctx, connected, savePath2) {
998
1043
  if (!exec2)
999
1044
  return `获取图片失败`;
1000
1045
  return `第${exec2.page}页,共${exec2.total}页
1001
- ${exec2.result?.map((item) => import_koishi10.h.image((0, import_url.pathToFileURL)(item).href)).join("\n\n")}`;
1046
+ ${exec2.result?.map((item) => import_koishi11.h.image((0, import_url.pathToFileURL)(item).href)).join("\n\n")}`;
1002
1047
  }
1003
1048
  let exec = await randomImgByTag(tag, session.guildId);
1004
1049
  if (!exec)
1005
1050
  return `获取图片失败`;
1006
1051
  let path2 = (0, import_url.pathToFileURL)(exec).href;
1007
- return import_koishi10.h.image(path2);
1052
+ return import_koishi11.h.image(path2);
1008
1053
  });
1009
1054
  ctx.command("bind <参数>", "标签绑定别名").action(async ({ session }, ...args) => {
1010
1055
  if (!dev_mode) {
@@ -1147,7 +1192,7 @@ function registerRepeatMiddleware(ctx, config) {
1147
1192
  __name(registerRepeatMiddleware, "registerRepeatMiddleware");
1148
1193
 
1149
1194
  // src/services/rbq_func/rbq_command.ts
1150
- var import_koishi11 = require("koishi");
1195
+ var import_koishi12 = require("koishi");
1151
1196
 
1152
1197
  // src/models/rbq_persons.ts
1153
1198
  var import_sequelize5 = require("sequelize");
@@ -1474,7 +1519,7 @@ function registerRbqCommands(ctx, connected) {
1474
1519
  if (!list || list.length === 0) {
1475
1520
  return "当前群聊还没有设置任何rbq";
1476
1521
  }
1477
- return "当前群聊rbq列表:\n" + list.map((item) => (0, import_koishi11.h)("at", { id: item })).join(",");
1522
+ return "当前群聊rbq列表:\n" + list.map((item) => (0, import_koishi12.h)("at", { id: item })).join(",");
1478
1523
  });
1479
1524
  ctx.command("rbqadd <参数>", "添加rbq").action(async ({ session }, ...args) => {
1480
1525
  if (!dev_mode) {
@@ -1492,7 +1537,7 @@ function registerRbqCommands(ctx, connected) {
1492
1537
  exec = await create_person(session.guildId, uid);
1493
1538
  if (!exec.result)
1494
1539
  return `添加rbq失败: ${exec.error}`;
1495
- return "已添加rbq:" + (0, import_koishi11.h)("at", { id: uid });
1540
+ return "已添加rbq:" + (0, import_koishi12.h)("at", { id: uid });
1496
1541
  });
1497
1542
  ctx.command("rbqinstead <参数>", "替换rbq").action(async ({ session }, ...args) => {
1498
1543
  if (!dev_mode) {
@@ -1517,12 +1562,12 @@ function registerRbqCommands(ctx, connected) {
1517
1562
  exec = await instead_person(session.guildId, source_uid, new_target);
1518
1563
  if (!exec.result)
1519
1564
  return `替换rbq失败:${exec.error}`;
1520
- return "倒反天罡!进去吧你,已替换rbq:\n" + (0, import_koishi11.h)("at", { id: source_uid }) + " -> " + (0, import_koishi11.h)("at", { id: new_target });
1565
+ return "倒反天罡!进去吧你,已替换rbq:\n" + (0, import_koishi12.h)("at", { id: source_uid }) + " -> " + (0, import_koishi12.h)("at", { id: new_target });
1521
1566
  }
1522
1567
  exec = await instead_person(session.guildId, source_uid, target_uid);
1523
1568
  if (!exec.result)
1524
1569
  return `替换rbq失败:${exec.error}`;
1525
- return (0, import_koishi11.h)("p", "已替换rbq:", (0, import_koishi11.h)("at", { id: source_uid }), " -> ", (0, import_koishi11.h)("at", { id: target_uid }));
1570
+ return (0, import_koishi12.h)("p", "已替换rbq:", (0, import_koishi12.h)("at", { id: source_uid }), " -> ", (0, import_koishi12.h)("at", { id: target_uid }));
1526
1571
  });
1527
1572
  ctx.command("rbqadd_txt <参数>", "添加自定义文本").action(async ({ session }, ...args) => {
1528
1573
  if (!dev_mode) {
@@ -1549,10 +1594,10 @@ function registerRbqCommands(ctx, connected) {
1549
1594
  const contents = await get_content_list(session.guildId, target_uid);
1550
1595
  let content2 = "*死你";
1551
1596
  if (contents && contents.length > 0) {
1552
- const random = new import_koishi11.Random(() => Math.random());
1597
+ const random = new import_koishi12.Random(() => Math.random());
1553
1598
  content2 = contents[random.int(0, contents.length)];
1554
1599
  }
1555
- return (0, import_koishi11.h)("at", { id: target_uid }) + "还想自己加文本?!\n" + content2;
1600
+ return (0, import_koishi12.h)("at", { id: target_uid }) + "还想自己加文本?!\n" + content2;
1556
1601
  } catch (error) {
1557
1602
  logger.error("[rbq rbqadd_txt] Error:", error);
1558
1603
  return "不能给自己设置文本,请输入其他qq号";
@@ -1582,10 +1627,10 @@ function registerRbqCommands(ctx, connected) {
1582
1627
  const contents = await get_content_list(guildId, matchedUid);
1583
1628
  let content = "*死你";
1584
1629
  if (contents && contents.length > 0) {
1585
- const random = new import_koishi11.Random(() => Math.random());
1630
+ const random = new import_koishi12.Random(() => Math.random());
1586
1631
  content = contents[random.int(0, contents.length)];
1587
1632
  }
1588
- return (0, import_koishi11.h)("at", { id: matchedUid }) + " " + content;
1633
+ return (0, import_koishi12.h)("at", { id: matchedUid }) + " " + content;
1589
1634
  } catch (error) {
1590
1635
  logger.error("[rbq middleware] Error:", error);
1591
1636
  return next();
@@ -1810,7 +1855,7 @@ __name(is_at_bot_quote, "is_at_bot_quote");
1810
1855
 
1811
1856
  // src/services/himg_func/himg_service.ts
1812
1857
  var import_axios2 = __toESM(require("axios"));
1813
- var import_koishi12 = require("koishi");
1858
+ var import_koishi13 = require("koishi");
1814
1859
  async function randomHImg(keywords, ...args) {
1815
1860
  try {
1816
1861
  const r18 = keywords?.[0];
@@ -1840,7 +1885,7 @@ async function randomHImg(keywords, ...args) {
1840
1885
  let author = item.author;
1841
1886
  let url = item.urls.regular;
1842
1887
  let tags2 = item.tags;
1843
- result_content += "作者: " + author + "\n标签: \n[" + tags2.join(",") + "]\n" + import_koishi12.h.image(url) + "\n";
1888
+ result_content += "作者: " + author + "\n标签: \n[" + tags2.join(",") + "]\n" + import_koishi13.h.image(url) + "\n";
1844
1889
  }
1845
1890
  return {
1846
1891
  result: result_content,
@@ -1897,7 +1942,7 @@ function registerHImgCommands(ctx) {
1897
1942
  __name(registerHImgCommands, "registerHImgCommands");
1898
1943
 
1899
1944
  // src/services/wish_func/wish_command.ts
1900
- var import_koishi13 = require("koishi");
1945
+ var import_koishi14 = require("koishi");
1901
1946
 
1902
1947
  // src/services/wish_func/wish_service.ts
1903
1948
  var chatHistory2 = [];
@@ -2272,9 +2317,9 @@ function registerWishCommands(ctx, yaml_config_path, ai_config, wish_config) {
2272
2317
  if (!exec_generation) return "愿望实现失败,请重新许愿";
2273
2318
  const imageResult = await renderWishImage(ctx, wish_content, exec_generation);
2274
2319
  if (typeof imageResult === "string") {
2275
- return (0, import_koishi13.h)("at", { id: session.userId }) + " " + imageResult + "\n" + exec_generation;
2320
+ return (0, import_koishi14.h)("at", { id: session.userId }) + " " + imageResult + "\n" + exec_generation;
2276
2321
  }
2277
- return (0, import_koishi13.h)("at", { id: session.userId }) + " 祈祷成功,愿梦想成真!\n" + import_koishi13.h.image(imageResult, "image/png");
2322
+ return (0, import_koishi14.h)("at", { id: session.userId }) + " 祈祷成功,愿梦想成真!\n" + import_koishi14.h.image(imageResult, "image/png");
2278
2323
  } finally {
2279
2324
  think_flag2 = false;
2280
2325
  }
@@ -2693,7 +2738,7 @@ function registerKuroCommands(ctx, connected) {
2693
2738
  __name(registerKuroCommands, "registerKuroCommands");
2694
2739
 
2695
2740
  // src/services/game_func/game_command.ts
2696
- var import_koishi14 = require("koishi");
2741
+ var import_koishi15 = require("koishi");
2697
2742
 
2698
2743
  // src/services/game_func/game_service.ts
2699
2744
  var gameTimeout = null;
@@ -3059,7 +3104,7 @@ async function situationPuzzleMiddleware(session, ai_config) {
3059
3104
  return checkResp(resp2);
3060
3105
  }
3061
3106
  const resp = await questSituationPuzzle(text, ai_config);
3062
- return (0, import_koishi14.h)("at", { id: userId }) + " " + checkResp(resp);
3107
+ return (0, import_koishi15.h)("at", { id: userId }) + " " + checkResp(resp);
3063
3108
  } finally {
3064
3109
  is_thinking = false;
3065
3110
  }
@@ -3074,7 +3119,7 @@ function checkResp(resp) {
3074
3119
  __name(checkResp, "checkResp");
3075
3120
 
3076
3121
  // src/services/sum_func/sum_command.ts
3077
- var import_koishi15 = require("koishi");
3122
+ var import_koishi16 = require("koishi");
3078
3123
 
3079
3124
  // src/services/sum_func/sum_service.ts
3080
3125
  var import_sequelize10 = require("sequelize");
@@ -3595,7 +3640,7 @@ function registerSumCommands(ctx, yaml_config_path, ai_config, sum_config) {
3595
3640
  const imageResult = await renderChatSummaryImage(ctx, exec.result, exec.hours, exec.stats, false);
3596
3641
  if (typeof imageResult === "string")
3597
3642
  return imageResult + "\n" + exec.result;
3598
- return import_koishi15.h.image(imageResult, "image/png");
3643
+ return import_koishi16.h.image(imageResult, "image/png");
3599
3644
  }
3600
3645
  return exec.result;
3601
3646
  });
@@ -3606,23 +3651,239 @@ function registerSumCommands(ctx, yaml_config_path, ai_config, sum_config) {
3606
3651
  }
3607
3652
  __name(registerSumCommands, "registerSumCommands");
3608
3653
 
3654
+ // src/services/jm_func/jm_service.ts
3655
+ var import_axios4 = __toESM(require("axios"));
3656
+ var import_fs4 = require("fs");
3657
+ var import_koishi17 = require("koishi");
3658
+ var guildActiveTasks = /* @__PURE__ */ new Map();
3659
+ function normalizeBaseUrl(apiUrl) {
3660
+ return apiUrl.replace(/\/+$/, "");
3661
+ }
3662
+ __name(normalizeBaseUrl, "normalizeBaseUrl");
3663
+ function buildHeaders(config) {
3664
+ const headers = {
3665
+ "Content-Type": "application/json"
3666
+ };
3667
+ if (config.api_key)
3668
+ headers["X-API-Key"] = config.api_key;
3669
+ return headers;
3670
+ }
3671
+ __name(buildHeaders, "buildHeaders");
3672
+ function getMaxConcurrent(config) {
3673
+ const max = config.max_concurrent_per_guild ?? 5;
3674
+ return max > 0 ? max : 5;
3675
+ }
3676
+ __name(getMaxConcurrent, "getMaxConcurrent");
3677
+ function registerTask(record, config) {
3678
+ const guildId = record.guildId;
3679
+ const list = guildActiveTasks.get(guildId) ?? [];
3680
+ if (list.length >= getMaxConcurrent(config))
3681
+ return false;
3682
+ list.push(record);
3683
+ guildActiveTasks.set(guildId, list);
3684
+ return true;
3685
+ }
3686
+ __name(registerTask, "registerTask");
3687
+ function updateTaskId(guildId, oldTaskId, newTaskId) {
3688
+ const list = guildActiveTasks.get(guildId);
3689
+ if (!list) return;
3690
+ const target = list.find((item) => item.taskId === oldTaskId);
3691
+ if (target)
3692
+ target.taskId = newTaskId;
3693
+ }
3694
+ __name(updateTaskId, "updateTaskId");
3695
+ function unregisterTask(guildId, taskId) {
3696
+ const list = guildActiveTasks.get(guildId);
3697
+ if (!list) return;
3698
+ const next = list.filter((item) => item.taskId !== taskId);
3699
+ if (next.length === 0)
3700
+ guildActiveTasks.delete(guildId);
3701
+ else
3702
+ guildActiveTasks.set(guildId, next);
3703
+ }
3704
+ __name(unregisterTask, "unregisterTask");
3705
+ function sleep(ms) {
3706
+ return new Promise((resolve) => setTimeout(resolve, ms));
3707
+ }
3708
+ __name(sleep, "sleep");
3709
+ async function submitDownload(albumId, config) {
3710
+ const baseUrl = normalizeBaseUrl(config.api_url || "http://127.0.0.1:6789");
3711
+ try {
3712
+ const response = await import_axios4.default.post(
3713
+ `${baseUrl}/api/download`,
3714
+ { album_id: albumId },
3715
+ { headers: buildHeaders(config), timeout: 3e4 }
3716
+ );
3717
+ return { ok: true, data: response.data };
3718
+ } catch (error) {
3719
+ const message = error?.response?.data?.detail ?? error?.response?.data?.message ?? error?.message ?? String(error);
3720
+ logger.error("[jm submitDownload Error]: " + message);
3721
+ return { ok: false, error: message };
3722
+ }
3723
+ }
3724
+ __name(submitDownload, "submitDownload");
3725
+ async function getTask(taskId, config) {
3726
+ const baseUrl = normalizeBaseUrl(config.api_url || "http://127.0.0.1:6789");
3727
+ try {
3728
+ const response = await import_axios4.default.get(
3729
+ `${baseUrl}/api/task/${taskId}`,
3730
+ { headers: buildHeaders(config), timeout: 3e4 }
3731
+ );
3732
+ return { ok: true, data: response.data };
3733
+ } catch (error) {
3734
+ const message = error?.response?.data?.detail ?? error?.response?.data?.message ?? error?.message ?? String(error);
3735
+ logger.error("[jm getTask Error]: " + message);
3736
+ return { ok: false, error: message };
3737
+ }
3738
+ }
3739
+ __name(getTask, "getTask");
3740
+ async function deleteAlbum(albumId, config) {
3741
+ const baseUrl = normalizeBaseUrl(config.api_url || "http://127.0.0.1:6789");
3742
+ try {
3743
+ await import_axios4.default.delete(
3744
+ `${baseUrl}/api/album/${albumId}`,
3745
+ { headers: buildHeaders(config), timeout: 3e4 }
3746
+ );
3747
+ logger.info(`[jm deleteAlbum Info]: album_id=${albumId} cleaned up`);
3748
+ } catch (error) {
3749
+ if (error?.response?.status === 404) {
3750
+ logger.info(`[jm deleteAlbum Info]: album_id=${albumId} no local files to delete`);
3751
+ return;
3752
+ }
3753
+ const message = error?.response?.data?.detail ?? error?.response?.data?.message ?? error?.message ?? String(error);
3754
+ logger.warn("[jm deleteAlbum Error]: " + message);
3755
+ }
3756
+ }
3757
+ __name(deleteAlbum, "deleteAlbum");
3758
+ async function readLocalPdf(pdfPath) {
3759
+ return import_fs4.promises.readFile(pdfPath);
3760
+ }
3761
+ __name(readLocalPdf, "readLocalPdf");
3762
+ async function notifyUser(bot, record, message) {
3763
+ await bot.sendMessage(record.channelId, message);
3764
+ }
3765
+ __name(notifyUser, "notifyUser");
3766
+ async function pollAndDeliver(bot, record, config) {
3767
+ const pollInterval = config.poll_interval_ms ?? 5e3;
3768
+ const pollTimeout = config.poll_timeout_ms ?? 18e5;
3769
+ const startedAt = Date.now();
3770
+ const deliver = /* @__PURE__ */ __name(async (message) => {
3771
+ await deleteAlbum(record.albumId, config);
3772
+ await notifyUser(bot, record, message);
3773
+ }, "deliver");
3774
+ try {
3775
+ while (true) {
3776
+ if (Date.now() - startedAt > pollTimeout) {
3777
+ await deliver(`${(0, import_koishi17.h)("at", { id: record.userId })} 下载超时,请稍后重试。`);
3778
+ return;
3779
+ }
3780
+ await sleep(pollInterval);
3781
+ const result = await getTask(record.taskId, config);
3782
+ if (!result.ok) {
3783
+ await deliver(`${(0, import_koishi17.h)("at", { id: record.userId })} 查询任务失败:${result.error}`);
3784
+ return;
3785
+ }
3786
+ const task = result.data;
3787
+ if (task.status === "pending" || task.status === "running")
3788
+ continue;
3789
+ if (task.status === "failed") {
3790
+ const errorMsg = task.error || task.message || "未知错误";
3791
+ logger.error(
3792
+ `[jm task Failed]: album_id=${record.albumId} task_id=${record.taskId} error=${errorMsg}`
3793
+ );
3794
+ await deliver(`${(0, import_koishi17.h)("at", { id: record.userId })} 下载失败:${errorMsg}`);
3795
+ return;
3796
+ }
3797
+ if (task.status === "success") {
3798
+ let message;
3799
+ try {
3800
+ const pdfPath = task.pdf_path;
3801
+ if (!pdfPath)
3802
+ throw new Error("任务成功但未返回文件路径");
3803
+ const pdfBuffer = await readLocalPdf(pdfPath);
3804
+ const filename = `${record.albumId}.pdf` || task.pdf_filename;
3805
+ message = [
3806
+ (0, import_koishi17.h)("at", { id: record.userId }),
3807
+ ` 本子[${record.albumId}]下载完成:`,
3808
+ import_koishi17.h.file(pdfBuffer, "application/pdf", { name: filename })
3809
+ ];
3810
+ } catch (error) {
3811
+ const errorMsg = error?.message || String(error);
3812
+ logger.error("[jm readLocalPdf Error]: " + errorMsg);
3813
+ message = `${(0, import_koishi17.h)("at", { id: record.userId })} 文件读取失败:${errorMsg}`;
3814
+ }
3815
+ await deliver(message);
3816
+ return;
3817
+ }
3818
+ }
3819
+ } finally {
3820
+ unregisterTask(record.guildId, record.taskId);
3821
+ }
3822
+ }
3823
+ __name(pollAndDeliver, "pollAndDeliver");
3824
+ async function startJmDownload(bot, record, config) {
3825
+ void pollAndDeliver(bot, record, config);
3826
+ }
3827
+ __name(startJmDownload, "startJmDownload");
3828
+
3829
+ // src/services/jm_func/jm_command.ts
3830
+ function registerJmCommands(ctx, jm_config) {
3831
+ ctx.command("jm <参数>", "提交禁漫本子下载任务").action(async ({ session }, ...args) => {
3832
+ if (!dev_mode) {
3833
+ if (!is_at_bot(session)) return;
3834
+ }
3835
+ const albumId = args?.[0]?.trim();
3836
+ if (!albumId)
3837
+ return "请提供正确格式,如:@bot jm [comic_id]";
3838
+ if (!/^\d+$/.test(albumId))
3839
+ return "comic_id 应为数字,如:@bot jm 123456";
3840
+ const guildId = session.guildId;
3841
+ const channelId = session.channelId;
3842
+ const userId = session.userId;
3843
+ if (!guildId || !channelId || !userId)
3844
+ return "无法获取群聊或用户信息";
3845
+ const maxConcurrent = jm_config.max_concurrent_per_guild ?? 5;
3846
+ const pendingTaskId = `pending-${Date.now()}-${userId}`;
3847
+ const record = {
3848
+ taskId: pendingTaskId,
3849
+ guildId,
3850
+ channelId,
3851
+ userId,
3852
+ albumId
3853
+ };
3854
+ if (!registerTask(record, jm_config))
3855
+ return `当前群聊已有${maxConcurrent}个下载任务进行中,请稍后再试`;
3856
+ const submitResult = await submitDownload(albumId, jm_config);
3857
+ if (!submitResult.ok) {
3858
+ unregisterTask(guildId, pendingTaskId);
3859
+ return `提交下载失败:${submitResult.error}`;
3860
+ }
3861
+ const taskId = submitResult.data.task_id;
3862
+ updateTaskId(guildId, pendingTaskId, taskId);
3863
+ startJmDownload(session.bot, record, jm_config);
3864
+ return `已收到本子[${albumId}]的下载请求,完成后会在此群@你。`;
3865
+ });
3866
+ }
3867
+ __name(registerJmCommands, "registerJmCommands");
3868
+
3609
3869
  // src/index.ts
3610
3870
  var name = "cocoyyy-console";
3611
3871
  var inject = { optional: ["puppeteer"] };
3612
3872
  var dev_mode;
3613
- var Config = import_koishi16.Schema.object({
3873
+ var Config = import_koishi18.Schema.object({
3614
3874
  function_config: FunctionConfigSchema.description("功能开关配置"),
3615
3875
  function_enable_config: GroupFunctionLimitConfigSchema.description("群聊功能限制配置"),
3616
3876
  ai_config: AiAPIConfigSchema.description("AI API配置"),
3617
- yaml_config_path: import_koishi16.Schema.string().default("").description("统一配置文件路径"),
3877
+ yaml_config_path: import_koishi18.Schema.string().default("").description("统一配置文件路径"),
3618
3878
  mysql_config: MysqlConfigSchema.description("MySQL 数据库配置"),
3619
3879
  tag_config: SaveConfigSchema.description("tag图片保存配置"),
3620
3880
  repeat_config: RepeatConfigSchema.description("复读配置"),
3621
3881
  wish_config: WishConfigSchema.description("许愿配置"),
3622
3882
  sum_config: SumConfigSchema.description("总结配置"),
3623
- test: import_koishi16.Schema.string().description("测试")
3883
+ jm_config: JmConfigSchema.description("禁漫下载配置"),
3884
+ test: import_koishi18.Schema.string().description("测试")
3624
3885
  });
3625
- var logger = new import_koishi16.Logger(name);
3886
+ var logger = new import_koishi18.Logger(name);
3626
3887
  var savePath = null;
3627
3888
  async function apply(ctx, config) {
3628
3889
  ctx = ctx.guild();
@@ -3640,26 +3901,38 @@ async function apply(ctx, config) {
3640
3901
  savePath = resolveTagBaseDir(config?.tag_config);
3641
3902
  loadGroupFunctionLimitConfig(config?.function_enable_config);
3642
3903
  registerMenuCommands(ctx, connected, config.function_config);
3643
- if (config.function_config.tag_flag)
3644
- registerTagCommands(ctx, connected, savePath);
3645
- if (config.function_config.repeat_flag)
3646
- registerRepeatMiddleware(ctx, config?.repeat_config);
3647
- if (config.function_config.son_flag)
3648
- registerShitOrNotCommands(ctx, config?.yaml_config_path, config?.ai_config);
3649
- if (config.function_config.setu_flag)
3650
- registerHImgCommands(ctx);
3651
- if (config.function_config.wish_flag)
3652
- registerWishCommands(ctx, config?.yaml_config_path, config?.ai_config, config?.wish_config);
3653
- if (config.function_config.game_flag) {
3654
- registerGameCommands(ctx, config?.yaml_config_path, config?.ai_config);
3655
- registerGameMiddleware(ctx, config?.ai_config);
3656
- }
3657
- if (config.function_config.rbq_flag)
3658
- registerRbqCommands(ctx, connected);
3659
- if (config.function_config)
3660
- registerKuroCommands(ctx, connected);
3661
- if (config.function_config.sum_flag)
3662
- registerSumCommands(ctx, config?.yaml_config_path, config?.ai_config, config?.sum_config);
3904
+ const tagCtx = getCtxForFunction(ctx, 1);
3905
+ if (config.function_config.tag_flag && tagCtx)
3906
+ registerTagCommands(tagCtx, connected, savePath);
3907
+ const repeatCtx = getCtxForFunction(ctx, 2);
3908
+ if (config.function_config.repeat_flag && repeatCtx)
3909
+ registerRepeatMiddleware(repeatCtx, config?.repeat_config);
3910
+ const rbqCtx = getCtxForFunction(ctx, 3);
3911
+ if (config.function_config.rbq_flag && rbqCtx)
3912
+ registerRbqCommands(rbqCtx, connected);
3913
+ const sonCtx = getCtxForFunction(ctx, 4);
3914
+ if (config.function_config.son_flag && sonCtx)
3915
+ registerShitOrNotCommands(sonCtx, config?.yaml_config_path, config?.ai_config);
3916
+ const setuCtx = getCtxForFunction(ctx, 5);
3917
+ if (config.function_config.setu_flag && setuCtx)
3918
+ registerHImgCommands(setuCtx);
3919
+ const wishCtx = getCtxForFunction(ctx, 6);
3920
+ if (config.function_config.wish_flag && wishCtx)
3921
+ registerWishCommands(wishCtx, config?.yaml_config_path, config?.ai_config, config?.wish_config);
3922
+ const gameCtx = getCtxForFunction(ctx, 7);
3923
+ if (config.function_config.game_flag && gameCtx) {
3924
+ registerGameCommands(gameCtx, config?.yaml_config_path, config?.ai_config);
3925
+ registerGameMiddleware(gameCtx, config?.ai_config);
3926
+ }
3927
+ const kuroCtx = getCtxForFunction(ctx, 8);
3928
+ if (config.function_config.kuro_flag && kuroCtx)
3929
+ registerKuroCommands(kuroCtx, connected);
3930
+ const sumCtx = getCtxForFunction(ctx, 9);
3931
+ if (config.function_config.sum_flag && sumCtx)
3932
+ registerSumCommands(sumCtx, config?.yaml_config_path, config?.ai_config, config?.sum_config);
3933
+ const jmCtx = getCtxForFunction(ctx, 10);
3934
+ if (config.function_config.jm_flag && jmCtx)
3935
+ registerJmCommands(jmCtx, config?.jm_config ?? {});
3663
3936
  if (dev_mode)
3664
3937
  registerTestCommands(ctx, config);
3665
3938
  }
@@ -1,4 +1,5 @@
1
1
  import * as my_config from '../config/config';
2
+ import { Context } from 'koishi';
2
3
  type GroupFunctionLimitItem = {
3
4
  group_id: string | number;
4
5
  menu_list: number[];
@@ -10,7 +11,17 @@ type MenuList = {
10
11
  description: string;
11
12
  };
12
13
  declare function loadGroupFunctionLimitConfig(config: my_config.GroupFunctionLimitConfig): boolean;
13
- export { groupFunctionLimitConfig, loadGroupFunctionLimitConfig };
14
+ /**
15
+ * 根据 groupFuncLimit.json 的 groupList 配置,为指定功能编号返回对应的 Koishi Context:
16
+ *
17
+ * - "#" 条目作为默认规则(适用于未在 groupList 中显式列出的所有群组)
18
+ * - 若默认规则允许该功能:返回排除了显式禁用该功能的群组的 ctx
19
+ * - 若默认规则不允许该功能:返回仅限显式允许该功能的群组的 ctx
20
+ * - 若没有任何群组允许该功能:返回 null(调用方应跳过注册)
21
+ * - 若未加载功能限制配置:直接返回原始 ctx(不加限制)
22
+ */
23
+ declare function getCtxForFunction(ctx: Context, menuNumber: number): Context | null;
24
+ export { groupFunctionLimitConfig, loadGroupFunctionLimitConfig, getCtxForFunction, };
14
25
  declare function getGroupFunctionLimitConfig(): GroupFunctionLimitItem[];
15
26
  declare function getMenuList(): MenuList[];
16
27
  export { getGroupFunctionLimitConfig, getMenuList, };
@@ -0,0 +1,4 @@
1
+ import { Context } from 'koishi';
2
+ import { JmConfig } from '../../config/config';
3
+ declare function registerJmCommands(ctx: Context, jm_config: JmConfig): void;
4
+ export { registerJmCommands, };
@@ -0,0 +1,34 @@
1
+ import { Bot } from 'koishi';
2
+ import { JmConfig } from '../../config/config';
3
+ type TaskStatus = 'pending' | 'running' | 'success' | 'failed';
4
+ interface DownloadResponse {
5
+ task_id: string;
6
+ status: TaskStatus;
7
+ album_id: string;
8
+ pdf_path?: string | null;
9
+ pdf_filename?: string | null;
10
+ error?: string | null;
11
+ message?: string;
12
+ }
13
+ interface JmTaskRecord {
14
+ taskId: string;
15
+ guildId: string;
16
+ channelId: string;
17
+ userId: string;
18
+ albumId: string;
19
+ }
20
+ declare function getActiveTaskCount(guildId: string): number;
21
+ declare function registerTask(record: JmTaskRecord, config: JmConfig): boolean;
22
+ declare function updateTaskId(guildId: string, oldTaskId: string, newTaskId: string): void;
23
+ declare function unregisterTask(guildId: string, taskId: string): void;
24
+ declare function submitDownload(albumId: string, config: JmConfig): Promise<{
25
+ ok: true;
26
+ data: DownloadResponse;
27
+ error?: undefined;
28
+ } | {
29
+ ok: false;
30
+ error: any;
31
+ data?: undefined;
32
+ }>;
33
+ declare function startJmDownload(bot: Bot, record: JmTaskRecord, config: JmConfig): Promise<void>;
34
+ export { DownloadResponse, JmTaskRecord, getActiveTaskCount, registerTask, submitDownload, startJmDownload, unregisterTask, updateTaskId, };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-cocoyyy-console",
3
3
  "description": "自用koishi插件,功能包含复读,记录黑历史,*人等",
4
- "version": "1.2.0-alpha.1",
4
+ "version": "1.2.0",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "contributors": [