koishi-plugin-starfx-bot 0.8.0 → 0.10.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.d.ts CHANGED
@@ -8,48 +8,61 @@ export interface Config {
8
8
  openLock: boolean;
9
9
  openSold: boolean;
10
10
  bangdreamBorder: boolean;
11
+ record: boolean;
12
+ roll: boolean;
11
13
  atNotSay: boolean;
12
- atNotSayOther: boolean;
13
14
  atNotSayProperty: number;
15
+ atNotSayOther: boolean;
14
16
  atNotSayOtherProperty: number;
15
- record: boolean;
17
+ iLoveYou: boolean;
18
+ replyBot: string;
16
19
  openRepeat: boolean;
17
20
  minRepeatTimes: number;
18
21
  repeatPossibility: number;
19
- saveArchive: boolean;
20
- replyBot: string;
21
- iLoveYou: boolean;
22
+ featureControl: string;
22
23
  }
23
24
  export declare const Config: Schema<Schemastery.ObjectS<{
24
25
  openLock: Schema<boolean, boolean>;
25
26
  openSold: Schema<boolean, boolean>;
26
27
  bangdreamBorder: Schema<boolean, boolean>;
28
+ }> | Schemastery.ObjectS<{
27
29
  record: Schema<boolean, boolean>;
28
- saveArchive: Schema<boolean, boolean>;
30
+ }> | Schemastery.ObjectS<{
31
+ roll: Schema<boolean, boolean>;
32
+ }> | Schemastery.ObjectS<{
29
33
  atNotSay: Schema<boolean, boolean>;
30
34
  atNotSayProperty: Schema<number, number>;
31
35
  atNotSayOther: Schema<boolean, boolean>;
32
36
  atNotSayOtherProperty: Schema<number, number>;
37
+ iLoveYou: Schema<boolean, boolean>;
38
+ replyBot: Schema<"关闭" | "无需at" | "必须at", "关闭" | "无需at" | "必须at">;
39
+ }> | Schemastery.ObjectS<{
33
40
  openRepeat: Schema<boolean, boolean>;
34
41
  minRepeatTimes: Schema<number, number>;
35
42
  repeatPossibility: Schema<number, number>;
36
- iLoveYou: Schema<boolean, boolean>;
37
- replyBot: Schema<"关闭" | "无需at" | "必须at", "关闭" | "无需at" | "必须at">;
43
+ }> | Schemastery.ObjectS<{
44
+ featureControl: Schema<string, string>;
38
45
  }>, {
39
46
  openLock: boolean;
40
47
  openSold: boolean;
41
48
  bangdreamBorder: boolean;
49
+ } & import("cosmokit").Dict & {
42
50
  record: boolean;
43
- saveArchive: boolean;
51
+ } & {
52
+ roll: boolean;
53
+ } & {
44
54
  atNotSay: boolean;
45
55
  atNotSayProperty: number;
46
56
  atNotSayOther: boolean;
47
57
  atNotSayOtherProperty: number;
58
+ iLoveYou: boolean;
59
+ replyBot: "关闭" | "无需at" | "必须at";
60
+ } & {
48
61
  openRepeat: boolean;
49
62
  minRepeatTimes: number;
50
63
  repeatPossibility: number;
51
- iLoveYou: boolean;
52
- replyBot: "关闭" | "无需at" | "必须at";
53
- } & import("cosmokit").Dict>;
54
- export declare const usage = "<h5>StarFreedomX\u7684\u81EA\u7528\u63D2\u4EF6 \u653E\u4E86\u4E00\u4E9B\u5C0F\u529F\u80FD</h5>\n ";
64
+ } & {
65
+ featureControl: string;
66
+ }>;
67
+ export declare const usage = "<h2>StarFreedomX\u7684\u81EA\u7528\u63D2\u4EF6 \u653E\u4E86\u4E00\u4E9B\u5C0F\u529F\u80FD</h2>\n ";
55
68
  export declare function apply(ctx: Context, cfg: Config): void;
package/lib/index.js CHANGED
@@ -33,7 +33,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
33
33
  // src/locales/zh-CN.yml
34
34
  var require_zh_CN = __commonJS({
35
35
  "src/locales/zh-CN.yml"(exports2, module2) {
36
- module2.exports = { commands: null, middleware: { messages: { atNotReply: "艾特我又不说话", atNotReplyOther: "艾特他又不说话", notBot: "我才不是机器人!", loveMessage: "我喜欢你", iLoveU: "我也喜欢你" } } };
36
+ module2.exports = { commands: { roll: { messages: { noParam: "你问啥?", invalid: "你要不看看你说的是啥", "too-many": "太、太多了啦!", noodles: "扔出了{num}个{noodles}面的骰子,点数如下:{points}", possibility: "{param}是{possibility}%", choose: "当然是{option}啦!" } } }, middleware: { messages: { atNotReply: "艾特我又不说话", atNotReplyOther: "艾特他又不说话", notBot: "我才不是机器人!", loveMessage: "我喜欢你", iLoveU: "我也喜欢你" } } };
37
37
  }
38
38
  });
39
39
 
@@ -350,6 +350,77 @@ async function drawBanGDream(avatar, inputOptions) {
350
350
  return `data:image/png;base64,${(await image.getBuffer("image/jpeg")).toString("base64")}`;
351
351
  }
352
352
  __name(drawBanGDream, "drawBanGDream");
353
+ function parseJsonControl(text) {
354
+ try {
355
+ return JSON.parse(text);
356
+ } catch (e) {
357
+ starfxLogger.warn("[功能控制] JSON 解析失败");
358
+ return null;
359
+ }
360
+ }
361
+ __name(parseJsonControl, "parseJsonControl");
362
+ function detectControl(controlJson, guildId, funName) {
363
+ const rule = controlJson?.[funName];
364
+ if (!rule || rule.whitelist === void 0 || !Array.isArray(rule.groups)) {
365
+ return true;
366
+ }
367
+ const inList = rule.groups.includes(Number(guildId));
368
+ return rule.whitelist ? inList : !inList;
369
+ }
370
+ __name(detectControl, "detectControl");
371
+ function handleRoll(session) {
372
+ const elements = session.elements;
373
+ let parts = [];
374
+ for (const element of elements) {
375
+ if (element?.type === "text") {
376
+ parts.push(...element.attrs.content.split(/(?:\s+)+/).filter(Boolean));
377
+ } else {
378
+ parts.push(element);
379
+ }
380
+ }
381
+ const commandLength = parts[0].length;
382
+ console.log(parts);
383
+ parts.shift();
384
+ if (!parts) return session.text(".noParam");
385
+ const last = session.elements[session.elements.length - 1];
386
+ if (last?.type === "text" && last?.attrs?.content?.endsWith("的概率") && last?.attrs?.content?.length > 3) {
387
+ return session.text(".possibility", {
388
+ param: parts,
389
+ possibility: Math.floor(Math.random() * 1e4 + 1) / 100
390
+ });
391
+ }
392
+ const items = parts.join(" ").split("r");
393
+ if (items.length === 2) {
394
+ const [num, noodles] = items.map(Number);
395
+ return getPoints(session, num, noodles);
396
+ }
397
+ const newParts = [];
398
+ parts.forEach((element) => {
399
+ if (typeof element === "string") {
400
+ newParts.push(...element.split(/(?:、|还是|,|,)+/).filter(Boolean));
401
+ } else {
402
+ newParts.push(element);
403
+ }
404
+ });
405
+ if (newParts.length > 1) {
406
+ return session.text(".choose", {
407
+ option: import_koishi.Random.pick(newParts)
408
+ });
409
+ }
410
+ return session.text(".noParam");
411
+ }
412
+ __name(handleRoll, "handleRoll");
413
+ function getPoints(session, num, noodles) {
414
+ if (isNaN(num) || isNaN(noodles)) return session.text(".invalid");
415
+ if (num > 20 || noodles > 1e8) return session.text(".too-many");
416
+ const points = Array(num).fill(0).map(() => Math.floor(Math.random() * noodles + 1));
417
+ return session.text(".noodles", {
418
+ num,
419
+ noodles,
420
+ points: points.join(", ")
421
+ });
422
+ }
423
+ __name(getPoints, "getPoints");
353
424
 
354
425
  // src/index.ts
355
426
  var name = "starfx-bot";
@@ -361,93 +432,104 @@ var Config2 = import_koishi2.Schema.intersect([
361
432
  import_koishi2.Schema.object({
362
433
  openLock: import_koishi2.Schema.boolean().default(true).description("开启明日方舟封印功能"),
363
434
  openSold: import_koishi2.Schema.boolean().default(true).description('开启闲鱼"卖掉了"功能'),
364
- bangdreamBorder: import_koishi2.Schema.boolean().default(true).description("开启BanG Dream!边框功能"),
365
- record: import_koishi2.Schema.boolean().default(true).description("开启群语录功能"),
366
- saveArchive: import_koishi2.Schema.boolean().default(false).description("开启入典功能").hidden(),
435
+ bangdreamBorder: import_koishi2.Schema.boolean().default(true).description("开启BanG Dream!边框功能")
436
+ }).description("绘图功能"),
437
+ import_koishi2.Schema.object({
438
+ record: import_koishi2.Schema.boolean().default(true).description("开启群语录功能")
439
+ //saveArchive: Schema.boolean().default(false).description('开启入典功能').hidden(),
440
+ }).description("语录记录功能"),
441
+ import_koishi2.Schema.object({
442
+ roll: import_koishi2.Schema.boolean().default(true).description("开启roll随机数功能")
443
+ }).description("指令小功能"),
444
+ import_koishi2.Schema.object({
367
445
  atNotSay: import_koishi2.Schema.boolean().default(true).description("开启‘艾特我又不说话’功能"),
368
446
  atNotSayProperty: import_koishi2.Schema.number().role("slider").min(0).max(1).step(0.01).default(0.5).description("'艾特我又不说话'回复概率"),
369
447
  atNotSayOther: import_koishi2.Schema.boolean().default(true).description("开启‘艾特他又不说话’功能"),
370
448
  atNotSayOtherProperty: import_koishi2.Schema.number().role("slider").min(0).max(1).step(0.01).default(0.5).description("'艾特他又不说话'回复概率"),
371
- openRepeat: import_koishi2.Schema.boolean().default(true).description("开启复读功能"),
372
- minRepeatTimes: import_koishi2.Schema.number().default(2).description("最少重复次数"),
373
- repeatPossibility: import_koishi2.Schema.number().role("slider").min(0).max(1).step(0.01).default(0.3).description("复读发生概率"),
374
449
  iLoveYou: import_koishi2.Schema.boolean().default(true).description("开启‘我喜欢你’功能"),
375
450
  replyBot: import_koishi2.Schema.union(["关闭", "无需at", "必须at"]).default("无需at").description("回复‘我才不是机器人!’功能")
376
- })
451
+ }).description("特定回应功能"),
452
+ import_koishi2.Schema.object({
453
+ openRepeat: import_koishi2.Schema.boolean().default(true).description("开启复读功能"),
454
+ minRepeatTimes: import_koishi2.Schema.number().default(2).description("最少重复次数"),
455
+ repeatPossibility: import_koishi2.Schema.number().role("slider").min(0).max(1).step(0.01).default(0.3).description("复读发生概率")
456
+ }).description("复读功能"),
457
+ import_koishi2.Schema.object({
458
+ featureControl: import_koishi2.Schema.string().role("textarea", { rows: [15] }).default("{\n\n}").description(`黑/白名单配置,语法为JSON格式(可以不缩进),<br>
459
+ 可配置功能键及语法详见 [项目地址](https://github.com/StarFreedomX/starfx-bot)或[npm发布页](https://www.npmjs.com/package/koishi-plugin-bangdream-ccg)`)
460
+ }).description("高级配置")
377
461
  ]);
378
- var usage = `<h5>StarFreedomX的自用插件 放了一些小功能</h5>
462
+ var usage = `<h2>StarFreedomX的自用插件 放了一些小功能</h2>
379
463
  `;
380
464
  function apply(ctx, cfg) {
381
465
  ctx.i18n.define("zh-CN", require_zh_CN());
382
466
  baseDir = ctx.baseDir;
383
467
  assetsDir = `${ctx.baseDir}/data/starfx-bot/assets`;
384
468
  initAssets();
469
+ const controlJson = parseJsonControl(cfg.featureControl);
385
470
  if (cfg.openLock) {
386
471
  ctx.command("封印 [param]").action(async ({ session }, param) => {
387
- return await drawLock(ctx, await getImageSrc(session, param));
472
+ if (detectControl(controlJson, session.guildId, "lock"))
473
+ return await drawLock(ctx, await getImageSrc(session, param));
388
474
  });
389
475
  }
390
476
  if (cfg.openSold) {
391
477
  ctx.command("卖掉了 [param]").action(async ({ session }, param) => {
392
- return await drawSold(ctx, await getImageSrc(session, param));
478
+ if (detectControl(controlJson, session.guildId, "sold"))
479
+ return await drawSold(ctx, await getImageSrc(session, param));
480
+ });
481
+ }
482
+ if (cfg.roll) {
483
+ ctx.command("roll").action(async ({ session }) => {
484
+ if (detectControl(controlJson, session.guildId, "roll")) {
485
+ return handleRoll(session);
486
+ }
393
487
  });
394
488
  }
395
489
  if (cfg.bangdreamBorder) {
396
- ctx.command("bangdreamborder [param]").alias("bdbd").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) => {
397
- const p = session.send("图片处理中请稍等...");
398
- console.log(param);
399
- const drawConfig = await handleBanGDreamConfig(options);
400
- const imageBase64 = await drawBanGDream(await getImageSrc(session, param), drawConfig);
401
- await p;
402
- return import_koishi2.h.image(imageBase64);
490
+ 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) => {
491
+ if (detectControl(controlJson, session.guildId, "bdbd")) {
492
+ const p = session.send("图片处理中请稍等...");
493
+ console.log(param);
494
+ const drawConfig = await handleBanGDreamConfig(options);
495
+ const imageBase64 = await drawBanGDream(await getImageSrc(session, param), drawConfig);
496
+ await p;
497
+ return import_koishi2.h.image(imageBase64);
498
+ }
403
499
  });
404
500
  }
405
501
  if (cfg.record) {
406
502
  ctx.command("投稿 [param]").action(async ({ session }, param) => {
407
- const imageSrc = await getImageSrc(
408
- session,
409
- param,
410
- {
411
- img: true,
412
- at: false,
413
- quote: true,
414
- noParam: false,
415
- number: false
503
+ if (detectControl(controlJson, session.guildId, "record")) {
504
+ const imageSrc = await getImageSrc(
505
+ session,
506
+ param,
507
+ {
508
+ img: true,
509
+ at: false,
510
+ quote: true,
511
+ noParam: false,
512
+ number: false
513
+ }
514
+ );
515
+ if (!imageSrc) {
516
+ return "请发送带图片的指令消息或引用图片消息进行投稿";
416
517
  }
417
- );
418
- if (!imageSrc) {
419
- return "请发送带图片的指令消息或引用图片消息进行投稿";
518
+ return await addRecord(ctx, session.gid.replace(":", "_"), imageSrc);
420
519
  }
421
- return await addRecord(ctx, session.gid.replace(":", "_"), imageSrc);
422
520
  });
423
521
  ctx.command("语录").action(async ({ session }) => {
424
- const filepath = await getRecord(session.gid.replace(":", "_"));
425
- starfxLogger.info(`send record: ${filepath}`);
426
- if (!filepath) return "暂无语录呢";
427
- return import_koishi2.h.image(filepath);
428
- });
429
- }
430
- if (cfg.saveArchive) {
431
- ctx.command("入典 [param]").action(async ({ session }, param) => {
432
- const imageSrc = await getImageSrc(
433
- session,
434
- param,
435
- {
436
- img: true,
437
- at: false,
438
- quote: true,
439
- noParam: false,
440
- number: false
441
- }
442
- );
443
- if (!imageSrc) {
444
- return "请发送带图片的指令消息或引用图片消息进行投稿";
522
+ if (detectControl(controlJson, session.guildId, "record")) {
523
+ const filepath = await getRecord(session.gid.replace(":", "_"));
524
+ starfxLogger.info(`send record: ${filepath}`);
525
+ if (!filepath) return "暂无语录呢";
526
+ return import_koishi2.h.image(filepath);
445
527
  }
446
528
  });
447
529
  }
448
530
  ctx.middleware(async (session, next) => {
449
531
  const elements = session.elements;
450
- if (cfg.openRepeat) {
532
+ if (cfg.openRepeat && detectControl(controlJson, session.guildId, "repeat")) {
451
533
  const content = session.content;
452
534
  const ctxArr = repeatContextMap.get(session.gid);
453
535
  if (!ctxArr || ctxArr[0] !== content) {
@@ -459,9 +541,12 @@ function apply(ctx, cfg) {
459
541
  }
460
542
  }
461
543
  }
462
- await atNotSayReply(cfg, session, elements);
463
- await replyBot(cfg, session, elements);
464
- await iLoveYou(cfg, session, elements);
544
+ if (detectControl(controlJson, session.guildId, "atNotSay"))
545
+ await atNotSayReply(cfg, session, elements);
546
+ if (detectControl(controlJson, session.guildId, "replyBot"))
547
+ await replyBot(cfg, session, elements);
548
+ if (detectControl(controlJson, session.guildId, "iLoveYou"))
549
+ await iLoveYou(cfg, session, elements);
465
550
  return next();
466
551
  });
467
552
  function initAssets() {
package/lib/utils.d.ts CHANGED
@@ -1,6 +1,12 @@
1
1
  import { Context, h, Session } from "koishi";
2
2
  import sharp from "sharp";
3
3
  import { Config } from "./index";
4
+ interface FeatureControl {
5
+ [feature: string]: {
6
+ whitelist: boolean;
7
+ groups: number[];
8
+ };
9
+ }
4
10
  /**
5
11
  * 添加投稿
6
12
  * @param ctx Context
@@ -120,3 +126,7 @@ export declare function drawBanGDream(avatar: string, inputOptions?: {
120
126
  starNum: number;
121
127
  border: string;
122
128
  }): Promise<string>;
129
+ export declare function parseJsonControl(text: string): FeatureControl | null;
130
+ export declare function detectControl(controlJson: FeatureControl, guildId: string, funName: string): boolean;
131
+ export declare function handleRoll(session: Session): string;
132
+ export {};
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "contributors": [
5
5
  "StarFreedomX <starfreedomx@outlook.com>"
6
6
  ],
7
- "version": "0.8.0",
7
+ "version": "0.10.0",
8
8
  "main": "lib/index.js",
9
9
  "typings": "lib/index.d.ts",
10
10
  "files": [
package/readme.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  StarFreedomX机器人的小功能,自用
6
6
 
7
- # 已加入的功能列表:
7
+ ## 已加入的功能列表:
8
8
 
9
9
  * 明日方舟封印功能
10
10
  * 闲鱼“卖掉了”功能
@@ -15,27 +15,70 @@ StarFreedomX机器人的小功能,自用
15
15
  * 群语录
16
16
  * 复读
17
17
 
18
- # List to Do
18
+ ## List to Do
19
19
 
20
20
  * 为每种功能添加单独的群聊控制开关
21
21
  * 修改BanG Dream!边框的绘制为使用sharp,加快速度
22
22
  * 增加入典功能
23
23
 
24
- # 更新日志
25
- | 版本 | 更新日志 |
26
- |---------|-------------------------------|
27
- | `0.0.1` | 加入封印功能 |
28
- | `0.1.0` | 加入"卖掉了"功能 |
29
- | `0.2.0` | 加入"艾特我又不说话"回复功能 |
30
- | `0.3.0` | 加入"我喜欢你"和"我才不是机器人!"回复功能 |
31
- | `0.3.3` | 修订添加"我才不是机器人"是否需要at |
32
- | `0.3.4` | 分离"艾特我/他又不说话"的两个选项为单独的开关 |
33
- | `0.3.5` | 修复丢失的assets |
34
- | `0.3.6` | 添加"艾特我/他又不说话"的概率配置 |
35
- | `0.4.0` | 更改处理库为sharp |
36
- | `0.4.1` | 修复sharp处理w>h的图报错的bug |
37
- | `0.5.0` | 加入BanG Dream!边框功能 |
38
- | `0.5.1` | 对边框的参数做了限定,修复了异常输入导致的报错 |
39
- | `0.6.0` | 加入群语录功能,修复一处bangdream绘制的bug |
40
- | `0.7.0` | 加入复读功能 |
41
- | `0.8.0` | 将各个工具函数封装在utils.ts中,更改语录的触发方式 |
24
+
25
+ ## 🔧 功能权限控制(可选)
26
+
27
+ 本插件支持为各个功能设置 **群聊白名单 / 黑名单**,用于控制不同功能在指定群聊中是否启用。
28
+
29
+ 配置格式为 JSON
30
+
31
+
32
+ - `whitelist: true`:启用白名单模式,仅允许列出的群使用该功能
33
+ - `whitelist: false`:启用黑名单模式,禁止列出的群使用该功能
34
+ - `groups`:群号数组,必须为数字
35
+
36
+ 若未配置某功能项,则默认所有群均可使用。
37
+
38
+ ---
39
+
40
+ ### 📌 可配置功能键一览
41
+
42
+ | 键名 | 功能说明 |
43
+ |------------|----------------------------------------|
44
+ | `lock` | 明日方舟封印功能(对应 `openLock`) |
45
+ | `sold` | 闲鱼“卖掉了”功能(对应 `openSold`) |
46
+ | `repeat` | 群复读功能(对应 `openRepeat`) |
47
+ | `record` | 群语录功能(对应 `投稿、语录`) |
48
+ | `atNotSay` | “艾特我/他又不说话”系列功能 |
49
+ | `replyBot` | “我才不是机器人!”系列功能 |
50
+ | `iLoveYou` | “我也喜欢你”系列功能 |
51
+ | `bdbd` | BanG Dream! 边框功能(对应 `bangdreamBorder`) |
52
+ | `roll` | 随机数功能 |
53
+
54
+ ---
55
+
56
+ ### 🧪 示例:仅允许特定群使用 `roll`,禁止某群使用 `sold`
57
+
58
+ ```json
59
+ {
60
+ "roll": {
61
+ "whitelist": true,
62
+ "groups": [123456789,114514191]
63
+ },
64
+ "sold": {
65
+ "whitelist": false,
66
+ "groups": [987654321]
67
+ }
68
+ }
69
+ ```
70
+
71
+ ## 更新日志
72
+ | 版本 | 更新日志 |
73
+ |----------|-------------------------------|
74
+ | `0.0.1` | 加入封印功能 |
75
+ | `0.1.0` | 加入"卖掉了"功能 |
76
+ | `0.2.0` | 加入"艾特我又不说话"回复功能 |
77
+ | `0.3.0` | 加入"我喜欢你"和"我才不是机器人!"回复功能 |
78
+ | `0.4.0` | 更改处理库为sharp |
79
+ | `0.5.0` | 加入BanG Dream!边框功能 |
80
+ | `0.6.0` | 加入群语录功能,修复一处bangdream绘制的bug |
81
+ | `0.7.0` | 加入复读功能 |
82
+ | `0.8.0` | 将各个工具函数封装在utils.ts中,更改语录的触发方式 |
83
+ | `0.9.0` | 添加白名单/黑名单模式,对每个功能做过滤 |
84
+ | `0.10.0` | 添加随机数功能 |