koishi-plugin-csss 1.0.1 → 1.1.1

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/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Tang
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Tang
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/lib/index.d.ts CHANGED
@@ -20,6 +20,9 @@ export interface Config {
20
20
  scheduleEndTime: string;
21
21
  scheduleGroups: string[];
22
22
  scheduleUseImage: boolean;
23
+ qqAdapterName: string;
24
+ useFullChannelId: boolean;
23
25
  }
24
26
  export declare const Config: Schema<Config>;
25
27
  export declare function apply(ctx: Context, config: Config): void;
28
+ export declare const inject: string[];
package/lib/index.js CHANGED
@@ -1,8 +1,6 @@
1
- var __create = Object.create;
2
1
  var __defProp = Object.defineProperty;
3
2
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __getProtoOf = Object.getPrototypeOf;
6
4
  var __hasOwnProp = Object.prototype.hasOwnProperty;
7
5
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
8
6
  var __export = (target, all) => {
@@ -17,14 +15,6 @@ var __copyProps = (to, from, except, desc) => {
17
15
  }
18
16
  return to;
19
17
  };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
19
 
30
20
  // src/index.ts
@@ -32,11 +22,11 @@ var src_exports = {};
32
22
  __export(src_exports, {
33
23
  Config: () => Config,
34
24
  apply: () => apply,
25
+ inject: () => inject,
35
26
  name: () => name
36
27
  });
37
28
  module.exports = __toCommonJS(src_exports);
38
29
  var import_koishi = require("koishi");
39
- var import_canvas = require("canvas");
40
30
  var name = "cs-server-status";
41
31
  var Config = import_koishi.Schema.object({
42
32
  timeout: import_koishi.Schema.number().min(1e3).max(3e4).default(5e3).description("查询超时时间(毫秒)"),
@@ -57,14 +47,41 @@ var Config = import_koishi.Schema.object({
57
47
  "edgebug.cn:27018"
58
48
  ]),
59
49
  batchTimeout: import_koishi.Schema.number().min(1e3).max(6e4).default(15e3).description("批量查询总超时时间(毫秒)"),
60
- // 新增定时任务配置
50
+ // 定时任务配置
61
51
  scheduleEnabled: import_koishi.Schema.boolean().default(false).description("是否启用定时自动查询功能"),
62
52
  scheduleInterval: import_koishi.Schema.number().min(1).max(1440).default(5).description("定时查询间隔时间(分钟)"),
63
53
  scheduleStartTime: import_koishi.Schema.string().pattern(/^([01]?[0-9]|2[0-3]):[0-5][0-9]$/).default("08:00").description("定时任务开始时间(24小时制,格式: HH:MM)"),
64
54
  scheduleEndTime: import_koishi.Schema.string().pattern(/^([01]?[0-9]|2[0-3]):[0-5][0-9]$/).default("23:00").description("定时任务结束时间(24小时制,格式: HH:MM)"),
65
55
  scheduleGroups: import_koishi.Schema.array(import_koishi.Schema.string()).role("table").description("定时发送的群组ID列表(每行一个群组ID)").default([]),
66
- scheduleUseImage: import_koishi.Schema.boolean().default(true).description("定时任务是否使用图片格式输出")
56
+ scheduleUseImage: import_koishi.Schema.boolean().default(true).description("定时任务是否使用图片格式输出"),
57
+ // QQ适配器配置
58
+ qqAdapterName: import_koishi.Schema.string().default("qq").description('QQ适配器名称(默认为"qq",如果在QQ配置中指定了其他名称请修改)'),
59
+ useFullChannelId: import_koishi.Schema.boolean().default(true).description("是否使用完整的频道ID格式(推荐开启)")
67
60
  });
61
+ var COLORS = {
62
+ background: "rgba(28,28,31,0.80)",
63
+ text: "rgb(113, 113, 122)",
64
+ textLight: "#aaaaaa",
65
+ textLighter: "#dddddd",
66
+ textWhite: "#ffffff",
67
+ border: "#2e2e33",
68
+ accent: "#fbbf24",
69
+ success: "#4CAF50",
70
+ warning: "#FFC107",
71
+ error: "#c03f36",
72
+ pingGreen: "#4CAF50",
73
+ pingYellow: "#FFC107",
74
+ pingOrange: "#FF9800",
75
+ pingRed: "#c03f36",
76
+ playerOnline: "#4CAF50",
77
+ playerOffline: "#c03f36",
78
+ title: "#71717a",
79
+ highlight: "#fbbf24",
80
+ divider: "#555555",
81
+ timestamp: "#666666",
82
+ gold: "#FFD700",
83
+ playerName: "rgb(252, 248, 222)"
84
+ };
68
85
  var utils = {
69
86
  formatPing(ping) {
70
87
  if (!ping || ping < 0) return "未知";
@@ -80,37 +97,111 @@ var utils = {
80
97
  return text.length > maxLength ? text.substring(0, maxLength) + "..." : text;
81
98
  },
82
99
  getPingColor(ping) {
83
- if (ping < 50) return "#4CAF50";
84
- if (ping < 100) return "#FFC107";
85
- if (ping < 200) return "#FF9800";
86
- return "#c03f36";
100
+ if (ping < 50) return COLORS.pingGreen;
101
+ if (ping < 100) return COLORS.pingYellow;
102
+ if (ping < 200) return COLORS.pingOrange;
103
+ return COLORS.pingRed;
87
104
  },
88
105
  getPlayerColor(count) {
89
- return count > 0 ? "#4CAF50" : "#c03f36";
106
+ return count > 0 ? COLORS.playerOnline : COLORS.playerOffline;
90
107
  },
91
- // 新增:格式化时间
92
108
  formatTime(ms) {
93
109
  if (ms < 1e3) return `${ms}ms`;
94
110
  if (ms < 6e4) return `${(ms / 1e3).toFixed(1)}秒`;
95
111
  return `${(ms / 1e3).toFixed(0)}秒`;
96
112
  },
97
- // 新增:解析时间字符串为分钟数
98
113
  parseTimeToMinutes(timeStr) {
99
114
  const [hours, minutes] = timeStr.split(":").map(Number);
100
115
  return hours * 60 + minutes;
101
116
  },
102
- // 新增:检查当前时间是否在定时任务时间范围内
103
117
  isWithinScheduleTime(startTime, endTime) {
104
118
  const now = /* @__PURE__ */ new Date();
105
119
  const currentMinutes = now.getHours() * 60 + now.getMinutes();
106
120
  const startMinutes = this.parseTimeToMinutes(startTime);
107
121
  const endMinutes = this.parseTimeToMinutes(endTime);
108
122
  return currentMinutes >= startMinutes && currentMinutes <= endMinutes;
123
+ },
124
+ formatGroupId(groupId, adapterName, useFullChannelId) {
125
+ if (useFullChannelId) {
126
+ return `${adapterName}:${groupId}`;
127
+ }
128
+ return groupId;
109
129
  }
110
130
  };
111
131
  function apply(ctx, config) {
112
132
  const cache = /* @__PURE__ */ new Map();
113
133
  let scheduleTimer = null;
134
+ if (!ctx.gamedig) {
135
+ console.error("koishi-plugin-gamedig 未安装或未启用");
136
+ return ctx.logger("cs-server-status").error("需要安装并启用 koishi-plugin-gamedig 插件");
137
+ }
138
+ if (!ctx.canvas) {
139
+ console.error("koishi-plugin-canvas 未安装或未启用");
140
+ return ctx.logger("cs-server-status").error("需要安装并启用 koishi-plugin-canvas 插件");
141
+ }
142
+ async function queryServers(serversToQuery) {
143
+ const startTime = Date.now();
144
+ const results = await Promise.allSettled(
145
+ serversToQuery.map(async (server, index) => {
146
+ try {
147
+ const { host, port } = parseAddress(server);
148
+ const data = await queryServer(host, port);
149
+ return {
150
+ index: index + 1,
151
+ server,
152
+ success: true,
153
+ data
154
+ };
155
+ } catch (error) {
156
+ return {
157
+ index: index + 1,
158
+ server,
159
+ success: false,
160
+ error: error.message
161
+ };
162
+ }
163
+ })
164
+ );
165
+ const endTime = Date.now();
166
+ const queryTime = endTime - startTime;
167
+ return { results, queryTime, serversToQuery };
168
+ }
169
+ __name(queryServers, "queryServers");
170
+ function generateTextTable(results, serversToQuery, queryTime, title = "批量查询结果") {
171
+ const successful = results.filter((r) => r.status === "fulfilled" && r.value.success).length;
172
+ const failed = results.length - successful;
173
+ let message = `📊 ${title} (${utils.formatTime(queryTime)})
174
+ `;
175
+ message += `✅ 成功: ${successful} 个 | ❌ 失败: ${failed} 个
176
+
177
+ `;
178
+ message += "序号 服务器名称 在线人数\n";
179
+ message += "──────────────────────────────\n";
180
+ results.forEach((result, index) => {
181
+ const serverInfo = serversToQuery[index];
182
+ if (result.status === "fulfilled") {
183
+ const { success, data, error } = result.value;
184
+ if (success && data) {
185
+ const { result: serverData } = data;
186
+ const serverName = serverData.name ? utils.cleanName(serverData.name) : "未知";
187
+ const playerCount = serverData.players?.length || 0;
188
+ const maxPlayers = serverData.maxplayers || 0;
189
+ const truncatedName = utils.truncateText(serverName, 20);
190
+ const paddedName = truncatedName.padEnd(20, " ");
191
+ message += `${(index + 1).toString().padStart(2, " ")} ${paddedName} ${playerCount}/${maxPlayers}
192
+ `;
193
+ } else {
194
+ message += `${(index + 1).toString().padStart(2, " ")} ${serverInfo} ❌ 查询失败: ${error}
195
+ `;
196
+ }
197
+ } else {
198
+ message += `${(index + 1).toString().padStart(2, " ")} ${serverInfo} ❌ 查询失败
199
+ `;
200
+ }
201
+ });
202
+ return message;
203
+ }
204
+ __name(generateTextTable, "generateTextTable");
114
205
  async function executeScheduleTask() {
115
206
  if (!config.scheduleEnabled || config.scheduleGroups.length === 0 || config.serverList.length === 0) {
116
207
  return;
@@ -119,36 +210,13 @@ function apply(ctx, config) {
119
210
  return;
120
211
  }
121
212
  try {
122
- const startTime = Date.now();
123
- const results = await Promise.allSettled(
124
- config.serverList.map(async (server, index) => {
125
- try {
126
- const { host, port } = parseAddress(server);
127
- const data = await queryServer(host, port);
128
- return {
129
- index: index + 1,
130
- server,
131
- success: true,
132
- data
133
- };
134
- } catch (error) {
135
- return {
136
- index: index + 1,
137
- server,
138
- success: false,
139
- error: error.message
140
- };
141
- }
142
- })
143
- );
144
- const endTime = Date.now();
145
- const queryTime = endTime - startTime;
213
+ const { results, queryTime, serversToQuery } = await queryServers(config.serverList);
146
214
  const now = /* @__PURE__ */ new Date();
147
215
  const timeStr = now.toLocaleString("zh-CN");
148
216
  let outputContent;
149
217
  if (config.scheduleUseImage) {
150
218
  try {
151
- const imageBuffer = await generateBatchImage(results, config.serverList, queryTime);
219
+ const imageBuffer = await generateBatchImage(results, serversToQuery, queryTime);
152
220
  outputContent = import_koishi.h.image(imageBuffer, "image/png");
153
221
  } catch (imageError) {
154
222
  console.error("定时任务生成图片失败:", imageError);
@@ -159,42 +227,16 @@ function apply(ctx, config) {
159
227
  }
160
228
  }
161
229
  if (typeof outputContent === "string" || !config.scheduleUseImage) {
162
- const successful = results.filter((r) => r.status === "fulfilled" && r.value.success).length;
163
- const failed = results.length - successful;
164
- let textMessage = `🕒 ${timeStr} 服务器状态更新 (耗时: ${utils.formatTime(queryTime)})
165
- `;
166
- textMessage += `✅ 成功: ${successful} 个 | ❌ 失败: ${failed} 个
230
+ const textMessage = generateTextTable(results, serversToQuery, queryTime, "服务器状态更新");
231
+ outputContent = `🕒 ${timeStr}
167
232
 
168
- `;
169
- textMessage += "序号 服务器名称 在线人数\n";
170
- textMessage += "──────────────────────────────\n";
171
- results.forEach((result, index) => {
172
- const serverInfo = config.serverList[index];
173
- if (result.status === "fulfilled") {
174
- const { success, data, error } = result.value;
175
- if (success && data) {
176
- const { result: serverData } = data;
177
- const serverName = serverData.name ? utils.cleanName(serverData.name) : "未知";
178
- const playerCount = serverData.players?.length || 0;
179
- const maxPlayers = serverData.maxplayers || 0;
180
- const truncatedName = utils.truncateText(serverName, 20);
181
- const paddedName = truncatedName.padEnd(20, " ");
182
- textMessage += `${(index + 1).toString().padStart(2, " ")} ${paddedName} ${playerCount}/${maxPlayers}
183
- `;
184
- } else {
185
- textMessage += `${(index + 1).toString().padStart(2, " ")} ${serverInfo} ❌ 查询失败: ${error}
186
- `;
187
- }
188
- } else {
189
- textMessage += `${(index + 1).toString().padStart(2, " ")} ${serverInfo} ❌ 查询失败
190
- `;
191
- }
192
- });
193
- outputContent = typeof outputContent === "string" ? outputContent + textMessage : textMessage;
233
+ ${textMessage}`;
194
234
  }
195
235
  for (const groupId of config.scheduleGroups) {
196
236
  try {
197
- await ctx.broadcast([`onebot:${groupId}`], outputContent);
237
+ const formattedGroupId = utils.formatGroupId(groupId, config.qqAdapterName, config.useFullChannelId);
238
+ await ctx.broadcast([formattedGroupId], outputContent);
239
+ console.log(`定时任务消息已发送到群组: ${formattedGroupId}`);
198
240
  } catch (error) {
199
241
  console.error(`定时任务发送消息到群组 ${groupId} 失败:`, error);
200
242
  }
@@ -231,16 +273,6 @@ function apply(ctx, config) {
231
273
  stopScheduleTask();
232
274
  }
233
275
  });
234
- async function loadGamedig() {
235
- try {
236
- const gamedigModule = await import("gamedig");
237
- return gamedigModule.default || gamedigModule.GameDig || gamedigModule;
238
- } catch (error) {
239
- throw new Error(`无法加载 gamedig 模块:${error.message}
240
- 请确保已安装 gamedig:npm install gamedig`);
241
- }
242
- }
243
- __name(loadGamedig, "loadGamedig");
244
276
  function parseAddress(input) {
245
277
  let address = input.replace(/^(http|https|udp|tcp):\/\//, "");
246
278
  if (address.includes("[")) {
@@ -272,11 +304,10 @@ function apply(ctx, config) {
272
304
  return cached.data;
273
305
  }
274
306
  }
275
- const Gamedig = await loadGamedig();
276
307
  let lastError;
277
308
  for (let i = 0; i <= config.retryCount; i++) {
278
309
  try {
279
- const result = await Gamedig.query({
310
+ const result = await ctx.gamedig.query({
280
311
  type: "csgo",
281
312
  host,
282
313
  port,
@@ -357,20 +388,17 @@ function apply(ctx, config) {
357
388
  needTwoColumns: playerCount > 10
358
389
  };
359
390
  },
360
- drawBackground(ctx2, width, height) {
361
- const gradient = ctx2.createLinearGradient(0, 0, width, height);
362
- gradient.addColorStop(0, "#1a1a2e");
363
- gradient.addColorStop(1, "#16213e");
364
- ctx2.fillStyle = gradient;
391
+ drawBackground(ctx2, width, height, color = COLORS.background) {
392
+ ctx2.fillStyle = color;
365
393
  ctx2.fillRect(0, 0, width, height);
366
394
  },
367
- drawTitle(ctx2, text, x, y, fontSize, fontFamily, color = "#ffffff") {
395
+ drawTitle(ctx2, text, x, y, fontSize, fontFamily, color = COLORS.textWhite) {
368
396
  ctx2.fillStyle = color;
369
397
  ctx2.font = `bold ${fontSize}px ${fontFamily}`;
370
398
  ctx2.textAlign = "center";
371
399
  ctx2.fillText(text, x, y);
372
400
  },
373
- drawDivider(ctx2, x1, y1, x2, y2, color, width = 2) {
401
+ drawDivider(ctx2, x1, y1, x2, y2, color = COLORS.divider, width = 2) {
374
402
  ctx2.strokeStyle = color;
375
403
  ctx2.lineWidth = width;
376
404
  ctx2.beginPath();
@@ -380,7 +408,7 @@ function apply(ctx, config) {
380
408
  },
381
409
  drawText(ctx2, text, x, y, options = {}) {
382
410
  const {
383
- color = "#cccccc",
411
+ color = COLORS.text,
384
412
  fontSize = config.fontSize,
385
413
  fontFamily = config.fontFamily,
386
414
  align = "left",
@@ -396,7 +424,7 @@ function apply(ctx, config) {
396
424
  drawPlayerList(ctx2, players, startY, width, maxHeight, params) {
397
425
  let y = startY;
398
426
  if (players.length === 0) {
399
- this.drawText(ctx2, "服务器当前无在线玩家", 80, y, { italic: true, color: "#aaaaaa" });
427
+ this.drawText(ctx2, "服务器当前无在线玩家", 80, y, { color: COLORS.textLight });
400
428
  return { y: y + 35, displayedCount: 0 };
401
429
  }
402
430
  const sortedPlayers = [...players].sort((a, b) => {
@@ -417,7 +445,7 @@ function apply(ctx, config) {
417
445
  const name2 = utils.truncateText(utils.cleanName(player.name), params.nameMaxLength);
418
446
  this.drawText(ctx2, name2, leftColumnX, currentY, {
419
447
  fontSize: config.fontSize * params.fontSizeMultiplier,
420
- color: "#dddddd"
448
+ color: COLORS.textLighter
421
449
  });
422
450
  currentY += params.rowHeight;
423
451
  displayedCount++;
@@ -427,7 +455,7 @@ function apply(ctx, config) {
427
455
  const name2 = utils.truncateText(utils.cleanName(player.name), params.nameMaxLength);
428
456
  this.drawText(ctx2, name2, rightColumnX, currentY, {
429
457
  fontSize: config.fontSize * params.fontSizeMultiplier,
430
- color: "#dddddd"
458
+ color: COLORS.textLighter
431
459
  });
432
460
  currentY += params.rowHeight;
433
461
  displayedCount++;
@@ -437,7 +465,7 @@ function apply(ctx, config) {
437
465
  if (players.length > totalDisplayed) {
438
466
  this.drawText(ctx2, `... 还有 ${players.length - totalDisplayed} 位玩家未显示`, leftColumnX, y, {
439
467
  fontSize: config.fontSize * 0.8,
440
- color: "#aaaaaa",
468
+ color: COLORS.textLight,
441
469
  italic: true
442
470
  });
443
471
  y += 30;
@@ -449,12 +477,29 @@ function apply(ctx, config) {
449
477
  const name2 = utils.truncateText(utils.cleanName(player.name), params.nameMaxLength);
450
478
  this.drawText(ctx2, name2, 80, y, {
451
479
  fontSize: config.fontSize * params.fontSizeMultiplier,
452
- color: "#dddddd"
480
+ color: COLORS.textLighter
453
481
  });
454
482
  y += params.rowHeight;
455
483
  });
456
484
  return { y, displayedCount: displayPlayers.length };
457
485
  }
486
+ },
487
+ // 统一边框绘制函数
488
+ drawBorder(ctx2, width, height) {
489
+ this.drawDivider(ctx2, 1, 1, width - 1, 1, COLORS.border, 2);
490
+ this.drawDivider(ctx2, width - 1, 1, width - 1, height - 1, COLORS.border, 2);
491
+ this.drawDivider(ctx2, width - 1, height - 1, 1, height - 1, COLORS.border, 2);
492
+ this.drawDivider(ctx2, 1, height - 1, 1, 1, COLORS.border, 2);
493
+ this.drawDivider(ctx2, 5, 0.5 * height - 0.05 * height, 5, height - 0.5 * height + 0.05 * height, COLORS.border, 6);
494
+ this.drawDivider(ctx2, width - 5, 0.5 * height - 0.05 * height, width - 5, height - 0.5 * height + 0.05 * height, COLORS.border, 6);
495
+ this.drawDivider(ctx2, 2, 2, 0.025 * width, 2, COLORS.accent, 3);
496
+ this.drawDivider(ctx2, 2, 2, 2, 0.025 * width, COLORS.accent, 3);
497
+ this.drawDivider(ctx2, width - 2, 2, width - 2, 0.025 * width, COLORS.accent, 3);
498
+ this.drawDivider(ctx2, width - 2, 2, width - 0.025 * width, 2, COLORS.accent, 3);
499
+ this.drawDivider(ctx2, width - 2, height - 2, width - 2, height - 0.025 * width, COLORS.accent, 3);
500
+ this.drawDivider(ctx2, width - 2, height - 2, width - 0.025 * width, height - 2, COLORS.accent, 3);
501
+ this.drawDivider(ctx2, 2, height - 2, 0.025 * width, height - 2, COLORS.accent, 3);
502
+ this.drawDivider(ctx2, 2, height - 2, 2, height - 0.025 * width, COLORS.accent, 3);
458
503
  }
459
504
  };
460
505
  function calculateImageHeight(data) {
@@ -491,52 +536,49 @@ function apply(ctx, config) {
491
536
  const { result } = data;
492
537
  const width = config.imageWidth;
493
538
  const height = calculateImageHeight(data);
494
- const canvas = (0, import_canvas.createCanvas)(width, height);
495
- const ctx2 = canvas.getContext("2d");
496
- imageUtils.drawBackground(ctx2, width, height);
539
+ const canvas = await ctx.canvas.createCanvas(width, height);
540
+ const ctx2d = canvas.getContext("2d");
541
+ imageUtils.drawBackground(ctx2d, width, height);
497
542
  const titleY = 80;
498
- imageUtils.drawTitle(ctx2, "服务器状态", width / 2, titleY, config.fontSize * 2, config.fontFamily);
543
+ imageUtils.drawTitle(ctx2d, "[服务器状态查询]", width / 2, titleY, config.fontSize * 1.5, config.fontFamily, COLORS.title);
499
544
  if (result.name) {
500
545
  const cleanName = utils.cleanName(result.name);
501
- const fontSize = imageUtils.calculateServerNameFontSize(ctx2, cleanName, width - 160, config.fontSize);
502
- imageUtils.drawTitle(ctx2, cleanName, width / 2, titleY + 50, fontSize, config.fontFamily, "#FFD700");
546
+ const fontSize = imageUtils.calculateServerNameFontSize(ctx2d, cleanName, width - 160, config.fontSize);
547
+ imageUtils.drawTitle(ctx2d, cleanName, width / 2, titleY + 50, fontSize * 0.8, config.fontFamily, COLORS.highlight);
503
548
  }
504
- imageUtils.drawDivider(ctx2, 80, titleY + 80, width - 80, titleY + 80, "#FFD700", 3);
549
+ imageUtils.drawDivider(ctx2d, 80, titleY + 80, width - 80, titleY + 80, COLORS.border, 2);
505
550
  let y = titleY + 120;
506
551
  if (result.map) {
507
- imageUtils.drawText(ctx2, `地图: ${result.map}`, 80, y);
552
+ imageUtils.drawText(ctx2d, `地图: ${result.map}`, 80, y);
508
553
  }
509
- imageUtils.drawText(ctx2, `IP: ${host}:${port}`, width - 80, y, { align: "right", color: "#bbbbbb" });
554
+ imageUtils.drawText(ctx2d, `IP: ${host}:${port}`, width - 80, y, { align: "right" });
510
555
  y += 40;
511
556
  const playerCount = result.players?.length || 0;
512
557
  const botCount = result.bots?.length || 0;
513
558
  const maxPlayers = result.maxplayers || 0;
514
559
  const playerText = `人数: ${playerCount}/${maxPlayers}${botCount > 0 ? ` (${botCount} Bot)` : ""}`;
515
- imageUtils.drawText(ctx2, playerText, 80, y, { color: utils.getPlayerColor(playerCount) });
560
+ imageUtils.drawText(ctx2d, playerText, 80, y, { color: utils.getPlayerColor(playerCount) });
516
561
  if (result.ping) {
517
- imageUtils.drawText(ctx2, `Ping: ${result.ping}ms`, width - 80, y, {
562
+ imageUtils.drawText(ctx2d, `Ping: ${result.ping}ms`, width - 80, y, {
518
563
  align: "right",
519
564
  color: utils.getPingColor(result.ping)
520
565
  });
521
566
  }
522
567
  y += 50;
523
568
  const playerParams = imageUtils.calculatePlayerListParams(playerCount);
524
- imageUtils.drawText(ctx2, "在线玩家", 80, y, { color: "#ffffff", bold: true, fontSize: config.fontSize * 1.2 });
569
+ imageUtils.drawText(ctx2d, "在线玩家", 80, y, { color: COLORS.playerName, bold: true, fontSize: config.fontSize });
525
570
  y += 40;
526
- imageUtils.drawDivider(ctx2, 80, y - 15, width - 80, y - 15, "#555555", 1.5);
571
+ imageUtils.drawDivider(ctx2d, 80, y - 15, width - 80, y - 15, COLORS.divider, 1.5);
527
572
  y += 25;
528
- const playerListResult = imageUtils.drawPlayerList(ctx2, result.players || [], y, width, height, playerParams);
573
+ const playerListResult = imageUtils.drawPlayerList(ctx2d, result.players || [], y, width, height, playerParams);
529
574
  y = playerListResult.y;
530
575
  y += 30;
531
576
  const now = /* @__PURE__ */ new Date();
532
- imageUtils.drawText(ctx2, `查询时间: ${now.toLocaleString("zh-CN")}`, 80, height - 20, {
577
+ imageUtils.drawText(ctx2d, `查询时间: ${now.toLocaleString("zh-CN")}`, 80, height - 20, {
533
578
  fontSize: config.fontSize * 0.8,
534
- color: "#666666"
579
+ color: COLORS.timestamp
535
580
  });
536
- imageUtils.drawDivider(ctx2, 8, 8, width - 8, 8, "#7D8B92", 4);
537
- imageUtils.drawDivider(ctx2, width - 8, 8, width - 8, height - 8, "#7D8B92", 4);
538
- imageUtils.drawDivider(ctx2, width - 8, height - 8, 8, height - 8, "#7D8B92", 4);
539
- imageUtils.drawDivider(ctx2, 8, height - 8, 8, 8, "#7D8B92", 4);
581
+ imageUtils.drawBorder(ctx2d, width, height);
540
582
  return canvas.toBuffer("image/png");
541
583
  }
542
584
  __name(generateServerImage, "generateServerImage");
@@ -547,14 +589,14 @@ function apply(ctx, config) {
547
589
  const serverHeight = 100;
548
590
  const height = baseHeight + results.length * serverHeight;
549
591
  const width = 1200;
550
- const canvas = (0, import_canvas.createCanvas)(width, height);
551
- const ctx2 = canvas.getContext("2d");
552
- imageUtils.drawBackground(ctx2, width, height);
553
- imageUtils.drawTitle(ctx2, "服务器状态批量查询", width / 2, 100, config.fontSize * 2, config.fontFamily);
592
+ const canvas = await ctx.canvas.createCanvas(width, height);
593
+ const ctx2d = canvas.getContext("2d");
594
+ imageUtils.drawBackground(ctx2d, width, height);
595
+ imageUtils.drawTitle(ctx2d, "[服务器状态批量查询]", width / 2, 100, config.fontSize * 1.8, config.fontFamily, COLORS.title);
554
596
  const now = /* @__PURE__ */ new Date();
555
- imageUtils.drawText(ctx2, `查询时间: ${now.toLocaleString("zh-CN")}`, 80, 150);
556
- imageUtils.drawText(ctx2, `耗时: ${utils.formatTime(queryTime)} 成功: ${successful}/${results.length}`, width - 80, 150, { align: "right" });
557
- imageUtils.drawDivider(ctx2, 80, 165, width - 80, 165, "#FFD700", 3);
597
+ imageUtils.drawText(ctx2d, `查询时间: ${now.toLocaleString("zh-CN")}`, 80, 150);
598
+ imageUtils.drawText(ctx2d, `耗时: ${utils.formatTime(queryTime)} 成功: ${successful}/${results.length}`, width - 80, 150, { align: "right" });
599
+ imageUtils.drawDivider(ctx2d, 80, 165, width - 80, 165, COLORS.gold, 2);
558
600
  let y = 200;
559
601
  results.forEach((result, index) => {
560
602
  const server = serversToQuery[index];
@@ -565,62 +607,60 @@ function apply(ctx, config) {
565
607
  const serverName = serverData.name ? utils.cleanName(serverData.name) : "未知";
566
608
  const playerCount = serverData.players?.length || 0;
567
609
  const maxPlayers = serverData.maxplayers || 0;
568
- const botCount = serverData.bots?.length || 0;
569
- imageUtils.drawText(ctx2, `${index + 1}. ${serverName}`, 80, y, {
570
- color: "#ffffff",
610
+ imageUtils.drawText(ctx2d, `${index + 1}. ${serverName}`, 80, y, {
611
+ color: COLORS.textWhite,
571
612
  bold: true,
572
613
  fontSize: config.fontSize * 1.1
573
614
  });
574
- imageUtils.drawText(ctx2, server, 80, y + 30, {
615
+ imageUtils.drawText(ctx2d, server, 80, y + 30, {
575
616
  fontSize: config.fontSize * 0.8,
576
- color: "#aaaaaa"
617
+ color: COLORS.textLight
577
618
  });
578
619
  const playerText = `${playerCount}/${maxPlayers}`;
579
- const playerColor = playerCount > 0 ? "#4CAF50" : "#c03f36";
580
- imageUtils.drawText(ctx2, playerText, width - 80, y, {
620
+ const playerColor = playerCount > 0 ? COLORS.success : COLORS.error;
621
+ imageUtils.drawText(ctx2d, playerText, width - 80, y, {
581
622
  align: "right",
582
623
  color: playerColor,
583
624
  bold: true
584
625
  });
585
626
  if (serverData.map) {
586
- imageUtils.drawText(ctx2, `地图: ${serverData.map}`, 80, y + 60, {
627
+ imageUtils.drawText(ctx2d, `地图: ${serverData.map}`, 80, y + 60, {
587
628
  fontSize: config.fontSize * 0.8,
588
- color: "#aaaaaa"
629
+ color: COLORS.textLight
589
630
  });
590
631
  }
591
632
  if (serverData.ping) {
592
633
  const pingColor = utils.getPingColor(serverData.ping);
593
- imageUtils.drawText(ctx2, `延迟: ${serverData.ping}ms`, width - 80, y + 60, {
634
+ imageUtils.drawText(ctx2d, `延迟: ${serverData.ping}ms`, width - 80, y + 60, {
594
635
  align: "right",
595
636
  fontSize: config.fontSize * 0.9,
596
637
  color: pingColor
597
638
  });
598
639
  }
599
640
  } else {
600
- imageUtils.drawText(ctx2, `${index + 1}. ${server}`, 80, y, { color: "#ffffff", bold: true });
601
- imageUtils.drawText(ctx2, `❌ 查询失败: ${error}`, 200, y + 35, { color: "#c03f36" });
641
+ imageUtils.drawText(ctx2d, `${index + 1}. ${server}`, 80, y, { color: COLORS.textWhite, bold: true });
642
+ imageUtils.drawText(ctx2d, `❌ 查询失败: ${error}`, 200, y + 35, { color: COLORS.error });
602
643
  }
603
644
  } else {
604
- imageUtils.drawText(ctx2, `${index + 1}. ${server}`, 80, y, { color: "#ffffff", bold: true });
605
- imageUtils.drawText(ctx2, "❌ 查询失败", 200, y + 35, { color: "#c03f36" });
645
+ imageUtils.drawText(ctx2d, `${index + 1}. ${server}`, 80, y, { color: COLORS.textWhite, bold: true });
646
+ imageUtils.drawText(ctx2d, "❌ 查询失败", 200, y + 35, { color: COLORS.error });
606
647
  }
607
648
  if (index < results.length - 1) {
608
- imageUtils.drawDivider(ctx2, 80, y + 70, width - 80, y + 70, "#555555", 1);
649
+ imageUtils.drawDivider(ctx2d, 80, y + 70, width - 80, y + 70, COLORS.divider, 1);
609
650
  }
610
651
  y += 100;
611
652
  });
612
- imageUtils.drawDivider(ctx2, 8, 8, width - 8, 8, "#7D8B92", 4);
613
- imageUtils.drawDivider(ctx2, width - 8, 8, width - 8, height - 8, "#7D8B92", 4);
614
- imageUtils.drawDivider(ctx2, width - 8, height - 8, 8, height - 8, "#7D8B92", 4);
615
- imageUtils.drawDivider(ctx2, 8, height - 8, 8, 8, "#7D8B92", 4);
653
+ imageUtils.drawBorder(ctx2d, width, height);
616
654
  return canvas.toBuffer("image/png");
617
655
  }
618
656
  __name(generateBatchImage, "generateBatchImage");
619
- ctx.command("cs.schedule", "定时任务管理").alias("定时任务").option("status", "-s 查看定时任务状态", { type: Boolean, fallback: false }).option("start", "-S 启动定时任务", { type: Boolean, fallback: false }).option("stop", "-T 停止定时任务", { type: Boolean, fallback: false }).option("test", "-t 测试定时任务", { type: Boolean, fallback: false }).option("addGroup", "-a <groupId> 添加群组到定时任务", { type: String }).option("removeGroup", "-r <groupId> 从定时任务移除群组", { type: String }).option("listGroups", "-l 列出定时任务群组", { type: Boolean, fallback: false }).option("run", "-R 立即执行一次定时任务", { type: Boolean, fallback: false }).action(async ({ session, options }) => {
657
+ ctx.command("cs.schedule", "定时任务管理").alias("定时任务").option("status", "-s 查看定时任务状态", { type: Boolean, fallback: false }).option("start", "-S 启动定时任务", { type: Boolean, fallback: false }).option("stop", "-T 停止定时任务", { type: Boolean, fallback: false }).option("test", "-t 测试定时任务", { type: Boolean, fallback: false }).option("addGroup", "-a <groupId> 添加群组到定时任务", { type: String }).option("removeGroup", "-r <groupId> 从定时任务移除群组", { type: String }).option("listGroups", "-l 列出定时任务群组", { type: Boolean, fallback: false }).option("run", "-R 立即执行一次定时任务", { type: Boolean, fallback: false }).option("testQQ", "-q 测试QQ适配器连接", { type: Boolean, fallback: false }).action(async ({ session, options }) => {
620
658
  if (options.status) {
621
659
  const status = config.scheduleEnabled ? "✅ 已启用" : "❌ 已禁用";
622
660
  const nextRun = scheduleTimer ? "运行中" : "未运行";
623
661
  const groups = config.scheduleGroups.length;
662
+ const qqBots = ctx.bots.filter((bot) => bot.platform === config.qqAdapterName);
663
+ const qqStatus = qqBots.length > 0 ? `✅ 可用 (${qqBots.length}个)` : "❌ 不可用";
624
664
  return `📅 定时任务状态
625
665
  状态: ${status}
626
666
  定时器: ${nextRun}
@@ -629,6 +669,8 @@ function apply(ctx, config) {
629
669
  输出格式: ${config.scheduleUseImage ? "图片" : "文本"}
630
670
  监控服务器: ${config.serverList.length}个
631
671
  目标群组: ${groups}个
672
+ QQ适配器: ${qqStatus} (名称: ${config.qqAdapterName})
673
+ 群组ID格式: ${config.useFullChannelId ? "适配器:群号" : "群号"}
632
674
 
633
675
  使用 cs.schedule -h 查看所有命令选项`;
634
676
  }
@@ -650,12 +692,40 @@ function apply(ctx, config) {
650
692
  await executeScheduleTask();
651
693
  return "✅ 已立即执行一次定时任务";
652
694
  }
695
+ if (options.testQQ) {
696
+ const qqBots = ctx.bots.filter((bot) => bot.platform === config.qqAdapterName);
697
+ if (qqBots.length === 0) {
698
+ return `❌ 找不到 ${config.qqAdapterName} 适配器的机器人
699
+ 请确保已正确配置QQ适配器`;
700
+ }
701
+ let message = `✅ 找到 ${qqBots.length} 个 ${config.qqAdapterName} 适配器机器人:
702
+ `;
703
+ qqBots.forEach((bot, index) => {
704
+ message += `${index + 1}. ${bot.selfId} (在线: ${bot.status})
705
+ `;
706
+ });
707
+ if (session) {
708
+ try {
709
+ await session.send("测试消息: QQ适配器连接正常 ✓");
710
+ message += "\n✅ 当前会话消息发送测试成功";
711
+ } catch (error) {
712
+ message += `
713
+ ❌ 当前会话消息发送失败: ${error.message}`;
714
+ }
715
+ }
716
+ return message;
717
+ }
653
718
  if (options.addGroup) {
654
- if (!config.scheduleGroups.includes(options.addGroup)) {
655
- config.scheduleGroups.push(options.addGroup);
656
- return `✅ 已添加群组 ${options.addGroup} 到定时任务`;
719
+ let groupId = options.addGroup.trim();
720
+ if (config.useFullChannelId && !groupId.includes(":")) {
721
+ groupId = `${config.qqAdapterName}:${groupId}`;
722
+ }
723
+ if (!config.scheduleGroups.includes(groupId)) {
724
+ config.scheduleGroups.push(groupId);
725
+ return `✅ 已添加群组 ${groupId} 到定时任务
726
+ 当前列表: ${config.scheduleGroups.length} 个群组`;
657
727
  } else {
658
- return `❌ 群组 ${options.addGroup} 已在列表中`;
728
+ return `❌ 群组 ${groupId} 已在列表中`;
659
729
  }
660
730
  }
661
731
  if (options.removeGroup) {
@@ -686,6 +756,7 @@ function apply(ctx, config) {
686
756
  -T, -stop 停止定时任务
687
757
  -t, -test 测试定时任务
688
758
  -R, -run 立即执行一次定时任务
759
+ -q, -testQQ 测试QQ适配器连接
689
760
  -a, -addGroup 添加群组到定时任务
690
761
  -r, -removeGroup 从定时任务移除群组
691
762
  -l, -listGroups 列出定时任务群组
@@ -694,7 +765,8 @@ function apply(ctx, config) {
694
765
  cs.schedule -s # 查看状态
695
766
  cs.schedule -S # 启动定时任务
696
767
  cs.schedule -a 123456 # 添加群组123456
697
- cs.schedule -t # 测试执行`;
768
+ cs.schedule -t # 测试执行
769
+ cs.schedule -q # 测试QQ适配器连接`;
698
770
  });
699
771
  ctx.command("cs <address>", "查询服务器状态").alias("查询").alias("server").option("noPlayers", "-n 隐藏玩家列表", { type: Boolean, fallback: false }).option("image", "-i 生成图片横幅", { type: Boolean, fallback: false }).option("text", "-t 输出文本信息", { type: Boolean, fallback: false }).option("clear", "-c 清除缓存", { type: Boolean, fallback: false }).action(async ({ session, options }, address) => {
700
772
  if (!address) return "使用格式: cs [地址:端口]\n示例: cs 127.0.0.1:27015\n示例: cs edgebug.cn";
@@ -725,9 +797,9 @@ cs.schedule -t # 测试执行`;
725
797
 
726
798
  `;
727
799
  if (error.message.includes("无法加载 gamedig")) {
728
- errorMessage += "请确保已安装 gamedig:\n";
729
- errorMessage += "1. 在插件目录运行:npm install gamedig\n";
730
- errorMessage += "2. 重启 Koishi";
800
+ errorMessage += "请确保已安装 koishi-plugin-gamedig:\n";
801
+ errorMessage += "1. 在插件市场搜索并安装 koishi-plugin-gamedig\n";
802
+ errorMessage += "2. 启用该插件后重启";
731
803
  } else if (error.message.includes("无效的地址格式")) {
732
804
  errorMessage += "地址格式应为: 地址:端口\n";
733
805
  errorMessage += "示例: 127.0.0.1:27015 或 edgebug.cn:27015\n";
@@ -744,21 +816,28 @@ cs.schedule -t # 测试执行`;
744
816
  });
745
817
  ctx.command("cs.status", "检查插件状态和配置").action(async () => {
746
818
  try {
747
- await loadGamedig();
748
- const cacheSize = cache.size;
819
+ const gamedigStatus = ctx.gamedig ? "✅ 可用" : "❌ 不可用";
749
820
  let canvasStatus = "❌ 不可用";
750
- try {
751
- (0, import_canvas.createCanvas)(1, 1);
752
- canvasStatus = "✅ 可用";
753
- } catch (error) {
754
- canvasStatus = `❌ 不可用: ${error.message}`;
821
+ if (ctx.canvas) {
822
+ try {
823
+ const canvas = await ctx.canvas.createCanvas(1, 1);
824
+ const ctx2d = canvas.getContext("2d");
825
+ canvasStatus = "✅ 可用";
826
+ } catch (error) {
827
+ canvasStatus = `❌ 不可用: ${error.message}`;
828
+ }
755
829
  }
830
+ const cacheSize = cache.size;
756
831
  const scheduleStatus = config.scheduleEnabled ? "✅ 已启用" : "❌ 已禁用";
757
832
  const scheduleTimerStatus = scheduleTimer ? "运行中" : "未运行";
833
+ const qqBots = ctx.bots.filter((bot) => bot.platform === config.qqAdapterName);
834
+ const qqStatus = qqBots.length > 0 ? `✅ 可用 (${qqBots.length}个)` : "❌ 不可用";
758
835
  return `✅ CS服务器查询插件状态
759
836
  💾 缓存数量: ${cacheSize} 条
760
- 🖼️ 图片生成: ${canvasStatus}
837
+ 🕹️ Gamedig插件: ${gamedigStatus}
838
+ 🖼️ Canvas插件: ${canvasStatus}
761
839
  📅 定时任务: ${scheduleStatus} (${scheduleTimerStatus})
840
+ 🤖 QQ适配器: ${qqStatus} (名称: ${config.qqAdapterName})
762
841
  ⚙️ 配置参数:
763
842
  超时时间: ${config.timeout}ms
764
843
  缓存时间: ${config.cacheTime}ms
@@ -770,13 +849,14 @@ cs.schedule -t # 测试执行`;
770
849
  图片宽度: ${config.imageWidth}px
771
850
  图片最小高度: ${config.imageHeight}px
772
851
  字体大小: ${config.fontSize}px
852
+ 群组ID格式: ${config.useFullChannelId ? "适配器:群号" : "群号"}
773
853
 
774
854
  📝 使用: cs [地址:端口]
775
855
  📝 选项: -i 生成图片, -t 输出文本, -c 清除缓存
776
856
  📅 定时任务: cs.schedule 查看定时任务管理`;
777
857
  } catch (error) {
778
858
  return `❌ 插件状态异常: ${error.message}
779
- 请运行: npm install gamedig`;
859
+ 请确保已安装并启用 koishi-plugin-gamedig koishi-plugin-canvas 插件`;
780
860
  }
781
861
  });
782
862
  ctx.command("cs.help", "查看帮助").action(() => {
@@ -804,12 +884,13 @@ cs.help - 显示此帮助
804
884
  定时自动向指定QQ群组发送服务器状态
805
885
  配置: 插件配置面板中设置
806
886
  管理: cs.schedule 命令
807
- 群组ID: 填写QQ群号即可
887
+ 群组ID格式: ${config.useFullChannelId ? "适配器:群号 (如: qq:123456)" : "群号 (如: 123456)"}
808
888
 
809
889
  💡 提示:
810
890
  1. 如果不指定端口,默认使用27015
811
891
  2. 只支持CS服务器查询
812
- 3. 查询结果缓存${config.cacheTime}ms,使用 -c 清除缓存`;
892
+ 3. 查询结果缓存${config.cacheTime}ms,使用 -c 清除缓存
893
+ 4. 需要安装 koishi-plugin-gamedig 和 koishi-plugin-canvas 插件`;
813
894
  });
814
895
  ctx.command("csss", "批量查询服务器状态").alias("batch").alias("multi").alias("批量查询").option("list", "-l 显示配置的服务器列表", { type: Boolean, fallback: false }).option("add", "-a <address> 添加服务器到列表", { type: String }).option("remove", "-r <index> 从列表中移除服务器", { type: Number }).option("clear", "-c 清空服务器列表", { type: Boolean, fallback: false }).option("image", "-i 生成图片横幅", { type: Boolean, fallback: false }).option("text", "-t 输出文本信息", { type: Boolean, fallback: false }).action(async ({ session, options }, ...addresses) => {
815
896
  if (options.list) {
@@ -860,30 +941,7 @@ cs.help - 显示此帮助
860
941
  session?.send(`⚠️ 服务器数量超过限制,仅查询前 ${maxServers} 个`);
861
942
  }
862
943
  try {
863
- const startTime = Date.now();
864
- const results = await Promise.allSettled(
865
- serversToQuery.map(async (server, index) => {
866
- try {
867
- const { host, port } = parseAddress(server);
868
- const data = await queryServer(host, port);
869
- return {
870
- index: index + 1,
871
- server,
872
- success: true,
873
- data
874
- };
875
- } catch (error) {
876
- return {
877
- index: index + 1,
878
- server,
879
- success: false,
880
- error: error.message
881
- };
882
- }
883
- })
884
- );
885
- const endTime = Date.now();
886
- const queryTime = endTime - startTime;
944
+ const { results, queryTime } = await queryServers(serversToQuery);
887
945
  const shouldGenerateImage = options.image || config.generateImage && !options.text;
888
946
  if (shouldGenerateImage) {
889
947
  try {
@@ -893,37 +951,7 @@ cs.help - 显示此帮助
893
951
  console.error("生成批量查询图片失败:", imageError);
894
952
  }
895
953
  }
896
- const successful = results.filter((r) => r.status === "fulfilled" && r.value.success).length;
897
- const failed = serversToQuery.length - successful;
898
- let message = `📊 批量查询结果 (${utils.formatTime(queryTime)})
899
- `;
900
- message += `✅ 成功: ${successful} 个 | ❌ 失败: ${failed} 个
901
-
902
- `;
903
- message += "序号 服务器名称 在线人数\n";
904
- message += "──────────────────────────────\n";
905
- results.forEach((result, index) => {
906
- const serverInfo = serversToQuery[index];
907
- if (result.status === "fulfilled") {
908
- const { success, data, error } = result.value;
909
- if (success && data) {
910
- const { result: serverData } = data;
911
- const serverName = serverData.name ? utils.cleanName(serverData.name) : "未知";
912
- const playerCount = serverData.players?.length || 0;
913
- const maxPlayers = serverData.maxplayers || 0;
914
- const truncatedName = utils.truncateText(serverName, 20);
915
- const paddedName = truncatedName.padEnd(20, " ");
916
- message += `${(index + 1).toString().padStart(2, " ")} ${paddedName} ${playerCount}/${maxPlayers}
917
- `;
918
- } else {
919
- message += `${(index + 1).toString().padStart(2, " ")} ${serverInfo} ❌ 查询失败: ${error}
920
- `;
921
- }
922
- } else {
923
- message += `${(index + 1).toString().padStart(2, " ")} ${serverInfo} ❌ 查询失败
924
- `;
925
- }
926
- });
954
+ let message = generateTextTable(results, serversToQuery, queryTime, "批量查询结果");
927
955
  message += "\n📋 输入 `cs <序号>` 查看服务器详情";
928
956
  message += "\n📋 输入 `cs <服务器地址>` 查询单个服务器";
929
957
  return message;
@@ -940,9 +968,11 @@ cs.help - 显示此帮助
940
968
  });
941
969
  }
942
970
  __name(apply, "apply");
971
+ var inject = ["canvas", "gamedig"];
943
972
  // Annotate the CommonJS export names for ESM import in node:
944
973
  0 && (module.exports = {
945
974
  Config,
946
975
  apply,
976
+ inject,
947
977
  name
948
978
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-csss",
3
3
  "description": "Check the status of the CS server",
4
- "version": "1.0.1",
4
+ "version": "1.1.1",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [
@@ -14,21 +14,25 @@
14
14
  "koishi",
15
15
  "plugin"
16
16
  ],
17
- "peerDependencies": {
18
- "koishi": "^4.18.7"
19
- },
20
- "dependencies": {
21
- "canvas": "^3.2.1",
22
- "gamedig": "^5.3.2"
23
- },
24
17
  "koishi": {
25
18
  "description": {
26
19
  "zh": "CS服务器状态查询,包括CS1.6/CSS/CSGO/CS2"
27
20
  },
28
21
  "service": {
29
22
  "required": [
30
- "database"
23
+ "canvas",
24
+ "gamedig"
31
25
  ]
26
+ },
27
+ "devDependencies": {
28
+ "koishi": "^4.18.7",
29
+ "koishi-plugin-canvas": "^0.2.2",
30
+ "koishi-plugin-gamedig": "^1.2.2"
32
31
  }
32
+ },
33
+ "dependencies": {
34
+ "koishi": "^4.18.7",
35
+ "koishi-plugin-canvas": "^0.2.2",
36
+ "koishi-plugin-gamedig": "^1.2.2"
33
37
  }
34
38
  }