koishi-plugin-starfx-bot 0.27.2 → 0.28.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.
package/lib/index.js CHANGED
@@ -5,6 +5,9 @@ var __getOwnPropNames = Object.getOwnPropertyNames;
5
5
  var __getProtoOf = Object.getPrototypeOf;
6
6
  var __hasOwnProp = Object.prototype.hasOwnProperty;
7
7
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
8
+ var __esm = (fn, res) => function __init() {
9
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
+ };
8
11
  var __commonJS = (cb, mod) => function __require() {
9
12
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
10
13
  };
@@ -30,106 +33,76 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
30
33
  ));
31
34
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
35
 
33
- // src/locales/zh-CN.yml
34
- var require_zh_CN = __commonJS({
35
- "src/locales/zh-CN.yml"(exports2, module2) {
36
- module2.exports = { commands: { roll: { messages: { noParam: "你问啥?", invalid: "你要不看看你说的是啥", "too-many": "太、太多了啦!", noodles: "扔出了{num}个{noodles}面的骰子,点数如下:{points}", possibility: "{param}是{possibility}%", choose: "当然是{option}啦!" } }, "room-number": { messages: { roomNumber: "当前的房间号是: {room}", changeRoom: "已将当前房间号 {oldRoom} 修改为 {newRoom}", newRoom: "已添加房间号: {room}", noRoom: "当前没有保存的房间", delRoom: "已删除房间: {room}", invalid: "无效输入" } }, forward: { messages: { delete: "已删除转发群聊: {gid}", noTarget: "未配置转发群组", success: "已转发消息到: {target}", noMessage: "请引用要转发的消息", setOK: "已配置转发: {target}", forwardContent: "[转发消息]<br/> {content}" } }, "waiting-play": { messages: { addReady: "已添加,当前待机{num}人: <br/>{list}", delReady: "已删除,当前待机{num}人: <br/>{list}", delFailed: "未删除,当前待机{num}人: <br/>{list}", clearReady: "待机列表已清空", listReady: "当前待机{num}人: <br/>{list}", invalid: "输入无效" } }, 开启车牌检测: { messages: { success: "车牌检测:已打开\n当前车牌位数: {length}", noPermission: "你没有权限开启车牌检测", noGuild: "请在群聊中使用该指令", invalidLength: "位数设定不合理,请输入 1-20 之间的数字" } }, 关闭车牌检测: { messages: { success: "已关闭车牌检测", noPermission: "你没有权限关闭车牌检测", noGuild: "请在群聊中使用该指令" } }, 车牌检测状态: { messages: { enabled: "车牌检测: 已打开\n当前车牌位数: {length}", disabled: "车牌检测: 已关闭", managerEnabled: "管理员权限正常", managerDisabled: "无管理员权限,无法修改群名", noPermission: "你没有权限查看车牌检测状态", noGuild: "请在群聊中使用该指令" } }, 车牌检测权限: { messages: { status: { enabled: "普通群员开关车牌检测: 允许", disabled: "普通群员开关车牌检测: 禁止" }, enabled: "已允许普通群员开关车牌检测", disabled: "已禁止普通群员开关车牌检测", invalid: "无效输入,请输入 开 / 关", noPermission: "你没有权限设置车牌检测权限", noGuild: "请在群聊中使用该指令" } } }, middleware: { messages: { atNotReply: "艾特我又不说话", atNotReplyOther: "艾特他又不说话", notBot: "我才不是机器人!", loveMessage: "我喜欢你", iLoveU: "我也喜欢你", notManager: "当前bot没有管理员权限,无法修改群名", editFuncNotFound: "无法找到设置群名的底层方法", editGroupNameSuccess: "检测到车牌 {content},群名修改成功!", editGroupNameRetrySuccess: '检测到车牌 {content},由于限制已修改为 "{spacedContent}"' } } };
37
- }
38
- });
39
-
40
- // src/index.ts
41
- var src_exports = {};
42
- __export(src_exports, {
43
- Config: () => Config,
44
- apply: () => apply,
45
- assetsDir: () => assetsDir,
46
- baseDir: () => baseDir,
47
- inject: () => inject,
48
- name: () => name,
49
- repeatContextMap: () => repeatContextMap,
50
- starfxLogger: () => starfxLogger,
51
- usage: () => usage
52
- });
53
- module.exports = __toCommonJS(src_exports);
54
- var fs2 = __toESM(require("node:fs"));
55
- var import_node_path4 = __toESM(require("node:path"));
56
- var import_koishi5 = require("koishi");
57
- var import_mime_types = __toESM(require("mime-types"));
58
-
59
36
  // package.json
60
- var package_default = {
61
- name: "koishi-plugin-starfx-bot",
62
- description: "StarFreedomX机器人的小功能,自用",
63
- contributors: [
64
- "StarFreedomX <starfreedomx@outlook.com>"
65
- ],
66
- version: "0.27.2",
67
- main: "lib/index.js",
68
- typings: "lib/index.d.ts",
69
- files: [
70
- "lib",
71
- "dist",
72
- "assets"
73
- ],
74
- license: "MIT",
75
- homepage: "https://github.com/StarFreedomX/starfx-bot",
76
- repository: {
77
- type: "git",
78
- url: "git+https://github.com/StarFreedomX/starfx-bot.git"
79
- },
80
- keywords: [
81
- "chatbot",
82
- "koishi",
83
- "plugin"
84
- ],
85
- koishi: {
86
- description: {
87
- zh: "starfx的机器人小插件,目前支持: 明日方舟封印功能 闲鱼“卖掉了”功能 艾特我/他又不说话 我才不是机器人! 我也喜欢你! BanG Dream!边框绘制 群语录 roll 待机人数记录 房间号记录 推特查看原图 复读 echo 撤回 查汇率 黑白名单配置"
88
- },
89
- service: {
90
- optional: [
91
- "skia",
92
- "QhzySharp"
93
- ]
94
- },
95
- preview: true,
96
- hidden: false
97
- },
98
- peerDependencies: {
99
- koishi: "^4.18.7"
100
- },
101
- dependencies: {
102
- axios: "^1.15.0",
103
- "chart.js": "^4.5.1",
104
- "chartjs-adapter-dayjs-3": "^1.2.3",
105
- cheerio: "^1.0.0",
106
- dayjs: "^1.11.19",
107
- "http-proxy-agent": "^7.0.2",
108
- "https-proxy-agent": "^7.0.6",
109
- "mime-types": "^3.0.1",
110
- "rss-parser": "^3.13.0"
111
- },
112
- devDependencies: {
113
- "@biomejs/biome": "2.3.7",
114
- "@ltxhhz/koishi-plugin-skia-canvas": "^0.0.10",
115
- "@quanhuzeyu/koishi-plugin-qhzy-sharp": "^1.2.1",
116
- "@quanhuzeyu/sharp-for-koishi": "^0.0.7",
117
- "@types/mime-types": "^3.0.1"
37
+ var package_default;
38
+ var init_package = __esm({
39
+ "package.json"() {
40
+ package_default = {
41
+ name: "koishi-plugin-starfx-bot",
42
+ description: "StarFreedomX机器人的小功能,自用",
43
+ contributors: [
44
+ "StarFreedomX <starfreedomx@outlook.com>"
45
+ ],
46
+ version: "0.28.0",
47
+ main: "lib/index.js",
48
+ typings: "lib/index.d.ts",
49
+ files: [
50
+ "lib",
51
+ "dist",
52
+ "assets"
53
+ ],
54
+ license: "MIT",
55
+ homepage: "https://github.com/StarFreedomX/starfx-bot",
56
+ repository: {
57
+ type: "git",
58
+ url: "git+https://github.com/StarFreedomX/starfx-bot.git"
59
+ },
60
+ keywords: [
61
+ "chatbot",
62
+ "koishi",
63
+ "plugin"
64
+ ],
65
+ koishi: {
66
+ description: {
67
+ zh: "starfx的机器人小插件,目前支持: 明日方舟封印功能 闲鱼“卖掉了”功能 艾特我/他又不说话 我才不是机器人! 我也喜欢你! BanG Dream!边框绘制 群语录 roll 待机人数记录 房间号记录 推特查看原图 复读 echo 撤回 查汇率 黑白名单配置"
68
+ },
69
+ service: {
70
+ optional: [
71
+ "skia",
72
+ "QhzySharp"
73
+ ]
74
+ },
75
+ preview: true,
76
+ hidden: false
77
+ },
78
+ peerDependencies: {
79
+ koishi: "^4.18.7"
80
+ },
81
+ dependencies: {
82
+ axios: "^1.15.0",
83
+ "chart.js": "^4.5.1",
84
+ "chartjs-adapter-dayjs-3": "^1.2.3",
85
+ cheerio: "^1.0.0",
86
+ dayjs: "^1.11.19",
87
+ "http-proxy-agent": "^7.0.2",
88
+ "https-proxy-agent": "^7.0.6",
89
+ "mime-types": "^3.0.1",
90
+ "rss-parser": "^3.13.0"
91
+ },
92
+ devDependencies: {
93
+ "@biomejs/biome": "2.3.7",
94
+ "@ltxhhz/koishi-plugin-skia-canvas": "^0.0.10",
95
+ "@quanhuzeyu/koishi-plugin-qhzy-sharp": "^1.2.1",
96
+ "@quanhuzeyu/sharp-for-koishi": "^0.0.7",
97
+ "@types/mime-types": "^3.0.1"
98
+ }
99
+ };
118
100
  }
119
- };
101
+ });
120
102
 
121
103
  // src/plugins/currencySearch.ts
122
- var import_node_path = __toESM(require("node:path"));
123
- var import_chart = require("chart.js");
124
- var cheerio = __toESM(require("cheerio"));
125
- var import_koishi = require("koishi");
126
- import_chart.Chart.register(...import_chart.registerables);
127
- var mvpAPIKey;
128
- var currencyCodes = [];
129
- var currencyCodesMap = {};
130
104
  async function intervalGetExchangeRate(_ctx, _cfg, _session, _searchString, _exchangeRatePath) {
131
105
  }
132
- __name(intervalGetExchangeRate, "intervalGetExchangeRate");
133
106
  async function parseNaturalCurrency(searchString) {
134
107
  const index = await getCurrencyCodesMap();
135
108
  const s = searchString.replace(/\s+/g, "");
@@ -146,7 +119,6 @@ async function parseNaturalCurrency(searchString) {
146
119
  }
147
120
  return null;
148
121
  }
149
- __name(parseNaturalCurrency, "parseNaturalCurrency");
150
122
  async function getExchangeRate(ctx, cfg, session, searchString, raw, retryTimes = 1) {
151
123
  const apiKey = retryTimes ? await getMvpAPIKey() : await updateMvpAPIKey();
152
124
  try {
@@ -250,7 +222,6 @@ ${item.name}
250
222
  }
251
223
  }
252
224
  }
253
- __name(getExchangeRate, "getExchangeRate");
254
225
  async function mergeBuffersVertical(ctx2, buf1, buf2) {
255
226
  const { Canvas, loadImage } = ctx2.skia;
256
227
  const img1 = await loadImage(buf1);
@@ -263,7 +234,6 @@ async function mergeBuffersVertical(ctx2, buf1, buf2) {
263
234
  ctx.drawImage(img2, 0, img1.height);
264
235
  return await canvas.toBuffer("png");
265
236
  }
266
- __name(mergeBuffersVertical, "mergeBuffersVertical");
267
237
  async function updateMvpAPIKey() {
268
238
  try {
269
239
  const htmlResp = await fetch(
@@ -315,11 +285,9 @@ async function updateMvpAPIKey() {
315
285
  return null;
316
286
  }
317
287
  }
318
- __name(updateMvpAPIKey, "updateMvpAPIKey");
319
288
  async function getMvpAPIKey() {
320
289
  return mvpAPIKey ? mvpAPIKey : updateMvpAPIKey();
321
290
  }
322
- __name(getMvpAPIKey, "getMvpAPIKey");
323
291
  async function getExchangeGuids(symbols, apikey) {
324
292
  try {
325
293
  const url = `https://assets.msn.cn/service/Finance/IdMap?apikey=${apikey}&MStarIds=${encodeURIComponent(symbols)}`;
@@ -335,7 +303,6 @@ async function getExchangeGuids(symbols, apikey) {
335
303
  return [];
336
304
  }
337
305
  }
338
- __name(getExchangeGuids, "getExchangeGuids");
339
306
  async function getQuotes(ids, apiKey) {
340
307
  try {
341
308
  const url = `https://assets.msn.com/service/Finance/Quotes?apikey=${encodeURIComponent(apiKey)}&cm=zh-cn&it=edgeid&ids=${encodeURIComponent(ids)}&wrapodata=false`;
@@ -376,7 +343,6 @@ async function getQuotes(ids, apiKey) {
376
343
  return [];
377
344
  }
378
345
  }
379
- __name(getQuotes, "getQuotes");
380
346
  async function getMSNPrices(ids, apiKey, type = "1M1H") {
381
347
  const url = `https://assets.msn.com/service/Finance/QuoteSummary?apikey=${apiKey}&ids=${ids}&intents=Charts,Exchanges&type=${type}&wrapodata=false`;
382
348
  const res = await fetch(url);
@@ -398,7 +364,6 @@ async function getMSNPrices(ids, apiKey, type = "1M1H") {
398
364
  }
399
365
  );
400
366
  }
401
- __name(getMSNPrices, "getMSNPrices");
402
367
  async function drawCurrencyChartSkia(ctx, prices, timeStamps, title = "兑换汇率", width = 1200, height = 600) {
403
368
  if (!prices.length || !timeStamps.length || prices.length !== timeStamps.length)
404
369
  return;
@@ -474,19 +439,16 @@ async function drawCurrencyChartSkia(ctx, prices, timeStamps, title = "兑换汇
474
439
  });
475
440
  return await canvas.toBuffer("png");
476
441
  }
477
- __name(drawCurrencyChartSkia, "drawCurrencyChartSkia");
478
442
  async function getCurrencyCodes() {
479
443
  if (currencyCodes?.length) return currencyCodes;
480
444
  currencyCodes = require(import_node_path.default.resolve(assetsDir, "./currency.json"));
481
445
  return currencyCodes;
482
446
  }
483
- __name(getCurrencyCodes, "getCurrencyCodes");
484
447
  async function getCurrencyCodesMap() {
485
448
  if (Object.keys(currencyCodesMap)?.length) return currencyCodesMap;
486
449
  currencyCodesMap = await buildCurrencyIndex();
487
450
  return currencyCodesMap;
488
451
  }
489
- __name(getCurrencyCodesMap, "getCurrencyCodesMap");
490
452
  async function buildCurrencyIndex() {
491
453
  const map = {};
492
454
  (await getCurrencyCodes()).forEach((c) => {
@@ -498,18 +460,34 @@ async function buildCurrencyIndex() {
498
460
  map.港币 = "HKD";
499
461
  return map;
500
462
  }
501
- __name(buildCurrencyIndex, "buildCurrencyIndex");
502
-
503
- // src/plugins/drawHead.ts
504
- var fsp = __toESM(require("node:fs/promises"));
505
- var import_node_path3 = __toESM(require("node:path"));
506
- var import_koishi3 = require("koishi");
463
+ var import_node_path, import_chart, cheerio, import_koishi, mvpAPIKey, currencyCodes, currencyCodesMap;
464
+ var init_currencySearch = __esm({
465
+ "src/plugins/currencySearch.ts"() {
466
+ import_node_path = __toESM(require("node:path"));
467
+ import_chart = require("chart.js");
468
+ cheerio = __toESM(require("cheerio"));
469
+ import_koishi = require("koishi");
470
+ init_src();
471
+ import_chart.Chart.register(...import_chart.registerables);
472
+ currencyCodes = [];
473
+ currencyCodesMap = {};
474
+ __name(intervalGetExchangeRate, "intervalGetExchangeRate");
475
+ __name(parseNaturalCurrency, "parseNaturalCurrency");
476
+ __name(getExchangeRate, "getExchangeRate");
477
+ __name(mergeBuffersVertical, "mergeBuffersVertical");
478
+ __name(updateMvpAPIKey, "updateMvpAPIKey");
479
+ __name(getMvpAPIKey, "getMvpAPIKey");
480
+ __name(getExchangeGuids, "getExchangeGuids");
481
+ __name(getQuotes, "getQuotes");
482
+ __name(getMSNPrices, "getMSNPrices");
483
+ __name(drawCurrencyChartSkia, "drawCurrencyChartSkia");
484
+ __name(getCurrencyCodes, "getCurrencyCodes");
485
+ __name(getCurrencyCodesMap, "getCurrencyCodesMap");
486
+ __name(buildCurrencyIndex, "buildCurrencyIndex");
487
+ }
488
+ });
507
489
 
508
490
  // src/utils.ts
509
- var import_node_fs = __toESM(require("node:fs"));
510
- var import_node_path2 = __toESM(require("node:path"));
511
- var import_koishi2 = require("koishi");
512
- var import_chartjs_adapter_dayjs_3 = require("chartjs-adapter-dayjs-3");
513
491
  async function addRecord(ctx, gid, avatarUrl) {
514
492
  const recordDir = `${assetsDir}/record/${gid}`;
515
493
  const avatarBuffer = await ctx.http.get(avatarUrl, {
@@ -518,7 +496,6 @@ async function addRecord(ctx, gid, avatarUrl) {
518
496
  saveImage(avatarBuffer, recordDir);
519
497
  return "投稿收到啦";
520
498
  }
521
- __name(addRecord, "addRecord");
522
499
  async function getRecord(cfg, gid, tag) {
523
500
  const links = structuredClone(cfg.recordLink);
524
501
  links[gid] = { linkGroup: gid, linkWeight: 100 };
@@ -545,7 +522,6 @@ async function getRecord(cfg, gid, tag) {
545
522
  }
546
523
  return null;
547
524
  }
548
- __name(getRecord, "getRecord");
549
525
  function getRandomLinkGroup(record) {
550
526
  const entries = Object.values(record);
551
527
  const totalWeight = entries.reduce((sum, item) => sum + item.linkWeight, 0);
@@ -558,7 +534,6 @@ function getRandomLinkGroup(record) {
558
534
  }
559
535
  return entries[entries.length - 1].linkGroup;
560
536
  }
561
- __name(getRandomLinkGroup, "getRandomLinkGroup");
562
537
  function getTodayPrefix() {
563
538
  const now = /* @__PURE__ */ new Date();
564
539
  const yyyy = now.getFullYear();
@@ -566,7 +541,6 @@ function getTodayPrefix() {
566
541
  const dd = String(now.getDate()).padStart(2, "0");
567
542
  return `${yyyy}${mm}${dd}`;
568
543
  }
569
- __name(getTodayPrefix, "getTodayPrefix");
570
544
  function getNextSequenceNumber(directory, prefix, suffix = "jpg") {
571
545
  const files = import_node_fs.default.existsSync(directory) ? import_node_fs.default.readdirSync(directory) : [];
572
546
  const regex = new RegExp(`^${prefix}-(\\d+)\\.${suffix}$`);
@@ -582,7 +556,6 @@ function getNextSequenceNumber(directory, prefix, suffix = "jpg") {
582
556
  });
583
557
  return maxNum + 1;
584
558
  }
585
- __name(getNextSequenceNumber, "getNextSequenceNumber");
586
559
  function saveImage(arrayBuffer, directory, filename) {
587
560
  if (!filename) {
588
561
  const prefix = getTodayPrefix();
@@ -597,37 +570,58 @@ function saveImage(arrayBuffer, directory, filename) {
597
570
  import_node_fs.default.writeFileSync(filepath, buffer);
598
571
  console.log(`已保存图片:${filepath}`);
599
572
  }
600
- __name(saveImage, "saveImage");
601
573
  async function getImageSrc(session, param, option) {
602
- const number = option?.number ?? true, img = option?.img ?? true, at = option?.at ?? true, noParam = option?.noParam ?? true, quote = option?.quote ?? true;
603
- if (number && param?.length && /^\d+$/.test(param)) {
604
- return `https://q1.qlogo.cn/g?b=qq&nk=${param}&s=640`;
605
- } else if (noParam && !param?.length) {
606
- return `https://q1.qlogo.cn/g?b=qq&nk=${session.userId}&s=640`;
607
- }
608
- if (quote) {
609
- const quoteElementArray = session?.quote?.elements;
610
- if (quoteElementArray?.length) {
611
- for (const element of quoteElementArray) {
612
- if (img && element?.type === "img") {
613
- return element?.attrs?.src;
614
- } else if (at && element?.type === "at" && element?.attrs?.id && element.attrs.id !== session.selfId) {
615
- return `https://q1.qlogo.cn/g?b=qq&nk=${element?.attrs?.id}&s=640`;
616
- }
574
+ const {
575
+ number = true,
576
+ img = true,
577
+ at = true,
578
+ noParam = true,
579
+ quote = true
580
+ } = option ?? {};
581
+ if (number && /^\d+$/.test(param)) {
582
+ const avatar = await getHeadUrlById(session, param);
583
+ if (avatar) return avatar;
584
+ }
585
+ if (noParam && !param?.length) {
586
+ const avatar = await getHeadUrlById(session, session.userId);
587
+ if (avatar) return avatar;
588
+ }
589
+ const findSrcInElements = /* @__PURE__ */ __name(async (elements, skipSelfAt = false) => {
590
+ if (!elements?.length) return null;
591
+ let list = elements;
592
+ if (skipSelfAt) {
593
+ const startIdx = list.findIndex(
594
+ (el) => !(el?.type === "at" && el?.attrs?.id === session.selfId)
595
+ );
596
+ list = startIdx === -1 ? [] : list.slice(startIdx);
597
+ }
598
+ for (const el of list) {
599
+ if (img && el?.type === "img" && el?.attrs?.src) {
600
+ return el.attrs.src;
601
+ }
602
+ if (at && el?.type === "at" && el?.attrs?.id && el.attrs.id !== session.selfId) {
603
+ const avatar = await getHeadUrlById(session, el.attrs.id);
604
+ if (avatar) return avatar;
617
605
  }
618
606
  }
607
+ return null;
608
+ }, "findSrcInElements");
609
+ if (quote) {
610
+ const avatar = await findSrcInElements(session?.quote?.elements);
611
+ if (avatar) return avatar;
619
612
  }
620
- const elementArray = session.elements;
621
- for (const element of elementArray) {
622
- if (img && element?.type === "img") {
623
- return element?.attrs?.src;
624
- } else if (at && element?.type === "at" && element?.attrs?.id) {
625
- return `https://q1.qlogo.cn/g?b=qq&nk=${element.attrs.id}&s=640`;
626
- }
613
+ return await findSrcInElements(session?.elements, true) ?? "";
614
+ }
615
+ async function getHeadUrlById(session, id) {
616
+ switch (session.platform) {
617
+ case "onebot":
618
+ return `https://q1.qlogo.cn/g?b=qq&nk=${id}&s=640`;
619
+ case "qq":
620
+ return `https://thirdqq.qlogo.cn/qqapp/${session.selfId}/${id}/640`;
621
+ default:
622
+ return (await session.bot.getUser(id)).avatar || "";
627
623
  }
628
- return "";
629
624
  }
630
- __name(getImageSrc, "getImageSrc");
631
625
  async function getImageFromUrl(ctx, url) {
632
626
  if (!url) throw new Error("URL must be provided");
633
627
  const sharp = getSharpConstructor(ctx);
@@ -647,7 +641,6 @@ async function getImageFromUrl(ctx, url) {
647
641
  throw new Error("Get image failed");
648
642
  }
649
643
  }
650
- __name(getImageFromUrl, "getImageFromUrl");
651
644
  async function atNotSayReply(cfg, session, elements) {
652
645
  const trimElements = elements.filter(
653
646
  (e) => !(e.type === "text" && /^\s*$/.test(e.attrs.content))
@@ -661,7 +654,6 @@ async function atNotSayReply(cfg, session, elements) {
661
654
  }
662
655
  }
663
656
  }
664
- __name(atNotSayReply, "atNotSayReply");
665
657
  async function replyBot(cfg, session, elements) {
666
658
  if (cfg.replyBot !== "关闭") {
667
659
  const bots = ["bot", "机器人", "Bot", "BOT", "机器人!", "机器人!", "人机"];
@@ -674,7 +666,6 @@ async function replyBot(cfg, session, elements) {
674
666
  }
675
667
  }
676
668
  }
677
- __name(replyBot, "replyBot");
678
669
  async function iLoveYou(cfg, session, elements) {
679
670
  if (cfg.iLoveYou) {
680
671
  const hasAtMe = elements?.some(
@@ -693,7 +684,6 @@ async function iLoveYou(cfg, session, elements) {
693
684
  }
694
685
  }
695
686
  }
696
- __name(iLoveYou, "iLoveYou");
697
687
  function parseFeatureControl(array) {
698
688
  try {
699
689
  return Object.fromEntries(
@@ -712,7 +702,6 @@ function parseFeatureControl(array) {
712
702
  return {};
713
703
  }
714
704
  }
715
- __name(parseFeatureControl, "parseFeatureControl");
716
705
  function detectControl(controlJson, guildId, funName) {
717
706
  const rule = controlJson?.[funName];
718
707
  if (!rule || rule.whitelist === void 0 || !Array.isArray(rule.groups)) {
@@ -721,7 +710,6 @@ function detectControl(controlJson, guildId, funName) {
721
710
  const inList = rule.groups.includes(Number(guildId));
722
711
  return rule.whitelist ? inList : !inList;
723
712
  }
724
- __name(detectControl, "detectControl");
725
713
  function handleRoll(session) {
726
714
  const elements = session.elements;
727
715
  const parts = [];
@@ -767,7 +755,6 @@ function handleRoll(session) {
767
755
  }
768
756
  return session.text(".noParam");
769
757
  }
770
- __name(handleRoll, "handleRoll");
771
758
  function getPoints(session, num, noodles) {
772
759
  if (!Number.isInteger(num) || !Number.isInteger(noodles) || num <= 0 || noodles <= 0)
773
760
  return session.text(".invalid");
@@ -779,7 +766,6 @@ function getPoints(session, num, noodles) {
779
766
  points: points.join(", ")
780
767
  });
781
768
  }
782
- __name(getPoints, "getPoints");
783
769
  async function undo(_cfg, session) {
784
770
  if (session?.quote?.id && session.quote.user.id === session.selfId && Date.now() - session.quote.timestamp < 2 * 60 * 1e3 - 5 * 1e3) {
785
771
  await session.bot.deleteMessage(
@@ -788,7 +774,6 @@ async function undo(_cfg, session) {
788
774
  );
789
775
  }
790
776
  }
791
- __name(undo, "undo");
792
777
  function safeQuote(str, useQuote) {
793
778
  let unquoted = str.trim();
794
779
  if (unquoted.startsWith('"')) {
@@ -803,7 +788,6 @@ function safeQuote(str, useQuote) {
803
788
  return unquoted;
804
789
  }
805
790
  }
806
- __name(safeQuote, "safeQuote");
807
791
  function writeMap(map, dest) {
808
792
  const dir = import_node_path2.default.dirname(dest);
809
793
  if (!import_node_fs.default.existsSync(dir)) {
@@ -811,7 +795,6 @@ function writeMap(map, dest) {
811
795
  }
812
796
  import_node_fs.default.writeFileSync(dest, JSON.stringify([...map], null, 2), "utf-8");
813
797
  }
814
- __name(writeMap, "writeMap");
815
798
  function readMap(url) {
816
799
  if (!import_node_fs.default.existsSync(url)) {
817
800
  const map = /* @__PURE__ */ new Map();
@@ -821,7 +804,6 @@ function readMap(url) {
821
804
  const mapArray = JSON.parse(raw);
822
805
  return new Map(mapArray);
823
806
  }
824
- __name(readMap, "readMap");
825
807
  function ready(session, cfg, param, readyMap) {
826
808
  const nowReadyMap = cfg.saveReadyAsFile ? readMap(cfg.saveReadyAsFile) : readyMap;
827
809
  let strArr = nowReadyMap.get(session.gid) ?? [];
@@ -855,17 +837,17 @@ function ready(session, cfg, param, readyMap) {
855
837
  writeMap(nowReadyMap, cfg.saveReadyAsFile);
856
838
  return returnMessage;
857
839
  }
858
- __name(ready, "ready");
859
840
  function getSharpConstructor(ctx) {
860
841
  const raw = ctx.QhzySharp?.Sharp;
861
842
  if (!raw) throw new Error("Sharp Service 尚未就绪");
862
843
  const sharpConstructor = typeof raw === "function" ? raw : raw.default;
863
844
  if (typeof sharpConstructor !== "function") {
864
- throw new Error("无法获取 Sharp 构造函数,请尝试重启 Koishi 或检查 w-node 状态");
845
+ throw new Error(
846
+ "无法获取 Sharp 构造函数,请尝试重启 Koishi 或检查 w-node 状态"
847
+ );
865
848
  }
866
849
  return sharpConstructor;
867
850
  }
868
- __name(getSharpConstructor, "getSharpConstructor");
869
851
  async function getAuthority(session) {
870
852
  const user = await session.observeUser(["authority"]);
871
853
  const authority = user?.authority || 0;
@@ -874,22 +856,59 @@ async function getAuthority(session) {
874
856
  );
875
857
  return { authority, roles };
876
858
  }
877
- __name(getAuthority, "getAuthority");
878
859
  async function canBotManage(session) {
879
860
  try {
880
- const selfMember = await session.bot.getGuildMember(session.guildId, session.selfId);
881
- const roles = (selfMember.roles || []).map((r) => typeof r === "string" ? r : r.id);
861
+ const selfMember = await session.bot.getGuildMember(
862
+ session.guildId,
863
+ session.selfId
864
+ );
865
+ const roles = (selfMember.roles || []).map(
866
+ (r) => typeof r === "string" ? r : r.id
867
+ );
882
868
  return roles.includes("admin") || roles.includes("owner");
883
869
  } catch (e) {
884
870
  return false;
885
871
  }
886
872
  }
887
- __name(canBotManage, "canBotManage");
888
873
  async function canGrant(session) {
889
874
  const { authority, roles } = await getAuthority(session);
890
875
  return authority > 1 || roles.includes("admin") || roles.includes("owner");
891
876
  }
892
- __name(canGrant, "canGrant");
877
+ var import_node_fs, import_node_path2, import_koishi2, import_chartjs_adapter_dayjs_3;
878
+ var init_utils = __esm({
879
+ "src/utils.ts"() {
880
+ import_node_fs = __toESM(require("node:fs"));
881
+ import_node_path2 = __toESM(require("node:path"));
882
+ import_koishi2 = require("koishi");
883
+ init_src();
884
+ import_chartjs_adapter_dayjs_3 = require("chartjs-adapter-dayjs-3");
885
+ __name(addRecord, "addRecord");
886
+ __name(getRecord, "getRecord");
887
+ __name(getRandomLinkGroup, "getRandomLinkGroup");
888
+ __name(getTodayPrefix, "getTodayPrefix");
889
+ __name(getNextSequenceNumber, "getNextSequenceNumber");
890
+ __name(saveImage, "saveImage");
891
+ __name(getImageSrc, "getImageSrc");
892
+ __name(getHeadUrlById, "getHeadUrlById");
893
+ __name(getImageFromUrl, "getImageFromUrl");
894
+ __name(atNotSayReply, "atNotSayReply");
895
+ __name(replyBot, "replyBot");
896
+ __name(iLoveYou, "iLoveYou");
897
+ __name(parseFeatureControl, "parseFeatureControl");
898
+ __name(detectControl, "detectControl");
899
+ __name(handleRoll, "handleRoll");
900
+ __name(getPoints, "getPoints");
901
+ __name(undo, "undo");
902
+ __name(safeQuote, "safeQuote");
903
+ __name(writeMap, "writeMap");
904
+ __name(readMap, "readMap");
905
+ __name(ready, "ready");
906
+ __name(getSharpConstructor, "getSharpConstructor");
907
+ __name(getAuthority, "getAuthority");
908
+ __name(canBotManage, "canBotManage");
909
+ __name(canGrant, "canGrant");
910
+ }
911
+ });
893
912
 
894
913
  // src/plugins/drawHead.ts
895
914
  async function handleBanGDreamConfig(options) {
@@ -1017,18 +1036,17 @@ async function handleBanGDreamConfig(options) {
1017
1036
  }
1018
1037
  return drawConfig;
1019
1038
  }
1020
- __name(handleBanGDreamConfig, "handleBanGDreamConfig");
1021
1039
  async function drawLock(ctx, baseImage) {
1022
1040
  let image;
1023
1041
  try {
1024
1042
  image = await getImageFromUrl(ctx, baseImage);
1025
- } catch (error) {
1026
- if (error.message === "Get image failed") {
1043
+ } catch (error2) {
1044
+ if (error2.message === "Get image failed") {
1027
1045
  return "发生错误";
1028
- } else if (error.message === "URL must be provided") {
1046
+ } else if (error2.message === "URL must be provided") {
1029
1047
  return "输入无效";
1030
1048
  } else {
1031
- console.error(error.message);
1049
+ console.error(error2.message);
1032
1050
  }
1033
1051
  }
1034
1052
  const sharp = getSharpConstructor(ctx);
@@ -1041,18 +1059,17 @@ async function drawLock(ctx, baseImage) {
1041
1059
  image.composite([{ input: await overlay.toBuffer() }]);
1042
1060
  return import_koishi3.h.image(await image.png().toBuffer(), "image/png");
1043
1061
  }
1044
- __name(drawLock, "drawLock");
1045
1062
  async function drawSold(ctx, baseImage) {
1046
1063
  let image;
1047
1064
  try {
1048
1065
  image = await getImageFromUrl(ctx, baseImage);
1049
- } catch (error) {
1050
- if (error.message === "Get image failed") {
1066
+ } catch (error2) {
1067
+ if (error2.message === "Get image failed") {
1051
1068
  return "发生错误";
1052
- } else if (error.message === "URL must be provided") {
1069
+ } else if (error2.message === "URL must be provided") {
1053
1070
  return "输入无效";
1054
1071
  } else {
1055
- console.error(error.message);
1072
+ console.error(error2.message);
1056
1073
  }
1057
1074
  }
1058
1075
  const sharp = getSharpConstructor(ctx);
@@ -1085,7 +1102,6 @@ async function drawSold(ctx, baseImage) {
1085
1102
  ]);
1086
1103
  return import_koishi3.h.image(await image.png().toBuffer(), "image/png");
1087
1104
  }
1088
- __name(drawSold, "drawSold");
1089
1105
  async function drawBanGDream(ctx, avatar, inputOptions) {
1090
1106
  if (!avatar) return "";
1091
1107
  const colors = ["cool", "pure", "happy", "powerful"];
@@ -1166,12 +1182,22 @@ async function drawBanGDream(ctx, avatar, inputOptions) {
1166
1182
  return "";
1167
1183
  }
1168
1184
  }
1169
- __name(drawBanGDream, "drawBanGDream");
1185
+ var fsp, import_node_path3, import_koishi3;
1186
+ var init_drawHead = __esm({
1187
+ "src/plugins/drawHead.ts"() {
1188
+ fsp = __toESM(require("node:fs/promises"));
1189
+ import_node_path3 = __toESM(require("node:path"));
1190
+ import_koishi3 = require("koishi");
1191
+ init_src();
1192
+ init_utils();
1193
+ __name(handleBanGDreamConfig, "handleBanGDreamConfig");
1194
+ __name(drawLock, "drawLock");
1195
+ __name(drawSold, "drawSold");
1196
+ __name(drawBanGDream, "drawBanGDream");
1197
+ }
1198
+ });
1170
1199
 
1171
1200
  // src/plugins/getOriginImg.ts
1172
- var cheerio2 = __toESM(require("cheerio"));
1173
- var import_koishi4 = require("koishi");
1174
- var import_rss_parser = __toESM(require("rss-parser"));
1175
1201
  async function getXUrl(urls) {
1176
1202
  const regex = /https:\/\/x\.com\/([^/]+)\/status\/(\d+)/g;
1177
1203
  let match;
@@ -1187,16 +1213,9 @@ async function getXUrl(urls) {
1187
1213
  } while (match !== null);
1188
1214
  return results;
1189
1215
  }
1190
- __name(getXUrl, "getXUrl");
1191
- var parser = new import_rss_parser.default({
1192
- customFields: {
1193
- item: ["description", "link"]
1194
- }
1195
- });
1196
1216
  async function getXNum(session) {
1197
1217
  return session.content.trim().split(" ").slice(1).filter((item) => !Number.isNaN(+item) && item).map((str) => Number(str) - 1);
1198
1218
  }
1199
- __name(getXNum, "getXNum");
1200
1219
  async function getXImage(rssUrl, xUrls) {
1201
1220
  const xUrlsArray = Array.isArray(xUrls) ? xUrls : [xUrls];
1202
1221
  const feed = await parser.parseURL(rssUrl);
@@ -1213,7 +1232,6 @@ async function getXImage(rssUrl, xUrls) {
1213
1232
  }
1214
1233
  return allImageUrls;
1215
1234
  }
1216
- __name(getXImage, "getXImage");
1217
1235
  function chunk(arr, size) {
1218
1236
  const res = [];
1219
1237
  for (let i = 0; i < arr.length; i += size) {
@@ -1221,7 +1239,6 @@ function chunk(arr, size) {
1221
1239
  }
1222
1240
  return res;
1223
1241
  }
1224
- __name(chunk, "chunk");
1225
1242
  async function sendImages(ctx, session, imageUrls) {
1226
1243
  const chunks = chunk(imageUrls, 10);
1227
1244
  for (const group of chunks) {
@@ -1238,121 +1255,640 @@ async function sendImages(ctx, session, imageUrls) {
1238
1255
  }
1239
1256
  }
1240
1257
  }
1241
- __name(sendImages, "sendImages");
1242
1258
  async function getXImageBase64(ctx, url) {
1243
1259
  const res = await ctx.http.get(url, { responseType: "arraybuffer" });
1244
1260
  const base64 = Buffer.from(res).toString("base64");
1245
1261
  return `data:image/png;base64,${base64}`;
1246
1262
  }
1247
- __name(getXImageBase64, "getXImageBase64");
1263
+ var cheerio2, import_koishi4, import_rss_parser, parser;
1264
+ var init_getOriginImg = __esm({
1265
+ "src/plugins/getOriginImg.ts"() {
1266
+ cheerio2 = __toESM(require("cheerio"));
1267
+ import_koishi4 = require("koishi");
1268
+ import_rss_parser = __toESM(require("rss-parser"));
1269
+ __name(getXUrl, "getXUrl");
1270
+ parser = new import_rss_parser.default({
1271
+ customFields: {
1272
+ item: ["description", "link"]
1273
+ }
1274
+ });
1275
+ __name(getXNum, "getXNum");
1276
+ __name(getXImage, "getXImage");
1277
+ __name(chunk, "chunk");
1278
+ __name(sendImages, "sendImages");
1279
+ __name(getXImageBase64, "getXImageBase64");
1280
+ }
1281
+ });
1282
+
1283
+ // src/locales/zh-CN.yml
1284
+ var require_zh_CN = __commonJS({
1285
+ "src/locales/zh-CN.yml"(exports2, module2) {
1286
+ module2.exports = { commands: { roll: { messages: { noParam: "你问啥?", invalid: "你要不看看你说的是啥", "too-many": "太、太多了啦!", noodles: "扔出了{num}个{noodles}面的骰子,点数如下:{points}", possibility: "{param}是{possibility}%", choose: "当然是{option}啦!" } }, "room-number": { messages: { roomNumber: "当前的房间号是: {room}", changeRoom: "已将当前房间号 {oldRoom} 修改为 {newRoom}", newRoom: "已添加房间号: {room}", noRoom: "当前没有保存的房间", delRoom: "已删除房间: {room}", invalid: "无效输入" } }, forward: { messages: { delete: "已删除转发群聊: {gid}", noTarget: "未配置转发群组", success: "已转发消息到: {target}", noMessage: "请引用要转发的消息", setOK: "已配置转发: {target}", forwardContent: "[转发消息]<br/> {content}" } }, "waiting-play": { messages: { addReady: "已添加,当前待机{num}人: <br/>{list}", delReady: "已删除,当前待机{num}人: <br/>{list}", delFailed: "未删除,当前待机{num}人: <br/>{list}", clearReady: "待机列表已清空", listReady: "当前待机{num}人: <br/>{list}", invalid: "输入无效" } }, 开启车牌检测: { messages: { success: "车牌检测:已打开\n当前车牌位数: {length}", noPermission: "你没有权限开启车牌检测", noGuild: "请在群聊中使用该指令", invalidLength: "位数设定不合理,请输入 1-20 之间的数字" } }, 关闭车牌检测: { messages: { success: "已关闭车牌检测", noPermission: "你没有权限关闭车牌检测", noGuild: "请在群聊中使用该指令" } }, 车牌检测状态: { messages: { enabled: "车牌检测: 已打开\n当前车牌位数: {length}", disabled: "车牌检测: 已关闭", managerEnabled: "管理员权限正常", managerDisabled: "无管理员权限,无法修改群名", noPermission: "你没有权限查看车牌检测状态", noGuild: "请在群聊中使用该指令" } }, 车牌检测权限: { messages: { status: { enabled: "普通群员开关车牌检测: 允许", disabled: "普通群员开关车牌检测: 禁止" }, enabled: "已允许普通群员开关车牌检测", disabled: "已禁止普通群员开关车牌检测", invalid: "无效输入,请输入 开 / 关", noPermission: "你没有权限设置车牌检测权限", noGuild: "请在群聊中使用该指令" } } }, middleware: { messages: { atNotReply: "艾特我又不说话", atNotReplyOther: "艾特他又不说话", notBot: "我才不是机器人!", loveMessage: "我喜欢你", iLoveU: "我也喜欢你", notManager: "当前bot没有管理员权限,无法修改群名", editFuncNotFound: "无法找到设置群名的底层方法", editGroupNameSuccess: "已修改群名: {content}", editGroupNameRetrySuccess: '修改群名: "{content}"失败,由于限制已修改为: "{spacedContent}"' } } };
1287
+ }
1288
+ });
1289
+
1290
+ // src/plugins/logService.ts
1291
+ var logService_exports = {};
1292
+ __export(logService_exports, {
1293
+ error: () => error,
1294
+ info: () => info,
1295
+ initLog: () => initLog,
1296
+ readRecent: () => readRecent,
1297
+ warn: () => warn
1298
+ });
1299
+ function ensureDir() {
1300
+ if (!import_node_fs2.default.existsSync(logDir)) {
1301
+ import_node_fs2.default.mkdirSync(logDir, { recursive: true });
1302
+ }
1303
+ }
1304
+ function today() {
1305
+ const d = /* @__PURE__ */ new Date();
1306
+ const y = d.getFullYear();
1307
+ const m = String(d.getMonth() + 1).padStart(2, "0");
1308
+ const day = String(d.getDate()).padStart(2, "0");
1309
+ return `${y}-${m}-${day}`;
1310
+ }
1311
+ function timestamp() {
1312
+ const d = /* @__PURE__ */ new Date();
1313
+ const h6 = String(d.getHours()).padStart(2, "0");
1314
+ const m = String(d.getMinutes()).padStart(2, "0");
1315
+ const s = String(d.getSeconds()).padStart(2, "0");
1316
+ return `${today()} ${h6}:${m}:${s}`;
1317
+ }
1318
+ function initLog(baseDir2) {
1319
+ logDir = import_node_path4.default.join(baseDir2, "data/starfx-bot/logs");
1320
+ ensureDir();
1321
+ todayFile = import_node_path4.default.join(logDir, `record-${today()}.log`);
1322
+ ensureFile();
1323
+ }
1324
+ function ensureFile() {
1325
+ const f = import_node_path4.default.join(logDir, `record-${today()}.log`);
1326
+ if (f !== todayFile) {
1327
+ todayFile = f;
1328
+ }
1329
+ if (!import_node_fs2.default.existsSync(todayFile)) {
1330
+ import_node_fs2.default.writeFileSync(todayFile, "", "utf8");
1331
+ }
1332
+ }
1333
+ function write(level, msg) {
1334
+ ensureFile();
1335
+ const line = `[${timestamp()}] [${level}] ${msg}
1336
+ `;
1337
+ import_node_fs2.default.appendFileSync(todayFile, line, "utf8");
1338
+ console.log(`[log] ${line.trim()}`);
1339
+ }
1340
+ function info(msg) {
1341
+ write("INFO", msg);
1342
+ }
1343
+ function warn(msg) {
1344
+ write("WARN", msg);
1345
+ }
1346
+ function error(msg) {
1347
+ write("ERROR", msg);
1348
+ }
1349
+ function readRecent(days = 7) {
1350
+ ensureDir();
1351
+ const files = import_node_fs2.default.readdirSync(logDir).filter((f) => f.startsWith("record-") && f.endsWith(".log")).sort().reverse().slice(0, days);
1352
+ const lines = [];
1353
+ for (const f of files.reverse()) {
1354
+ const content = import_node_fs2.default.readFileSync(import_node_path4.default.join(logDir, f), "utf8");
1355
+ lines.push(...content.trim().split("\n").filter(Boolean));
1356
+ }
1357
+ return lines.join("\n");
1358
+ }
1359
+ var import_node_fs2, import_node_path4, logDir, todayFile;
1360
+ var init_logService = __esm({
1361
+ "src/plugins/logService.ts"() {
1362
+ import_node_fs2 = __toESM(require("node:fs"));
1363
+ import_node_path4 = __toESM(require("node:path"));
1364
+ logDir = "";
1365
+ todayFile = "";
1366
+ __name(ensureDir, "ensureDir");
1367
+ __name(today, "today");
1368
+ __name(timestamp, "timestamp");
1369
+ __name(initLog, "initLog");
1370
+ __name(ensureFile, "ensureFile");
1371
+ __name(write, "write");
1372
+ __name(info, "info");
1373
+ __name(warn, "warn");
1374
+ __name(error, "error");
1375
+ __name(readRecent, "readRecent");
1376
+ }
1377
+ });
1378
+
1379
+ // src/plugins/verifyService.ts
1380
+ var verifyService_exports = {};
1381
+ __export(verifyService_exports, {
1382
+ VerifyService: () => VerifyService
1383
+ });
1384
+ function randomCode(length) {
1385
+ let code = "";
1386
+ for (let i = 0; i < length; i++) {
1387
+ code += CODE_CHARS[Math.floor(Math.random() * CODE_CHARS.length)];
1388
+ }
1389
+ return code;
1390
+ }
1391
+ function randomToken() {
1392
+ const chars = "abcdefghijklmnopqrstuvwxyz0123456789";
1393
+ let t = TOKEN_PREFIX;
1394
+ for (let i = 0; i < TOKEN_RANDOM_LEN; i++) {
1395
+ t += chars[Math.floor(Math.random() * chars.length)];
1396
+ }
1397
+ return t;
1398
+ }
1399
+ var import_node_fs3, import_node_path5, CODE_CHARS, CODE_LENGTH, PREFIX_LENGTH, TTL_MS, CLEANUP_INTERVAL_MS, MAX_PENDING, TOKEN_PREFIX, TOKEN_RANDOM_LEN, VerifyService;
1400
+ var init_verifyService = __esm({
1401
+ "src/plugins/verifyService.ts"() {
1402
+ import_node_fs3 = __toESM(require("node:fs"));
1403
+ import_node_path5 = __toESM(require("node:path"));
1404
+ init_utils();
1405
+ CODE_CHARS = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
1406
+ CODE_LENGTH = 10;
1407
+ PREFIX_LENGTH = 6;
1408
+ TTL_MS = 5 * 60 * 1e3;
1409
+ CLEANUP_INTERVAL_MS = 3e4;
1410
+ MAX_PENDING = 1e3;
1411
+ TOKEN_PREFIX = "sfx_";
1412
+ TOKEN_RANDOM_LEN = 16;
1413
+ __name(randomCode, "randomCode");
1414
+ __name(randomToken, "randomToken");
1415
+ VerifyService = class {
1416
+ constructor(ctx, cfg, ownerId) {
1417
+ this.ctx = ctx;
1418
+ this.cfg = cfg;
1419
+ this.ownerId = ownerId;
1420
+ this.log = this.ctx.logger("starfx-bot");
1421
+ }
1422
+ static {
1423
+ __name(this, "VerifyService");
1424
+ }
1425
+ pending = /* @__PURE__ */ new Map();
1426
+ timer = null;
1427
+ log;
1428
+ get autoTokensPath() {
1429
+ return import_node_path5.default.join(
1430
+ this.ctx.baseDir,
1431
+ "data/starfx-bot/assets",
1432
+ "auto-tokens.json"
1433
+ );
1434
+ }
1435
+ // ========== 生命周期 ==========
1436
+ start() {
1437
+ this.timer = this.ctx.setInterval(
1438
+ () => this.cleanup(),
1439
+ CLEANUP_INTERVAL_MS
1440
+ );
1441
+ this.ctx.on("dispose", () => this.stop());
1442
+ }
1443
+ stop() {
1444
+ if (this.timer) {
1445
+ this.timer();
1446
+ this.timer = null;
1447
+ }
1448
+ this.pending.clear();
1449
+ }
1450
+ // ========== HTTP API ==========
1451
+ requestVerify(qqId, mode = "login") {
1452
+ if (this.pending.size >= MAX_PENDING && !this.pending.has(qqId))
1453
+ return null;
1454
+ const fullCode = randomCode(CODE_LENGTH);
1455
+ this.pending.set(qqId, {
1456
+ fullCode,
1457
+ createdAt: Date.now(),
1458
+ verified: false,
1459
+ mode
1460
+ });
1461
+ return fullCode;
1462
+ }
1463
+ checkVerify(fullCode) {
1464
+ for (const [, entry] of this.pending) {
1465
+ if (entry.fullCode === fullCode) {
1466
+ if (Date.now() - entry.createdAt > TTL_MS)
1467
+ return { verified: false, token: null };
1468
+ return { verified: entry.verified, token: entry.token ?? null };
1469
+ }
1470
+ }
1471
+ return { verified: false, token: null };
1472
+ }
1473
+ async addGroup(token, rawGroupId) {
1474
+ const data = this.load();
1475
+ const qqId = this.findQqIdByToken(data, token);
1476
+ if (!qqId) return { success: false, message: "Token 无效" };
1477
+ const entry = data.users[qqId];
1478
+ const fullGid = `${entry.platform}:${rawGroupId}`;
1479
+ if (entry.groups[fullGid])
1480
+ return { success: false, message: "该群已在列表中" };
1481
+ const bot = this.ctx.bots.find((b) => b.platform === entry.platform);
1482
+ if (!bot)
1483
+ return {
1484
+ success: false,
1485
+ message: `未找到 ${entry.platform} 平台的机器人`
1486
+ };
1487
+ const featureControl = parseFeatureControl(this.cfg.featureControl);
1488
+ if (!detectControl(featureControl, rawGroupId, "record")) {
1489
+ return { success: false, message: "该群未启用语录功能" };
1490
+ }
1491
+ try {
1492
+ const member = await bot.getGuildMember(rawGroupId, qqId);
1493
+ if (!member) return { success: false, message: "你不在该群中" };
1494
+ } catch {
1495
+ return { success: false, message: "查询群成员失败,请确认群号正确" };
1496
+ }
1497
+ let groupName = fullGid;
1498
+ try {
1499
+ const guild = await bot.getGuild(rawGroupId);
1500
+ if (guild?.name) groupName = guild.name;
1501
+ } catch {
1502
+ }
1503
+ entry.groups[fullGid] = groupName;
1504
+ this.save(data);
1505
+ return { success: true, message: "添加成功", groupId: fullGid, groupName };
1506
+ }
1507
+ revokeToken(token) {
1508
+ const data = this.load();
1509
+ const qqId = this.findQqIdByToken(data, token);
1510
+ if (!qqId) return { success: false, message: "Token 无效" };
1511
+ delete data.users[qqId];
1512
+ this.pending.delete(qqId);
1513
+ this.save(data);
1514
+ return { success: true, message: "已撤销" };
1515
+ }
1516
+ // ========== QQ 命令 ==========
1517
+ async verifyCommand(qqId, platform, prefix) {
1518
+ if (prefix.length !== PREFIX_LENGTH) return "验证码格式错误";
1519
+ const entry = this.pending.get(qqId);
1520
+ if (!entry) return "没有待验证的请求,请先在网页上获取验证码";
1521
+ if (Date.now() - entry.createdAt > TTL_MS) {
1522
+ this.pending.delete(qqId);
1523
+ return "验证码已过期,请重新在网页上获取";
1524
+ }
1525
+ if (!entry.fullCode.startsWith(prefix)) return "验证码错误";
1526
+ const data = this.load();
1527
+ const existingUser = data.users[qqId];
1528
+ let token;
1529
+ if (entry.mode === "login" && existingUser) {
1530
+ token = existingUser.token;
1531
+ } else {
1532
+ token = randomToken();
1533
+ }
1534
+ entry.verified = true;
1535
+ entry.token = token;
1536
+ let username = qqId;
1537
+ for (const bot of this.ctx.bots) {
1538
+ try {
1539
+ const user = await bot.getUser(qqId);
1540
+ if (user?.nickname || user?.name) {
1541
+ username = (user.nickname || user.name) ?? qqId;
1542
+ break;
1543
+ }
1544
+ } catch {
1545
+ }
1546
+ }
1547
+ data.users[qqId] = {
1548
+ token,
1549
+ username,
1550
+ platform,
1551
+ groups: data.users[qqId]?.groups ?? {}
1552
+ };
1553
+ this.save(data);
1554
+ return "";
1555
+ }
1556
+ resetByQqId(qqId) {
1557
+ this.pending.delete(qqId);
1558
+ const data = this.load();
1559
+ if (!data.users[qqId])
1560
+ return { success: false, message: "你还没有绑定 Token" };
1561
+ delete data.users[qqId];
1562
+ this.save(data);
1563
+ return { success: true, message: "已重置,请重新验证" };
1564
+ }
1565
+ async removeGroup(qqId, platform, rawGroupId) {
1566
+ const data = this.load();
1567
+ const entry = data.users[qqId];
1568
+ if (!entry) return { success: false, message: "你还没有绑定 Token" };
1569
+ const fullGid = `${platform}:${rawGroupId}`;
1570
+ if (!entry.groups[fullGid])
1571
+ return { success: false, message: "该群不在你的列表中" };
1572
+ delete entry.groups[fullGid];
1573
+ this.save(data);
1574
+ return { success: true, message: "已移除" };
1575
+ }
1576
+ // ========== 角色查询 ==========
1577
+ getRoleByQqId(qqId) {
1578
+ const data = this.load();
1579
+ if (data.roles.owner === qqId) return "owner";
1580
+ if (data.roles.admin.includes(qqId)) return "admin";
1581
+ return "user";
1582
+ }
1583
+ getRoleByToken(token) {
1584
+ const data = this.load();
1585
+ const qqId = this.findQqIdByToken(data, token);
1586
+ return qqId ? this.getRoleByQqId(qqId) : "user";
1587
+ }
1588
+ getLabelByToken(token) {
1589
+ const data = this.load();
1590
+ const qqId = this.findQqIdByToken(data, token);
1591
+ if (!qqId) return `${String(token).substring(0, 8)}…`;
1592
+ const entry = data.users[qqId];
1593
+ return entry ? `${entry.username}(${qqId})` : qqId;
1594
+ }
1595
+ // ========== 权限管理(owner) ==========
1596
+ setRole(operatorQqId, targetQqId, role) {
1597
+ if (this.getRoleByQqId(operatorQqId) !== "owner") {
1598
+ return { success: false, message: "权限不足" };
1599
+ }
1600
+ if (operatorQqId === targetQqId) {
1601
+ return { success: false, message: "不能修改自己的权限" };
1602
+ }
1603
+ if (role === "owner" && operatorQqId !== this.ownerId) {
1604
+ return {
1605
+ success: false,
1606
+ message: "只有配置文件中指定的 owner 才能授予 owner 权限"
1607
+ };
1608
+ }
1609
+ if (role === "owner" && targetQqId !== this.ownerId) {
1610
+ return { success: false, message: "owner 已由配置文件指定,无法更改" };
1611
+ }
1612
+ const data = this.load();
1613
+ const targetEntry = data.users[targetQqId];
1614
+ if (!targetEntry) return { success: false, message: "目标用户未验证" };
1615
+ if (data.roles.owner === targetQqId) data.roles.owner = this.ownerId;
1616
+ data.roles.admin = data.roles.admin.filter((id) => id !== targetQqId);
1617
+ if (role === "admin") {
1618
+ data.roles.admin.push(targetQqId);
1619
+ } else if (role === "owner") {
1620
+ data.roles.owner = targetQqId;
1621
+ }
1622
+ this.save(data);
1623
+ return {
1624
+ success: true,
1625
+ message: `已将 ${targetEntry.username} 设为 ${role}`
1626
+ };
1627
+ }
1628
+ listUsers(operatorQqId) {
1629
+ if (this.getRoleByQqId(operatorQqId) !== "owner") {
1630
+ return { success: false, message: "权限不足" };
1631
+ }
1632
+ const data = this.load();
1633
+ const users = Object.entries(data.users).map(([qqId, e]) => ({
1634
+ qqId,
1635
+ username: e.username,
1636
+ role: this.getRoleByQqId(qqId)
1637
+ }));
1638
+ return { success: true, users };
1639
+ }
1640
+ deleteUser(operatorQqId, targetQqId) {
1641
+ if (this.getRoleByQqId(operatorQqId) !== "owner") {
1642
+ return { success: false, message: "权限不足" };
1643
+ }
1644
+ if (targetQqId === operatorQqId)
1645
+ return { success: false, message: "不能删除自己" };
1646
+ if (targetQqId === this.ownerId)
1647
+ return { success: false, message: "无法删除配置文件中指定的 owner" };
1648
+ const data = this.load();
1649
+ if (!data.users[targetQqId])
1650
+ return { success: false, message: "目标用户不存在" };
1651
+ delete data.users[targetQqId];
1652
+ if (data.roles.owner === targetQqId) data.roles.owner = this.ownerId;
1653
+ data.roles.admin = data.roles.admin.filter((id) => id !== targetQqId);
1654
+ this.pending.delete(targetQqId);
1655
+ this.save(data);
1656
+ return { success: true, message: "已删除" };
1657
+ }
1658
+ // ========== HTTP API 代理(token → qqId 转换) ==========
1659
+ findQqIdByToken(data, token) {
1660
+ for (const [qqId, e] of Object.entries(data.users)) {
1661
+ if (e.token === token) return qqId;
1662
+ }
1663
+ return null;
1664
+ }
1665
+ listUsersByToken(token) {
1666
+ const qqId = this.findQqIdByToken(this.load(), token);
1667
+ if (!qqId) return { success: false, message: "Token 无效" };
1668
+ const result = this.listUsers(qqId);
1669
+ return { ...result, selfQqId: result.success ? qqId : void 0 };
1670
+ }
1671
+ setRoleByToken(token, targetQqId, role) {
1672
+ const qqId = this.findQqIdByToken(this.load(), token);
1673
+ if (!qqId) return { success: false, message: "Token 无效" };
1674
+ return this.setRole(qqId, targetQqId, role);
1675
+ }
1676
+ deleteUserByToken(token, targetQqId) {
1677
+ const qqId = this.findQqIdByToken(this.load(), token);
1678
+ if (!qqId) return { success: false, message: "Token 无效" };
1679
+ return this.deleteUser(qqId, targetQqId);
1680
+ }
1681
+ // ========== 内部实现 ==========
1682
+ cleanup() {
1683
+ const now = Date.now();
1684
+ for (const [qqId, entry] of this.pending) {
1685
+ if (now - entry.createdAt > TTL_MS) this.pending.delete(qqId);
1686
+ }
1687
+ }
1688
+ defaultData() {
1689
+ return { roles: { owner: this.ownerId, admin: [] }, users: {} };
1690
+ }
1691
+ load() {
1692
+ try {
1693
+ if (import_node_fs3.default.existsSync(this.autoTokensPath)) {
1694
+ return JSON.parse(import_node_fs3.default.readFileSync(this.autoTokensPath, "utf8"));
1695
+ }
1696
+ } catch (e) {
1697
+ this.log.warn("读取 auto-tokens.json 失败", e);
1698
+ }
1699
+ return this.defaultData();
1700
+ }
1701
+ save(data) {
1702
+ try {
1703
+ const dir = import_node_path5.default.dirname(this.autoTokensPath);
1704
+ if (!import_node_fs3.default.existsSync(dir)) import_node_fs3.default.mkdirSync(dir, { recursive: true });
1705
+ import_node_fs3.default.writeFileSync(
1706
+ this.autoTokensPath,
1707
+ JSON.stringify(data, null, 2),
1708
+ "utf8"
1709
+ );
1710
+ } catch (e) {
1711
+ this.log.error("写入 auto-tokens.json 失败", e);
1712
+ }
1713
+ }
1714
+ };
1715
+ }
1716
+ });
1717
+
1718
+ // src/plugins/recordApi.ts
1719
+ var recordApi_exports = {};
1720
+ __export(recordApi_exports, {
1721
+ runRecordApi: () => runRecordApi
1722
+ });
1723
+ function runRecordApi(ctx, cfg, verifyService) {
1724
+ const { initLog: initLog2 } = (init_logService(), __toCommonJS(logService_exports));
1725
+ initLog2(ctx.baseDir);
1726
+ if (ctx.server) {
1727
+ const secretGuard = /* @__PURE__ */ __name((kctx) => {
1728
+ if (kctx.get("x-secret") !== cfg.apiSecret) {
1729
+ kctx.status = 401;
1730
+ kctx.body = { error: "unauthorized" };
1731
+ return false;
1732
+ }
1733
+ return true;
1734
+ }, "secretGuard");
1735
+ ctx.server.post(
1736
+ "/starfx/api/record/verify-request",
1737
+ async (kctx) => {
1738
+ if (!secretGuard(kctx)) return;
1739
+ const body = kctx.request.body ?? {};
1740
+ const qqId = body.qqId;
1741
+ if (!qqId) {
1742
+ kctx.status = 400;
1743
+ kctx.body = { error: "missing qqId" };
1744
+ return;
1745
+ }
1746
+ const fullCode = verifyService.requestVerify(
1747
+ String(qqId),
1748
+ body.mode === "reset" ? "reset" : "login"
1749
+ );
1750
+ if (fullCode === null) {
1751
+ kctx.status = 429;
1752
+ kctx.body = { error: "too many requests" };
1753
+ return;
1754
+ }
1755
+ kctx.body = { fullCode };
1756
+ }
1757
+ );
1758
+ ctx.server.post("/starfx/api/record/check-verify", async (kctx) => {
1759
+ if (!secretGuard(kctx)) return;
1760
+ const { fullCode } = kctx.request.body ?? {};
1761
+ if (!fullCode) {
1762
+ kctx.status = 400;
1763
+ kctx.body = { error: "missing fullCode" };
1764
+ return;
1765
+ }
1766
+ kctx.body = verifyService.checkVerify(String(fullCode));
1767
+ });
1768
+ ctx.server.post("/starfx/api/record/add-group", async (kctx) => {
1769
+ if (!secretGuard(kctx)) return;
1770
+ const { token, groupId } = kctx.request.body ?? {};
1771
+ if (!token || !groupId) {
1772
+ kctx.status = 400;
1773
+ kctx.body = { error: "missing token or groupId" };
1774
+ return;
1775
+ }
1776
+ kctx.body = await verifyService.addGroup(String(token), String(groupId));
1777
+ });
1778
+ ctx.server.post("/starfx/api/record/revoke-token", async (kctx) => {
1779
+ if (!secretGuard(kctx)) return;
1780
+ const { token } = kctx.request.body ?? {};
1781
+ if (!token) {
1782
+ kctx.status = 400;
1783
+ kctx.body = { error: "missing token" };
1784
+ return;
1785
+ }
1786
+ kctx.body = verifyService.revokeToken(String(token));
1787
+ });
1788
+ ctx.server.post("/starfx/api/record/list-users", async (kctx) => {
1789
+ if (!secretGuard(kctx)) return;
1790
+ const { token } = kctx.request.body ?? {};
1791
+ const role = verifyService.getRoleByToken(String(token ?? ""));
1792
+ if (role !== "owner") {
1793
+ kctx.status = 403;
1794
+ kctx.body = { error: "权限不足" };
1795
+ return;
1796
+ }
1797
+ kctx.body = verifyService.listUsersByToken(String(token));
1798
+ });
1799
+ ctx.server.post("/starfx/api/record/set-role", async (kctx) => {
1800
+ if (!secretGuard(kctx)) return;
1801
+ const {
1802
+ token,
1803
+ targetQqId,
1804
+ role: newRole
1805
+ } = kctx.request.body ?? {};
1806
+ const opRole = verifyService.getRoleByToken(String(token ?? ""));
1807
+ if (opRole !== "owner") {
1808
+ kctx.status = 403;
1809
+ kctx.body = { error: "权限不足" };
1810
+ return;
1811
+ }
1812
+ kctx.body = verifyService.setRoleByToken(
1813
+ String(token),
1814
+ String(targetQqId),
1815
+ newRole ?? ""
1816
+ );
1817
+ });
1818
+ ctx.server.post("/starfx/api/record/delete-user", async (kctx) => {
1819
+ if (!secretGuard(kctx)) return;
1820
+ const { token, targetQqId } = kctx.request.body ?? {};
1821
+ const opRole = verifyService.getRoleByToken(String(token ?? ""));
1822
+ if (opRole !== "owner") {
1823
+ kctx.status = 403;
1824
+ kctx.body = { error: "权限不足" };
1825
+ return;
1826
+ }
1827
+ kctx.body = verifyService.deleteUserByToken(
1828
+ String(token),
1829
+ String(targetQqId)
1830
+ );
1831
+ });
1832
+ }
1833
+ ctx.command("语录.验证 <code>").action(async ({ session }, code) => {
1834
+ const error2 = await verifyService.verifyCommand(
1835
+ session.userId,
1836
+ session.platform,
1837
+ code
1838
+ );
1839
+ if (error2) return error2;
1840
+ return "验证成功!回到网页等待自动跳转即可";
1841
+ });
1842
+ ctx.command("语录.重置").action(async ({ session }) => {
1843
+ return verifyService.resetByQqId(session.userId).message;
1844
+ });
1845
+ ctx.command("语录.删除群 <group>").action(async ({ session }, groupId) => {
1846
+ const r = await verifyService.removeGroup(
1847
+ session.userId,
1848
+ session.platform,
1849
+ groupId
1850
+ );
1851
+ return r.message;
1852
+ });
1853
+ ctx.command("语录.设权限 <qqId> <role>").action(async ({ session }, qqId, role) => {
1854
+ if (role !== "user" && role !== "admin" && role !== "owner") {
1855
+ return "角色只能是 user、admin 或 owner";
1856
+ }
1857
+ return verifyService.setRole(
1858
+ session.userId,
1859
+ qqId,
1860
+ role
1861
+ ).message;
1862
+ });
1863
+ ctx.command("语录.用户列表").action(async ({ session }) => {
1864
+ const r = verifyService.listUsers(session.userId);
1865
+ if (!r.success) return r.message;
1866
+ return r.users?.map((u) => `${u.username}(${u.qqId}) - ${u.role}`).join("\n") || "暂无用户";
1867
+ });
1868
+ ctx.command("语录.删除用户 <qqId>").action(async ({ session }, qqId) => {
1869
+ return verifyService.deleteUser(session.userId, qqId).message;
1870
+ });
1871
+ }
1872
+ var init_recordApi = __esm({
1873
+ "src/plugins/recordApi.ts"() {
1874
+ __name(runRecordApi, "runRecordApi");
1875
+ }
1876
+ });
1248
1877
 
1249
1878
  // src/index.ts
1250
- var name = "starfx-bot";
1251
- var inject = {
1252
- optional: ["skia", "QhzySharp"]
1253
- };
1254
- var baseDir;
1255
- var assetsDir;
1256
- var starfxLogger = new import_koishi5.Logger("starfx-bot");
1257
- var usage = `
1258
- <h1>StarFreedomX的自用插件</h1>
1259
- <h2>可选功能依赖:</h2>
1260
- <h3><a href="/market?keyword=skia-canvas">skia</a></h3>
1261
- <li>查汇率</li>
1262
- <h3><a href="/market?keyword=@quanhuzeyu+sharp">QhzySharp</a></h3>
1263
- <li>卖掉了</li>
1264
- <li>封印</li>
1265
- <li>bdbd</li>
1266
- `;
1267
- var repeatContextMap = /* @__PURE__ */ new Map();
1268
- var Config = import_koishi5.Schema.intersect([
1269
- import_koishi5.Schema.object({
1270
- openLock: import_koishi5.Schema.boolean().default(true).description("开启明日方舟封印功能"),
1271
- openSold: import_koishi5.Schema.boolean().default(true).description('开启闲鱼"卖掉了"功能'),
1272
- bangdreamBorder: import_koishi5.Schema.boolean().default(true).description("开启BanG Dream!边框功能")
1273
- }).description("绘图功能"),
1274
- import_koishi5.Schema.object({
1275
- record: import_koishi5.Schema.boolean().default(true).description("开启群语录功能"),
1276
- tagWeight: import_koishi5.Schema.number().default(5).min(1).description("tag匹配时的权重,越高权重越大"),
1277
- recordLink: import_koishi5.Schema.dict(
1278
- import_koishi5.Schema.object({
1279
- linkGroup: import_koishi5.Schema.string(),
1280
- linkWeight: import_koishi5.Schema.number()
1281
- })
1282
- ).role("table").description(
1283
- "群组链接,使得群可以调用被链接群的语录,<br>可以配置权重,作为键的群自身的权重为100(注意格式为平台名:群组名)"
1284
- ),
1285
- saveArchive: import_koishi5.Schema.boolean().default(false).description("开启入典功能").hidden()
1286
- }).description("语录记录功能"),
1287
- import_koishi5.Schema.object({
1288
- roll: import_koishi5.Schema.boolean().default(true).description("开启roll随机数功能"),
1289
- undo: import_koishi5.Schema.boolean().default(true).description("机器人撤回消息功能(只测试了qq的onebot适配器)"),
1290
- echo: import_koishi5.Schema.boolean().default(true).description("echo回声洞功能"),
1291
- echoBanner: import_koishi5.Schema.array(String).role("table").description("echo屏蔽词,对文本生效"),
1292
- ready: import_koishi5.Schema.boolean().default(false).description("待机人数记录功能"),
1293
- saveReadyAsFile: import_koishi5.Schema.string().description(
1294
- "写入待机人数的本地地址,留空则不写入"
1295
- ),
1296
- roomNumber: import_koishi5.Schema.boolean().default(false).description("主跑房间号记录功能"),
1297
- saveRoomAsFile: import_koishi5.Schema.string().description(
1298
- "写入房间号的本地地址,留空则不写入"
1299
- ),
1300
- forward: import_koishi5.Schema.boolean().default(true).description("消息转发功能"),
1301
- searchExchangeRate: import_koishi5.Schema.boolean().default(false).description("查汇率功能"),
1302
- intervalGetExchangeRate: import_koishi5.Schema.boolean().default(false).description("汇率定时推送功能").hidden(),
1303
- roomNumToName: import_koishi5.Schema.boolean().default(false).description("监听车牌修改群名功能"),
1304
- roomNumLength: import_koishi5.Schema.number().default(5).description("默认车牌位数")
1305
- }).description("指令小功能"),
1306
- import_koishi5.Schema.object({
1307
- atNotSay: import_koishi5.Schema.boolean().default(true).description("开启‘艾特我又不说话’功能"),
1308
- atNotSayProperty: import_koishi5.Schema.number().role("slider").min(0).max(1).step(0.01).default(0.5).description("'艾特我又不说话'回复概率"),
1309
- atNotSayOther: import_koishi5.Schema.boolean().default(true).description("开启‘艾特他又不说话’功能"),
1310
- atNotSayOtherProperty: import_koishi5.Schema.number().role("slider").min(0).max(1).step(0.01).default(0.5).description("'艾特他又不说话'回复概率"),
1311
- iLoveYou: import_koishi5.Schema.boolean().default(true).description("开启‘我喜欢你’功能"),
1312
- replyBot: import_koishi5.Schema.union(["关闭", "无需at", "必须at"]).default("无需at").description("回复‘我才不是机器人!’功能")
1313
- }).description("特定回应功能"),
1314
- import_koishi5.Schema.object({
1315
- sendLocalImage: import_koishi5.Schema.dict(
1316
- import_koishi5.Schema.object({
1317
- hiddenInHelp: import_koishi5.Schema.boolean(),
1318
- imgPath: import_koishi5.Schema.string()
1319
- })
1320
- ).role("table").description(
1321
- "特定指令发送本地图片功能,其中键是指令名称,imgPath是图片文件的绝对路径"
1322
- )
1323
- }),
1324
- import_koishi5.Schema.object({
1325
- openRepeat: import_koishi5.Schema.boolean().default(true).description("开启复读功能"),
1326
- minRepeatTimes: import_koishi5.Schema.number().default(2).description("最少重复次数"),
1327
- repeatPossibility: import_koishi5.Schema.number().role("slider").min(0).max(1).step(0.01).default(0.3).description("复读发生概率")
1328
- }).description("复读功能"),
1329
- import_koishi5.Schema.object({
1330
- myId: import_koishi5.Schema.boolean().default(false).description("查询gid uid cid")
1331
- }).description("我的信息查询"),
1332
- import_koishi5.Schema.object({
1333
- filePathToBase64: import_koishi5.Schema.boolean().default(false).description(
1334
- "在消息发送前检查是否有file://,如果有那么转换为base64再发送"
1335
- ),
1336
- originImg: import_koishi5.Schema.boolean().default(false).description("根据链接获取原图开关")
1337
- }).description("自用功能"),
1338
- import_koishi5.Schema.union([
1339
- import_koishi5.Schema.object({
1340
- originImg: import_koishi5.Schema.const(true).required(),
1341
- originImgRSSUrl: import_koishi5.Schema.string().required().description("推特列表rss地址")
1342
- }),
1343
- import_koishi5.Schema.object({})
1344
- ]),
1345
- import_koishi5.Schema.object({
1346
- featureControl: import_koishi5.Schema.array(
1347
- import_koishi5.Schema.object({
1348
- functionName: import_koishi5.Schema.string(),
1349
- whitelist: import_koishi5.Schema.boolean(),
1350
- groups: import_koishi5.Schema.string()
1351
- })
1352
- ).role("table").description(`黑/白名单配置,群组间用英文半角逗号分隔,<br>
1353
- 可配置功能键及用法详见 [项目地址](https://github.com/StarFreedomX/starfx-bot)或[npm发布页](https://www.npmjs.com/package/koishi-plugin-bangdream-ccg)`)
1354
- }).description("高级配置")
1355
- ]);
1879
+ var src_exports = {};
1880
+ __export(src_exports, {
1881
+ Config: () => Config,
1882
+ apply: () => apply,
1883
+ assetsDir: () => assetsDir,
1884
+ baseDir: () => baseDir,
1885
+ inject: () => inject,
1886
+ name: () => name,
1887
+ repeatContextMap: () => repeatContextMap,
1888
+ starfxLogger: () => starfxLogger,
1889
+ usage: () => usage
1890
+ });
1891
+ module.exports = __toCommonJS(src_exports);
1356
1892
  function apply(ctx, cfg) {
1357
1893
  ctx.model.extend("channel", {
1358
1894
  pickupLength: "unsigned",
@@ -1363,7 +1899,7 @@ function apply(ctx, cfg) {
1363
1899
  baseDir = ctx.baseDir;
1364
1900
  assetsDir = `${ctx.baseDir}/data/starfx-bot/assets`;
1365
1901
  initAssets();
1366
- let featureControl = parseFeatureControl(cfg.featureControl);
1902
+ const featureControl = parseFeatureControl(cfg.featureControl);
1367
1903
  if (cfg.openLock) {
1368
1904
  ctx.command("封印 [param]").action(async ({ session }, param) => {
1369
1905
  if (ctx.QhzySharp && detectControl(featureControl, session.guildId, "lock"))
@@ -1432,7 +1968,7 @@ function apply(ctx, cfg) {
1432
1968
  });
1433
1969
  }
1434
1970
  if (cfg.bangdreamBorder) {
1435
- ctx.command("bdbd [param]").option("starNum", "-n <starNum: number>").option("color", "-c <color: string>").option("train", "-t <train: string>").option("band", "-b <band: string>").action(async ({ session, options }, param) => {
1971
+ ctx.command("bdbd [param:text]").option("starNum", "-n <starNum: number>").option("color", "-c <color: string>").option("train", "-t <train: string>").option("band", "-b <band: string>").action(async ({ session, options }, param) => {
1436
1972
  if (ctx.QhzySharp && detectControl(featureControl, session.guildId, "bdbd")) {
1437
1973
  const drawConfig = await handleBanGDreamConfig(options);
1438
1974
  const imgSrc = await getImageSrc(session, param);
@@ -1448,6 +1984,8 @@ function apply(ctx, cfg) {
1448
1984
  });
1449
1985
  }
1450
1986
  if (cfg.record) {
1987
+ const { info: logRecord } = cfg.autoToken ? (init_logService(), __toCommonJS(logService_exports)) : { info: /* @__PURE__ */ __name(() => {
1988
+ }, "info") };
1451
1989
  ctx.command("投稿 [param]").action(async ({ session }, param) => {
1452
1990
  if (detectControl(featureControl, session.guildId, "record") && detectControl(featureControl, session.guildId, "record-push")) {
1453
1991
  const imageSrc = await getImageSrc(session, param, {
@@ -1460,11 +1998,12 @@ function apply(ctx, cfg) {
1460
1998
  if (!imageSrc) {
1461
1999
  return "请发送带图片的指令消息或引用图片消息进行投稿";
1462
2000
  }
1463
- return await addRecord(
1464
- ctx,
1465
- session.gid.replaceAll(":", "_"),
1466
- imageSrc
2001
+ const groupFolder = session.gid.replaceAll(":", "_");
2002
+ const result = await addRecord(ctx, groupFolder, imageSrc);
2003
+ logRecord(
2004
+ `[投稿] ${session.username || session.userId}(${session.userId}) group=${session.gid}`
1467
2005
  );
2006
+ return result;
1468
2007
  }
1469
2008
  });
1470
2009
  ctx.command("语录 [tag:string]").action(async ({ session }, tag) => {
@@ -1480,6 +2019,13 @@ function apply(ctx, cfg) {
1480
2019
  }
1481
2020
  });
1482
2021
  }
2022
+ if (cfg.autoToken && cfg.apiSecret) {
2023
+ const { VerifyService: VerifyService2 } = (init_verifyService(), __toCommonJS(verifyService_exports));
2024
+ const { runRecordApi: runRecordApi2 } = (init_recordApi(), __toCommonJS(recordApi_exports));
2025
+ const verifyService = new VerifyService2(ctx, cfg, cfg.ownerId);
2026
+ verifyService.start();
2027
+ runRecordApi2(ctx, cfg, verifyService);
2028
+ }
1483
2029
  for (const key in cfg.sendLocalImage) {
1484
2030
  ctx.command(key, { hidden: cfg.sendLocalImage[key].hiddenInHelp }).action(async ({ session }) => {
1485
2031
  if (detectControl(
@@ -1536,7 +2082,7 @@ function apply(ctx, cfg) {
1536
2082
  if (cfg.forward) {
1537
2083
  ctx.command("forward").option("group", "-g <group:string>").option("platform", "-p <platform:string>").usage("转发消息").action(async ({ session, options }) => {
1538
2084
  if (detectControl(featureControl, session.guildId, "forward")) {
1539
- const mapPath = import_node_path4.default.join(assetsDir, "forward.json");
2085
+ const mapPath = import_node_path6.default.join(assetsDir, "forward.json");
1540
2086
  const groupMap = readMap(mapPath);
1541
2087
  if (options.group) {
1542
2088
  if (["0", "clear", "del"].includes(options.group)) {
@@ -1609,7 +2155,7 @@ function apply(ctx, cfg) {
1609
2155
  if (cfg.intervalGetExchangeRate) {
1610
2156
  ctx.command("开启汇率推送 [exchangeParam:string]").action(async ({ session }, exchangeParam) => {
1611
2157
  if (ctx.skia && detectControl(featureControl, session.guildId, "exchangeRate")) {
1612
- const exchangeRatePath = import_node_path4.default.join(assetsDir, "exchangeRate.json");
2158
+ const exchangeRatePath = import_node_path6.default.join(assetsDir, "exchangeRate.json");
1613
2159
  return await intervalGetExchangeRate(
1614
2160
  ctx,
1615
2161
  cfg,
@@ -1635,19 +2181,19 @@ function apply(ctx, cfg) {
1635
2181
  } else {
1636
2182
  }
1637
2183
  }
1638
- return import_node_path4.default.normalize(filePath);
2184
+ return import_node_path6.default.normalize(filePath);
1639
2185
  } catch (e) {
1640
2186
  starfxLogger.error("URL解析失败:", e);
1641
2187
  return uri;
1642
2188
  }
1643
2189
  }
1644
- if (import_node_path4.default.isAbsolute(uri) || uri.startsWith(".") || uri.startsWith("..")) {
1645
- return import_node_path4.default.normalize(uri);
2190
+ if (import_node_path6.default.isAbsolute(uri) || uri.startsWith(".") || uri.startsWith("..")) {
2191
+ return import_node_path6.default.normalize(uri);
1646
2192
  }
1647
2193
  return uri;
1648
2194
  }, toBase64String = function(src) {
1649
2195
  try {
1650
- const data = fs2.readFileSync(src);
2196
+ const data = fs4.readFileSync(src);
1651
2197
  return data.toString("base64");
1652
2198
  } catch (err) {
1653
2199
  starfxLogger.error(
@@ -1691,51 +2237,67 @@ function apply(ctx, cfg) {
1691
2237
  }, "canTogglePickup");
1692
2238
  if (cfg.roomNumToName) {
1693
2239
  ctx.command("车牌检测权限 [allow:text]").channelFields(["pickupGrant"]).action(async ({ session }, allow) => {
1694
- if (!detectControl(featureControl, session.guildId, "pickup")) return;
2240
+ if (!detectControl(featureControl, session.guildId, "pickup"))
2241
+ return;
1695
2242
  if (!session.guildId) return session.text(".noGuild");
1696
- if (!await canGrant(session)) return session.text(".noPermission");
2243
+ if (!await canGrant(session))
2244
+ return session.text(".noPermission");
1697
2245
  if (!allow) {
1698
2246
  return session.channel.pickupGrant ? session.text(".status.enabled") : session.text(".status.disabled");
1699
2247
  }
1700
2248
  const normalized = String(allow).trim().toLowerCase();
1701
- if (["1", "true", "yes", "y", "on", "开", "开启", "允许"].includes(normalized)) {
2249
+ if (["1", "true", "yes", "y", "on", "开", "开启", "允许"].includes(
2250
+ normalized
2251
+ )) {
1702
2252
  session.channel.pickupGrant = true;
1703
2253
  return session.text(".enabled");
1704
2254
  }
1705
- if (["0", "false", "no", "n", "off", "关", "关闭", "禁止"].includes(normalized)) {
2255
+ if (["0", "false", "no", "n", "off", "关", "关闭", "禁止"].includes(
2256
+ normalized
2257
+ )) {
1706
2258
  session.channel.pickupGrant = false;
1707
2259
  return session.text(".disabled");
1708
2260
  }
1709
2261
  return session.text(".invalid");
1710
2262
  });
1711
2263
  ctx.command("开启车牌检测 [length:number]").alias("打开车牌检测", "打开拾取").channelFields(["pickupLength", "pickupGrant"]).action(async ({ session }, length) => {
1712
- if (!detectControl(featureControl, session.guildId, "pickup")) return;
2264
+ if (!detectControl(featureControl, session.guildId, "pickup"))
2265
+ return;
1713
2266
  if (!session.guildId) return session.text(".noGuild");
1714
- if (!await canTogglePickup(session)) return session.text(".noPermission");
1715
- if (!await canBotManage(session)) return session.text("middleware.messages.notManager");
2267
+ if (!await canTogglePickup(session))
2268
+ return session.text(".noPermission");
2269
+ if (!await canBotManage(session))
2270
+ return session.text("middleware.messages.notManager");
1716
2271
  const finalLength = length || cfg.roomNumLength || 5;
1717
- if (finalLength < 1 || finalLength > 20) return session.text(".invalidLength");
2272
+ if (finalLength < 1 || finalLength > 20)
2273
+ return session.text(".invalidLength");
1718
2274
  session.channel.pickupLength = finalLength;
1719
2275
  return session.text(".success", { length: finalLength });
1720
2276
  });
1721
2277
  ctx.command("关闭车牌检测").alias("关闭拾取").channelFields(["pickupLength", "pickupGrant"]).action(async ({ session }) => {
1722
- if (!detectControl(featureControl, session.guildId, "pickup")) return;
2278
+ if (!detectControl(featureControl, session.guildId, "pickup"))
2279
+ return;
1723
2280
  if (!session.guildId) return session.text(".noGuild");
1724
- if (!await canTogglePickup(session)) return session.text(".noPermission");
2281
+ if (!await canTogglePickup(session))
2282
+ return session.text(".noPermission");
1725
2283
  session.channel.pickupLength = 0;
1726
2284
  return session.text(".success");
1727
2285
  });
1728
2286
  ctx.command("车牌检测状态").channelFields(["pickupLength", "pickupGrant"]).action(async ({ session }) => {
1729
- if (!detectControl(featureControl, session.guildId, "pickup")) return;
2287
+ if (!detectControl(featureControl, session.guildId, "pickup"))
2288
+ return;
1730
2289
  if (!session.guildId) return session.text(".noGuild");
1731
2290
  return `${session.channel.pickupLength > 0 ? session.text(".enabled", { length: session.channel.pickupLength }) : session.text(".disabled")}
1732
- ${!!await canBotManage(session) ? session.text(".managerEnabled") : session.text(".managerDisabled")}`;
2291
+ ${await canBotManage(session) ? session.text(".managerEnabled") : session.text(".managerDisabled")}`;
1733
2292
  });
1734
2293
  }
1735
2294
  ctx.middleware(async (session, next) => {
1736
2295
  const elements = session.elements;
1737
2296
  if (cfg.roomNumToName && session.guildId && detectControl(featureControl, session.guildId, "pickup")) {
1738
- const channel = await session.observeChannel(["pickupLength", "pickupGrant"]);
2297
+ const channel = await session.observeChannel([
2298
+ "pickupLength",
2299
+ "pickupGrant"
2300
+ ]);
1739
2301
  const targetLength = channel.pickupLength;
1740
2302
  const content = session.content?.trim();
1741
2303
  if (targetLength > 0 && new RegExp(`^\\d{${targetLength}}$`).test(content)) {
@@ -1747,7 +2309,9 @@ ${!!await canBotManage(session) ? session.text(".managerEnabled") : session.text
1747
2309
  group_name: name2
1748
2310
  });
1749
2311
  if (response && response.retcode !== 0 && response.status !== "ok") {
1750
- throw new Error(`OneBot 报错 (Code: ${response.retcode}): ${JSON.stringify(response)}`);
2312
+ throw new Error(
2313
+ `OneBot 报错 (Code: ${response.retcode}): ${JSON.stringify(response)}`
2314
+ );
1751
2315
  }
1752
2316
  return response;
1753
2317
  }
@@ -1788,7 +2352,11 @@ ${!!await canBotManage(session) ? session.text(".managerEnabled") : session.text
1788
2352
  newName = contentDigits;
1789
2353
  }
1790
2354
  await setGroupName(newName);
1791
- await session.send(session.text("middleware.messages.editGroupNameSuccess", { content: newName }));
2355
+ await session.send(
2356
+ session.text("middleware.messages.editGroupNameSuccess", {
2357
+ content: newName
2358
+ })
2359
+ );
1792
2360
  return;
1793
2361
  } catch (e) {
1794
2362
  starfxLogger.warn(`纯数字修改失败,尝试添加空格重试: ${content}`);
@@ -1810,7 +2378,12 @@ ${!!await canBotManage(session) ? session.text(".managerEnabled") : session.text
1810
2378
  return spacedContent + " " + currentName;
1811
2379
  })() : spacedContent;
1812
2380
  await setGroupName(finalName);
1813
- await session.send(session.text("middleware.messages.editGroupNameRetrySuccess", { content, spacedContent: finalName }));
2381
+ await session.send(
2382
+ session.text("middleware.messages.editGroupNameRetrySuccess", {
2383
+ content,
2384
+ spacedContent: finalName
2385
+ })
2386
+ );
1814
2387
  return;
1815
2388
  } catch (retryError) {
1816
2389
  starfxLogger.error(`尝试添加空格修改群名仍失败: ${retryError}`);
@@ -1847,27 +2420,27 @@ ${!!await canBotManage(session) ? session.text(".managerEnabled") : session.text
1847
2420
  });
1848
2421
  }
1849
2422
  function initAssets() {
1850
- const defaultAssetsDir = import_node_path4.default.join(__dirname, "../assets");
1851
- assetsDir = import_node_path4.default.join(ctx.baseDir, "data/starfx-bot/assets");
1852
- if (!fs2.existsSync(assetsDir)) fs2.mkdirSync(assetsDir, { recursive: true });
1853
- const versionFile = import_node_path4.default.join(assetsDir, "plugin_version.json");
2423
+ const defaultAssetsDir = import_node_path6.default.join(__dirname, "../assets");
2424
+ assetsDir = import_node_path6.default.join(ctx.baseDir, "data/starfx-bot/assets");
2425
+ if (!fs4.existsSync(assetsDir)) fs4.mkdirSync(assetsDir, { recursive: true });
2426
+ const versionFile = import_node_path6.default.join(assetsDir, "plugin_version.json");
1854
2427
  let localVersion = "0";
1855
- if (fs2.existsSync(versionFile)) {
2428
+ if (fs4.existsSync(versionFile)) {
1856
2429
  try {
1857
- localVersion = JSON.parse(fs2.readFileSync(versionFile, "utf-8")).version || "0";
2430
+ localVersion = JSON.parse(fs4.readFileSync(versionFile, "utf-8")).version || "0";
1858
2431
  } catch {
1859
2432
  }
1860
2433
  }
1861
2434
  const pluginVersion = package_default.version;
1862
2435
  if (pluginVersion > localVersion) {
1863
2436
  try {
1864
- if (fs2.existsSync(defaultAssetsDir)) {
1865
- fs2.cpSync(defaultAssetsDir, assetsDir, {
2437
+ if (fs4.existsSync(defaultAssetsDir)) {
2438
+ fs4.cpSync(defaultAssetsDir, assetsDir, {
1866
2439
  recursive: true,
1867
2440
  force: true
1868
2441
  });
1869
2442
  }
1870
- fs2.writeFileSync(
2443
+ fs4.writeFileSync(
1871
2444
  versionFile,
1872
2445
  JSON.stringify({ version: pluginVersion })
1873
2446
  );
@@ -1878,7 +2451,133 @@ ${!!await canBotManage(session) ? session.text(".managerEnabled") : session.text
1878
2451
  }
1879
2452
  __name(initAssets, "initAssets");
1880
2453
  }
1881
- __name(apply, "apply");
2454
+ var fs4, import_node_path6, import_koishi5, import_mime_types, name, inject, baseDir, assetsDir, starfxLogger, usage, repeatContextMap, Config;
2455
+ var init_src = __esm({
2456
+ "src/index.ts"() {
2457
+ fs4 = __toESM(require("node:fs"));
2458
+ import_node_path6 = __toESM(require("node:path"));
2459
+ import_koishi5 = require("koishi");
2460
+ import_mime_types = __toESM(require("mime-types"));
2461
+ init_package();
2462
+ init_currencySearch();
2463
+ init_drawHead();
2464
+ init_getOriginImg();
2465
+ init_utils();
2466
+ name = "starfx-bot";
2467
+ inject = {
2468
+ optional: ["skia", "QhzySharp", "server"]
2469
+ };
2470
+ starfxLogger = new import_koishi5.Logger("starfx-bot");
2471
+ usage = `
2472
+ <h1>StarFreedomX的自用插件</h1>
2473
+ <h2>可选功能依赖:</h2>
2474
+ <h3><a href="/market?keyword=skia-canvas">skia</a></h3>
2475
+ <li>查汇率</li>
2476
+ <h3><a href="/market?keyword=@quanhuzeyu+sharp">QhzySharp</a></h3>
2477
+ <li>卖掉了</li>
2478
+ <li>封印</li>
2479
+ <li>bdbd</li>
2480
+ `;
2481
+ repeatContextMap = /* @__PURE__ */ new Map();
2482
+ Config = import_koishi5.Schema.intersect([
2483
+ import_koishi5.Schema.object({
2484
+ openLock: import_koishi5.Schema.boolean().default(true).description("开启明日方舟封印功能"),
2485
+ openSold: import_koishi5.Schema.boolean().default(true).description('开启闲鱼"卖掉了"功能'),
2486
+ bangdreamBorder: import_koishi5.Schema.boolean().default(true).description("开启BanG Dream!边框功能")
2487
+ }).description("绘图功能"),
2488
+ import_koishi5.Schema.object({
2489
+ record: import_koishi5.Schema.boolean().default(true).description("开启群语录功能"),
2490
+ tagWeight: import_koishi5.Schema.number().default(5).min(1).description("tag匹配时的权重,越高权重越大"),
2491
+ recordLink: import_koishi5.Schema.dict(
2492
+ import_koishi5.Schema.object({
2493
+ linkGroup: import_koishi5.Schema.string(),
2494
+ linkWeight: import_koishi5.Schema.number()
2495
+ })
2496
+ ).role("table").description(
2497
+ "群组链接,使得群可以调用被链接群的语录,<br>可以配置权重,作为键的群自身的权重为100(注意格式为平台名:群组名)"
2498
+ ),
2499
+ saveArchive: import_koishi5.Schema.boolean().default(false).description("开启入典功能").hidden()
2500
+ }).description("语录记录功能"),
2501
+ import_koishi5.Schema.object({
2502
+ autoToken: import_koishi5.Schema.boolean().default(false).description("开启自动获取 Token 功能(配合 image-tag-editor-web 使用)"),
2503
+ apiSecret: import_koishi5.Schema.string().description("Web 端调用 Bot API 的共享密钥"),
2504
+ ownerId: import_koishi5.Schema.string().description(
2505
+ "owner 的用户 ID(自动获得 owner 权限)"
2506
+ )
2507
+ }).description("Token 自动获取"),
2508
+ import_koishi5.Schema.object({
2509
+ roll: import_koishi5.Schema.boolean().default(true).description("开启roll随机数功能"),
2510
+ undo: import_koishi5.Schema.boolean().default(true).description("机器人撤回消息功能(只测试了qq的onebot适配器)"),
2511
+ echo: import_koishi5.Schema.boolean().default(true).description("echo回声洞功能"),
2512
+ echoBanner: import_koishi5.Schema.array(String).role("table").description("echo屏蔽词,对文本生效"),
2513
+ ready: import_koishi5.Schema.boolean().default(false).description("待机人数记录功能"),
2514
+ saveReadyAsFile: import_koishi5.Schema.string().description(
2515
+ "写入待机人数的本地地址,留空则不写入"
2516
+ ),
2517
+ roomNumber: import_koishi5.Schema.boolean().default(false).description("主跑房间号记录功能"),
2518
+ saveRoomAsFile: import_koishi5.Schema.string().description(
2519
+ "写入房间号的本地地址,留空则不写入"
2520
+ ),
2521
+ forward: import_koishi5.Schema.boolean().default(true).description("消息转发功能"),
2522
+ searchExchangeRate: import_koishi5.Schema.boolean().default(false).description("查汇率功能"),
2523
+ intervalGetExchangeRate: import_koishi5.Schema.boolean().default(false).description("汇率定时推送功能").hidden(),
2524
+ roomNumToName: import_koishi5.Schema.boolean().default(false).description("监听车牌修改群名功能"),
2525
+ roomNumLength: import_koishi5.Schema.number().default(5).description("默认车牌位数")
2526
+ }).description("指令小功能"),
2527
+ import_koishi5.Schema.object({
2528
+ atNotSay: import_koishi5.Schema.boolean().default(true).description("开启‘艾特我又不说话’功能"),
2529
+ atNotSayProperty: import_koishi5.Schema.number().role("slider").min(0).max(1).step(0.01).default(0.5).description("'艾特我又不说话'回复概率"),
2530
+ atNotSayOther: import_koishi5.Schema.boolean().default(true).description("开启‘艾特他又不说话’功能"),
2531
+ atNotSayOtherProperty: import_koishi5.Schema.number().role("slider").min(0).max(1).step(0.01).default(0.5).description("'艾特他又不说话'回复概率"),
2532
+ iLoveYou: import_koishi5.Schema.boolean().default(true).description("开启‘我喜欢你’功能"),
2533
+ replyBot: import_koishi5.Schema.union(["关闭", "无需at", "必须at"]).default("无需at").description("回复‘我才不是机器人!’功能")
2534
+ }).description("特定回应功能"),
2535
+ import_koishi5.Schema.object({
2536
+ sendLocalImage: import_koishi5.Schema.dict(
2537
+ import_koishi5.Schema.object({
2538
+ hiddenInHelp: import_koishi5.Schema.boolean(),
2539
+ imgPath: import_koishi5.Schema.string()
2540
+ })
2541
+ ).role("table").description(
2542
+ "特定指令发送本地图片功能,其中键是指令名称,imgPath是图片文件的绝对路径"
2543
+ )
2544
+ }),
2545
+ import_koishi5.Schema.object({
2546
+ openRepeat: import_koishi5.Schema.boolean().default(true).description("开启复读功能"),
2547
+ minRepeatTimes: import_koishi5.Schema.number().default(2).description("最少重复次数"),
2548
+ repeatPossibility: import_koishi5.Schema.number().role("slider").min(0).max(1).step(0.01).default(0.3).description("复读发生概率")
2549
+ }).description("复读功能"),
2550
+ import_koishi5.Schema.object({
2551
+ myId: import_koishi5.Schema.boolean().default(false).description("查询gid uid cid")
2552
+ }).description("我的信息查询"),
2553
+ import_koishi5.Schema.object({
2554
+ filePathToBase64: import_koishi5.Schema.boolean().default(false).description(
2555
+ "在消息发送前检查是否有file://,如果有那么转换为base64再发送"
2556
+ ),
2557
+ originImg: import_koishi5.Schema.boolean().default(false).description("根据链接获取原图开关")
2558
+ }).description("自用功能"),
2559
+ import_koishi5.Schema.union([
2560
+ import_koishi5.Schema.object({
2561
+ originImg: import_koishi5.Schema.const(true).required(),
2562
+ originImgRSSUrl: import_koishi5.Schema.string().required().description("推特列表rss地址")
2563
+ }),
2564
+ import_koishi5.Schema.object({})
2565
+ ]),
2566
+ import_koishi5.Schema.object({
2567
+ featureControl: import_koishi5.Schema.array(
2568
+ import_koishi5.Schema.object({
2569
+ functionName: import_koishi5.Schema.string(),
2570
+ whitelist: import_koishi5.Schema.boolean(),
2571
+ groups: import_koishi5.Schema.string()
2572
+ })
2573
+ ).role("table").description(`黑/白名单配置,群组间用英文半角逗号分隔,<br>
2574
+ 可配置功能键及用法详见 [项目地址](https://github.com/StarFreedomX/starfx-bot)或[npm发布页](https://www.npmjs.com/package/koishi-plugin-bangdream-ccg)`)
2575
+ }).description("高级配置")
2576
+ ]);
2577
+ __name(apply, "apply");
2578
+ }
2579
+ });
2580
+ init_src();
1882
2581
  // Annotate the CommonJS export names for ESM import in node:
1883
2582
  0 && (module.exports = {
1884
2583
  Config,