koishi-plugin-starfx-bot 0.5.0 → 0.6.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
@@ -1,7 +1,8 @@
1
- import { Context, h, Schema, Session } from 'koishi';
1
+ import { Context, h, Logger, Schema, Session } from 'koishi';
2
2
  export declare const name = "starfx-bot";
3
3
  export declare let baseDir: string;
4
4
  export declare let assetsDir: string;
5
+ export declare const starfxLogger: Logger;
5
6
  export interface Config {
6
7
  openLock: boolean;
7
8
  openSold: boolean;
@@ -10,6 +11,7 @@ export interface Config {
10
11
  atNotSayOther: boolean;
11
12
  atNotSayProperty: number;
12
13
  atNotSayOtherProperty: number;
14
+ record: boolean;
13
15
  replyBot: string;
14
16
  iLoveYou: boolean;
15
17
  }
@@ -17,6 +19,7 @@ export declare const Config: Schema<Schemastery.ObjectS<{
17
19
  openLock: Schema<boolean, boolean>;
18
20
  openSold: Schema<boolean, boolean>;
19
21
  bangdreamBorder: Schema<boolean, boolean>;
22
+ record: Schema<boolean, boolean>;
20
23
  atNotSay: Schema<boolean, boolean>;
21
24
  atNotSayProperty: Schema<number, number>;
22
25
  atNotSayOther: Schema<boolean, boolean>;
@@ -27,6 +30,7 @@ export declare const Config: Schema<Schemastery.ObjectS<{
27
30
  openLock: boolean;
28
31
  openSold: boolean;
29
32
  bangdreamBorder: boolean;
33
+ record: boolean;
30
34
  atNotSay: boolean;
31
35
  atNotSayProperty: number;
32
36
  atNotSayOther: boolean;
@@ -36,7 +40,15 @@ export declare const Config: Schema<Schemastery.ObjectS<{
36
40
  } & import("cosmokit").Dict>;
37
41
  export declare const usage = "<h5>StarFreedomX\u7684\u81EA\u7528\u63D2\u4EF6 \u653E\u4E86\u4E00\u4E9B\u5C0F\u529F\u80FD</h5>\n ";
38
42
  export declare function apply(ctx: Context, cfg: Config): void;
39
- export declare function getImageSrc(session: Session, param: string): Promise<string>;
43
+ export declare function addRecord(ctx: Context, gid: string, avatarUrl: string): Promise<string>;
44
+ export declare function getRecord(gid: string): Promise<string>;
45
+ export declare function getImageSrc(session: Session, param: string, option?: {
46
+ number?: boolean;
47
+ img?: boolean;
48
+ at?: boolean;
49
+ noParam?: boolean;
50
+ quote?: boolean;
51
+ }): Promise<string>;
40
52
  export declare function handleBanGDreamConfig(ctx: Context, options: any): Promise<{
41
53
  color: string;
42
54
  band: string;
package/lib/index.js CHANGED
@@ -41,14 +41,17 @@ var require_zh_CN = __commonJS({
41
41
  var src_exports = {};
42
42
  __export(src_exports, {
43
43
  Config: () => Config,
44
+ addRecord: () => addRecord,
44
45
  apply: () => apply,
45
46
  assetsDir: () => assetsDir,
46
47
  baseDir: () => baseDir,
47
48
  drawLock: () => drawLock,
48
49
  drawSold: () => drawSold,
49
50
  getImageSrc: () => getImageSrc,
51
+ getRecord: () => getRecord,
50
52
  handleBanGDreamConfig: () => handleBanGDreamConfig,
51
53
  name: () => name,
54
+ starfxLogger: () => starfxLogger,
52
55
  usage: () => usage
53
56
  });
54
57
  module.exports = __toCommonJS(src_exports);
@@ -56,14 +59,17 @@ var import_koishi = require("koishi");
56
59
  var import_sharp = __toESM(require("sharp"));
57
60
  var fs = __toESM(require("fs"));
58
61
  var import_jimp = require("jimp");
62
+ var import_node_path = __toESM(require("node:path"));
59
63
  var name = "starfx-bot";
60
64
  var baseDir;
61
65
  var assetsDir;
66
+ var starfxLogger = new import_koishi.Logger("starfx-bot");
62
67
  var Config = import_koishi.Schema.intersect([
63
68
  import_koishi.Schema.object({
64
69
  openLock: import_koishi.Schema.boolean().default(true).description("开启明日方舟封印功能"),
65
70
  openSold: import_koishi.Schema.boolean().default(true).description('开启闲鱼"卖掉了"功能'),
66
71
  bangdreamBorder: import_koishi.Schema.boolean().default(true).description("开启BanG Dream!边框功能"),
72
+ record: import_koishi.Schema.boolean().default(true).description("开启群语录功能"),
67
73
  atNotSay: import_koishi.Schema.boolean().default(true).description("开启‘艾特我又不说话’功能"),
68
74
  atNotSayProperty: import_koishi.Schema.number().role("slider").min(0).max(1).step(0.01).default(0.5).description("'艾特我又不说话'回复概率"),
69
75
  atNotSayOther: import_koishi.Schema.boolean().default(true).description("开启‘艾特他又不说话’功能"),
@@ -98,11 +104,36 @@ function apply(ctx, cfg) {
98
104
  return import_koishi.h.image(imageBase64);
99
105
  });
100
106
  }
107
+ if (cfg.record) {
108
+ ctx.command("投稿 [param]").action(async ({ session }, param) => {
109
+ const imageSrc = await getImageSrc(
110
+ session,
111
+ param,
112
+ {
113
+ img: true,
114
+ at: false,
115
+ quote: true,
116
+ noParam: false,
117
+ number: false
118
+ }
119
+ );
120
+ if (!imageSrc) {
121
+ return "请发送带图片的指令消息或引用图片消息进行投稿";
122
+ }
123
+ return await addRecord(ctx, session.gid.replace(":", "_"), imageSrc);
124
+ });
125
+ }
101
126
  ctx.middleware(async (session, next) => {
102
127
  const elements = session.elements;
103
128
  await atNotSayReply(cfg, session, elements);
104
129
  await replyBot(cfg, session, elements);
105
130
  await iLoveYou(cfg, session, elements);
131
+ if (cfg.record && session.content?.startsWith("语录")) {
132
+ const filepath = await getRecord(session.gid.replace(":", "_"));
133
+ starfxLogger.info(`send record: ${filepath}`);
134
+ if (!filepath) return "暂无语录呢";
135
+ return import_koishi.h.image(filepath);
136
+ }
106
137
  return next();
107
138
  });
108
139
  function initAssets() {
@@ -121,27 +152,80 @@ function apply(ctx, cfg) {
121
152
  __name(initAssets, "initAssets");
122
153
  }
123
154
  __name(apply, "apply");
124
- async function getImageSrc(session, param) {
125
- if (param?.length && param?.length === String(Number(param))?.length) {
155
+ async function addRecord(ctx, gid, avatarUrl) {
156
+ const recordDir = `${assetsDir}/record/${gid}`;
157
+ const avatarBuffer = await ctx.http.get(avatarUrl, { responseType: "arraybuffer" });
158
+ saveImage(avatarBuffer, recordDir);
159
+ return "添加成功!";
160
+ }
161
+ __name(addRecord, "addRecord");
162
+ async function getRecord(gid) {
163
+ const recordDir = `${assetsDir}/record/${gid}`;
164
+ const files = fs.readdirSync(recordDir);
165
+ return files?.length ? import_node_path.default.join(recordDir, import_koishi.Random.pick(files)) : null;
166
+ }
167
+ __name(getRecord, "getRecord");
168
+ function getTodayPrefix() {
169
+ const now = /* @__PURE__ */ new Date();
170
+ const yyyy = now.getFullYear();
171
+ const mm = String(now.getMonth() + 1).padStart(2, "0");
172
+ const dd = String(now.getDate()).padStart(2, "0");
173
+ return `${yyyy}${mm}${dd}`;
174
+ }
175
+ __name(getTodayPrefix, "getTodayPrefix");
176
+ function getNextSequenceNumber(directory, prefix) {
177
+ const files = fs.existsSync(directory) ? fs.readdirSync(directory) : [];
178
+ const regex = new RegExp(`^${prefix}-(\\d+)\\.jpg$`);
179
+ let maxNum = 0;
180
+ files.forEach((file) => {
181
+ const match = file.match(regex);
182
+ if (match) {
183
+ const num = parseInt(match[1], 10);
184
+ if (num > maxNum) {
185
+ maxNum = num;
186
+ }
187
+ }
188
+ });
189
+ return maxNum + 1;
190
+ }
191
+ __name(getNextSequenceNumber, "getNextSequenceNumber");
192
+ function saveImage(arrayBuffer, directory) {
193
+ const prefix = getTodayPrefix();
194
+ const seq = getNextSequenceNumber(directory, prefix);
195
+ const filename = `${prefix}-${seq}.jpg`;
196
+ const filepath = import_node_path.default.join(directory, filename);
197
+ if (!fs.existsSync(directory)) {
198
+ fs.mkdirSync(directory, { recursive: true });
199
+ }
200
+ const buffer = Buffer.from(arrayBuffer);
201
+ fs.writeFileSync(filepath, buffer);
202
+ console.log(`已保存图片:${filepath}`);
203
+ }
204
+ __name(saveImage, "saveImage");
205
+ async function getImageSrc(session, param, option) {
206
+ const number = option?.number ?? true, img = option?.img ?? true, at = option?.at ?? true, noParam = option?.noParam ?? true, quote = option?.quote ?? true;
207
+ if (number && param?.length && param?.length === String(Number(param))?.length) {
126
208
  return `https://q1.qlogo.cn/g?b=qq&nk=${param}&s=640`;
127
- } else if (!param?.length) {
209
+ } else if (noParam && !param?.length) {
128
210
  return `https://q1.qlogo.cn/g?b=qq&nk=${session.userId}&s=640`;
129
211
  }
130
212
  const elementArray = session.elements;
131
213
  for (const element of elementArray) {
132
- if (element?.type === "img") {
214
+ if (img && element?.type === "img") {
133
215
  return element?.attrs?.src;
134
- } else if (element?.type === "at" && element?.attrs?.id) {
216
+ } else if (at && element?.type === "at" && element?.attrs?.id) {
135
217
  return `https://q1.qlogo.cn/g?b=qq&nk=${element.attrs.id}&s=640`;
136
218
  }
137
219
  }
138
- const quoteElementArray = session?.quote?.elements;
139
- if (quoteElementArray?.length) {
140
- for (const element of quoteElementArray) {
141
- if (element?.type === "img") {
142
- return element?.attrs?.src;
143
- } else if (element?.type === "at" && element?.attrs?.id && element.attrs.id !== session.selfId) {
144
- return `https://q1.qlogo.cn/g?b=qq&nk=${element?.attrs?.id}&s=640`;
220
+ if (quote) {
221
+ const quoteElementArray = session?.quote?.elements;
222
+ if (quoteElementArray?.length) {
223
+ for (const element of quoteElementArray) {
224
+ if (img && element?.type === "img") {
225
+ return element?.attrs?.src;
226
+ } else if (at && element?.type === "at" && element?.attrs?.id && element.attrs.id !== session.selfId) {
227
+ return `https://q1.qlogo.cn/g?b=qq&nk=${element?.attrs?.id}&s=640`;
228
+ }
145
229
  }
146
230
  }
147
231
  }
@@ -156,14 +240,14 @@ async function handleBanGDreamConfig(ctx, options) {
156
240
  happy: ["happy", "orange", "橙", "橙色"]
157
241
  };
158
242
  const bands = {
159
- ppp: ["ppp", "Poppin'Party", "破琵琶", "步品破茶", "poppin", "popipa", "poppinparty", "ポピパ"],
160
- ag: ["ag", "Afterglow", "夕阳红", "悪蓋愚狼"],
161
- pp: ["pp", "PastelPalettes", "Pastel*Palettes", "PastelPalettes", "怕死怕累", "pastel", "palettes", "pasupare", "パスパレ", "破巣照破烈斗"],
162
- hhw: ["hhw", "ハロー、ハッピーワールド!", "Hello,HappyWorld!", "helloHappyWorld", "ハロハピ", "HelloHappyWorld!", "harohapi", "破狼法被威悪怒", "儿歌团", "好好玩"],
163
- r: ["r", "Roselia", "露世里恶", "萝", "露世裏悪", "ロゼリア", "r组", "相声团", "相声组"],
164
- ras: ["ras", "RaiseASuilen", "raise", "suilen", "ラス", "零図悪酔恋", "睡莲", "麗厨唖睡蓮", "睡蓮"],
165
- mnk: ["mnk", "モニカ", "蝶团", "蝶", "Morfonica", "毛二力", "monika", "monica"],
166
- go: ["go", "MyGO!!!!!", "MyGO!!!!!", "mygo", "我去!!!!!", "我去!!!!!", "我去", "卖狗"]
243
+ ppp: ["ppp", "poppin'Party", "破琵琶", "步品破茶", "poppin", "popipa", "poppinparty", "ポピパ"],
244
+ ag: ["ag", "afterglow", "夕阳红", "悪蓋愚狼"],
245
+ pp: ["pp", "pastelpalettes", "pastel*palettes", "pastelPalettes", "怕死怕累", "pastel", "palettes", "pasupare", "パスパレ", "破巣照破烈斗"],
246
+ hhw: ["hhw", "ハロー、ハッピーワールド!", "hello,happyworld!", "hellohappyworld", "ハロハピ", "hellohappyworld!", "harohapi", "破狼法被威悪怒", "儿歌团", "好好玩"],
247
+ r: ["r", "roselia", "露世里恶", "萝", "露世裏悪", "ロゼリア", "r组", "相声团", "相声组"],
248
+ ras: ["ras", "raiseasuilen", "raise", "suilen", "ラス", "零図悪酔恋", "睡莲", "麗厨唖睡蓮", "睡蓮"],
249
+ mnk: ["mnk", "モニカ", "蝶团", "蝶", "morfonica", "毛二力", "monika", "monica"],
250
+ go: ["go", "mygo!!!!!", "mygo!!!!!", "mygo", "我去!!!!!", "我去!!!!!", "我去", "卖狗"]
167
251
  };
168
252
  const trains = {
169
253
  "color_star": ["花后", "1", "彩", "true"],
@@ -192,10 +276,11 @@ async function handleBanGDreamConfig(ctx, options) {
192
276
  }
193
277
  }
194
278
  }
195
- drawConfig.starNum = options.starNum ? parseInt(options.starNum) : 0;
196
- if (drawConfig.starType) {
279
+ const starNum = options.starNum ? parseInt(options.starNum) : 0;
280
+ drawConfig.starNum = starNum > 0 && starNum < 10 ? starNum : 0;
281
+ if (options.train) {
197
282
  for (const [train, aliases] of Object.entries(trains)) {
198
- if (aliases.includes(options.color.toLowerCase())) {
283
+ if (aliases.includes(options.train.toLowerCase())) {
199
284
  drawConfig.starType = train;
200
285
  break;
201
286
  }
@@ -319,15 +404,16 @@ async function drawBanGDream(avatar, inputOptions) {
319
404
  const colors = ["cool", "pure", "happy", "powerful"];
320
405
  const bands = ["ppp", "ag", "pp", "r", "hhw", "ras", "mnk", "go"];
321
406
  const starTypes = ["normal_star", "color_star"];
407
+ const starNums = [1, 2, 3, 4, 5];
322
408
  const options = {
323
409
  color: inputOptions.color || import_koishi.Random.pick(colors),
324
410
  band: inputOptions.band || import_koishi.Random.pick(bands),
325
- starNum: inputOptions.starNum || import_koishi.Random.pick([1, 2, 3, 4, 5]),
411
+ starNum: inputOptions.starNum || import_koishi.Random.pick(starNums),
326
412
  starType: inputOptions.starType || "",
327
413
  border: inputOptions.border || ""
328
414
  };
329
415
  options.starType ||= options.starNum < 3 ? starTypes[0] : import_koishi.Random.pick(starTypes);
330
- options.border ||= `card-${options.starNum}${options.starNum == 1 ? `-${options.color}` : ""}`;
416
+ options.border ||= `card-${starNums.includes(options.starNum) ? options.starNum : 5}${options.starNum == 1 ? `-${options.color}` : ""}`;
331
417
  const [image, colorImage, bandImage, starImage, borderImage] = await Promise.all([
332
418
  import_jimp.Jimp.read(avatar),
333
419
  import_jimp.Jimp.read(`${assetsDir}/bangborder/${options.color}.png`),
@@ -358,13 +444,16 @@ __name(drawBanGDream, "drawBanGDream");
358
444
  // Annotate the CommonJS export names for ESM import in node:
359
445
  0 && (module.exports = {
360
446
  Config,
447
+ addRecord,
361
448
  apply,
362
449
  assetsDir,
363
450
  baseDir,
364
451
  drawLock,
365
452
  drawSold,
366
453
  getImageSrc,
454
+ getRecord,
367
455
  handleBanGDreamConfig,
368
456
  name,
457
+ starfxLogger,
369
458
  usage
370
459
  });
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "contributors": [
5
5
  "StarFreedomX <starfreedomx@outlook.com>"
6
6
  ],
7
- "version": "0.5.0",
7
+ "version": "0.6.0",
8
8
  "main": "lib/index.js",
9
9
  "typings": "lib/index.d.ts",
10
10
  "files": [
package/readme.md CHANGED
@@ -13,16 +13,18 @@ StarFreedomX机器人的小功能,自用
13
13
  * 我也喜欢你!
14
14
 
15
15
  # 更新日志
16
- | 版本 | 更新日志 |
17
- |---------|--------------------------|
18
- | `0.0.1` | 加入封印功能 |
19
- | `0.1.0` | 加入"卖掉了"功能 |
20
- | `0.2.0` | 加入"艾特我又不说话"回复功能 |
21
- | `0.3.0` | 加入"我喜欢你"和"我才不是机器人!"回复功能 |
22
- | `0.3.3` | 修订添加"我才不是机器人"是否需要at |
23
- | `0.3.4` | 分离"艾特我/他又不说话"的两个选项为单独的开关 |
24
- | `0.3.5` | 修复丢失的assets |
25
- | `0.3.6` | 添加"艾特我/他又不说话"的概率配置 |
26
- | `0.4.0` | 更改处理库为sharp |
27
- | `0.4.1` | 修复sharp处理w>h的图报错的bug |
28
- | `0.5.0` | 加入BanG Dream!边框功能 |
16
+ | 版本 | 更新日志 |
17
+ |---------|-----------------------------|
18
+ | `0.0.1` | 加入封印功能 |
19
+ | `0.1.0` | 加入"卖掉了"功能 |
20
+ | `0.2.0` | 加入"艾特我又不说话"回复功能 |
21
+ | `0.3.0` | 加入"我喜欢你"和"我才不是机器人!"回复功能 |
22
+ | `0.3.3` | 修订添加"我才不是机器人"是否需要at |
23
+ | `0.3.4` | 分离"艾特我/他又不说话"的两个选项为单独的开关 |
24
+ | `0.3.5` | 修复丢失的assets |
25
+ | `0.3.6` | 添加"艾特我/他又不说话"的概率配置 |
26
+ | `0.4.0` | 更改处理库为sharp |
27
+ | `0.4.1` | 修复sharp处理w>h的图报错的bug |
28
+ | `0.5.0` | 加入BanG Dream!边框功能 |
29
+ | `0.5.1` | 对边框的参数做了限定,修复了异常输入导致的报错 |
30
+ | `0.6.0` | 加入群语录功能,修复一处bangdream绘制的bug |