koishi-plugin-starfx-bot 0.19.4 → 0.19.6

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
@@ -40,10 +40,10 @@ var require_zh_CN = __commonJS({
40
40
  // src/index.ts
41
41
  var src_exports = {};
42
42
  __export(src_exports, {
43
- Config: () => Config2,
43
+ Config: () => Config3,
44
44
  apply: () => apply,
45
45
  assetsDir: () => assetsDir,
46
- baseDir: () => baseDir,
46
+ baseDir: () => baseDir2,
47
47
  inject: () => inject,
48
48
  name: () => name,
49
49
  repeatContextMap: () => repeatContextMap,
@@ -51,7 +51,7 @@ __export(src_exports, {
51
51
  usage: () => usage
52
52
  });
53
53
  module.exports = __toCommonJS(src_exports);
54
- var import_koishi2 = require("koishi");
54
+ var import_koishi5 = require("koishi");
55
55
  var fs2 = __toESM(require("fs"));
56
56
 
57
57
  // src/utils.ts
@@ -59,18 +59,7 @@ var import_koishi = require("koishi");
59
59
  var import_fs = __toESM(require("fs"));
60
60
  var import_node_path = __toESM(require("node:path"));
61
61
  var import_sharp = __toESM(require("sharp"));
62
- var import_jimp = require("jimp");
63
- var import_rss_parser = __toESM(require("rss-parser"));
64
62
  var import_chartjs_adapter_dayjs_3 = require("chartjs-adapter-dayjs-3");
65
- var cheerio = __toESM(require("cheerio"));
66
- var import_http_proxy_agent = require("http-proxy-agent");
67
- var import_https_proxy_agent = require("https-proxy-agent");
68
- var import_axios = __toESM(require("axios"));
69
- var import_chart = require("chart.js");
70
- var import_skia_canvas = require("skia-canvas");
71
- import_chart.Chart.register(
72
- ...import_chart.registerables
73
- );
74
63
  async function addRecord(ctx, gid, avatarUrl) {
75
64
  const recordDir = `${assetsDir}/record/${gid}`;
76
65
  const avatarBuffer = await ctx.http.get(avatarUrl, { responseType: "arraybuffer" });
@@ -187,117 +176,6 @@ async function getImageSrc(session, param, option) {
187
176
  return "";
188
177
  }
189
178
  __name(getImageSrc, "getImageSrc");
190
- async function handleBanGDreamConfig(options) {
191
- const types = {
192
- cool: ["cool", "blue", "蓝", "蓝色"],
193
- powerful: ["powerful", "red", "红", "红色"],
194
- pure: ["pure", "green", "绿", "绿色"],
195
- happy: ["happy", "orange", "橙", "橙色"]
196
- };
197
- const bands = {
198
- ppp: ["ppp", "poppin'Party", "破琵琶", "步品破茶", "poppin", "popipa", "poppinparty", "ポピパ"],
199
- ag: ["ag", "afterglow", "夕阳红", "悪蓋愚狼"],
200
- pp: ["pp", "pastel*palettes", "pastel*palettes", "pastelPalettes", "怕死怕累", "pastel", "palettes", "pasupare", "パスパレ", "破巣照破烈斗"],
201
- hhw: ["hhw", "ハロー、ハッピーワールド!", "hello,happyworld!", "hellohappyworld", "ハロハピ", "hello,happyworld!", "harohapi", "破狼法被威悪怒", "儿歌团", "好好玩"],
202
- r: ["r", "roselia", "露世里恶", "萝", "露世裏悪", "ロゼリア", "r组", "相声团", "相声组"],
203
- ras: ["ras", "raiseasuilen", "raise", "suilen", "ラス", "零図悪酔恋", "睡莲", "麗厨唖睡蓮", "睡蓮"],
204
- mnk: ["mnk", "モニカ", "蝶团", "蝶", "morfonica", "毛二力", "monika", "monica"],
205
- go: ["go", "mygo!!!!!", "mygo!!!!!", "mygo", "我去!!!!!", "我去!!!!!", "我去", "卖狗"]
206
- };
207
- const trains = {
208
- "color_star": ["花后", "1", "彩", "true"],
209
- "normal_star": ["花前", "0", "false"]
210
- };
211
- const drawConfig = {
212
- color: "",
213
- band: "",
214
- starType: "",
215
- starNum: 0,
216
- border: ""
217
- };
218
- if (options?.color) {
219
- for (const [type, aliases] of Object.entries(types)) {
220
- if (aliases.includes(options.color.toLowerCase())) {
221
- drawConfig.color = type;
222
- break;
223
- }
224
- }
225
- }
226
- if (options?.band) {
227
- for (const [band, aliases] of Object.entries(bands)) {
228
- if (aliases.includes(options.band.toLowerCase())) {
229
- drawConfig.band = band;
230
- break;
231
- }
232
- }
233
- }
234
- const starNum = options?.starNum ? parseInt(options.starNum) : 0;
235
- drawConfig.starNum = starNum > 0 && starNum < 10 ? starNum : 0;
236
- if (options?.train) {
237
- for (const [train, aliases] of Object.entries(trains)) {
238
- if (aliases.includes(options.train.toLowerCase())) {
239
- drawConfig.starType = train;
240
- break;
241
- }
242
- }
243
- }
244
- return drawConfig;
245
- }
246
- __name(handleBanGDreamConfig, "handleBanGDreamConfig");
247
- async function drawLock(ctx, baseImage) {
248
- const image = await getImageFromUrl(ctx, baseImage);
249
- if (image === -1) {
250
- return "发生错误";
251
- } else if (image === -2) {
252
- return "输入无效";
253
- }
254
- const imageMetadata = await image.metadata();
255
- const lockUrl = `${baseDir}/data/starfx-bot/assets/lock.png`;
256
- const size1 = Math.min(imageMetadata.width, imageMetadata.height);
257
- image.resize({ width: size1, height: size1, fit: "cover" });
258
- const overlay = (0, import_sharp.default)(lockUrl).png();
259
- overlay.resize({ width: size1 });
260
- image.composite([{ input: await overlay.toBuffer() }]);
261
- return import_koishi.h.image(await image.png().toBuffer(), "image/png");
262
- }
263
- __name(drawLock, "drawLock");
264
- async function drawSold(ctx, baseImage) {
265
- const image = await getImageFromUrl(ctx, baseImage);
266
- if (image === -1) {
267
- return "发生错误";
268
- } else if (image === -2) {
269
- return "输入无效";
270
- }
271
- const imageMetadata = await image.metadata();
272
- const size1 = Math.min(imageMetadata.width, imageMetadata.height);
273
- image.resize({ width: size1, height: size1, fit: "cover" });
274
- const middle = (0, import_sharp.default)({
275
- create: {
276
- width: size1,
277
- height: size1,
278
- channels: 4,
279
- background: { r: 255, g: 255, b: 255, alpha: 0.4 }
280
- }
281
- }).png();
282
- const soldUrl = `${assetsDir}/sold.png`;
283
- const overlay = (0, import_sharp.default)(soldUrl).png();
284
- const overlaySize = Math.round(size1 * 182 / 240);
285
- overlay.resize({
286
- width: overlaySize,
287
- height: overlaySize
288
- });
289
- const topLeft = Math.round(overlaySize * 29 / 182);
290
- image.composite([
291
- { input: await middle.toBuffer() },
292
- {
293
- input: await overlay.toBuffer(),
294
- top: topLeft,
295
- left: topLeft
296
- }
297
- ]);
298
- return import_koishi.h.image(await image.png().toBuffer(), "image/png");
299
- }
300
- __name(drawSold, "drawSold");
301
179
  async function getImageFromUrl(ctx, url) {
302
180
  if (!url) return -2;
303
181
  let image;
@@ -353,150 +231,6 @@ async function iLoveYou(cfg, session, elements) {
353
231
  }
354
232
  }
355
233
  __name(iLoveYou, "iLoveYou");
356
- async function drawBanGDream(avatar, inputOptions) {
357
- if (!avatar) {
358
- return "";
359
- }
360
- const colors = ["cool", "pure", "happy", "powerful"];
361
- const bands = ["ppp", "ag", "pp", "r", "hhw", "ras", "mnk", "go"];
362
- const starTypes = ["normal_star", "color_star"];
363
- const starNums = [1, 2, 3, 4, 5];
364
- const options = {
365
- color: inputOptions.color || import_koishi.Random.pick(colors),
366
- band: inputOptions.band || import_koishi.Random.pick(bands),
367
- starNum: inputOptions.starNum || import_koishi.Random.pick(starNums),
368
- starType: inputOptions.starType || "",
369
- border: inputOptions.border || ""
370
- };
371
- options.starType ||= options.starNum < 3 ? starTypes[0] : import_koishi.Random.pick(starTypes);
372
- options.border ||= `card-${starNums.includes(options.starNum) ? options.starNum : 5}${options.starNum == 1 ? `-${options.color}` : ""}`;
373
- let image;
374
- try {
375
- image = await import_jimp.Jimp.read(avatar);
376
- } catch (e) {
377
- starfxLogger.error(e);
378
- return;
379
- }
380
- const [colorImage, bandImage, starImage, borderImage] = await Promise.all([
381
- import_jimp.Jimp.read(`${assetsDir}/bangborder/${options.color}.png`),
382
- import_jimp.Jimp.read(`${assetsDir}/bangborder/${options.band}.png`),
383
- import_jimp.Jimp.read(`${assetsDir}/bangborder/${options.starType}.png`),
384
- import_jimp.Jimp.read(`${assetsDir}/bangborder/${options.border}.png`)
385
- ]);
386
- const zoom = 2;
387
- image.cover({ w: 500 * zoom, h: 500 * zoom });
388
- borderImage.cover({ w: 500 * zoom, h: 500 * zoom });
389
- image.composite(borderImage);
390
- colorImage.cover({ w: 130 * zoom, h: 130 * zoom });
391
- image.composite(colorImage, image.width - colorImage.width - 3 * zoom, 5.5);
392
- bandImage.width > bandImage.height ? bandImage.resize({ w: 120 * zoom }) : bandImage.resize({ h: 120 * zoom });
393
- image.composite(bandImage, 15 * zoom, 15 * zoom);
394
- starImage.resize({ w: 90 * zoom });
395
- const step = 60 * zoom;
396
- let hei = 410 * zoom;
397
- let times = options.starNum;
398
- while (times > 0) {
399
- image.composite(starImage, 10 * zoom, hei);
400
- hei -= step;
401
- times--;
402
- }
403
- return `data:image/png;base64,${(await image.getBuffer("image/jpeg")).toString("base64")}`;
404
- }
405
- __name(drawBanGDream, "drawBanGDream");
406
- async function intervalGetExchangeRate(ctx, cfg, session, searchString, exchangeRatePath) {
407
- }
408
- __name(intervalGetExchangeRate, "intervalGetExchangeRate");
409
- async function parseNaturalCurrency(searchString) {
410
- const index = await getCurrencyCodesMap();
411
- const s = searchString.replace(/\s+/g, "");
412
- const match = s.match(/(.+?)(兑|对)(.+)/);
413
- if (match) {
414
- const from = index[match[1]];
415
- const to = index[match[3]];
416
- if (from && to) {
417
- return from + to;
418
- }
419
- }
420
- if (index[s]) {
421
- return index[s];
422
- }
423
- return null;
424
- }
425
- __name(parseNaturalCurrency, "parseNaturalCurrency");
426
- async function getExchangeRate(ctx, cfg, session, searchString, raw, retryTimes = 1) {
427
- const apiKey = retryTimes ? await getMvpAPIKey() : await updateMvpAPIKey();
428
- try {
429
- let guids = [];
430
- if (searchString) {
431
- const parsed = await parseNaturalCurrency(searchString);
432
- if (parsed) {
433
- searchString = parsed;
434
- }
435
- }
436
- if (raw && /^([a-z0-9]{6})([,\s]([a-z0-9]{6}))*$/.test(raw)) {
437
- guids = raw.split(",");
438
- } else if (/^([a-zA-Z]{3}|[a-zA-Z]{6})([,\s]([a-zA-Z]{3}|[a-zA-Z]{6}))*$/.test(searchString)) {
439
- const currencies = await getCurrencyCodes();
440
- const codes = searchString.split(/[,\s]+/);
441
- const invalidCodes = [];
442
- let search6Strings = [];
443
- codes.forEach((code) => {
444
- const first = code.slice(0, 3).toUpperCase();
445
- const second = code.length === 3 ? "CNY" : code.slice(3, 6).toUpperCase();
446
- search6Strings.push(code.length === 3 ? first + second : code);
447
- if (!currencies.some((c) => c.code === first)) invalidCodes.push(first);
448
- if (code.length === 6 && !currencies.some((c) => c.code === second)) invalidCodes.push(second);
449
- });
450
- if (invalidCodes.length > 0) {
451
- throw new Error(`输入的货币代码不合法: ${invalidCodes.join(", ")}`);
452
- }
453
- guids = await getExchangeGuids(search6Strings.join(","), apiKey);
454
- }
455
- if (!guids.length || guids.every((g) => !g)) {
456
- throw new Error(`输入无效: ${searchString}`);
457
- }
458
- const result = [];
459
- for (const guid of guids) {
460
- if (!guid) throw new Error("GUID not found");
461
- const nowPriceArr = await getQuotes(guid, apiKey);
462
- const monthPriceArr = await getMonthMSNClosePrices(guid, apiKey);
463
- const nowPrice = nowPriceArr?.[0];
464
- const oneMonthPrice = monthPriceArr?.[0];
465
- if (!nowPrice || !oneMonthPrice) {
466
- throw new Error("Failed to fetch price");
467
- }
468
- const chartBuffer = await drawOneMonthChartSkia(oneMonthPrice.prices, oneMonthPrice.timeStamps, `1 ${nowPrice.fromCurrency} to 1 ${nowPrice.currency}`);
469
- const imgSrc = "data:image/png;base64," + chartBuffer.toString("base64");
470
- result.push({
471
- name: nowPrice.symbolName,
472
- fromCurrency: nowPrice.fromCurrency,
473
- currency: nowPrice.currency,
474
- nowPrice: nowPrice.price,
475
- oneMonthChart: import_koishi.h.image(imgSrc)
476
- });
477
- }
478
- for (const item of result) {
479
- await session.send([
480
- import_koishi.h.text(`
481
- ${(/* @__PURE__ */ new Date()).toLocaleString()}
482
- ${item.name}
483
- (${item.fromCurrency}/${item.currency})
484
- 当前价格: ${item.nowPrice}
485
- 近30天价格走势:
486
- `),
487
- item.oneMonthChart
488
- ]);
489
- }
490
- } catch (err) {
491
- if (retryTimes === 0) {
492
- const message = err instanceof Error ? err.message : typeof err === "string" ? err : JSON.stringify(err);
493
- await session.send(`查询失败:${message}`);
494
- } else {
495
- await getExchangeRate(ctx, cfg, session, searchString, raw, retryTimes - 1);
496
- }
497
- }
498
- }
499
- __name(getExchangeRate, "getExchangeRate");
500
234
  function parseJsonControl(text) {
501
235
  try {
502
236
  return JSON.parse(text);
@@ -579,78 +313,6 @@ async function undo(cfg, session) {
579
313
  }
580
314
  }
581
315
  __name(undo, "undo");
582
- async function getXUrl(urls) {
583
- const regex = /https:\/\/x\.com\/([^\/]+)\/status\/(\d+)/g;
584
- let match;
585
- const results = [];
586
- while ((match = regex.exec(urls)) !== null) {
587
- const [fullUrl] = match;
588
- results.push(fullUrl);
589
- }
590
- return results;
591
- }
592
- __name(getXUrl, "getXUrl");
593
- var parser = new import_rss_parser.default({
594
- customFields: {
595
- item: ["description", "link"]
596
- }
597
- });
598
- async function getXNum(session) {
599
- return session.content.trim().split(" ").slice(1).filter((item) => !isNaN(+item) && item).map((str) => Number(str) - 1);
600
- }
601
- __name(getXNum, "getXNum");
602
- async function getXImage(rssUrl, xUrls) {
603
- const xUrlsArray = Array.isArray(xUrls) ? xUrls : [xUrls];
604
- const feed = await parser.parseURL(rssUrl);
605
- const allImageUrls = [];
606
- for (const xUrl of xUrlsArray) {
607
- const item = feed.items.find((i) => i.link === xUrl);
608
- if (item) {
609
- const $ = cheerio.load(item.description);
610
- $("img").each((_, el) => {
611
- const src = $(el).attr("src");
612
- if (src) allImageUrls.push(src);
613
- });
614
- }
615
- }
616
- return allImageUrls;
617
- }
618
- __name(getXImage, "getXImage");
619
- function chunk(arr, size) {
620
- const res = [];
621
- for (let i = 0; i < arr.length; i += size) {
622
- res.push(arr.slice(i, i + size));
623
- }
624
- return res;
625
- }
626
- __name(chunk, "chunk");
627
- async function sendImages(session, cfg, imageUrls) {
628
- const chunks = chunk(imageUrls, 10);
629
- for (const group of chunks) {
630
- const messages = await Promise.all(
631
- group.map(async (url) => import_koishi.h.image(await getXImageBase64(url, cfg)))
632
- );
633
- if (messages.length > 0) {
634
- const message = messages.join("");
635
- await session.send(message);
636
- } else {
637
- await session.send("未找到图片,请引用包含图片且处于RSS列表中的的推特链接");
638
- }
639
- }
640
- }
641
- __name(sendImages, "sendImages");
642
- async function getXImageBase64(url, cfg) {
643
- const httpAgent = new import_http_proxy_agent.HttpProxyAgent(cfg.proxyUrl);
644
- const httpsAgent = new import_https_proxy_agent.HttpsProxyAgent(cfg.proxyUrl);
645
- import_axios.default.defaults.httpAgent = httpAgent;
646
- import_axios.default.defaults.httpsAgent = httpsAgent;
647
- const res = await import_axios.default.get(url, { responseType: "arraybuffer" });
648
- const base64 = Buffer.from(res.data, "binary").toString("base64");
649
- const dataUrl = `data:image/png;base64,${base64}`;
650
- console.log("success");
651
- return dataUrl;
652
- }
653
- __name(getXImageBase64, "getXImageBase64");
654
316
  function safeQuote(str, useQuote) {
655
317
  let unquoted = str.trim();
656
318
  if (unquoted.startsWith('"')) {
@@ -718,6 +380,135 @@ function ready(session, cfg, param, readyMap) {
718
380
  return returnMessage;
719
381
  }
720
382
  __name(ready, "ready");
383
+
384
+ // src/plugins/currencySearch.ts
385
+ var cheerio = __toESM(require("cheerio"));
386
+ var import_node_path2 = __toESM(require("node:path"));
387
+ var import_koishi2 = require("koishi");
388
+ var import_chart = require("chart.js");
389
+ var import_skia_canvas = require("skia-canvas");
390
+ import_chart.Chart.register(
391
+ ...import_chart.registerables
392
+ );
393
+ var mvpAPIKey;
394
+ var currencyCodes = [];
395
+ var currencyCodesMap = {};
396
+ async function intervalGetExchangeRate(ctx, cfg, session, searchString, exchangeRatePath) {
397
+ }
398
+ __name(intervalGetExchangeRate, "intervalGetExchangeRate");
399
+ async function parseNaturalCurrency(searchString) {
400
+ const index = await getCurrencyCodesMap();
401
+ const s = searchString.replace(/\s+/g, "");
402
+ const match = s.match(/(.+?)(兑|对)(.+)/);
403
+ if (match) {
404
+ const from = index[match[1]];
405
+ const to = index[match[3]];
406
+ if (from && to) {
407
+ return from + to;
408
+ }
409
+ }
410
+ if (index[s]) {
411
+ return index[s];
412
+ }
413
+ return null;
414
+ }
415
+ __name(parseNaturalCurrency, "parseNaturalCurrency");
416
+ async function getExchangeRate(ctx, cfg, session, searchString, raw, retryTimes = 1) {
417
+ const apiKey = retryTimes ? await getMvpAPIKey() : await updateMvpAPIKey();
418
+ try {
419
+ let guids = [];
420
+ if (searchString) {
421
+ const parsed = await parseNaturalCurrency(searchString);
422
+ if (parsed) {
423
+ searchString = parsed;
424
+ }
425
+ }
426
+ if (raw && /^([a-z0-9]{6})([,\s]([a-z0-9]{6}))*$/.test(raw)) {
427
+ guids = raw.split(",");
428
+ } else if (/^([a-zA-Z]{3}|[a-zA-Z]{6})([,\s]([a-zA-Z]{3}|[a-zA-Z]{6}))*$/.test(searchString)) {
429
+ const currencies = await getCurrencyCodes();
430
+ const codes = searchString.split(/[,\s]+/);
431
+ const invalidCodes = [];
432
+ let search6Strings = [];
433
+ codes.forEach((code) => {
434
+ const first = code.slice(0, 3).toUpperCase();
435
+ const second = code.length === 3 ? "CNY" : code.slice(3, 6).toUpperCase();
436
+ search6Strings.push(code.length === 3 ? first + second : code);
437
+ if (!currencies.some((c) => c.code === first)) invalidCodes.push(first);
438
+ if (code.length === 6 && !currencies.some((c) => c.code === second)) invalidCodes.push(second);
439
+ });
440
+ if (invalidCodes.length > 0) {
441
+ throw new Error(`输入的货币代码不合法: ${invalidCodes.join(", ")}`);
442
+ }
443
+ guids = await getExchangeGuids(search6Strings.join(","), apiKey);
444
+ }
445
+ if (!guids.length || guids.every((g) => !g)) {
446
+ throw new Error(`输入无效: ${searchString}`);
447
+ }
448
+ const result = [];
449
+ for (const guid of guids) {
450
+ if (!guid) throw new Error("GUID not found");
451
+ const nowPriceArr = await getQuotes(guid, apiKey);
452
+ const monthPriceArr = await getMSNPrices(guid, apiKey, "1M1H");
453
+ const day5PriceArr = await getMSNPrices(guid, apiKey, "5D");
454
+ const nowPrice = nowPriceArr?.[0];
455
+ const oneMonthPrice = monthPriceArr?.[0];
456
+ const fiveDayPrice = day5PriceArr?.[0];
457
+ if (!nowPrice || !oneMonthPrice || !fiveDayPrice) {
458
+ throw new Error("Failed to fetch price");
459
+ }
460
+ const monthChartBuffer = await drawCurrencyChartSkia(oneMonthPrice.prices, oneMonthPrice.timeStamps, `1 ${nowPrice.fromCurrency} to 1 ${nowPrice.currency}`);
461
+ const day5ChartBuffer = await drawCurrencyChartSkia(fiveDayPrice.prices, fiveDayPrice.timeStamps, `1 ${nowPrice.fromCurrency} to 1 ${nowPrice.currency}`);
462
+ const mergeImgSrc = "data:image/png;base64," + (await mergeBuffersVertical(day5ChartBuffer, monthChartBuffer)).toString("base64");
463
+ result.push({
464
+ name: nowPrice.symbolName,
465
+ fromCurrency: nowPrice.fromCurrency,
466
+ currency: nowPrice.currency,
467
+ nowPrice: nowPrice.price,
468
+ // oneMonthChart: h.image(monthImgSrc),
469
+ // fiveDayChart: h.image(day5ImgSrc),
470
+ currencyChart: import_koishi2.h.image(mergeImgSrc)
471
+ });
472
+ }
473
+ for (const item of result) {
474
+ await session.send([
475
+ import_koishi2.h.text(`
476
+ ${(/* @__PURE__ */ new Date()).toLocaleString()}
477
+ ${item.name}
478
+ (${item.fromCurrency}/${item.currency})
479
+ 当前价格: ${item.nowPrice}
480
+ 近5天/近1个月价格走势:
481
+ `),
482
+ item.currencyChart
483
+ // item.fiveDayChart,
484
+ // h.text(`
485
+ // 近30天价格走势:
486
+ // `),
487
+ // item.oneMonthChart
488
+ ]);
489
+ }
490
+ } catch (err) {
491
+ if (retryTimes === 0) {
492
+ const message = err instanceof Error ? err.message : typeof err === "string" ? err : JSON.stringify(err);
493
+ await session.send(`查询失败:${message}`);
494
+ } else {
495
+ await getExchangeRate(ctx, cfg, session, searchString, raw, retryTimes - 1);
496
+ }
497
+ }
498
+ }
499
+ __name(getExchangeRate, "getExchangeRate");
500
+ async function mergeBuffersVertical(buf1, buf2) {
501
+ const img1 = await (0, import_skia_canvas.loadImage)(buf1);
502
+ const img2 = await (0, import_skia_canvas.loadImage)(buf2);
503
+ const width = img1.width;
504
+ const height = img1.height + img2.height;
505
+ const canvas = new import_skia_canvas.Canvas(width, height);
506
+ const ctx = canvas.getContext("2d");
507
+ ctx.drawImage(img1, 0, 0);
508
+ ctx.drawImage(img2, 0, img1.height);
509
+ return await canvas.toBuffer("png");
510
+ }
511
+ __name(mergeBuffersVertical, "mergeBuffersVertical");
721
512
  async function updateMvpAPIKey() {
722
513
  try {
723
514
  const htmlResp = await fetch("https://www.msn.com/zh-cn/money/tools/currencyconverter");
@@ -755,7 +546,6 @@ async function updateMvpAPIKey() {
755
546
  }
756
547
  }
757
548
  __name(updateMvpAPIKey, "updateMvpAPIKey");
758
- var mvpAPIKey;
759
549
  async function getMvpAPIKey() {
760
550
  return mvpAPIKey ? mvpAPIKey : updateMvpAPIKey();
761
551
  }
@@ -809,8 +599,8 @@ async function getQuotes(ids, apiKey) {
809
599
  }
810
600
  }
811
601
  __name(getQuotes, "getQuotes");
812
- async function getMonthMSNClosePrices(ids, apiKey) {
813
- const url = `https://assets.msn.com/service/Finance/QuoteSummary?apikey=${apiKey}&ids=${ids}&intents=Charts,Exchanges&type=1M1H&wrapodata=false`;
602
+ async function getMSNPrices(ids, apiKey, type = "1M1H") {
603
+ const url = `https://assets.msn.com/service/Finance/QuoteSummary?apikey=${apiKey}&ids=${ids}&intents=Charts,Exchanges&type=${type}&wrapodata=false`;
814
604
  const res = await fetch(url);
815
605
  if (!res.ok) throw new Error(`HTTP error! status: ${res.status}`);
816
606
  let data = await res.json();
@@ -828,8 +618,8 @@ async function getMonthMSNClosePrices(ids, apiKey) {
828
618
  };
829
619
  });
830
620
  }
831
- __name(getMonthMSNClosePrices, "getMonthMSNClosePrices");
832
- async function drawOneMonthChartSkia(prices, timeStamps, title = "兑换汇率", width = 1200, height = 600) {
621
+ __name(getMSNPrices, "getMSNPrices");
622
+ async function drawCurrencyChartSkia(prices, timeStamps, title = "兑换汇率", width = 1200, height = 600) {
833
623
  if (!prices.length || !timeStamps.length || prices.length !== timeStamps.length) return;
834
624
  const dataPoints = timeStamps.map((t, i) => ({ x: new Date(t), y: prices[i] }));
835
625
  const canvas = new import_skia_canvas.Canvas(width, height);
@@ -897,15 +687,13 @@ async function drawOneMonthChartSkia(prices, timeStamps, title = "兑换汇率",
897
687
  });
898
688
  return await canvas.toBuffer("png");
899
689
  }
900
- __name(drawOneMonthChartSkia, "drawOneMonthChartSkia");
901
- var currencyCodes = [];
690
+ __name(drawCurrencyChartSkia, "drawCurrencyChartSkia");
902
691
  async function getCurrencyCodes() {
903
692
  if (currencyCodes?.length) return currencyCodes;
904
- currencyCodes = require(import_node_path.default.resolve(assetsDir, "./currency.json"));
693
+ currencyCodes = require(import_node_path2.default.resolve(assetsDir, "./currency.json"));
905
694
  return currencyCodes;
906
695
  }
907
696
  __name(getCurrencyCodes, "getCurrencyCodes");
908
- var currencyCodesMap = {};
909
697
  async function getCurrencyCodesMap() {
910
698
  if (Object.keys(currencyCodesMap)?.length) return currencyCodesMap;
911
699
  currencyCodesMap = await buildCurrencyIndex();
@@ -925,8 +713,254 @@ async function buildCurrencyIndex() {
925
713
  }
926
714
  __name(buildCurrencyIndex, "buildCurrencyIndex");
927
715
 
716
+ // src/plugins/getOriginImg.ts
717
+ var import_rss_parser = __toESM(require("rss-parser"));
718
+ var import_koishi3 = require("koishi");
719
+ var cheerio2 = __toESM(require("cheerio"));
720
+ var import_http_proxy_agent = require("http-proxy-agent");
721
+ var import_https_proxy_agent = require("https-proxy-agent");
722
+ var import_axios = __toESM(require("axios"));
723
+ async function getXUrl(urls) {
724
+ const regex = /https:\/\/x\.com\/([^\/]+)\/status\/(\d+)/g;
725
+ let match;
726
+ const results = [];
727
+ while ((match = regex.exec(urls)) !== null) {
728
+ const [fullUrl] = match;
729
+ results.push(fullUrl);
730
+ }
731
+ return results;
732
+ }
733
+ __name(getXUrl, "getXUrl");
734
+ var parser = new import_rss_parser.default({
735
+ customFields: {
736
+ item: ["description", "link"]
737
+ }
738
+ });
739
+ async function getXNum(session) {
740
+ return session.content.trim().split(" ").slice(1).filter((item) => !isNaN(+item) && item).map((str) => Number(str) - 1);
741
+ }
742
+ __name(getXNum, "getXNum");
743
+ async function getXImage(rssUrl, xUrls) {
744
+ const xUrlsArray = Array.isArray(xUrls) ? xUrls : [xUrls];
745
+ const feed = await parser.parseURL(rssUrl);
746
+ const allImageUrls = [];
747
+ for (const xUrl of xUrlsArray) {
748
+ const item = feed.items.find((i) => i.link === xUrl);
749
+ if (item) {
750
+ const $ = cheerio2.load(item.description);
751
+ $("img").each((_, el) => {
752
+ const src = $(el).attr("src");
753
+ if (src) allImageUrls.push(src);
754
+ });
755
+ }
756
+ }
757
+ return allImageUrls;
758
+ }
759
+ __name(getXImage, "getXImage");
760
+ function chunk(arr, size) {
761
+ const res = [];
762
+ for (let i = 0; i < arr.length; i += size) {
763
+ res.push(arr.slice(i, i + size));
764
+ }
765
+ return res;
766
+ }
767
+ __name(chunk, "chunk");
768
+ async function sendImages(session, cfg, imageUrls) {
769
+ const chunks = chunk(imageUrls, 10);
770
+ for (const group of chunks) {
771
+ const messages = await Promise.all(
772
+ group.map(async (url) => import_koishi3.h.image(await getXImageBase64(url, cfg)))
773
+ );
774
+ if (messages.length > 0) {
775
+ const message = messages.join("");
776
+ await session.send(message);
777
+ } else {
778
+ await session.send("未找到图片,请引用包含图片且处于RSS列表中的的推特链接");
779
+ }
780
+ }
781
+ }
782
+ __name(sendImages, "sendImages");
783
+ async function getXImageBase64(url, cfg) {
784
+ const httpAgent = new import_http_proxy_agent.HttpProxyAgent(cfg.proxyUrl);
785
+ const httpsAgent = new import_https_proxy_agent.HttpsProxyAgent(cfg.proxyUrl);
786
+ import_axios.default.defaults.httpAgent = httpAgent;
787
+ import_axios.default.defaults.httpsAgent = httpsAgent;
788
+ const res = await import_axios.default.get(url, { responseType: "arraybuffer" });
789
+ const base64 = Buffer.from(res.data, "binary").toString("base64");
790
+ const dataUrl = `data:image/png;base64,${base64}`;
791
+ console.log("success");
792
+ return dataUrl;
793
+ }
794
+ __name(getXImageBase64, "getXImageBase64");
795
+
796
+ // src/plugins/drawHead.ts
797
+ var import_koishi4 = require("koishi");
798
+ var import_sharp2 = __toESM(require("sharp"));
799
+ var import_jimp = require("jimp");
800
+ async function handleBanGDreamConfig(options) {
801
+ const types = {
802
+ cool: ["cool", "blue", "蓝", "蓝色"],
803
+ powerful: ["powerful", "red", "红", "红色"],
804
+ pure: ["pure", "green", "绿", "绿色"],
805
+ happy: ["happy", "orange", "橙", "橙色"]
806
+ };
807
+ const bands = {
808
+ ppp: ["ppp", "poppin'Party", "破琵琶", "步品破茶", "poppin", "popipa", "poppinparty", "ポピパ"],
809
+ ag: ["ag", "afterglow", "夕阳红", "悪蓋愚狼"],
810
+ pp: ["pp", "pastel*palettes", "pastel*palettes", "pastelPalettes", "怕死怕累", "pastel", "palettes", "pasupare", "パスパレ", "破巣照破烈斗"],
811
+ hhw: ["hhw", "ハロー、ハッピーワールド!", "hello,happyworld!", "hellohappyworld", "ハロハピ", "hello,happyworld!", "harohapi", "破狼法被威悪怒", "儿歌团", "好好玩"],
812
+ r: ["r", "roselia", "露世里恶", "萝", "露世裏悪", "ロゼリア", "r组", "相声团", "相声组"],
813
+ ras: ["ras", "raiseasuilen", "raise", "suilen", "ラス", "零図悪酔恋", "睡莲", "麗厨唖睡蓮", "睡蓮"],
814
+ mnk: ["mnk", "モニカ", "蝶团", "蝶", "morfonica", "毛二力", "monika", "monica"],
815
+ go: ["go", "mygo!!!!!", "mygo!!!!!", "mygo", "我去!!!!!", "我去!!!!!", "我去", "卖狗"]
816
+ };
817
+ const trains = {
818
+ "color_star": ["花后", "1", "彩", "true"],
819
+ "normal_star": ["花前", "0", "false"]
820
+ };
821
+ const drawConfig = {
822
+ color: "",
823
+ band: "",
824
+ starType: "",
825
+ starNum: 0,
826
+ border: ""
827
+ };
828
+ if (options?.color) {
829
+ for (const [type, aliases] of Object.entries(types)) {
830
+ if (aliases.includes(options.color.toLowerCase())) {
831
+ drawConfig.color = type;
832
+ break;
833
+ }
834
+ }
835
+ }
836
+ if (options?.band) {
837
+ for (const [band, aliases] of Object.entries(bands)) {
838
+ if (aliases.includes(options.band.toLowerCase())) {
839
+ drawConfig.band = band;
840
+ break;
841
+ }
842
+ }
843
+ }
844
+ const starNum = options?.starNum ? parseInt(options.starNum) : 0;
845
+ drawConfig.starNum = starNum > 0 && starNum < 10 ? starNum : 0;
846
+ if (options?.train) {
847
+ for (const [train, aliases] of Object.entries(trains)) {
848
+ if (aliases.includes(options.train.toLowerCase())) {
849
+ drawConfig.starType = train;
850
+ break;
851
+ }
852
+ }
853
+ }
854
+ return drawConfig;
855
+ }
856
+ __name(handleBanGDreamConfig, "handleBanGDreamConfig");
857
+ async function drawLock(ctx, baseImage) {
858
+ const image = await getImageFromUrl(ctx, baseImage);
859
+ if (image === -1) {
860
+ return "发生错误";
861
+ } else if (image === -2) {
862
+ return "输入无效";
863
+ }
864
+ const imageMetadata = await image.metadata();
865
+ const lockUrl = `${baseDir2}/data/starfx-bot/assets/lock.png`;
866
+ const size1 = Math.min(imageMetadata.width, imageMetadata.height);
867
+ image.resize({ width: size1, height: size1, fit: "cover" });
868
+ const overlay = (0, import_sharp2.default)(lockUrl).png();
869
+ overlay.resize({ width: size1 });
870
+ image.composite([{ input: await overlay.toBuffer() }]);
871
+ return import_koishi4.h.image(await image.png().toBuffer(), "image/png");
872
+ }
873
+ __name(drawLock, "drawLock");
874
+ async function drawSold(ctx, baseImage) {
875
+ const image = await getImageFromUrl(ctx, baseImage);
876
+ if (image === -1) {
877
+ return "发生错误";
878
+ } else if (image === -2) {
879
+ return "输入无效";
880
+ }
881
+ const imageMetadata = await image.metadata();
882
+ const size1 = Math.min(imageMetadata.width, imageMetadata.height);
883
+ image.resize({ width: size1, height: size1, fit: "cover" });
884
+ const middle = (0, import_sharp2.default)({
885
+ create: {
886
+ width: size1,
887
+ height: size1,
888
+ channels: 4,
889
+ background: { r: 255, g: 255, b: 255, alpha: 0.4 }
890
+ }
891
+ }).png();
892
+ const soldUrl = `${assetsDir}/sold.png`;
893
+ const overlay = (0, import_sharp2.default)(soldUrl).png();
894
+ const overlaySize = Math.round(size1 * 182 / 240);
895
+ overlay.resize({
896
+ width: overlaySize,
897
+ height: overlaySize
898
+ });
899
+ const topLeft = Math.round(overlaySize * 29 / 182);
900
+ image.composite([
901
+ { input: await middle.toBuffer() },
902
+ {
903
+ input: await overlay.toBuffer(),
904
+ top: topLeft,
905
+ left: topLeft
906
+ }
907
+ ]);
908
+ return import_koishi4.h.image(await image.png().toBuffer(), "image/png");
909
+ }
910
+ __name(drawSold, "drawSold");
911
+ async function drawBanGDream(avatar, inputOptions) {
912
+ if (!avatar) {
913
+ return "";
914
+ }
915
+ const colors = ["cool", "pure", "happy", "powerful"];
916
+ const bands = ["ppp", "ag", "pp", "r", "hhw", "ras", "mnk", "go"];
917
+ const starTypes = ["normal_star", "color_star"];
918
+ const starNums = [1, 2, 3, 4, 5];
919
+ const options = {
920
+ color: inputOptions.color || import_koishi4.Random.pick(colors),
921
+ band: inputOptions.band || import_koishi4.Random.pick(bands),
922
+ starNum: inputOptions.starNum || import_koishi4.Random.pick(starNums),
923
+ starType: inputOptions.starType || "",
924
+ border: inputOptions.border || ""
925
+ };
926
+ options.starType ||= options.starNum < 3 ? starTypes[0] : import_koishi4.Random.pick(starTypes);
927
+ options.border ||= `card-${starNums.includes(options.starNum) ? options.starNum : 5}${options.starNum == 1 ? `-${options.color}` : ""}`;
928
+ let image;
929
+ try {
930
+ image = await import_jimp.Jimp.read(avatar);
931
+ } catch (e) {
932
+ starfxLogger.error(e);
933
+ return;
934
+ }
935
+ const [colorImage, bandImage, starImage, borderImage] = await Promise.all([
936
+ import_jimp.Jimp.read(`${assetsDir}/bangborder/${options.color}.png`),
937
+ import_jimp.Jimp.read(`${assetsDir}/bangborder/${options.band}.png`),
938
+ import_jimp.Jimp.read(`${assetsDir}/bangborder/${options.starType}.png`),
939
+ import_jimp.Jimp.read(`${assetsDir}/bangborder/${options.border}.png`)
940
+ ]);
941
+ const zoom = 2;
942
+ image.cover({ w: 500 * zoom, h: 500 * zoom });
943
+ borderImage.cover({ w: 500 * zoom, h: 500 * zoom });
944
+ image.composite(borderImage);
945
+ colorImage.cover({ w: 130 * zoom, h: 130 * zoom });
946
+ image.composite(colorImage, image.width - colorImage.width - 3 * zoom, 5.5);
947
+ bandImage.width > bandImage.height ? bandImage.resize({ w: 120 * zoom }) : bandImage.resize({ h: 120 * zoom });
948
+ image.composite(bandImage, 15 * zoom, 15 * zoom);
949
+ starImage.resize({ w: 90 * zoom });
950
+ const step = 60 * zoom;
951
+ let hei = 410 * zoom;
952
+ let times = options.starNum;
953
+ while (times > 0) {
954
+ image.composite(starImage, 10 * zoom, hei);
955
+ hei -= step;
956
+ times--;
957
+ }
958
+ return `data:image/png;base64,${(await image.getBuffer("image/jpeg")).toString("base64")}`;
959
+ }
960
+ __name(drawBanGDream, "drawBanGDream");
961
+
928
962
  // src/index.ts
929
- var import_node_path2 = __toESM(require("node:path"));
963
+ var import_node_path3 = __toESM(require("node:path"));
930
964
  var import_mime_types = __toESM(require("mime-types"));
931
965
 
932
966
  // package.json
@@ -936,7 +970,7 @@ var package_default = {
936
970
  contributors: [
937
971
  "StarFreedomX <starfreedomx@outlook.com>"
938
972
  ],
939
- version: "0.19.4",
973
+ version: "0.19.6",
940
974
  main: "lib/index.js",
941
975
  typings: "lib/index.d.ts",
942
976
  files: [
@@ -987,71 +1021,71 @@ var package_default = {
987
1021
  // src/index.ts
988
1022
  var name = "starfx-bot";
989
1023
  var inject = ["database"];
990
- var baseDir;
1024
+ var baseDir2;
991
1025
  var assetsDir;
992
- var starfxLogger = new import_koishi2.Logger("starfx-bot");
1026
+ var starfxLogger = new import_koishi5.Logger("starfx-bot");
993
1027
  var repeatContextMap = /* @__PURE__ */ new Map();
994
- var Config2 = import_koishi2.Schema.intersect([
995
- import_koishi2.Schema.object({
996
- openLock: import_koishi2.Schema.boolean().default(true).description("开启明日方舟封印功能"),
997
- openSold: import_koishi2.Schema.boolean().default(true).description('开启闲鱼"卖掉了"功能'),
998
- bangdreamBorder: import_koishi2.Schema.boolean().default(true).description("开启BanG Dream!边框功能")
1028
+ var Config3 = import_koishi5.Schema.intersect([
1029
+ import_koishi5.Schema.object({
1030
+ openLock: import_koishi5.Schema.boolean().default(true).description("开启明日方舟封印功能"),
1031
+ openSold: import_koishi5.Schema.boolean().default(true).description('开启闲鱼"卖掉了"功能'),
1032
+ bangdreamBorder: import_koishi5.Schema.boolean().default(true).description("开启BanG Dream!边框功能")
999
1033
  }).description("绘图功能"),
1000
- import_koishi2.Schema.object({
1001
- record: import_koishi2.Schema.boolean().default(true).description("开启群语录功能"),
1002
- tagWeight: import_koishi2.Schema.number().default(5).min(1).description("tag匹配时的权重,越高权重越大"),
1003
- recordLink: import_koishi2.Schema.dict(import_koishi2.Schema.object({
1004
- linkGroup: import_koishi2.Schema.string(),
1005
- linkWeight: import_koishi2.Schema.number()
1034
+ import_koishi5.Schema.object({
1035
+ record: import_koishi5.Schema.boolean().default(true).description("开启群语录功能"),
1036
+ tagWeight: import_koishi5.Schema.number().default(5).min(1).description("tag匹配时的权重,越高权重越大"),
1037
+ recordLink: import_koishi5.Schema.dict(import_koishi5.Schema.object({
1038
+ linkGroup: import_koishi5.Schema.string(),
1039
+ linkWeight: import_koishi5.Schema.number()
1006
1040
  })).role("table").description("群组链接,使得群可以调用被链接群的语录,<br>可以配置权重,作为键的群自身的权重为100(注意格式为平台名:群组名)"),
1007
- saveArchive: import_koishi2.Schema.boolean().default(false).description("开启入典功能").hidden()
1041
+ saveArchive: import_koishi5.Schema.boolean().default(false).description("开启入典功能").hidden()
1008
1042
  }).description("语录记录功能"),
1009
- import_koishi2.Schema.object({
1010
- roll: import_koishi2.Schema.boolean().default(true).description("开启roll随机数功能"),
1011
- undo: import_koishi2.Schema.boolean().default(true).description("机器人撤回消息功能(只测试了qq的onebot适配器)"),
1012
- echo: import_koishi2.Schema.boolean().default(true).description("echo回声洞功能"),
1013
- echoBanner: import_koishi2.Schema.array(String).role("table").description("echo屏蔽词,对文本生效"),
1014
- ready: import_koishi2.Schema.boolean().default(false).description("待机人数记录功能"),
1015
- saveReadyAsFile: import_koishi2.Schema.string().description("写入待机人数的本地地址,留空则不写入"),
1016
- roomNumber: import_koishi2.Schema.boolean().default(false).description("主跑房间号记录功能"),
1017
- saveRoomAsFile: import_koishi2.Schema.string().description("写入房间号的本地地址,留空则不写入"),
1018
- forward: import_koishi2.Schema.boolean().default(true).description("消息转发功能"),
1019
- searchExchangeRate: import_koishi2.Schema.boolean().default(false).description("查汇率功能"),
1020
- intervalGetExchangeRate: import_koishi2.Schema.boolean().default(false).description("汇率定时推送功能").hidden()
1043
+ import_koishi5.Schema.object({
1044
+ roll: import_koishi5.Schema.boolean().default(true).description("开启roll随机数功能"),
1045
+ undo: import_koishi5.Schema.boolean().default(true).description("机器人撤回消息功能(只测试了qq的onebot适配器)"),
1046
+ echo: import_koishi5.Schema.boolean().default(true).description("echo回声洞功能"),
1047
+ echoBanner: import_koishi5.Schema.array(String).role("table").description("echo屏蔽词,对文本生效"),
1048
+ ready: import_koishi5.Schema.boolean().default(false).description("待机人数记录功能"),
1049
+ saveReadyAsFile: import_koishi5.Schema.string().description("写入待机人数的本地地址,留空则不写入"),
1050
+ roomNumber: import_koishi5.Schema.boolean().default(false).description("主跑房间号记录功能"),
1051
+ saveRoomAsFile: import_koishi5.Schema.string().description("写入房间号的本地地址,留空则不写入"),
1052
+ forward: import_koishi5.Schema.boolean().default(true).description("消息转发功能"),
1053
+ searchExchangeRate: import_koishi5.Schema.boolean().default(false).description("查汇率功能"),
1054
+ intervalGetExchangeRate: import_koishi5.Schema.boolean().default(false).description("汇率定时推送功能").hidden()
1021
1055
  }).description("指令小功能"),
1022
- import_koishi2.Schema.object({
1023
- atNotSay: import_koishi2.Schema.boolean().default(true).description("开启‘艾特我又不说话’功能"),
1024
- atNotSayProperty: import_koishi2.Schema.number().role("slider").min(0).max(1).step(0.01).default(0.5).description("'艾特我又不说话'回复概率"),
1025
- atNotSayOther: import_koishi2.Schema.boolean().default(true).description("开启‘艾特他又不说话’功能"),
1026
- atNotSayOtherProperty: import_koishi2.Schema.number().role("slider").min(0).max(1).step(0.01).default(0.5).description("'艾特他又不说话'回复概率"),
1027
- iLoveYou: import_koishi2.Schema.boolean().default(true).description("开启‘我喜欢你’功能"),
1028
- replyBot: import_koishi2.Schema.union(["关闭", "无需at", "必须at"]).default("无需at").description("回复‘我才不是机器人!’功能")
1056
+ import_koishi5.Schema.object({
1057
+ atNotSay: import_koishi5.Schema.boolean().default(true).description("开启‘艾特我又不说话’功能"),
1058
+ atNotSayProperty: import_koishi5.Schema.number().role("slider").min(0).max(1).step(0.01).default(0.5).description("'艾特我又不说话'回复概率"),
1059
+ atNotSayOther: import_koishi5.Schema.boolean().default(true).description("开启‘艾特他又不说话’功能"),
1060
+ atNotSayOtherProperty: import_koishi5.Schema.number().role("slider").min(0).max(1).step(0.01).default(0.5).description("'艾特他又不说话'回复概率"),
1061
+ iLoveYou: import_koishi5.Schema.boolean().default(true).description("开启‘我喜欢你’功能"),
1062
+ replyBot: import_koishi5.Schema.union(["关闭", "无需at", "必须at"]).default("无需at").description("回复‘我才不是机器人!’功能")
1029
1063
  }).description("特定回应功能"),
1030
- import_koishi2.Schema.object({
1031
- sendLocalImage: import_koishi2.Schema.dict(import_koishi2.Schema.object({
1032
- hiddenInHelp: import_koishi2.Schema.boolean(),
1033
- imgPath: import_koishi2.Schema.string()
1064
+ import_koishi5.Schema.object({
1065
+ sendLocalImage: import_koishi5.Schema.dict(import_koishi5.Schema.object({
1066
+ hiddenInHelp: import_koishi5.Schema.boolean(),
1067
+ imgPath: import_koishi5.Schema.string()
1034
1068
  })).role("table").description("特定指令发送本地图片功能,其中键是指令名称,imgPath是图片文件的绝对路径")
1035
1069
  }),
1036
- import_koishi2.Schema.object({
1037
- openRepeat: import_koishi2.Schema.boolean().default(true).description("开启复读功能"),
1038
- minRepeatTimes: import_koishi2.Schema.number().default(2).description("最少重复次数"),
1039
- repeatPossibility: import_koishi2.Schema.number().role("slider").min(0).max(1).step(0.01).default(0.3).description("复读发生概率")
1070
+ import_koishi5.Schema.object({
1071
+ openRepeat: import_koishi5.Schema.boolean().default(true).description("开启复读功能"),
1072
+ minRepeatTimes: import_koishi5.Schema.number().default(2).description("最少重复次数"),
1073
+ repeatPossibility: import_koishi5.Schema.number().role("slider").min(0).max(1).step(0.01).default(0.3).description("复读发生概率")
1040
1074
  }).description("复读功能"),
1041
- import_koishi2.Schema.object({
1042
- filePathToBase64: import_koishi2.Schema.boolean().default(false).description("在消息发送前检查是否有file://,如果有那么转换为base64再发送"),
1043
- originImg: import_koishi2.Schema.boolean().default(false).description("根据链接获取原图开关")
1075
+ import_koishi5.Schema.object({
1076
+ filePathToBase64: import_koishi5.Schema.boolean().default(false).description("在消息发送前检查是否有file://,如果有那么转换为base64再发送"),
1077
+ originImg: import_koishi5.Schema.boolean().default(false).description("根据链接获取原图开关")
1044
1078
  }).description("自用功能"),
1045
- import_koishi2.Schema.union([
1046
- import_koishi2.Schema.object({
1047
- originImg: import_koishi2.Schema.const(true).required(),
1048
- originImgRSSUrl: import_koishi2.Schema.string().required().description("推特列表rss地址"),
1049
- proxyUrl: import_koishi2.Schema.string().default("http://127.0.0.1:7890").description("代理地址")
1079
+ import_koishi5.Schema.union([
1080
+ import_koishi5.Schema.object({
1081
+ originImg: import_koishi5.Schema.const(true).required(),
1082
+ originImgRSSUrl: import_koishi5.Schema.string().required().description("推特列表rss地址"),
1083
+ proxyUrl: import_koishi5.Schema.string().default("http://127.0.0.1:7890").description("代理地址")
1050
1084
  }),
1051
- import_koishi2.Schema.object({})
1085
+ import_koishi5.Schema.object({})
1052
1086
  ]),
1053
- import_koishi2.Schema.object({
1054
- featureControl: import_koishi2.Schema.string().role("textarea", { rows: [15] }).default("{\n\n}").description(`黑/白名单配置,语法为JSON格式(可以不缩进),<br>
1087
+ import_koishi5.Schema.object({
1088
+ featureControl: import_koishi5.Schema.string().role("textarea", { rows: [15] }).default("{\n\n}").description(`黑/白名单配置,语法为JSON格式(可以不缩进),<br>
1055
1089
  可配置功能键及语法详见 [项目地址](https://github.com/StarFreedomX/starfx-bot)或[npm发布页](https://www.npmjs.com/package/koishi-plugin-bangdream-ccg)`)
1056
1090
  }).description("高级配置")
1057
1091
  ]);
@@ -1059,7 +1093,7 @@ var usage = `<h2>StarFreedomX的自用插件 放了一些小功能</h2>
1059
1093
  `;
1060
1094
  function apply(ctx, cfg) {
1061
1095
  ctx.i18n.define("zh-CN", require_zh_CN());
1062
- baseDir = ctx.baseDir;
1096
+ baseDir2 = ctx.baseDir;
1063
1097
  assetsDir = `${ctx.baseDir}/data/starfx-bot/assets`;
1064
1098
  initAssets();
1065
1099
  const controlJson = parseJsonControl(cfg.featureControl);
@@ -1122,7 +1156,7 @@ function apply(ctx, cfg) {
1122
1156
  if (!imgSrc?.length) return "输入无效";
1123
1157
  const imageBase64 = await drawBanGDream(imgSrc, drawConfig);
1124
1158
  if (!imageBase64?.length) return "输入无效";
1125
- await session.send(import_koishi2.h.image(imageBase64));
1159
+ await session.send(import_koishi5.h.image(imageBase64));
1126
1160
  }
1127
1161
  });
1128
1162
  }
@@ -1151,14 +1185,14 @@ function apply(ctx, cfg) {
1151
1185
  const filepath = await getRecord(cfg, session.gid.replaceAll(":", "_"), tag);
1152
1186
  starfxLogger.info(`send record: ${filepath}`);
1153
1187
  if (!filepath) return "暂无语录呢";
1154
- await session.send(import_koishi2.h.image(filepath));
1188
+ await session.send(import_koishi5.h.image(filepath));
1155
1189
  }
1156
1190
  });
1157
1191
  }
1158
1192
  for (const key in cfg.sendLocalImage) {
1159
1193
  ctx.command(key, { hidden: cfg.sendLocalImage[key].hiddenInHelp }).action(async ({ session }) => {
1160
1194
  if (detectControl(controlJson, session.guildId, "sendLocalImage") && detectControl(controlJson, session.guildId, key))
1161
- return import_koishi2.h.image(safeQuote(cfg.sendLocalImage[key].imgPath, false));
1195
+ return import_koishi5.h.image(safeQuote(cfg.sendLocalImage[key].imgPath, false));
1162
1196
  });
1163
1197
  }
1164
1198
  if (cfg.roomNumber) {
@@ -1205,7 +1239,7 @@ function apply(ctx, cfg) {
1205
1239
  if (cfg.forward) {
1206
1240
  ctx.command("forward").option("group", "-g <group:string>").option("platform", "-p <platform:string>").usage("转发消息").action(async ({ session, options }) => {
1207
1241
  if (detectControl(controlJson, session.guildId, "forward")) {
1208
- const mapPath = import_node_path2.default.join(assetsDir, "forward.json");
1242
+ const mapPath = import_node_path3.default.join(assetsDir, "forward.json");
1209
1243
  const groupMap = readMap(mapPath);
1210
1244
  if (options.group) {
1211
1245
  if (["0", "clear", "del"].includes(options.group)) {
@@ -1252,7 +1286,7 @@ function apply(ctx, cfg) {
1252
1286
  if (cfg.intervalGetExchangeRate) {
1253
1287
  ctx.command("开启汇率推送 [exchangeParam:string]").action(async ({ session }, exchangeParam) => {
1254
1288
  if (detectControl(controlJson, session.guildId, "exchangeRate")) {
1255
- const exchangeRatePath = import_node_path2.default.join(assetsDir, "exchangeRate.json");
1289
+ const exchangeRatePath = import_node_path3.default.join(assetsDir, "exchangeRate.json");
1256
1290
  return await intervalGetExchangeRate(ctx, cfg, session, exchangeParam, exchangeRatePath);
1257
1291
  }
1258
1292
  });
@@ -1302,7 +1336,7 @@ function apply(ctx, cfg) {
1302
1336
  if (!ctxArr || ctxArr[0] !== content) {
1303
1337
  repeatContextMap.set(session.gid, [content, 1]);
1304
1338
  } else {
1305
- if (ctxArr[1] !== -1 && ++ctxArr[1] >= cfg.minRepeatTimes && import_koishi2.Random.bool(cfg.repeatPossibility)) {
1339
+ if (ctxArr[1] !== -1 && ++ctxArr[1] >= cfg.minRepeatTimes && import_koishi5.Random.bool(cfg.repeatPossibility)) {
1306
1340
  ctxArr[1] = -1;
1307
1341
  await session.send(content);
1308
1342
  }
@@ -1324,10 +1358,10 @@ function apply(ctx, cfg) {
1324
1358
  });
1325
1359
  }
1326
1360
  function initAssets() {
1327
- const defaultAssetsDir = import_node_path2.default.join(__dirname, "../assets");
1328
- assetsDir = import_node_path2.default.join(ctx.baseDir, "data/starfx-bot/assets");
1361
+ const defaultAssetsDir = import_node_path3.default.join(__dirname, "../assets");
1362
+ assetsDir = import_node_path3.default.join(ctx.baseDir, "data/starfx-bot/assets");
1329
1363
  if (!fs2.existsSync(assetsDir)) fs2.mkdirSync(assetsDir, { recursive: true });
1330
- const versionFile = import_node_path2.default.join(assetsDir, "plugin_version.json");
1364
+ const versionFile = import_node_path3.default.join(assetsDir, "plugin_version.json");
1331
1365
  let localVersion = "0";
1332
1366
  if (fs2.existsSync(versionFile)) {
1333
1367
  try {
@@ -0,0 +1,22 @@
1
+ import { Config } from "../index";
2
+ import { Context, Session } from "koishi";
3
+ interface CurrencyCode {
4
+ "country": string;
5
+ "currencyCn": string;
6
+ "code": string;
7
+ }
8
+ export declare function intervalGetExchangeRate(ctx: Context, cfg: Config, session: Session, searchString: string, exchangeRatePath: string): Promise<void>;
9
+ export declare function getExchangeRate(ctx: Context, cfg: Config, session: Session, searchString?: string, raw?: string, retryTimes?: number): Promise<void>;
10
+ /**
11
+ * 绘制走势图
12
+ * @param prices 收盘价数组
13
+ * @param timeStamps ISO 时间戳数组
14
+ * @param title 图表标题
15
+ * @param width 图表宽度
16
+ * @param height 图表高度
17
+ * @returns buffer
18
+ */
19
+ export declare function drawCurrencyChartSkia(prices: number[], timeStamps: string[], title?: string, width?: number, height?: number): Promise<Buffer>;
20
+ export declare function getCurrencyCodes(): Promise<CurrencyCode[]>;
21
+ export declare function getCurrencyCodesMap(): Promise<Record<string, string>>;
22
+ export {};
@@ -0,0 +1,39 @@
1
+ import { Context, h } from "koishi";
2
+ /**
3
+ * 将options的参数转换为drawBanGDreamBorder的配置
4
+ * @param options
5
+ * @return 适用于边框绘制的参数
6
+ */
7
+ export declare function handleBanGDreamConfig(options: any): Promise<{
8
+ color: string;
9
+ band: string;
10
+ starType: string;
11
+ starNum: number;
12
+ border: string;
13
+ }>;
14
+ /**
15
+ * "封印"绘图功能
16
+ * @param ctx Context
17
+ * @param baseImage 被封印的图片url
18
+ * @return 画完的图片 h对象
19
+ */
20
+ export declare function drawLock(ctx: Context, baseImage: string): Promise<"发生错误" | "输入无效" | h>;
21
+ /**
22
+ * "卖掉了"绘图函数
23
+ * @param ctx
24
+ * @param baseImage
25
+ * @return 画完的图片 h对象
26
+ */
27
+ export declare function drawSold(ctx: Context, baseImage: string): Promise<"发生错误" | "输入无效" | h>;
28
+ /**
29
+ * BanG Dream!边框绘制功能
30
+ * @param avatar 要绘制的底图
31
+ * @param inputOptions 输入参数,接受color band starType starNum border
32
+ */
33
+ export declare function drawBanGDream(avatar: string, inputOptions?: {
34
+ color: string;
35
+ band: string;
36
+ starType: string;
37
+ starNum: number;
38
+ border: string;
39
+ }): Promise<string>;
@@ -0,0 +1,7 @@
1
+ import { Session } from "koishi";
2
+ import { Config } from "../index";
3
+ export declare function getXUrl(urls: string): Promise<any[]>;
4
+ export declare function getXNum(session: Session): Promise<number[]>;
5
+ export declare function getXImage(rssUrl: string, xUrls: string | string[]): Promise<string[]>;
6
+ export declare function chunk<T>(arr: T[], size: number): T[][];
7
+ export declare function sendImages(session: Session, cfg: Config, imageUrls: string[]): Promise<void>;
package/lib/utils.d.ts CHANGED
@@ -63,32 +63,6 @@ export declare function getImageSrc(session: Session, param: string, option?: {
63
63
  noParam?: boolean;
64
64
  quote?: boolean;
65
65
  }): Promise<string>;
66
- /**
67
- * 将options的参数转换为drawBanGDreamBorder的配置
68
- * @param options
69
- * @return 适用于边框绘制的参数
70
- */
71
- export declare function handleBanGDreamConfig(options: any): Promise<{
72
- color: string;
73
- band: string;
74
- starType: string;
75
- starNum: number;
76
- border: string;
77
- }>;
78
- /**
79
- * "封印"绘图功能
80
- * @param ctx Context
81
- * @param baseImage 被封印的图片url
82
- * @return 画完的图片 h对象
83
- */
84
- export declare function drawLock(ctx: Context, baseImage: string): Promise<"发生错误" | "输入无效" | h>;
85
- /**
86
- * "卖掉了"绘图函数
87
- * @param ctx
88
- * @param baseImage
89
- * @return 画完的图片 h对象
90
- */
91
- export declare function drawSold(ctx: Context, baseImage: string): Promise<"发生错误" | "输入无效" | h>;
92
66
  /**
93
67
  * 从url下载图片并返回sharp对象
94
68
  * @param ctx Context
@@ -117,20 +91,6 @@ export declare function replyBot(cfg: Config, session: Session, elements: h[]):
117
91
  * @param elements 当前消息elements
118
92
  */
119
93
  export declare function iLoveYou(cfg: Config, session: Session, elements: h[]): Promise<void>;
120
- /**
121
- * BanG Dream!边框绘制功能
122
- * @param avatar 要绘制的底图
123
- * @param inputOptions 输入参数,接受color band starType starNum border
124
- */
125
- export declare function drawBanGDream(avatar: string, inputOptions?: {
126
- color: string;
127
- band: string;
128
- starType: string;
129
- starNum: number;
130
- border: string;
131
- }): Promise<string>;
132
- export declare function intervalGetExchangeRate(ctx: Context, cfg: Config, session: Session, searchString: string, exchangeRatePath: string): Promise<void>;
133
- export declare function getExchangeRate(ctx: Context, cfg: Config, session: Session, searchString?: string, raw?: string, retryTimes?: number): Promise<void>;
134
94
  export declare function parseJsonControl(text: string): FeatureControl | null;
135
95
  export declare function detectControl(controlJson: FeatureControl, guildId: string, funName: string): boolean;
136
96
  export declare function handleRoll(session: Session): string;
@@ -140,31 +100,9 @@ export declare function handleRoll(session: Session): string;
140
100
  * @param session session
141
101
  */
142
102
  export declare function undo(cfg: Config, session: Session): Promise<void>;
143
- export declare function getXUrl(urls: string): Promise<any[]>;
144
- export declare function getXNum(session: Session): Promise<number[]>;
145
- export declare function getXImage(rssUrl: string, xUrls: string | string[]): Promise<string[]>;
146
- export declare function chunk<T>(arr: T[], size: number): T[][];
147
- export declare function sendImages(session: Session, cfg: Config, imageUrls: string[]): Promise<void>;
148
103
  export declare function safeQuote(str: string, useQuote: boolean): string;
149
- export declare function test(url: string): Promise<void>;
150
104
  export declare function writeMap(map: Map<any, any>, dest: string): void;
151
105
  export declare function readMap(url: string): Map<any, any>;
152
106
  export declare function ready(session: Session, cfg: Config, param: string, readyMap: Map<string, string[]>): string;
153
- /**
154
- * 绘制近一个月收盘价走势图
155
- * @param prices 收盘价数组
156
- * @param timeStamps ISO 时间戳数组
157
- * @param title 图表标题
158
- * @param width 图表宽度
159
- * @param height 图表高度
160
- * @returns buffer
161
- */
162
- export declare function drawOneMonthChartSkia(prices: number[], timeStamps: string[], title?: string, width?: number, height?: number): Promise<Buffer>;
163
- interface CurrencyCode {
164
- "country": string;
165
- "currencyCn": string;
166
- "code": string;
167
- }
168
- export declare function getCurrencyCodes(): Promise<CurrencyCode[]>;
169
- export declare function getCurrencyCodesMap(): Promise<Record<string, string>>;
107
+ export declare function test(url: string): Promise<void>;
170
108
  export {};
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "contributors": [
5
5
  "StarFreedomX <starfreedomx@outlook.com>"
6
6
  ],
7
- "version": "0.19.4",
7
+ "version": "0.19.6",
8
8
  "main": "lib/index.js",
9
9
  "typings": "lib/index.d.ts",
10
10
  "files": [
package/readme.md CHANGED
@@ -89,30 +89,32 @@ StarFreedomX机器人的小功能,自用
89
89
  ## 更新日志
90
90
 
91
91
 
92
- | 版本 | 更新日志 |
93
- |----------|------------------------------------|
94
- | `0.0.1` | 加入封印功能 |
95
- | `0.1.0` | 加入"卖掉了"功能 |
96
- | `0.2.0` | 加入"艾特我又不说话"回复功能 |
97
- | `0.3.0` | 加入"我喜欢你"和"我才不是机器人!"回复功能 |
98
- | `0.4.0` | 更改处理库为sharp |
99
- | `0.5.0` | 加入BanG Dream!边框功能 |
100
- | `0.6.0` | 加入群语录功能,修复一处bangdream绘制的bug |
101
- | `0.7.0` | 加入复读功能 |
102
- | `0.8.0` | 将各个工具函数封装在utils.ts中,更改语录的触发方式 |
103
- | `0.9.0` | 添加白名单/黑名单模式,对每个功能做过滤 |
104
- | `0.10.0` | 添加随机数功能 |
105
- | `0.11.0` | 增加适配于onebot(主要是qq)的撤回功能 |
106
- | `0.12.0` | 加入echo功能 |
107
- | `0.13.0` | 语录支持tag以及调整权重 |
108
- | `0.14.0` | echo增加对引用消息的支持,且支持有at触发 |
109
- | `0.15.0` | 自用rss获取推特原图 |
110
- | `0.16.0` | 新增自定义指令发送本地图片功能(其实网络图片也行) |
111
- | `0.16.3` | 发送文件前转为使用base64 |
112
- | `0.17.0` | 语录功能新增链接,可以配置权重 |
113
- | `0.18.0` | 新增定时echo |
114
- | `0.19.0` | 新增查汇率功能 |
115
- | `0.19.1` | 查汇率适配更多语法 |
116
- | `0.19.2` | 查汇率修复文件缺失 |
117
- | `0.19.3` | 转移currency.json到assets |
118
- | `0.19.4` | inject database for ctx.broadcast |
92
+ | 版本 | 更新日志 |
93
+ |----------|-----------------------------------|
94
+ | `0.0.1` | 加入封印功能 |
95
+ | `0.1.0` | 加入"卖掉了"功能 |
96
+ | `0.2.0` | 加入"艾特我又不说话"回复功能 |
97
+ | `0.3.0` | 加入"我喜欢你"和"我才不是机器人!"回复功能 |
98
+ | `0.4.0` | 更改处理库为sharp |
99
+ | `0.5.0` | 加入BanG Dream!边框功能 |
100
+ | `0.6.0` | 加入群语录功能,修复一处bangdream绘制的bug |
101
+ | `0.7.0` | 加入复读功能 |
102
+ | `0.8.0` | 将各个工具函数封装在utils.ts中,更改语录的触发方式 |
103
+ | `0.9.0` | 添加白名单/黑名单模式,对每个功能做过滤 |
104
+ | `0.10.0` | 添加随机数功能 |
105
+ | `0.11.0` | 增加适配于onebot(主要是qq)的撤回功能 |
106
+ | `0.12.0` | 加入echo功能 |
107
+ | `0.13.0` | 语录支持tag以及调整权重 |
108
+ | `0.14.0` | echo增加对引用消息的支持,且支持有at触发 |
109
+ | `0.15.0` | 自用rss获取推特原图 |
110
+ | `0.16.0` | 新增自定义指令发送本地图片功能(其实网络图片也行) |
111
+ | `0.16.3` | 发送文件前转为使用base64 |
112
+ | `0.17.0` | 语录功能新增链接,可以配置权重 |
113
+ | `0.18.0` | 新增定时echo |
114
+ | `0.19.0` | 新增查汇率功能 |
115
+ | `0.19.1` | 查汇率适配更多语法 |
116
+ | `0.19.2` | 查汇率修复文件缺失 |
117
+ | `0.19.3` | 转移currency.json到assets |
118
+ | `0.19.4` | inject database for ctx.broadcast |
119
+ | `0.19.5` | 提取代码量较大的功能为单独插件 |
120
+ | `0.19.6` | 查汇率支持近5d |