koishi-plugin-cfmrmod 1.0.0 → 1.0.2

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.
@@ -3,11 +3,24 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Config = exports.name = void 0;
4
4
  exports.apply = apply;
5
5
  const { Schema, h } = require('koishi');
6
- // 【修复】这里添加了 Path2D 的引入
7
- const { createCanvas, loadImage, Path2D, GlobalFonts } = require('@napi-rs/canvas');
8
6
  const fetch = require('node-fetch');
9
7
  const cheerio = require('cheerio');
10
8
  const { marked } = require('marked');
9
+ let createCanvas;
10
+ let loadImage;
11
+ let Path2DRef;
12
+ let registerFont;
13
+ async function toImageSrc(input) {
14
+ const value = (input && typeof input.then === 'function') ? await input : input;
15
+ if (!value)
16
+ return '';
17
+ if (typeof value === 'string')
18
+ return value;
19
+ const buf = Buffer.isBuffer(value) ? value : (value instanceof Uint8Array ? Buffer.from(value) : null);
20
+ if (buf)
21
+ return `data:image/png;base64,${buf.toString('base64')}`;
22
+ return String(value);
23
+ }
11
24
  const CF_LOADER_MAP = {
12
25
  1: 'Forge',
13
26
  2: 'Cauldron',
@@ -560,6 +573,8 @@ async function drawProjectCard(data) {
560
573
  // Stats & Tags Row
561
574
  // Downloads Icon
562
575
  const drawIcon = (path, x, y) => {
576
+ if (!Path2DRef)
577
+ return;
563
578
  ctx.save();
564
579
  ctx.translate(x, y);
565
580
  ctx.scale(0.8, 0.8);
@@ -567,8 +582,7 @@ async function drawProjectCard(data) {
567
582
  ctx.lineWidth = 2;
568
583
  ctx.lineCap = 'round';
569
584
  ctx.lineJoin = 'round';
570
- // Path2D 需要引入
571
- const p = new Path2D(path);
585
+ const p = new Path2DRef(path);
572
586
  ctx.stroke(p);
573
587
  ctx.restore();
574
588
  };
@@ -777,7 +791,7 @@ async function drawProjectCard(data) {
777
791
  ctx.fillText('Generated by Koishi | Powered by Modrinth & CurseForge', width / 2, footerY);
778
792
  footerY += 18;
779
793
  // 3. 绘制要求的作者署名
780
- ctx.fillText('插件作者 Mai_xiyu(机器人作者 Mai_xiyu', width / 2, footerY);
794
+ ctx.fillText('Plugin By Mai_xiyu', width / 2, footerY);
781
795
  return [canvas.toBuffer('image/png')];
782
796
  }
783
797
  // ================= CurseForge 专用构图 =================
@@ -1050,7 +1064,7 @@ async function drawProjectCardCF(data) {
1050
1064
  ctx.font = `12px "${font}"`;
1051
1065
  ctx.textAlign = 'center';
1052
1066
  ctx.textBaseline = 'top';
1053
- ctx.fillText('插件作者 Mai_xiyu(机器人作者 Mai_xiyu', rightX + sidebarW / 2, fy);
1067
+ ctx.fillText('Plugin By Mai_xiyu', rightX + sidebarW / 2, fy);
1054
1068
  ctx.textAlign = 'left';
1055
1069
  ry += item.h;
1056
1070
  }
@@ -1488,18 +1502,25 @@ async function searchCurseForge(query, type, apiKey, timeout, gameId = 432) {
1488
1502
  function apply(ctx, config) {
1489
1503
  var _a, _b;
1490
1504
  const logger = ctx.logger('mc-search');
1491
- if (config.fontPath) {
1492
- try {
1493
- const ok = GlobalFonts.registerFromPath(config.fontPath, 'KoishiFont');
1494
- if (ok)
1495
- GLOBAL_FONT_FAMILY = 'KoishiFont';
1496
- else
1497
- logger.warn('字体加载失败: registerFromPath 返回 false');
1498
- }
1499
- catch (e) {
1500
- logger.warn('字体加载失败: ' + e.message);
1501
- }
1505
+ const skia = ctx.skia;
1506
+ if (!(skia === null || skia === void 0 ? void 0 : skia.Canvas) || !(skia === null || skia === void 0 ? void 0 : skia.loadImage)) {
1507
+ throw new Error('缺少 skia 服务,请先启用 @ltxhhz/koishi-plugin-skia-canvas');
1502
1508
  }
1509
+ createCanvas = (w, h) => {
1510
+ const c = new skia.Canvas(w || 0, h || 0);
1511
+ if (!c || typeof c.getContext !== 'function') {
1512
+ throw new Error('skia 服务异常:Canvas 无效,请确认使用 @ltxhhz/koishi-plugin-skia-canvas');
1513
+ }
1514
+ return c;
1515
+ };
1516
+ loadImage = skia.loadImage;
1517
+ registerFont = (path, options) => {
1518
+ var _a;
1519
+ if ((_a = skia.FontLibrary) === null || _a === void 0 ? void 0 : _a.use)
1520
+ skia.FontLibrary.use(path, options === null || options === void 0 ? void 0 : options.family);
1521
+ };
1522
+ Path2DRef = skia.Path2D || globalThis.Path2D;
1523
+ // 取消自定义字体配置,使用 skia 默认字体
1503
1524
  const states = new Map();
1504
1525
  const normalizeMessageIds = (res) => {
1505
1526
  if (!res)
@@ -1564,7 +1585,7 @@ function apply(ctx, config) {
1564
1585
  maxCanvasHeight: config.maxCanvasHeight || 8000
1565
1586
  });
1566
1587
  for (const buf of imgBufs) {
1567
- await session.send(h.image(buf, 'image/png'));
1588
+ await session.send(h.image(await toImageSrc(buf)));
1568
1589
  }
1569
1590
  if (config.sendLink)
1570
1591
  await session.send(`链接: ${detailData.url}`);
@@ -1625,7 +1646,7 @@ function apply(ctx, config) {
1625
1646
  maxCanvasHeight: config.maxCanvasHeight || 8000
1626
1647
  });
1627
1648
  for (const buf of imgBufs) {
1628
- await session.send(h.image(buf, 'image/png'));
1649
+ await session.send(h.image(await toImageSrc(buf)));
1629
1650
  }
1630
1651
  if (config.sendLink)
1631
1652
  await session.send(`链接: ${detailData.url}`);
package/dist/index.js CHANGED
@@ -33,19 +33,19 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.Config = exports.name = void 0;
36
+ exports.Config = exports.inject = exports.name = void 0;
37
37
  exports.apply = apply;
38
38
  const koishi_1 = require("koishi");
39
39
  const cfmr = __importStar(require("./plugins/cfmr"));
40
40
  const mcmod = __importStar(require("./plugins/mcmod"));
41
41
  exports.name = 'minecraft-search';
42
+ exports.inject = ['skia'];
42
43
  exports.Config = koishi_1.Schema.object({
43
44
  prefixes: koishi_1.Schema.object({
44
45
  cf: koishi_1.Schema.string().default('cf'),
45
46
  mr: koishi_1.Schema.string().default('mr'),
46
47
  cnmc: koishi_1.Schema.string().default('cnmc'),
47
48
  }).description('指令前缀设置'),
48
- fontPath: koishi_1.Schema.string().role('path').description('中文字体路径 (建议使用含中文和Emoji的字体)'),
49
49
  timeouts: koishi_1.Schema.number().default(60000).description('搜索会话超时时间(ms)'),
50
50
  debug: koishi_1.Schema.boolean().default(false).description('开启调试日志'),
51
51
  cfmr: cfmr.Config.description('CurseForge/Modrinth 搜索与图片卡片'),
@@ -55,7 +55,6 @@ function apply(ctx, config) {
55
55
  const prefixes = (config === null || config === void 0 ? void 0 : config.prefixes) || {};
56
56
  const shared = {
57
57
  prefixes,
58
- fontPath: config === null || config === void 0 ? void 0 : config.fontPath,
59
58
  timeouts: config === null || config === void 0 ? void 0 : config.timeouts,
60
59
  debug: config === null || config === void 0 ? void 0 : config.debug,
61
60
  };
@@ -6,8 +6,21 @@ const fetch = require('node-fetch');
6
6
  const cheerio = require('cheerio');
7
7
  const fs = require('fs');
8
8
  const path = require('path');
9
- const { createCanvas, loadImage, registerFont, GlobalFonts } = require('@napi-rs/canvas');
10
9
  const { h, Schema } = require('koishi');
10
+ let createCanvas;
11
+ let loadImage;
12
+ let registerFont;
13
+ async function toImageSrc(input) {
14
+ const value = (input && typeof input.then === 'function') ? await input : input;
15
+ if (!value)
16
+ return '';
17
+ if (typeof value === 'string')
18
+ return value;
19
+ const buf = Buffer.isBuffer(value) ? value : (value instanceof Uint8Array ? Buffer.from(value) : null);
20
+ if (buf)
21
+ return `data:image/png;base64,${buf.toString('base64')}`;
22
+ return String(value);
23
+ }
11
24
  // Cookie 管理器
12
25
  let cookieManager = null;
13
26
  try {
@@ -139,13 +152,14 @@ function wrapText(ctx, text, x, y, maxWidth, lineHeight, maxLines = 1000, draw =
139
152
  return currentY + lineHeight;
140
153
  }
141
154
  // ================= 字体注册 =================
142
- function initFont(preferredPath, logger) {
155
+ function initFont(preferredPath, logger, registerFontFn) {
143
156
  const fontName = 'MCModFont';
144
157
  const tryRegister = (filePath, source) => {
145
158
  if (!fs.existsSync(filePath))
146
159
  return false;
147
160
  try {
148
- if (GlobalFonts.registerFromPath(filePath, fontName)) {
161
+ if (registerFontFn) {
162
+ registerFontFn(filePath, { family: fontName });
149
163
  GLOBAL_FONT_FAMILY = fontName;
150
164
  logger.info(`[Font] 成功加载${source}: ${filePath}`);
151
165
  return true;
@@ -2165,7 +2179,7 @@ async function drawCenterCardImpl(uid, logger) {
2165
2179
  ctx.fillStyle = '#999';
2166
2180
  ctx.font = `12px "${font}"`;
2167
2181
  ctx.textAlign = 'center';
2168
- ctx.fillText('mcmod.cn & bbs.mcmod.cn | Powered by Koishi | Bot By Mai_xiyu', width / 2, totalHeight - 15);
2182
+ ctx.fillText('mcmod.cn & bbs.mcmod.cn | Powered by Koishi | Plugin By Mai_xiyu', width / 2, totalHeight - 15);
2169
2183
  return canvas.toBuffer('image/png');
2170
2184
  }
2171
2185
  // ================= 详情页卡片 =================
@@ -2433,7 +2447,24 @@ exports.Config = Schema.object({
2433
2447
  function apply(ctx, config) {
2434
2448
  var _a;
2435
2449
  const logger = ctx.logger('mcmod');
2436
- if (!initFont(config.fontPath, logger)) { }
2450
+ const skia = ctx.skia;
2451
+ if (!(skia === null || skia === void 0 ? void 0 : skia.Canvas) || !(skia === null || skia === void 0 ? void 0 : skia.loadImage)) {
2452
+ throw new Error('缺少 skia 服务,请先启用 @ltxhhz/koishi-plugin-skia-canvas');
2453
+ }
2454
+ createCanvas = (w, h) => {
2455
+ const c = new skia.Canvas(w || 0, h || 0);
2456
+ if (!c || typeof c.getContext !== 'function') {
2457
+ throw new Error('skia 服务异常:Canvas 无效,请确认使用 @ltxhhz/koishi-plugin-skia-canvas');
2458
+ }
2459
+ return c;
2460
+ };
2461
+ loadImage = skia.loadImage;
2462
+ registerFont = (path, options) => {
2463
+ var _a;
2464
+ if ((_a = skia.FontLibrary) === null || _a === void 0 ? void 0 : _a.use)
2465
+ skia.FontLibrary.use(path, options === null || options === void 0 ? void 0 : options.family);
2466
+ };
2467
+ // 取消自定义字体配置,使用 skia 默认字体
2437
2468
  // 初始化 Cookie
2438
2469
  if (config.cookie) {
2439
2470
  globalCookie = config.cookie;
@@ -2563,7 +2594,7 @@ function apply(ctx, config) {
2563
2594
  img = await drawTutorialCard(item.link);
2564
2595
  else
2565
2596
  img = await createInfoCard(item.link, type);
2566
- await session.send(h.image(img, 'image/png'));
2597
+ await session.send(h.image(await toImageSrc(img)));
2567
2598
  if (config.sendLink)
2568
2599
  await session.send(`链接: ${item.link}`);
2569
2600
  return;
@@ -2612,7 +2643,7 @@ function apply(ctx, config) {
2612
2643
  const item = results[0];
2613
2644
  await ensureValidCookie();
2614
2645
  const img = await drawModCard(item.link);
2615
- await session.send(h.image(img, 'image/png'));
2646
+ await session.send(h.image(await toImageSrc(img)));
2616
2647
  if (config.sendLink)
2617
2648
  await session.send(`链接: ${item.link}`);
2618
2649
  return;
@@ -2716,7 +2747,7 @@ function apply(ctx, config) {
2716
2747
  img = await drawTutorialCard(item.link);
2717
2748
  else
2718
2749
  img = await createInfoCard(item.link, currentState.type);
2719
- await session.send(h.image(img, 'image/png'));
2750
+ await session.send(h.image(await toImageSrc(img)));
2720
2751
  if (config.sendLink)
2721
2752
  await session.send(`链接: ${item.link}`);
2722
2753
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "koishi-plugin-cfmrmod",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Koishi 插件:搜索 CurseForge/Modrinth/MCMod 并渲染图片卡片",
5
5
  "main": "dist/index.js",
6
6
  "files": [
@@ -39,10 +39,10 @@
39
39
  "pub": "npm run build && npm publish --access public"
40
40
  },
41
41
  "peerDependencies": {
42
- "koishi": "^4.0.0"
42
+ "koishi": "^4.0.0",
43
+ "@ltxhhz/koishi-plugin-skia-canvas": "^0.0.10"
43
44
  },
44
45
  "dependencies": {
45
- "@napi-rs/canvas": "^0.1.55",
46
46
  "cheerio": "^1.0.0-rc.12",
47
47
  "marked": "^9.1.5",
48
48
  "node-fetch": "^2.6.12"
@@ -53,6 +53,9 @@
53
53
  "koishi": {
54
54
  "description": {
55
55
  "zh": "从 CurseForge/Modrinth/MCMod 搜索模组/整合包/光影等内容,并生成图片卡片。"
56
+ },
57
+ "service": {
58
+ "required": ["skia"]
56
59
  }
57
60
  }
58
61
  }