koishi-plugin-node-async-bot-all 2.30.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.js CHANGED
@@ -34,7 +34,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
34
34
  // src/locales/zh-CN.yml
35
35
  var require_zh_CN = __commonJS({
36
36
  "src/locales/zh-CN.yml"(exports2, module2) {
37
- module2.exports = { noApi: "未指定 API", noop: "无", unknownError: "未知错误。", failed: "{quote}{time}\n{error}", "failed-md": "**{time}**\n\n---\n\n{error}", commands: { na: { description: "NodeAsync Bot" }, cxgame: { description: "查询服务器当前人数。", messages: { msg: "{time}{list}\n进服指南请在群公告中查看。", "msg-md": "*{time}*\n\n---\n{list}\n\n---\n\n进服指南请在群公告中查看。", list: "【{name} 服务器 {count}】\n➣ {version}:{players}\n➣ {ne}:{list}\n➣ 备注:{note}", "list-md": "## {name} 服务器 {count}\n\n- {version}:{players}\n- {ne}:{list}\n- 备注:{note}", listFailed: "【{name} 服务器 {count}】\n➣ 查询失败:{data}\n➣ 请稍后重试。\n➣ 备注:{note}", "listFailed-md": "## {name} 服务器 {count}\n\n- 查询失败:{data}\n- 请稍后重试。\n- 备注:{note}", timeout: "请求超时。", fewData: "服务端返回的数据过少。", close: "服务器已关闭。", host: "没有到主机的路由。", dns: "解析失败。" } }, status: { description: "查询机器人状态。", messages: { msg: "{time}\n--- 系统状态 ---\n系统名称:{name}\nCPU使用率:{cpu}\n内存使用率:{memory}\n--- 机器人状态 ---\n昨日收/发消息数量:{msgCount}\n机器人版本:{version}\n运行时间:{online}", "msg-md": "*{time}*\n\n---\n\n## 系统状态\n\n- 系统名称:{name}\n- CPU使用率:{cpu}\n- 内存使用率:{memory}\n\n## 机器人状态\n\n- 昨日收/发消息数量:{msgCount}\n- 机器人版本:{version}\n- 运行时间:{online}" } }, random: { description: "随机数生成器。", usage: "缺少参数时默认生成 0-10000 的随机数。\n使用示例:", examples: "random 1 128 生成1到128范围的随机数", messages: { msg: "{time}\n生成了一个随机数:{data}", "msg-md": "*{time}*\n\n---\n\n生成了一个随机数:{data}" } }, info: { description: "查询机器人信息。", messages: { msg: "{time}\n--- NodeAsync {version} ---\n私有机器人,服务器专用。\n--- 开发者 ---\n德二吹风机(3112836258)\n--- 其他 ---\nNode.js 版本:{nodeVersion}\nKoishi 版本:{koishiVersion}\n开源地址:https://github.com/ccd2s/node-async-bot-all\n官网:https://www.tasaed.top", "msg-md": "*{time}*\n\n---\n\n## NodeAsync {version}\n\n私有机器人,服务器专用。\n\n## 开发者\n\n- 德二吹风机(3112836258)\n\n## 其他\n\n- Node.js 版本:{nodeVersion}\n- Koishi 版本:{koishiVersion}\n- 开源地址:https://github.com/ccd2s/node-async-bot-all\n- 官网:https://www.tasaed.top" } }, rw: { description: "随机名言名句。", messages: null }, randomba: { description: "随机BA图。", messages: { msg: "{quote}{image}" } }, centerservertest: { description: "查看中心服务器状态。", messages: { msg: "{time}{list}", "msg-md": "*{time}*\n\n---\n{list}", list: "== {name} ==\n状态:{status}\n存活率:{uptime}\n检测时间:{time}", "list-md": "## {name}\n\n- 状态:{status}\n- 存活率:{uptime}\n- 检测时间:{time}", listFailed: "== {name} ==\n查看失败:{data}", "listFailed-md": "## {name}\n\n查看失败:{data}", statusLive: "✅ 正常", statusDie: "❌ 故障", dataFail: "未能获取到此服务器的状态信息。" } }, meme: { description: "群友的怪话!", usage: "不带参数时随机查看\n带参数时为查看指定 meme", examples: "meme\nmeme 1145", messages: { msg: "{quote}{time}\n{image}\n{title}", "msg-qq": "{quote}{image}\n{time}\n{title}" } }, randomcat: { description: "随机猫猫图。", messages: { msg: "{quote}{image}" } }, getqqinfo: { description: "获取 QQ 号的信息。", usage: "获取 QQ 号的信息。", examples: "getqqinfo 10001", messages: { msg: "{quote}{image}", failed: "{quote}{time}\n获取失败:{data}", command: "QQ 号不正确。" } }, msg2img: { description: "引用一个消息并使用此指令,即可将消息转图。", usage: "引用一条消息,/m。(不要带@)", messages: { msg: "{quote}{image}", failed: "{quote}{time}\n获取失败:{data}", null: "未引用任何消息。", matroska: "{quote}禁止套娃!" } }, slnews: { description: "抓取 NorthWood 的 Steam 最新新闻。" }, use: { description: "使用 TA !", usage: "use @用户", examples: "use @用户", messages: { command: "请 @ 一个用户。", msg: "{at} {desc}了 {at2} !" } } } };
37
+ module2.exports = { noApi: "未指定 API", noop: "无", unknownError: "未知错误。", failed: "{quote}{time}\n{error}", "failed-md": "**{time}**\n{error}", commands: { na: { description: "NodeAsync Bot" }, cxgame: { description: "查询服务器当前人数。", messages: { msg: "{time}{list}\n进服指南请在群公告中查看。", "msg-md": "*{time}*\n\n---\n{list}\n\n---\n\n进服指南请在群公告中查看。", list: "【{name} 服务器 {count}】\n➣ {version}:{players}\n➣ {ne}:{list}\n➣ 备注:{note}", "list-md": "## {name} 服务器 {count}\n\n- {version}:{players}\n- {ne}:{list}\n- 备注:{note}", listFailed: "【{name} 服务器 {count}】\n➣ 查询失败:{data}\n➣ 请稍后重试。\n➣ 备注:{note}", "listFailed-md": "## {name} 服务器 {count}\n\n- 查询失败:{data}\n- 请稍后重试。\n- 备注:{note}", timeout: "请求超时。", fewData: "服务端返回的数据过少。", close: "服务器已关闭。", host: "没有到主机的路由。", dns: "解析失败。", "ne-a2s": "机器人", "ne-mc": "玩家列表", forbidden: "此指令不允许在本群使用。", failed: "查询失败:" } }, status: { description: "查询机器人状态。", messages: { msg: "{time}\n--- 系统状态 ---\n系统名称:{name}\nCPU使用率:{cpu}\n内存使用率:{memory}\n--- 机器人状态 ---\n昨日收/发消息数量:{msgCount}\n机器人版本:{version}\n运行时间:{online}", "msg-md": "*{time}*\n\n---\n\n## 系统状态\n\n- 系统名称:{name}\n- CPU使用率:{cpu}\n- 内存使用率:{memory}\n\n## 机器人状态\n\n- 昨日收/发消息数量:{msgCount}\n- 机器人版本:{version}\n- 运行时间:{online}", error: "状态获取失败。" } }, random: { description: "随机数生成器。", usage: "缺少参数时默认生成 0-10000 的随机数。\n使用示例:", examples: "random 1 128 生成1到128范围的随机数", messages: { msg: "{time}\n生成了一个随机数:{data}", "msg-md": "*{time}*\n\n---\n\n生成了一个随机数:{data}" } }, info: { description: "查询机器人信息。", messages: { msg: "{time}\n--- NodeAsync {version} ---\n私有机器人,服务器专用。\n--- 开发者 ---\n德二吹风机(3112836258)\n--- 其他 ---\nNode.js 版本:{nodeVersion}\nKoishi 版本:{koishiVersion}\n开源地址:https://github.com/ccd2s/node-async-bot-all\n官网:https://www.tasaed.top", "msg-md": "*{time}*\n\n---\n\n## NodeAsync {version}\n\n私有机器人,服务器专用。\n\n## 开发者\n\n- 德二吹风机(3112836258)\n\n## 其他\n\n- Node.js 版本:{nodeVersion}\n- Koishi 版本:{koishiVersion}\n- 开源地址:https://github.com/ccd2s/node-async-bot-all\n- 官网:https://www.tasaed.top", error: "读取信息失败。" } }, rw: { description: "随机名言名句。", messages: null }, randomba: { description: "随机BA图。", messages: { msg: "{quote}{image}" } }, centerservertest: { description: "查看中心服务器状态。", messages: { msg: "{time}{list}", "msg-md": "*{time}*\n\n---\n{list}", list: "== {name} ==\n状态:{status}\n存活率:{uptime}\n检测时间:{time}", "list-md": "## {name}\n\n- 状态:{status}\n- 存活率:{uptime}\n- 检测时间:{time}", listFailed: "== {name} ==\n查看失败:{data}", "listFailed-md": "## {name}\n\n查看失败:{data}", statusLive: "✅ 正常", statusDie: "❌ 故障", dataFail: "未能获取到此服务器的状态信息。" } }, meme: { description: "群友的怪话!", usage: "不带参数时随机查看\n带参数时为查看指定 meme", examples: "meme\nmeme 1145", messages: { msg: "{quote}{time}\n{image}\n{title}", "msg-qq": "{quote}{image}\n{time}\n{title}" } }, randomcat: { description: "随机猫猫图。", messages: { msg: "{quote}{image}" } }, getqqinfo: { description: "获取 QQ 号的信息。", usage: "获取 QQ 号的信息。", examples: "getqqinfo 10001", messages: { msg: "{quote}{image}", failed: "{quote}{time}\n获取失败:{data}", command: "QQ 号不正确。" } }, msg2img: { description: "引用一个消息并使用此指令,即可将消息转图。", usage: "引用一条消息,/m。(不要带@)", messages: { msg: "{quote}{image}", failed: "{quote}{time}\n获取失败:{data}", null: "未引用任何消息。", matroska: "{quote}禁止套娃!" } }, steamnews: { description: "抓取 Steam 游戏的最新新闻。" }, use: { description: "使用 TA !", usage: "use @用户", examples: "use @用户", messages: { command: "请 @ 一个用户。", msg: "{at} {desc}了 {at2} !" } } } };
38
38
  }
39
39
  });
40
40
 
@@ -42,13 +42,14 @@ var require_zh_CN = __commonJS({
42
42
  var src_exports = {};
43
43
  __export(src_exports, {
44
44
  Config: () => Config,
45
+ NodeAsyncBot: () => NodeAsyncBot,
45
46
  apply: () => apply,
46
47
  inject: () => inject,
47
48
  name: () => name,
48
49
  usage: () => usage
49
50
  });
50
51
  module.exports = __toCommonJS(src_exports);
51
- var import_koishi3 = require("koishi");
52
+ var import_koishi4 = require("koishi");
52
53
 
53
54
  // src/commands.ts
54
55
  var import_koishi2 = require("koishi");
@@ -59,9 +60,7 @@ var import_fs = __toESM(require("fs"));
59
60
  var import_path = __toESM(require("path"));
60
61
  var import_koishi = require("koishi");
61
62
  var import_steam_server_query = require("steam-server-query");
62
- var import_html = __toESM(require("@bbob/html"));
63
- var import_preset_html5 = __toESM(require("@bbob/preset-html5"));
64
- var import_bing_translate_api = require("bing-translate-api");
63
+ var import_feedsmith = require("feedsmith");
65
64
  var import_minecraft_server_util = require("minecraft-server-util");
66
65
  function getSystemName() {
67
66
  return import_os.default.type() + " " + import_os.default.release();
@@ -101,15 +100,15 @@ __name(getCpuUsage, "getCpuUsage");
101
100
  async function getSystemUsage() {
102
101
  try {
103
102
  return {
104
- "name": getSystemName(),
105
- "cpu": await getCpuUsage(),
106
- "memory": getMemoryUsage(),
107
- "success": 0
103
+ name: getSystemName(),
104
+ cpu: await getCpuUsage(),
105
+ memory: getMemoryUsage(),
106
+ success: 0
108
107
  };
109
108
  } catch (error) {
110
109
  return {
111
- "data": error.message,
112
- "success": 1
110
+ data: error.message,
111
+ success: 1
113
112
  };
114
113
  }
115
114
  }
@@ -158,7 +157,10 @@ function formatTimestampDiff(start, end) {
158
157
  }
159
158
  __name(formatTimestampDiff, "formatTimestampDiff");
160
159
  async function getMsgCount(ctx) {
161
- const array = await ctx.database.get("analytics.message", { date: import_koishi.Time.getDateNumber() - 1 }, ["type", "count"]);
160
+ const array = await ctx.database.get("analytics.message", { date: import_koishi.Time.getDateNumber() - 1 }, [
161
+ "type",
162
+ "count"
163
+ ]);
162
164
  let receive = 0;
163
165
  let send = 0;
164
166
  array.forEach((item) => {
@@ -168,7 +170,7 @@ async function getMsgCount(ctx) {
168
170
  send = send + item.count;
169
171
  }
170
172
  });
171
- return { "receive": receive, "send": send };
173
+ return { receive, send };
172
174
  }
173
175
  __name(getMsgCount, "getMsgCount");
174
176
  function random(type = 0, data, data2) {
@@ -188,91 +190,55 @@ function random(type = 0, data, data2) {
188
190
  }
189
191
  }
190
192
  __name(random, "random");
191
- async function request(url, options = {}, timeout = 8e3, log) {
192
- const signal = AbortSignal.timeout(timeout);
193
+ async function request(url, ctx, options = { method: "GET", timeout: 8e3 }, logger) {
194
+ const log = logger ?? ctx.logger("http");
193
195
  try {
194
- const response = await fetch(url, { ...options, signal });
196
+ const response = await ctx.http(url, options);
195
197
  let responseData;
196
- let isJson;
197
- const text = await response.text();
198
+ let isObj;
199
+ const text = await response.data;
198
200
  try {
199
201
  responseData = JSON.parse(text);
200
- isJson = true;
202
+ isObj = true;
201
203
  } catch {
202
204
  responseData = text;
203
- isJson = false;
205
+ isObj = false;
204
206
  }
205
- if (!response.ok) {
206
- log?.error(`HTTP Error ${response.status}: ${url}`, responseData);
207
- return {
207
+ if (response.status !== 200) {
208
+ log.error(`HTTP Error ${response.status}: ${url}`, responseData);
209
+ return isObj ? {
210
+ success: false,
211
+ code: response.status,
212
+ error: responseData,
213
+ isObj: true,
214
+ isError: false
215
+ } : {
208
216
  success: false,
209
217
  code: response.status,
210
- error: responseData || `HTTP ${response.status}`,
211
- isJson
218
+ error: responseData ?? `HTTP ${response.status}`,
219
+ isObj: false,
220
+ isError: false
212
221
  };
213
222
  }
214
- log?.info(`HTTP ${response.status}: ${url}`);
223
+ log.info(`HTTP ${response.status}: ${url}`);
215
224
  return {
216
225
  success: true,
217
226
  data: responseData
218
227
  };
219
228
  } catch (error) {
220
- const isTimeout = error.name === "TimeoutError" || error.name === "AbortError";
221
- const errorMessage = isTimeout ? `请求超时。(${timeout}ms)` : error.message;
222
- log?.error(url);
223
- log?.error(`Request Failed: ${errorMessage}`);
229
+ const { name: name2, message } = error instanceof Error ? error : { name: "UnknownError", message: "unknown message" };
230
+ const isTimeout = name2 === "TimeoutError" || name2 === "AbortError";
231
+ const errorMessage = isTimeout ? `请求超时。(${options?.timeout}ms)` : message;
232
+ log.error(url);
233
+ log.error(`Request Failed:`, error);
224
234
  return {
225
235
  success: false,
226
- error: { name: error.name, message: errorMessage },
227
- isJson: false
236
+ error: { name: name2, message: errorMessage },
237
+ isError: true
228
238
  };
229
239
  }
230
240
  }
231
241
  __name(request, "request");
232
- async function readUserCardFile(userInfo) {
233
- let card;
234
- try {
235
- const aPath = import_path.default.resolve(__dirname, "..") + import_path.default.sep + "res" + import_path.default.sep + "userCard.html";
236
- card = await import_fs.default.promises.readFile(aPath, "utf8");
237
- let sex_so;
238
- let sex;
239
- if (userInfo.sex == "male") {
240
- sex = "♂";
241
- sex_so = "sex-male";
242
- } else if (userInfo.sex == "female") {
243
- sex = "♀";
244
- sex_so = "sex-female";
245
- } else {
246
- sex = "猫娘";
247
- sex_so = "sex-unknown";
248
- }
249
- card = card.toString().replace("{avatarUrl}", userInfo.avatar_url).replace("{nickname}", userInfo.nickname).replace("{sex}", sex).replace("{sex-so}", sex_so).replace("{age}", String(userInfo.age)).replace("{longNick}", userInfo.long_nick == "" ? "<无>" : `“ ${userInfo.long_nick} ”`).replace("{qq}", userInfo.qq).replace("{qqLevel}", String(userInfo.qq_level)).replace("{qid}", userInfo.qid == "" ? "<无>" : userInfo.qid).replace("{location}", userInfo.location == "" ? "<无>" : userInfo.location).replace("{email}", userInfo.email == "" ? "<无>" : userInfo.email).replace("{regTime}", userInfo.reg_time).replace("{lastUpdated}", userInfo.last_updated);
250
- } catch (error) {
251
- card = error.message;
252
- }
253
- return card;
254
- }
255
- __name(readUserCardFile, "readUserCardFile");
256
- async function readUserMsgFile(userName, userAvatar, msg, inversion, replyUserName, replyMsg) {
257
- let html;
258
- try {
259
- const aPath = import_path.default.resolve(__dirname, "..") + import_path.default.sep + "res" + import_path.default.sep + "userMsg.html";
260
- html = await import_fs.default.promises.readFile(aPath, "utf8");
261
- html = html.toString().replace("{userData.avatarUrl}", userAvatar).replace("{userData.username}", userName).replace("{userData.message}", msg).replace("{replyData.username}", replyUserName).replace("{replyData.message}", replyMsg).replace(
262
- /<at\s+(?:id=["']([^"']*)["']\s+name=["']([^"']*)["']|name=["']([^"']*)["']\s+id=["']([^"']*)["'])\s*\/?>/g,
263
- (match, id1, name1, name2, id2) => {
264
- const name3 = name1 || name2 || id1 || id2 || match;
265
- return `@${name3}`;
266
- }
267
- ).replace('<at type="all"/>', "@全体成员");
268
- if (inversion) html = html.replace("//// ", "");
269
- if (replyUserName != void 0) html = html.replace("/**/", "//// ");
270
- } catch (error) {
271
- html = error.message;
272
- }
273
- return html;
274
- }
275
- __name(readUserMsgFile, "readUserMsgFile");
276
242
  async function queryA2S(host, log) {
277
243
  try {
278
244
  const playerResponse = await (0, import_steam_server_query.queryGameServerInfo)(host);
@@ -294,697 +260,570 @@ async function queryA2S(host, log) {
294
260
  }
295
261
  }
296
262
  __name(queryA2S, "queryA2S");
297
- async function readNewsFile(info, log) {
298
- let html;
263
+ async function parseNewsRssToHtml(rss, log, count) {
299
264
  try {
300
- const aPath = import_path.default.resolve(__dirname, "..") + import_path.default.sep + "res" + import_path.default.sep + "slNews.html";
301
- html = await import_fs.default.promises.readFile(aPath, "utf8");
302
- const content = info.appnews.newsitems[0].contents.replace("[spoiler]", "").replace("[/spoiler]", "").replace(/\r\n/g, "\n").replace(/\n{3,}/g, "\n\n").split("\n\n").map((p) => p.trim()).filter(Boolean);
303
- const bilingualParagraphs = [];
304
- for (const paragraph of content) {
305
- const zh = await translateAPI(log, paragraph);
306
- bilingualParagraphs.push(
307
- paragraph,
308
- zh,
309
- ""
310
- // 空行用于分隔段落
311
- );
312
- }
313
- const finalText = bilingualParagraphs.join("<br />").replace(/<br \/>{2,}/g, "<br />");
314
- const contentHtml = (0, import_html.default)(finalText, (0, import_preset_html5.default)());
315
- const date = Number(info.appnews.newsitems[0].date + "000");
316
- html = html.toString().replace("{date}", new Date(date).toLocaleString()).replace("{title}", info.appnews.newsitems[0].title).replace("{content}", contentHtml);
265
+ const aPath = import_path.default.resolve(__dirname, "..") + import_path.default.sep + "res" + import_path.default.sep + "steamNews.html";
266
+ let html = await import_fs.default.promises.readFile(aPath, "utf8");
267
+ const content = (0, import_feedsmith.parseRssFeed)(rss);
268
+ if (!content?.items) return { error: new Error("响应不正确") };
269
+ const item = content.items[count ?? 0];
270
+ if (!item || !item.guid) return { error: new Error("文章不存在") };
271
+ if (item.enclosures && item.enclosures[0] && item.enclosures[0].url)
272
+ html = html.replace("<!--!", "").replace("!!-->", "").replace("{imgUrl}", item.enclosures[0].url);
273
+ return {
274
+ data: html.replace("{date}", new Date(item.pubDate ?? 0).toLocaleString()).replace("{title}", item.title ?? "无").replace("{content}", item.description ?? "无"),
275
+ guid: item.guid?.value
276
+ };
317
277
  } catch (error) {
318
278
  log.error(error);
319
279
  log.error(error.message);
320
- return [error, error.message];
280
+ return { error };
321
281
  }
322
- return [html];
323
282
  }
324
- __name(readNewsFile, "readNewsFile");
325
- async function translateAPI(log, text) {
326
- const ms = random(0, 0, 250);
327
- await (0, import_koishi.sleep)(ms);
328
- await (0, import_bing_translate_api.translate)(text, "en", "zh-Hans").then((result) => {
329
- text = result?.translation;
330
- }).catch((err) => {
331
- log.error(err);
332
- });
333
- return text;
334
- }
335
- __name(translateAPI, "translateAPI");
283
+ __name(parseNewsRssToHtml, "parseNewsRssToHtml");
336
284
  async function slpInfo(log, host, port, timeout) {
337
285
  try {
338
286
  const info = await (0, import_minecraft_server_util.status)(host, port, { timeout });
339
287
  log.info(info);
340
288
  return {
341
- "success": true,
342
- "data": info
289
+ success: true,
290
+ data: info
343
291
  };
344
292
  } catch (error) {
345
293
  log.error(error);
346
294
  return {
347
- "success": false,
348
- "data": error.message
295
+ success: false,
296
+ data: error.message
349
297
  };
350
298
  }
351
299
  }
352
300
  __name(slpInfo, "slpInfo");
353
301
 
354
302
  // src/commands.ts
355
- async function getServer(ctx, session) {
356
- const log = ctx.logger("cx");
357
- log.debug(`Got: {"form":"${session.platform}:${session.event.guild?.id}","user":"${session.event.user?.id}","timestamp":${session.event.timestamp},"messageId":"${session.event.message?.id}"}`);
358
- let msg;
359
- const time = getHongKongTime();
360
- const index = ctx.config.cxV3.findIndex((item) => item.id === session.event.guild?.id);
361
- if (index !== -1) {
362
- const server = ctx.config.cxV3[index].server;
363
- if (server == void 0) {
364
- msg = {
365
- "time": time,
366
- "error": "查询失败:" + session.text("noApi"),
367
- "success": 2
368
- };
369
- log.warn("Sent:");
370
- log.warn(msg);
371
- await session?.send(session?.bot.adapterName == "qq" ? (0, import_koishi2.h)("qq:markdown", {
372
- content: session?.text("failed-md", msg)
373
- }) : session?.text("failed", msg));
374
- return 1;
375
- }
376
- let count = 0;
377
- let list = "";
378
- for (const item of server) {
379
- const note = item.note;
380
- const type = item.type;
381
- const api = item.api;
382
- count++;
383
- if (type == "a2s") {
384
- const info = await queryA2S(api, log);
385
- if (info.success) {
386
- log.debug(info);
387
- const temp = {
388
- "count": count,
389
- "players": info.players,
390
- "version": info.version,
391
- "list": info.bots,
392
- "note": note ?? session.text("noop"),
393
- "name": "A2S",
394
- "ne": "机器人"
395
- };
396
- log.info(`Server ${count}:`);
397
- log.info(temp);
398
- list = list + "\n" + session.text(session?.bot.adapterName == "qq" ? ".list-md" : ".list", temp);
399
- } else {
400
- let err;
401
- if (info.error.toString().includes("Timeout reached. Possible reasons: You are being rate limited; Timeout too short; Wrong server host configured")) {
402
- err = session.text(".timeout");
403
- } else {
404
- err = session.text("unknown");
405
- }
406
- const temp = {
407
- "count": count,
408
- "data": err,
409
- "note": note,
410
- "name": "A2S"
411
- };
412
- log.error(`Server ${count}:`);
413
- log.error(temp);
414
- list = list + "\n" + session.text(session?.bot.adapterName == "qq" ? ".listFailed-md" : ".listFailed", temp);
415
- }
416
- } else {
417
- const host = api.split(":");
418
- const serverInfo = await slpInfo(log, host[0], Number(host[1]), ctx.config.timeout);
419
- if (serverInfo.success) {
420
- log.debug(serverInfo);
421
- if (serverInfo.data.players.sample == null) {
303
+ var CommandHandler = class {
304
+ static {
305
+ __name(this, "CommandHandler");
306
+ }
307
+ ctx;
308
+ session;
309
+ log;
310
+ time;
311
+ isQQ;
312
+ constructor(ctx, session, loggerName) {
313
+ this.ctx = ctx;
314
+ this.session = session;
315
+ this.log = ctx.logger(loggerName);
316
+ this.time = getHongKongTime();
317
+ this.isQQ = session?.bot.adapterName == "qq";
318
+ this.log.debug(
319
+ `Got: {"form":"${session.platform}:${session.event.guild?.id}","user":"${session.event.user?.id}","timestamp":${session.event.timestamp},"messageId":"${session.event.message?.id}"}`
320
+ );
321
+ }
322
+ // 发送普通消息(自动判断 QQ markdown)
323
+ async sendMsg(msgKey, data) {
324
+ await this.session?.send(
325
+ this.isQQ ? (0, import_koishi2.h)("qq:markdown", { content: this.session?.text(msgKey, data) }) : this.session?.text(msgKey, data)
326
+ );
327
+ }
328
+ // 发送失败消息
329
+ async sendFailed(data) {
330
+ await this.sendMsg(this.isQQ ? "failed-md" : "failed", data);
331
+ }
332
+ // 指令 cx
333
+ async server() {
334
+ const { ctx, session, log, time, isQQ } = this;
335
+ let msg;
336
+ const index = ctx.config.cxV3.findIndex(
337
+ (item) => item.id === session.event.guild?.id
338
+ );
339
+ if (index !== -1) {
340
+ const server = ctx.config.cxV3[index].server;
341
+ if (server == void 0) {
342
+ msg = {
343
+ time,
344
+ error: session.text(".failed") + session.text("noApi"),
345
+ success: 2
346
+ };
347
+ log.warn("Sent:");
348
+ log.warn(msg);
349
+ await this.sendFailed(msg);
350
+ return 1;
351
+ }
352
+ let count = 0;
353
+ let list = "";
354
+ for (const item of server) {
355
+ const note = item.note;
356
+ const type = item.type;
357
+ const api = item.api;
358
+ count++;
359
+ if (type == "a2s") {
360
+ const info = await queryA2S(api, log);
361
+ if (info.success) {
362
+ log.debug(info);
422
363
  const temp = {
423
- "count": count,
424
- "players": serverInfo.data.players.online + "/" + serverInfo.data.players.max,
425
- "version": serverInfo.data.version.name,
426
- "note": note ?? session.text("noop"),
427
- "ne": "玩家列表",
428
- "list": "[]",
429
- "name": "MC"
364
+ count,
365
+ players: info.players,
366
+ version: info.version,
367
+ list: info.bots,
368
+ note: note ?? session.text("noop"),
369
+ name: "A2S",
370
+ ne: session.text(".ne-a2s")
430
371
  };
431
372
  log.info(`Server ${count}:`);
432
373
  log.info(temp);
433
- list = list + "\n" + session.text(session?.bot.adapterName == "qq" ? ".list-md" : ".list", temp);
374
+ list = list + "\n" + session.text(isQQ ? ".list-md" : ".list", temp);
434
375
  } else {
376
+ let err;
377
+ if (info.error.toString().includes(
378
+ "Timeout reached. Possible reasons: You are being rate limited; Timeout too short; Wrong server host configured"
379
+ )) {
380
+ err = session.text(".timeout");
381
+ } else {
382
+ err = session.text("unknown");
383
+ }
435
384
  const temp = {
436
- "count": count,
437
- "players": serverInfo.data.players.online + "/" + serverInfo.data.players.max,
438
- "version": serverInfo.data.version.name,
439
- "list": serverInfo.data.players.sample.map((item2) => item2.name).join(", "),
440
- "note": note ?? session.text("noop"),
441
- "ne": "玩家列表",
442
- "name": "MC"
385
+ count,
386
+ data: err,
387
+ note,
388
+ name: "A2S"
443
389
  };
444
- log.info(`Server ${count}:`);
445
- log.info(temp);
446
- list = list + "\n" + session.text(session?.bot.adapterName == "qq" ? ".list-md" : ".list", temp);
390
+ log.error(`Server ${count}:`);
391
+ log.error(temp);
392
+ list = list + "\n" + session.text(isQQ ? ".listFailed-md" : ".listFailed", temp);
447
393
  }
448
394
  } else {
449
- let err = serverInfo.data;
450
- if (err.includes("connect ECONNREFUSED") || err.includes("Server is offline or unreachable")) {
451
- err = session.text(".close");
452
- } else if (err.includes("connect EHOSTUNREACH")) {
453
- err = session.text(".host");
454
- } else if (err.includes("connect ETIMEDOUT")) {
455
- err = session.text(".timeout");
456
- } else if (err.includes("Ping payload did not match received payload")) {
457
- err = session.text(".fewData");
458
- } else if (err.includes("Expected server to send packet type")) {
459
- err = session.text(".fewData");
460
- } else if (err.includes("getaddrinfo")) {
461
- err = session.text(".dns");
395
+ const host = api.split(":");
396
+ const serverInfo = await slpInfo(log, host[0], Number(host[1]), ctx.config.timeout);
397
+ if (serverInfo.success) {
398
+ log.debug(serverInfo);
399
+ if (serverInfo.data.players.sample == null) {
400
+ const temp = {
401
+ count,
402
+ players: serverInfo.data.players.online + "/" + serverInfo.data.players.max,
403
+ version: serverInfo.data.version.name,
404
+ note: note ?? session.text("noop"),
405
+ ne: session.text(".ne-mc"),
406
+ list: "[]",
407
+ name: "MC"
408
+ };
409
+ log.info(`Server ${count}:`);
410
+ log.info(temp);
411
+ list = list + "\n" + session.text(isQQ ? ".list-md" : ".list", temp);
412
+ } else {
413
+ const temp = {
414
+ count,
415
+ players: serverInfo.data.players.online + "/" + serverInfo.data.players.max,
416
+ version: serverInfo.data.version.name,
417
+ list: serverInfo.data.players.sample.map((item2) => item2.name).join(", "),
418
+ note: note ?? session.text("noop"),
419
+ ne: session.text(".ne-mc"),
420
+ name: "MC"
421
+ };
422
+ log.info(`Server ${count}:`);
423
+ log.info(temp);
424
+ list = list + "\n" + session.text(isQQ ? ".list-md" : ".list", temp);
425
+ }
426
+ } else {
427
+ let err = serverInfo.data;
428
+ if (err.includes("connect ECONNREFUSED") || err.includes("Server is offline or unreachable")) {
429
+ err = session.text(".close");
430
+ } else if (err.includes("connect EHOSTUNREACH")) {
431
+ err = session.text(".host");
432
+ } else if (err.includes("connect ETIMEDOUT")) {
433
+ err = session.text(".timeout");
434
+ } else if (err.includes("Ping payload did not match received payload")) {
435
+ err = session.text(".fewData");
436
+ } else if (err.includes("Expected server to send packet type")) {
437
+ err = session.text(".fewData");
438
+ } else if (err.includes("getaddrinfo")) {
439
+ err = session.text(".dns");
440
+ }
441
+ const temp = {
442
+ count,
443
+ data: err,
444
+ note,
445
+ name: "MC"
446
+ };
447
+ log.error(`Server ${count}:`);
448
+ log.error(temp);
449
+ list = list + "\n" + session.text(isQQ ? ".listFailed-md" : ".listFailed", temp);
462
450
  }
463
- const temp = {
464
- "count": count,
465
- "data": err,
466
- "note": note,
467
- "name": "MC"
468
- };
469
- log.error(`Server ${count}:`);
470
- log.error(temp);
471
- list = list + "\n" + session.text(session?.bot.adapterName == "qq" ? ".listFailed-md" : ".listFailed", temp);
472
451
  }
473
452
  }
453
+ msg = {
454
+ time,
455
+ list,
456
+ success: 0
457
+ };
458
+ await this.sendMsg(isQQ ? ".msg-md" : ".msg", msg);
459
+ return 0;
460
+ } else {
461
+ msg = {
462
+ time,
463
+ error: session.text(".forbidden"),
464
+ success: 1
465
+ };
466
+ log.info("Sent:");
467
+ log.info(msg);
468
+ await this.sendFailed(msg);
469
+ return 1;
474
470
  }
475
- msg = {
476
- "time": time,
477
- "list": list,
478
- "success": 0
479
- };
480
- await session?.send(session?.bot.adapterName == "qq" ? (0, import_koishi2.h)("qq:markdown", {
481
- content: session?.text(".msg-md", msg)
482
- }) : session?.text(".msg", msg));
483
- return 0;
484
- } else {
485
- msg = {
486
- "time": time,
487
- "error": "此指令不允许在本群使用。",
488
- "success": 1
489
- };
490
- log.info("Sent:");
491
- log.info(msg);
492
- await session?.send(session?.bot.adapterName == "qq" ? (0, import_koishi2.h)("qq:markdown", {
493
- content: session?.text("failed-md", msg)
494
- }) : session?.text("failed", msg));
495
- return 1;
496
- }
497
- }
498
- __name(getServer, "getServer");
499
- async function getStatus(ctx, session) {
500
- const log = ctx.logger("status");
501
- log.debug(`Got: {"form":"${session.platform}:${session.event.guild?.id}","user":"${session.event.user?.id}","timestamp":${session.event.timestamp},"messageId":"${session.event.message?.id}"}`);
502
- const time = getHongKongTime();
503
- let msg;
504
- const vMsg = await getSystemUsage();
505
- if (vMsg["success"] == 1) {
506
- log.error(vMsg);
507
- msg = {
508
- "time": time,
509
- "data": vMsg["data"],
510
- "error": "状态获取失败。",
511
- "quote": import_koishi2.h.quote(session.messageId),
512
- "success": 1
513
- };
514
- } else {
515
- const msgCount = await getMsgCount(ctx);
516
- msg = {
517
- "time": time,
518
- "name": vMsg["name"],
519
- "cpu": vMsg["cpu"],
520
- "memory": vMsg["memory"],
521
- "online": formatTimestampDiff(
522
- Number((await ctx.database.get("botData", "uptime"))[0].data),
523
- Number(session.event.timestamp.toString().substring(0, 10))
524
- ),
525
- "msgCount": `${msgCount["receive"]}/${msgCount["send"]}`,
526
- "version": (await ctx.database.get("botData", "version"))[0].data,
527
- "success": 0
528
- };
529
- }
530
- log.debug("Sent:");
531
- log.debug(msg);
532
- return msg;
533
- }
534
- __name(getStatus, "getStatus");
535
- async function getRandom(ctx, session, min, max) {
536
- const log = ctx.logger("random");
537
- log.debug(`Got: {"form":"${session.platform}:${session.event.guild?.id}","user":"${session.event.user?.id}","timestamp":${session.event.timestamp},"messageId":"${session.event.message?.id}"}`);
538
- const time = getHongKongTime();
539
- let msg;
540
- let data;
541
- if (min == void 0 || max == void 0) {
542
- min = 0;
543
- max = 1e4;
544
- }
545
- min = Math.ceil(min);
546
- max = Math.floor(max);
547
- data = Math.floor(Math.random() * (max - min + 1)) + min + `(${min},${max})`;
548
- msg = {
549
- "time": time,
550
- "data": data,
551
- "success": 0
552
- };
553
- log.debug("Sent:");
554
- log.debug(msg);
555
- return msg;
556
- }
557
- __name(getRandom, "getRandom");
558
- async function getInfo(ctx, session) {
559
- const log = ctx.logger("info");
560
- log.debug(`Got: {"form":"${session.platform}:${session.event.guild?.id}","user":"${session.event.user?.id}","timestamp":${session.event.timestamp},"messageId":"${session.event.message?.id}"}`);
561
- const time = getHongKongTime();
562
- let msg;
563
- let data = await readInfo(ctx);
564
- if (typeof data == "string") {
565
- log.error("Error:", data);
566
- msg = {
567
- "time": time,
568
- "data": data,
569
- "error": "读取信息失败。",
570
- "quote": import_koishi2.h.quote(session.messageId),
571
- "success": 1
572
- };
573
- } else {
574
- msg = {
575
- "time": time,
576
- ...data,
577
- "success": 0
578
- };
579
- }
580
- log.debug("Sent:");
581
- log.debug(msg);
582
- return msg;
583
- }
584
- __name(getInfo, "getInfo");
585
- async function getRandomWord(ctx, session) {
586
- const log = ctx.logger("rw");
587
- log.debug(`Got: {"form":"${session.platform}:${session.event.guild?.id}","user":"${session.event.user?.id}","timestamp":${session.event.timestamp},"messageId":"${session.event.message?.id}"}`);
588
- let msg;
589
- const time = getHongKongTime();
590
- if (ctx.config.rwAPI == void 0) {
591
- msg = {
592
- "time": time,
593
- "error": session.text("noApi"),
594
- "quote": import_koishi2.h.quote(session.messageId),
595
- "success": 2
596
- };
597
- log.warn("Sent:");
598
- log.warn(msg);
599
- return msg;
600
471
  }
601
- const response = await request(ctx.config.rwAPI + "?format=json", {}, ctx.config.timeout, log);
602
- if (response.success) {
603
- log.debug(response.data);
604
- msg = {
605
- "time": time,
606
- "error": response.data.data,
607
- "quote": import_koishi2.h.quote(session.messageId),
608
- "success": 0
609
- };
610
- log.debug("Sent:");
611
- log.debug(msg);
612
- } else {
613
- let err;
614
- if (response.code) {
615
- err = response.isJson ? response.error["data"] : response.error;
472
+ // 指令 Status
473
+ async status() {
474
+ const { ctx, session, log, time } = this;
475
+ let msg;
476
+ const vMsg = await getSystemUsage();
477
+ if (vMsg["success"] == 1) {
478
+ log.error(vMsg);
479
+ msg = {
480
+ time,
481
+ data: vMsg["data"],
482
+ error: session.text(".error"),
483
+ quote: import_koishi2.h.quote(session.messageId),
484
+ success: 1
485
+ };
616
486
  } else {
617
- err = response.error.message;
487
+ const msgCount = await getMsgCount(ctx);
488
+ msg = {
489
+ time,
490
+ name: vMsg["name"],
491
+ cpu: vMsg["cpu"],
492
+ memory: vMsg["memory"],
493
+ online: formatTimestampDiff(
494
+ Number((await ctx.database.get("botData", "uptime"))[0].data),
495
+ Number(session.event.timestamp.toString().substring(0, 10))
496
+ ),
497
+ msgCount: `${msgCount["receive"]}/${msgCount["send"]}`,
498
+ version: (await ctx.database.get("botData", "version"))[0].data,
499
+ success: 0
500
+ };
618
501
  }
619
- msg = {
620
- "time": time,
621
- "error": err,
622
- "quote": import_koishi2.h.quote(session.messageId),
623
- "success": 1
624
- };
625
- log.warn("Sent:");
626
- log.warn(msg);
627
- }
628
- return msg;
629
- }
630
- __name(getRandomWord, "getRandomWord");
631
- async function getBlueArchive(ctx, session) {
632
- const log = ctx.logger("ba");
633
- log.debug(`Got: {"form":"${session.platform}:${session.event.guild?.id}","user":"${session.event.user?.id}","timestamp":${session.event.timestamp},"messageId":"${session.event.message?.id}"}`);
634
- if (ctx.config.baAPI == void 0) {
635
- await session.send(session.text(".msg", { "quote": import_koishi2.h.quote(session.messageId), "image": session.text("noApi") }));
636
- return 1;
502
+ log.debug("Sent:");
503
+ log.debug(msg);
504
+ return msg;
637
505
  }
638
- const ms = random(0, 0, 1500);
639
- const link = random(2, ctx.config.baAPI) + `?cacheBuster=${random(1, 1, 2147483647)}`;
640
- log.debug(`Link: ${link}`);
641
- await (0, import_koishi2.sleep)(ms);
642
- const status2 = await session.send(session.text(".msg", { "quote": import_koishi2.h.quote(session.messageId), "image": import_koishi2.h.image(link) }));
643
- if (!status2) await session.send(session.text(".msg", { "quote": import_koishi2.h.quote(session.messageId), "image": import_koishi2.h.image(link) }));
644
- return 0;
645
- }
646
- __name(getBlueArchive, "getBlueArchive");
647
- async function centerServerTest(ctx, session) {
648
- const log = ctx.logger("centerServerTest");
649
- log.debug(`Got: {"form":"${session.platform}:${session.event.guild?.id}","user":"${session.event.user?.id}","timestamp":${session.event.timestamp},"messageId":"${session.event.message?.id}"}`);
650
- const time = getHongKongTime();
651
- let msg;
652
- let list = "";
653
- const timeFormatter = new Intl.DateTimeFormat("zh-CN", {
654
- timeZone: "Asia/Shanghai",
655
- year: "numeric",
656
- month: "2-digit",
657
- day: "2-digit",
658
- hour: "2-digit",
659
- minute: "2-digit",
660
- second: "2-digit",
661
- hour12: false
662
- });
663
- const response = await request("https://status.scpslgame.com/api/status-page/heartbeat/nw", {}, ctx.config.timeout, log);
664
- if (response.success) {
665
- log.debug(response.data);
666
- for (const server of ctx.config.slTest) {
667
- const lastTime = response.data.heartbeatList[server.id].at(-1);
668
- if (lastTime) {
669
- const uptime24 = (response.data.uptimeList[server.id + "_24"] * 100).toFixed(2) + "%";
670
- const status2 = lastTime?.status == 1 ? session.text(".statusLive") : session.text(".statusDie");
671
- const testTime = timeFormatter.format(/* @__PURE__ */ new Date(lastTime?.time.replace(" ", "T") + "Z"));
672
- list = list + "\n" + session.text(session?.bot.adapterName == "qq" ? ".list-md" : ".list", {
673
- "name": server.name,
674
- "status": status2,
675
- "uptime": uptime24,
676
- "time": testTime
677
- });
678
- } else {
679
- list = list + "\n" + session.text(session?.bot.adapterName == "qq" ? ".listFailed-md" : ".listFailed", {
680
- "name": server.name,
681
- "data": session.text(".dataFail")
682
- });
683
- }
506
+ // 指令 Random
507
+ async random(min, max) {
508
+ const { log, time } = this;
509
+ let msg;
510
+ let data;
511
+ if (min == void 0 || max == void 0) {
512
+ min = 0;
513
+ max = 1e4;
684
514
  }
515
+ min = Math.ceil(min);
516
+ max = Math.floor(max);
517
+ data = Math.floor(Math.random() * (max - min + 1)) + min + `(${min},${max})`;
685
518
  msg = {
686
- "data": { "list": list, "time": time },
687
- "success": ".msg"
519
+ time,
520
+ data,
521
+ success: 0
688
522
  };
689
- await session?.send(session?.bot.adapterName == "qq" ? (0, import_koishi2.h)("qq:markdown", {
690
- content: session?.text(".msg-md", msg.data)
691
- }) : session?.text(".msg", msg.data));
692
523
  log.debug("Sent:");
693
524
  log.debug(msg);
694
- return 0;
695
- } else {
696
- let err;
697
- if (response.code) {
698
- err = response.isJson ? response.error["data"] : response.error;
525
+ return msg;
526
+ }
527
+ // 指令 Info
528
+ async info() {
529
+ const { ctx, session, log, time } = this;
530
+ let msg;
531
+ let data = await readInfo(ctx);
532
+ if (typeof data == "string") {
533
+ log.error("Error:", data);
534
+ msg = {
535
+ time,
536
+ data,
537
+ error: session.text(".error"),
538
+ quote: import_koishi2.h.quote(session.messageId),
539
+ success: 1
540
+ };
699
541
  } else {
700
- err = response.error.message;
542
+ msg = {
543
+ time,
544
+ ...data,
545
+ success: 0
546
+ };
701
547
  }
702
- msg = {
703
- "data": { "error": "查看失败:" + err, "time": time },
704
- "success": ".failed"
705
- };
706
- await session?.send(session?.bot.adapterName == "qq" ? (0, import_koishi2.h)("qq:markdown", {
707
- content: session?.text("failed-md", msg.data)
708
- }) : session?.text("failed", msg.data));
709
- log.warn("Sent:");
710
- log.warn(msg);
711
- return 1;
712
- }
713
- }
714
- __name(centerServerTest, "centerServerTest");
715
- async function getMeme(ctx, session, count) {
716
- const log = ctx.logger("getMeme");
717
- log.debug(`Got: {"form":"${session.platform}:${session.event.guild?.id}","user":"${session.event.user?.id}","timestamp":${session.event.timestamp},"messageId":"${session.event.message?.id}"}`);
718
- let msg;
719
- const time = getHongKongTime();
720
- if (ctx.config.memesAPI[`${session.event.guild?.id}`] == void 0) {
721
- msg = {
722
- "time": time,
723
- "quote": import_koishi2.h.quote(session.messageId),
724
- "error": "此指令不允许在本群使用。"
725
- };
726
- log.warn("Sent:");
727
- log.warn(msg);
728
- await session?.send(session?.bot.adapterName == "qq" ? (0, import_koishi2.h)("qq:markdown", {
729
- content: session?.text("failed-md", msg)
730
- }) : session?.text("failed", msg));
731
- return 0;
732
- }
733
- const api = count ? ctx.config.memesAPI[`${session.event.guild?.id}`] + `&type=1&count=${count}` : ctx.config.memesAPI[`${session.event.guild?.id}`];
734
- const response = await request(api, {}, ctx.config.timeout, log);
735
- if (response.success) {
736
- msg = {
737
- "time": time,
738
- "title": response.data.data.title,
739
- "image": import_koishi2.h.image(response.data.data.image),
740
- "quote": import_koishi2.h.quote(session.messageId)
741
- };
742
548
  log.debug("Sent:");
743
549
  log.debug(msg);
744
- await session?.send(session?.bot.adapterName == "qq" ? session?.text(".msg-qq", msg) : session?.text(".msg", msg));
745
- return 0;
746
- } else {
747
- let err;
748
- if (response.code) {
749
- err = response.isJson ? response.error["data"] : response.error;
750
- } else {
751
- err = response.error.message;
752
- }
753
- msg = {
754
- "time": time,
755
- "error": "获取失败:" + err,
756
- "quote": import_koishi2.h.quote(session.messageId)
757
- };
758
- log.warn("Sent:");
759
- log.warn(msg);
760
- await session?.send(session?.bot.adapterName == "qq" ? (0, import_koishi2.h)("qq:markdown", {
761
- content: session?.text("failed-md", msg)
762
- }) : session?.text("failed", msg));
763
- return 0;
764
- }
765
- }
766
- __name(getMeme, "getMeme");
767
- async function getCat(ctx, session) {
768
- const log = ctx.logger("cat");
769
- log.debug(`Got: {"form":"${session.platform}:${session.event.guild?.id}","user":"${session.event.user?.id}","timestamp":${session.event.timestamp},"messageId":"${session.event.message?.id}"}`);
770
- const time = getHongKongTime();
771
- if (ctx.config.catAPI == void 0) {
772
- await session.send(session.text(".failed", { "quote": import_koishi2.h.quote(session.messageId), "data": "未指定 API", "time": time }));
773
- log.warn("未指定 API");
774
- return 1;
550
+ return msg;
775
551
  }
776
- const response = await request(ctx.config.catAPI, {}, ctx.config.timeout, log);
777
- if (response.success) {
778
- log.debug(response.data);
779
- const msg = { "quote": import_koishi2.h.quote(session.messageId), "image": import_koishi2.h.image(response.data[0].url) };
780
- await session.send(session.text(".msg", msg));
781
- log.debug("Sent:");
782
- log.debug(response.data[0].url);
783
- } else {
784
- if (response.code) {
785
- const msg = {
786
- "quote": import_koishi2.h.quote(session.messageId),
787
- "data": response.isJson ? "获取失败:" + response.error["error"] : "获取失败:" + response.error,
788
- "time": time
552
+ // 指令 RW
553
+ async randomWord() {
554
+ const { ctx, session, log, time } = this;
555
+ let msg;
556
+ if (ctx.config.rwAPI == void 0) {
557
+ msg = {
558
+ time,
559
+ error: session.text("noApi"),
560
+ quote: import_koishi2.h.quote(session.messageId),
561
+ success: 2
789
562
  };
790
- await session?.send(session?.bot.adapterName == "qq" ? (0, import_koishi2.h)("qq:markdown", {
791
- content: session?.text("failed-md", msg)
792
- }) : session?.text("failed", msg));
793
563
  log.warn("Sent:");
794
- log.warn(response.error);
564
+ log.warn(msg);
565
+ return msg;
566
+ }
567
+ const response = await request(
568
+ ctx.config.rwAPI + "?format=json",
569
+ ctx,
570
+ { method: "GET", timeout: ctx.config.timeout },
571
+ log
572
+ );
573
+ if (response.success) {
574
+ log.debug(response.data);
575
+ msg = {
576
+ time,
577
+ error: response.data.data,
578
+ quote: import_koishi2.h.quote(session.messageId),
579
+ success: 0
580
+ };
581
+ log.debug("Sent:");
582
+ log.debug(msg);
795
583
  } else {
796
- const msg = { "quote": import_koishi2.h.quote(session.messageId), "data": "获取失败:" + response.error.message, "time": time };
797
- await session?.send(session?.bot.adapterName == "qq" ? (0, import_koishi2.h)("qq:markdown", {
798
- content: session?.text("failed-md", msg)
799
- }) : session?.text("failed", msg));
584
+ let err;
585
+ if (!response.isError && response.isObj) {
586
+ err = response.error["data"];
587
+ } else if (response.isError) {
588
+ err = response.error.message;
589
+ } else {
590
+ err = response.error;
591
+ }
592
+ msg = {
593
+ time,
594
+ error: err,
595
+ quote: import_koishi2.h.quote(session.messageId),
596
+ success: 1
597
+ };
800
598
  log.warn("Sent:");
801
- log.warn(response.error);
599
+ log.warn(msg);
802
600
  }
601
+ return msg;
803
602
  }
804
- return 0;
805
- }
806
- __name(getCat, "getCat");
807
- async function getQQInfo(ctx, session, qq) {
808
- const log = ctx.logger("getQQInfo");
809
- log.debug(`Got: {"form":"${session.platform}:${session.event.guild?.id}","user":"${session.event.user?.id}","timestamp":${session.event.timestamp},"messageId":"${session.event.message?.id}"}`);
810
- const time = getHongKongTime();
811
- if (ctx.config.qqAPI == void 0) {
812
- await session.send(session.text(".failed", { "quote": import_koishi2.h.quote(session.messageId), "data": "未指定 API", "time": time }));
813
- log.warn("未指定 API");
814
- return 1;
815
- }
816
- const response = await request(ctx.config.qqAPI + `?qq=${qq}`, {}, ctx.config.timeout, log);
817
- if (response.success) {
818
- const fullHtml = await readUserCardFile(response.data);
819
- log.debug(fullHtml);
820
- const page = await ctx.puppeteer.page();
821
- try {
822
- await page.setViewport({
823
- width: 450,
824
- height: 650,
825
- deviceScaleFactor: 2
826
- });
827
- await page.setContent(fullHtml, { timeout: ctx.config.htmlTimeout, waitUntil: "networkidle0" });
828
- const { width, height } = await page.evaluate(() => ({
829
- width: document.body.scrollWidth,
830
- height: document.body.scrollHeight
831
- }));
832
- await page.setViewport({ width, height, deviceScaleFactor: 2 });
833
- const image = await page.screenshot({ type: "png", omitBackground: true });
834
- await session.send(session.text(".msg", { "quote": import_koishi2.h.quote(session.messageId), "image": import_koishi2.h.image(image, "image/png") }));
835
- } catch (err) {
836
- await session.send(session.text(".failed", { "quote": import_koishi2.h.quote(session.messageId), "time": time, "data": "图片渲染失败" }));
837
- log.error("图片渲染失败:", err);
603
+ // 指令 BA
604
+ async blueArchive() {
605
+ const { ctx, session, log } = this;
606
+ if (ctx.config.baAPI == void 0) {
607
+ await session.send(
608
+ session.text(".msg", { quote: import_koishi2.h.quote(session.messageId), image: session.text("noApi") })
609
+ );
838
610
  return 1;
839
- } finally {
840
- if (page && !page.isClosed()) await page.close();
841
- }
842
- log.debug("Sent: Image");
843
- } else {
844
- if (response.code) {
845
- await session.send(session.text(".failed", { "quote": import_koishi2.h.quote(session.messageId), "data": response.isJson ? response.error["error"] : response.error, "time": time }));
846
- log.warn("Sent:");
847
- log.warn(response.error);
848
- } else {
849
- await session.send(session.text(".failed", { "quote": import_koishi2.h.quote(session.messageId), "data": response.error.message, "time": time }));
850
- log.warn("Sent:");
851
- log.warn(response.error);
852
611
  }
612
+ const ms = random(0, 0, 1500);
613
+ const link = random(2, ctx.config.baAPI) + `?cacheBuster=${random(1, 1, 2147483647)}`;
614
+ log.debug(`Link: ${link}`);
615
+ await (0, import_koishi2.sleep)(ms);
616
+ const status2 = await session.send(
617
+ session.text(".msg", { quote: import_koishi2.h.quote(session.messageId), image: import_koishi2.h.image(link) })
618
+ );
619
+ if (!status2)
620
+ await session.send(
621
+ session.text(".msg", { quote: import_koishi2.h.quote(session.messageId), image: import_koishi2.h.image(link) })
622
+ );
623
+ return 0;
853
624
  }
854
- return 0;
855
- }
856
- __name(getQQInfo, "getQQInfo");
857
- async function getMsg(ctx, session, inversion) {
858
- const log = ctx.logger("getMsg");
859
- log.debug(`Got: {"form":"${session.platform}:${session.event.guild?.id}","user":"${session.event.user?.id}","timestamp":${session.event.timestamp},"messageId":"${session.event.message?.id}"}`);
860
- log.debug(`inversion: ${inversion}`);
861
- const time = getHongKongTime();
862
- if (!session.quote || !session.quote.user) {
863
- await session.send(session.text(".null"));
864
- log.warn("未引用任何信息");
865
- return 1;
866
- }
867
- if (session.quote.user.id == session.event.selfId) {
868
- await session.send(session.text(".matroska", { "quote": import_koishi2.h.quote(session.messageId) }));
869
- log.debug("套娃");
870
- return 1;
871
- }
872
- const user = await session.bot.getUser(session.quote.user.id, session.channelId);
873
- const msg = session.quote.content;
874
- const quoteMsg = session.quote.quote?.content;
875
- const quoteUser = session.quote.quote?.user?.name;
876
- log.debug(msg);
877
- if (!user.name || !user.avatar) {
878
- await session.send(session.text(".failed", { "quote": import_koishi2.h.quote(session.messageId), "time": time, "data": "获取用户信息失败。" }));
879
- log.error("获取用户信息失败");
880
- return 1;
881
- }
882
- const page = await ctx.puppeteer.page();
883
- const html = await readUserMsgFile(user.name, user.avatar, msg, inversion, quoteUser, quoteMsg);
884
- log.debug(html);
885
- try {
886
- await page.setViewport({
887
- width: 450,
888
- height: 1,
889
- deviceScaleFactor: 2
625
+ // 指令 centerServerTest
626
+ async centerServerTest() {
627
+ const { ctx, session, log, time } = this;
628
+ let msg;
629
+ let list = "";
630
+ const timeFormatter = new Intl.DateTimeFormat("zh-CN", {
631
+ timeZone: "Asia/Shanghai",
632
+ year: "numeric",
633
+ month: "2-digit",
634
+ day: "2-digit",
635
+ hour: "2-digit",
636
+ minute: "2-digit",
637
+ second: "2-digit",
638
+ hour12: false
890
639
  });
891
- await page.setContent(html, { timeout: ctx.config.htmlTimeout, waitUntil: "networkidle0" });
892
- const { width, height } = await page.evaluate(() => ({
893
- width: document.body.scrollWidth + 50,
894
- height: document.body.scrollHeight
895
- }));
896
- await page.setViewport({ width, height, deviceScaleFactor: 2 });
897
- const element = await page.$("#target-element");
898
- if (element) {
899
- const image = await element.screenshot({
900
- type: "png",
901
- omitBackground: true
902
- // 使得 CSS 中未定义的背景部分透明
903
- });
904
- await session.send(session.text(".msg", { "quote": import_koishi2.h.quote(session.messageId), "image": import_koishi2.h.image(image, "image/png") }));
905
- log.debug("Sent: Image");
640
+ const response = await request(
641
+ "https://status.scpslgame.com/api/status-page/heartbeat/nw",
642
+ ctx,
643
+ { method: "GET", timeout: ctx.config.timeout },
644
+ log
645
+ );
646
+ if (response.success) {
647
+ log.debug(response.data);
648
+ for (const server of ctx.config.slTest) {
649
+ const lastTime = response.data.heartbeatList[server.id].at(-1);
650
+ if (lastTime) {
651
+ const uptime24 = (response.data.uptimeList[server.id + "_24"] * 100).toFixed(2) + "%";
652
+ const status2 = lastTime?.status == 1 ? session.text(".statusLive") : session.text(".statusDie");
653
+ const testTime = timeFormatter.format(/* @__PURE__ */ new Date(lastTime?.time.replace(" ", "T") + "Z"));
654
+ list = list + "\n" + session.text(this.isQQ ? ".list-md" : ".list", {
655
+ name: server.name,
656
+ status: status2,
657
+ uptime: uptime24,
658
+ time: testTime
659
+ });
660
+ } else {
661
+ list = list + "\n" + session.text(this.isQQ ? ".listFailed-md" : ".listFailed", {
662
+ name: server.name,
663
+ data: session.text(".dataFail")
664
+ });
665
+ }
666
+ }
667
+ msg = {
668
+ data: { list, time },
669
+ success: ".msg"
670
+ };
671
+ await this.sendMsg(".msg", msg.data);
672
+ log.debug("Sent:");
673
+ log.debug(msg);
674
+ return 0;
906
675
  } else {
907
- await session.send(session.text(".failed", { "quote": import_koishi2.h.quote(session.messageId), "time": time, "data": "未找到目标元素。" }));
908
- log.error("未找到目标元素");
676
+ let err;
677
+ if (!response.isError && response.isObj) {
678
+ err = response.error["data"];
679
+ } else if (response.isError) {
680
+ err = response.error.message;
681
+ } else {
682
+ err = response.error;
683
+ }
684
+ msg = {
685
+ data: { error: "查看失败:" + err, time },
686
+ success: ".failed"
687
+ };
688
+ await this.sendFailed(msg.data);
689
+ log.warn("Sent:");
690
+ log.warn(msg);
909
691
  return 1;
910
692
  }
911
- } catch (err) {
912
- await session.send(session.text(".failed", { "quote": import_koishi2.h.quote(session.messageId), "time": time, "data": "图片渲染失败" }));
913
- log.error("图片渲染失败:", err);
914
- return 1;
915
- } finally {
916
- if (page && !page.isClosed()) await page.close();
917
693
  }
918
- return 0;
919
- }
920
- __name(getMsg, "getMsg");
921
- async function getNewsMsg(ctx, type) {
922
- const log = ctx.logger("getNewsMsg");
923
- const response = await request(ctx.config.newsAPI, {}, ctx.config.timeout, log);
924
- if (response.success) {
925
- if ((await ctx.database.get("botData", "newsId"))[0]?.data == response.data.appnews.newsitems[0].gid && type != 1) {
926
- log.debug("无新闻");
927
- return { success: false, msg: "无可用新闻" };
694
+ // 指令 Cat
695
+ async cat() {
696
+ const { ctx, session, log, time } = this;
697
+ if (ctx.config.catAPI == void 0) {
698
+ await session.send(
699
+ session.text(".failed", {
700
+ quote: import_koishi2.h.quote(session.messageId),
701
+ data: session.text("noApi"),
702
+ time
703
+ })
704
+ );
705
+ log.warn("未指定 API");
706
+ return 1;
928
707
  }
929
- const db = await ctx.database.get("botData", response.data.appnews.newsitems[0].gid);
930
- let html = [];
931
- if (db[0]) {
932
- html[0] = db[0].data;
708
+ const response = await request(
709
+ ctx.config.catAPI,
710
+ ctx,
711
+ { method: "GET", timeout: ctx.config.timeout },
712
+ log
713
+ );
714
+ if (response.success) {
715
+ log.debug(response.data);
716
+ const msg = { quote: import_koishi2.h.quote(session.messageId), image: import_koishi2.h.image(response.data[0].url) };
717
+ await session.send(session.text(".msg", msg));
718
+ log.debug("Sent:");
719
+ log.debug(response.data[0].url);
933
720
  } else {
934
- html = await readNewsFile(response.data, log);
935
- if (html[1]) return { success: false, msg: `渲染图片失败` };
936
- await ctx.database.upsert("botData", [
937
- { id: response.data.appnews.newsitems[0].gid, data: html[0] }
938
- ]);
721
+ if (!response.isError) {
722
+ const msg = {
723
+ quote: import_koishi2.h.quote(session.messageId),
724
+ data: response.isObj ? "获取失败:" + response.error["error"] : "获取失败:" + response.error,
725
+ time
726
+ };
727
+ await this.sendFailed(msg);
728
+ log.warn("Sent:");
729
+ log.warn(response.error);
730
+ } else {
731
+ const msg = {
732
+ quote: import_koishi2.h.quote(session.messageId),
733
+ data: "获取失败:" + response.error?.message,
734
+ time
735
+ };
736
+ await this.sendFailed(msg);
737
+ log.warn("Sent:");
738
+ log.warn(response.error);
739
+ }
939
740
  }
940
- log.debug(html);
941
- const page = await ctx.puppeteer.page();
942
- try {
943
- await page.setViewport({
944
- width: 800,
945
- height: 800,
946
- deviceScaleFactor: 2
947
- });
948
- await page.setContent(html[0], { timeout: ctx.config.htmlTimeout, waitUntil: "networkidle0" });
949
- const { width, height } = await page.evaluate(() => ({
950
- width: document.body.scrollWidth,
951
- height: document.body.scrollHeight
952
- }));
953
- await page.setViewport({ width, height, deviceScaleFactor: 2 });
954
- const image = await page.screenshot({
955
- type: "png",
956
- fullPage: true,
957
- omitBackground: true
958
- // 使得 CSS 中未定义的背景部分透明
959
- });
960
- if (type == 0) await ctx.database.upsert("botData", [
961
- { id: "newsId", data: response.data.appnews.newsitems[0].gid }
962
- ]);
963
- return { success: true, data: image, msg: "NorthWood 发布了一个新闻(原文+机翻):" + response.data.appnews.newsitems[0].title };
964
- } catch (err) {
965
- log.error("图片渲染失败:", err);
966
- return { success: false, msg: "图片渲染失败" };
967
- } finally {
968
- if (page && !page.isClosed()) await page.close();
741
+ return 0;
742
+ }
743
+ // 定时任务 SL News(静态方法,无 session)
744
+ static async getNewsMsg(ctx, type) {
745
+ const log = ctx.logger("getNewsMsg");
746
+ const results = [];
747
+ const latestIds = [];
748
+ const storedIds = (await ctx.database.get("botData", "newsId"))[0]?.data?.split(",") ?? [];
749
+ for (const item of ctx.config.newsAPI) {
750
+ const rssUrl = `https://store.steampowered.com/feeds/news/app/${item.appUrl}`;
751
+ log.info(`获取新闻: ${item.name} -> ${rssUrl}`);
752
+ const response = await request(
753
+ rssUrl,
754
+ ctx,
755
+ { method: "GET", timeout: ctx.config.timeout },
756
+ log
757
+ );
758
+ if (!response.success) {
759
+ log.error(`请求失败: ${item.name}`);
760
+ results.push({ success: false, msg: `请求 ${item.name} 新闻失败` });
761
+ continue;
762
+ }
763
+ const parsed = await parseNewsRssToHtml(response.data, log);
764
+ if (parsed.error || !parsed.guid) {
765
+ log.error(`解析失败: ${item.name}`, parsed.error);
766
+ results.push({ success: false, msg: `解析 ${item.name} 新闻失败` });
767
+ continue;
768
+ }
769
+ latestIds.push(parsed.guid);
770
+ if (storedIds.includes(parsed.guid) && type != 1) {
771
+ log.debug(`无新闻更新: ${item.name}`);
772
+ continue;
773
+ }
774
+ const db = await ctx.database.get("botData", parsed.guid);
775
+ let html;
776
+ if (db[0]) {
777
+ html = db[0].data;
778
+ } else {
779
+ html = parsed.data;
780
+ await ctx.database.upsert("botData", [{ id: parsed.guid, data: html }]);
781
+ }
782
+ const page = await ctx.puppeteer.page();
783
+ try {
784
+ await page.setViewport({
785
+ width: 800,
786
+ height: 800,
787
+ deviceScaleFactor: 2
788
+ });
789
+ await page.setContent(html, {
790
+ timeout: ctx.config.htmlTimeout,
791
+ waitUntil: "networkidle0"
792
+ });
793
+ const { width, height } = await page.evaluate(() => ({
794
+ width: document.body.scrollWidth,
795
+ height: document.body.scrollHeight
796
+ }));
797
+ await page.setViewport({ width, height, deviceScaleFactor: 2 });
798
+ const image = await page.screenshot({
799
+ type: "png",
800
+ fullPage: true,
801
+ omitBackground: true
802
+ });
803
+ results.push({
804
+ success: true,
805
+ data: image,
806
+ msg: `抓取到了新的 Steam 新闻!${item.name} - ${parsed.guid}`
807
+ });
808
+ } catch (err) {
809
+ log.error(`${item.name} 图片渲染失败:`, err);
810
+ results.push({ success: false, msg: `${item.name} 图片渲染失败` });
811
+ } finally {
812
+ if (page && !page.isClosed()) await page.close();
813
+ }
814
+ }
815
+ if (type == 0 && latestIds.length > 0) {
816
+ await ctx.database.upsert("botData", [{ id: "newsId", data: latestIds.join(",") }]);
969
817
  }
970
- } else {
971
- return { success: false, msg: "请求 Steam API 失败" };
818
+ return results;
972
819
  }
973
- }
974
- __name(getNewsMsg, "getNewsMsg");
975
- async function getUse(ctx, session, qq, desc) {
976
- const log = ctx.logger("getUse");
977
- log.debug(`Got: {"form":"${session.platform}:${session.event.guild?.id}","user":"${session.event.user?.id}","timestamp":${session.event.timestamp},"messageId":"${session.event.message?.id}"}`);
978
- await session.send(session.text(".msg", { "at": import_koishi2.h.at(session.event.user?.id), "at2": import_koishi2.h.at(qq), "desc": desc ?? "使用" }));
979
- return 0;
980
- }
981
- __name(getUse, "getUse");
820
+ };
982
821
 
983
822
  // package.json
984
- var version = "2.30.0";
823
+ var version = "3.0.0";
985
824
 
986
- // src/index.ts
987
- var inject = ["database", "installer", "puppeteer", "cron"];
825
+ // src/config.ts
826
+ var import_koishi3 = require("koishi");
988
827
  var name = "node-async-bot-all";
989
828
  var usage = "这是一个私有插件。";
990
829
  var Config = import_koishi3.Schema.intersect([
@@ -1012,211 +851,246 @@ var Config = import_koishi3.Schema.intersect([
1012
851
  import_koishi3.Schema.object({
1013
852
  baAPI: import_koishi3.Schema.array(String).default(["https://rba.kanostar.top/portrait"]).description("随机BA图 API")
1014
853
  }).description("随机BA图"),
1015
- import_koishi3.Schema.object({
1016
- steamAPI: import_koishi3.Schema.string().default("https://api.tasaed.top/get/steamid/").description("转换 Steam ID API")
1017
- }).description("转换 Steam ID"),
1018
- import_koishi3.Schema.object({
1019
- memesAPI: import_koishi3.Schema.dict(String).role("table").description("群友 meme API")
1020
- }).description("群友 meme"),
1021
854
  import_koishi3.Schema.object({
1022
855
  catAPI: import_koishi3.Schema.string().default("https://api.thecatapi.com/v1/images/search").description("随机猫猫图 API")
1023
856
  }).description("随机猫猫图"),
1024
857
  import_koishi3.Schema.object({
1025
- qqAPI: import_koishi3.Schema.string().default("https://uapis.cn/api/v1/social/qq/userinfo").description("获取 QQ 信息 API")
1026
- }).description("获取 QQ 信息"),
1027
- import_koishi3.Schema.object({
1028
- slNews: import_koishi3.Schema.array(String).default([""]).description("{platform}:{channelId}"),
1029
- newsAPI: import_koishi3.Schema.string().default("https://api.steampowered.com/ISteamNews/GetNewsForApp/v2/?appid=700330&count=1").description("新闻 API")
1030
- }).description("SL新闻列表"),
858
+ steamNews: import_koishi3.Schema.array(String).default([""]).description("{platform}:{channelId}"),
859
+ newsAPI: import_koishi3.Schema.array(
860
+ import_koishi3.Schema.object({
861
+ name: import_koishi3.Schema.string().description("新闻抓取的 App 名称,随便写"),
862
+ appUrl: import_koishi3.Schema.string().description(
863
+ "新闻抓取的 AppId URL,可加参数,如 3629270/?l=schinese"
864
+ )
865
+ })
866
+ ).default([{ name: "SCP SL", appUrl: "700330/?l=schinese" }]).description("新闻抓取配置")
867
+ }).description("Steam 新闻抓取列表"),
1031
868
  import_koishi3.Schema.object({
1032
869
  specialMsg: import_koishi3.Schema.array(String).default([]).description("特殊消息"),
1033
870
  reactionId: import_koishi3.Schema.array(Number).default([]).description("回应表情 ID")
1034
- }).description("特殊消息回应"),
1035
- import_koishi3.Schema.object({
1036
- slTest: import_koishi3.Schema.array(import_koishi3.Schema.object({
1037
- id: import_koishi3.Schema.string().description("服务器 ID"),
1038
- name: import_koishi3.Schema.string().description("服务器 名称")
1039
- })).default([{ "id": "1", "name": "中心 鲁贝 1" }, { "id": "19", "name": "中心 斯特拉斯堡 1" }, { "id": "3", "name": "Steam 认证 API" }]).description("测试中心服务器")
1040
- }).description("测试中心服务器")
871
+ }).description("特殊消息回应")
1041
872
  ]).description("基础设置");
1042
- async function startReaction(session) {
1043
- if (session.bot.createReaction) await session.bot.createReaction(session.channelId, session.messageId, `face|424`);
1044
- }
1045
- __name(startReaction, "startReaction");
1046
- async function endReaction(session) {
1047
- if (session.bot.deleteReaction) await session.bot.deleteReaction(session.channelId, session.messageId, `face|424`);
1048
- if (session.bot.createReaction) await session.bot.createReaction(session.channelId, session.messageId, `face|144`);
1049
- }
1050
- __name(endReaction, "endReaction");
1051
- async function endReactionFailed(session) {
1052
- if (session.bot.deleteReaction) await session.bot.deleteReaction(session.channelId, session.messageId, `face|424`);
1053
- if (session.bot.createReaction) await session.bot.createReaction(session.channelId, session.messageId, `face|38`);
1054
- }
1055
- __name(endReactionFailed, "endReactionFailed");
873
+
874
+ // src/index.ts
875
+ var inject = ["database", "installer", "puppeteer", "cron"];
1056
876
  function apply(ctx) {
1057
877
  ctx.i18n.define("zh-CN", require_zh_CN());
1058
878
  ctx.on("ready", async () => {
1059
- ctx.model.extend("botData", {
879
+ const naBot = new NodeAsyncBot();
880
+ await naBot.init(ctx);
881
+ await naBot.registerNews();
882
+ await naBot.registerCommand();
883
+ });
884
+ }
885
+ __name(apply, "apply");
886
+ var NodeAsyncBot = class {
887
+ static {
888
+ __name(this, "NodeAsyncBot");
889
+ }
890
+ _ctx;
891
+ _botData;
892
+ _na;
893
+ _registeredNews = false;
894
+ _registeredCommand = false;
895
+ get ctx() {
896
+ if (!this._ctx) throw new Error("未初始化");
897
+ return this._ctx;
898
+ }
899
+ set ctx(value) {
900
+ this._ctx = value;
901
+ }
902
+ get botData() {
903
+ if (!this._botData) throw new Error("未初始化");
904
+ return this._botData;
905
+ }
906
+ set botData(value) {
907
+ this._botData = value;
908
+ }
909
+ get na() {
910
+ if (!this._na) throw new Error("未初始化");
911
+ return this._na;
912
+ }
913
+ set na(value) {
914
+ this._na = value;
915
+ }
916
+ async init(ct) {
917
+ this.ctx = ct;
918
+ const date = /* @__PURE__ */ new Date();
919
+ this.botData = {
920
+ version,
921
+ uptime: date.getTime().toString().substring(0, 10)
922
+ };
923
+ this.ctx.model.extend("botData", {
1060
924
  // 向表中注入字符串
1061
925
  id: "string",
1062
926
  data: "string"
1063
927
  });
1064
- const date = /* @__PURE__ */ new Date();
1065
- await ctx.database.upsert("botData", [
1066
- { id: "uptime", data: date.getTime().toString().substring(0, 10) },
1067
- { id: "version", data: version }
928
+ await this.ctx.database.upsert("botData", [
929
+ { id: "uptime", data: this.botData.uptime },
930
+ { id: "version", data: this.botData.version }
1068
931
  ]);
1069
- });
1070
- const na = ctx.command("na");
1071
- na.subcommand("slnews").action(async () => {
1072
- const log = ctx.logger("slnews");
1073
- const outMsg = await getNewsMsg(ctx, 1);
1074
- if (outMsg.data) {
1075
- return `${outMsg.msg}
1076
- ${import_koishi3.h.image(outMsg.data, "image/png")}`;
1077
- } else {
1078
- log.warn(outMsg);
1079
- return outMsg.msg;
1080
- }
1081
- });
1082
- ctx.cron("0 * * * *", async () => {
1083
- ctx.emit("node-async/news");
1084
- });
1085
- ctx.cron("30 * * * *", async () => {
1086
- ctx.emit("node-async/news");
1087
- });
1088
- ctx.on("node-async/news", async () => {
1089
- const outMsg = await getNewsMsg(ctx, 0);
1090
- if (outMsg.data) {
1091
- await ctx.broadcast(ctx.config.slNews, `${outMsg.msg}
1092
- ${import_koishi3.h.image(outMsg.data, "image/png")}`);
932
+ this.na = this.ctx.command("na");
933
+ }
934
+ // reaction 辅助方法
935
+ async startReaction(session) {
936
+ if (session.bot.createReaction)
937
+ await session.bot.createReaction(
938
+ session.channelId,
939
+ session.messageId,
940
+ `face|424`
941
+ );
942
+ }
943
+ async endReaction(session) {
944
+ if (session.bot.deleteReaction)
945
+ await session.bot.deleteReaction(
946
+ session.channelId,
947
+ session.messageId,
948
+ `face|424`
949
+ );
950
+ if (session.bot.createReaction)
951
+ await session.bot.createReaction(
952
+ session.channelId,
953
+ session.messageId,
954
+ `face|144`
955
+ );
956
+ }
957
+ async endReactionFailed(session) {
958
+ if (session.bot.deleteReaction)
959
+ await session.bot.deleteReaction(
960
+ session.channelId,
961
+ session.messageId,
962
+ `face|424`
963
+ );
964
+ if (session.bot.createReaction)
965
+ await session.bot.createReaction(
966
+ session.channelId,
967
+ session.messageId,
968
+ `face|38`
969
+ );
970
+ }
971
+ // 执行指令的通用流程:reaction + 命令执行
972
+ async execCommand(session, loggerName, fn) {
973
+ const handler = new CommandHandler(this.ctx, session, loggerName);
974
+ await this.startReaction(session);
975
+ const result = await fn(handler);
976
+ if (result === 0 || result === void 0) {
977
+ await this.endReaction(session);
1093
978
  } else {
1094
- if (outMsg.msg == "无可用新闻") return;
1095
- await ctx.broadcast(ctx.config.slNews, outMsg.msg);
979
+ await this.endReactionFailed(session);
1096
980
  }
1097
- });
1098
- ctx.on("message", async (session) => {
1099
- for (const content of ctx.config.specialMsg) {
1100
- if (session.content === content) {
1101
- await session.bot.createReaction(session.channelId, session.messageId, `face|${String(random(2, ctx.config.reactionId))}`);
981
+ }
982
+ async registerNews() {
983
+ if (this._registeredNews) return;
984
+ this._registeredNews = true;
985
+ this.na.subcommand("steamNews").action(async ({ session }) => {
986
+ const log = this.ctx.logger("steamNews");
987
+ const results = await CommandHandler.getNewsMsg(this.ctx, 1);
988
+ for (const outMsg of results) {
989
+ if (outMsg.data) {
990
+ await session?.send(`${outMsg.msg}
991
+ ${import_koishi4.h.image(outMsg.data, "image/png")}`);
992
+ } else {
993
+ log.error(outMsg);
994
+ await session?.send(outMsg.msg);
995
+ }
1102
996
  }
1103
- }
1104
- });
1105
- na.subcommand("cxGame").action(async ({ session }) => {
1106
- await startReaction(session);
1107
- const cx = await getServer(ctx, session);
1108
- if (cx == 0) {
1109
- await endReaction(session);
1110
- } else {
1111
- await endReactionFailed(session);
1112
- }
1113
- });
1114
- na.subcommand("status").alias("stats").alias("状态").action(async ({ session }) => {
1115
- await startReaction(session);
1116
- const status2 = await getStatus(ctx, session);
1117
- if (status2["success"] == 0) {
1118
- await session?.send(session?.bot.adapterName == "qq" ? (0, import_koishi3.h)("qq:markdown", {
1119
- content: session?.text(".msg-md", status2)
1120
- }) : session?.text(".msg", status2));
1121
- await endReaction(session);
1122
- } else {
1123
- await session?.send(session?.bot.adapterName == "qq" ? (0, import_koishi3.h)("qq:markdown", {
1124
- content: session?.text("failed-md", status2)
1125
- }) : session?.text("failed", status2));
1126
- await endReactionFailed(session);
1127
- }
1128
- });
1129
- na.subcommand("random [最小数:number] [最大数:number]").alias("随机数").action(async ({ session }, min, max) => {
1130
- await startReaction(session);
1131
- const random2 = await getRandom(ctx, session, min, max);
1132
- await session?.send(session?.bot.adapterName == "qq" ? (0, import_koishi3.h)("qq:markdown", {
1133
- content: session?.text(".msg-md", random2)
1134
- }) : session?.text(".msg", random2));
1135
- await endReaction(session);
1136
- });
1137
- na.subcommand("info").action(async ({ session }) => {
1138
- await startReaction(session);
1139
- const info = await getInfo(ctx, session);
1140
- if (info["success"] == 0) {
1141
- await session?.send(session?.bot.adapterName == "qq" ? (0, import_koishi3.h)("qq:markdown", {
1142
- content: session?.text(".msg-md", info)
1143
- }) : session?.text(".msg", info));
1144
- await endReaction(session);
1145
- } else {
1146
- await session?.send(session?.bot.adapterName == "qq" ? (0, import_koishi3.h)("qq:markdown", {
1147
- content: session?.text("failed-md", info)
1148
- }) : session?.text("failed", info));
1149
- await endReactionFailed(session);
1150
- }
1151
- });
1152
- na.subcommand("rw").action(async ({ session }) => {
1153
- await startReaction(session);
1154
- const rw = await getRandomWord(ctx, session);
1155
- if (rw["success"] == 0) {
1156
- await session?.send(session?.bot.adapterName == "qq" ? (0, import_koishi3.h)("qq:markdown", {
1157
- content: session?.text("failed-md", rw)
1158
- }) : session?.text("failed", rw));
1159
- await endReaction(session);
1160
- } else {
1161
- await session?.send(session?.bot.adapterName == "qq" ? (0, import_koishi3.h)("qq:markdown", {
1162
- content: session?.text("failed-md", rw)
1163
- }) : session?.text("failed", rw));
1164
- await endReactionFailed(session);
1165
- }
1166
- });
1167
- na.subcommand("randomBA").alias("随机ba图").action(async ({ session }) => {
1168
- await startReaction(session);
1169
- await getBlueArchive(ctx, session);
1170
- await endReaction(session);
1171
- });
1172
- na.subcommand("centerServerTest").alias("测测中心服务器").action(async ({ session }) => {
1173
- await startReaction(session);
1174
- const ct = await centerServerTest(ctx, session);
1175
- if (ct == 0) {
1176
- await endReaction(session);
1177
- } else {
1178
- await endReactionFailed(session);
1179
- }
1180
- });
1181
- na.subcommand("meme [序号:posint]").alias("memes").action(async ({ session }, count) => {
1182
- await startReaction(session);
1183
- await getMeme(ctx, session, count);
1184
- await endReaction(session);
1185
- });
1186
- na.subcommand("randomCat").alias("随机猫猫图").alias("随机猫猫").action(async ({ session }) => {
1187
- await startReaction(session);
1188
- await getCat(ctx, session);
1189
- await endReaction(session);
1190
- });
1191
- na.subcommand("getQQInfo <QQ号:string>").alias("获取QQ信息").action(async ({ session }, qq) => {
1192
- await startReaction(session);
1193
- if (qq == void 0 || isNaN(Number(qq))) {
1194
- await endReactionFailed(session);
1195
- return session?.text(".command");
1196
- }
1197
- await getQQInfo(ctx, session, qq);
1198
- await endReaction(session);
1199
- });
1200
- na.subcommand("msg2img").option("inversion", "-i").alias("消息转图").alias("m").action(async ({ session, options }) => {
1201
- await startReaction(session);
1202
- await getMsg(ctx, session, options?.inversion);
1203
- await endReaction(session);
1204
- });
1205
- na.subcommand("use <user:user> [方法:string]").alias("u").action(async ({ session }, user, desc) => {
1206
- await startReaction(session);
1207
- const qq = user?.split(":")?.[1];
1208
- if (qq == void 0 || isNaN(Number(qq))) {
1209
- await endReactionFailed(session);
1210
- return session?.text(".command");
1211
- }
1212
- await getUse(ctx, session, qq, desc);
1213
- await endReaction(session);
1214
- });
1215
- }
1216
- __name(apply, "apply");
997
+ });
998
+ this.ctx.cron("0 * * * *", async () => {
999
+ this.ctx.emit("node-async/news");
1000
+ });
1001
+ this.ctx.cron("30 * * * *", async () => {
1002
+ this.ctx.emit("node-async/news");
1003
+ });
1004
+ this.ctx.on("node-async/news", async () => {
1005
+ const results = await CommandHandler.getNewsMsg(this.ctx, 0);
1006
+ if (results.length === 0) return;
1007
+ for (const outMsg of results) {
1008
+ if (outMsg.data) {
1009
+ await this.ctx.broadcast(
1010
+ this.ctx.config.steamNews,
1011
+ `${outMsg.msg}
1012
+ ${import_koishi4.h.image(outMsg.data, "image/png")}`
1013
+ );
1014
+ } else {
1015
+ await this.ctx.broadcast(this.ctx.config.steamNews, outMsg.msg);
1016
+ }
1017
+ }
1018
+ });
1019
+ this.ctx.on("message", async (session) => {
1020
+ if (session.bot.createReaction) {
1021
+ for (const content of this.ctx.config.specialMsg) {
1022
+ if (session.content === content) {
1023
+ await session.bot.createReaction(
1024
+ session.channelId,
1025
+ session.messageId,
1026
+ `face|${String(random(2, this.ctx.config.reactionId))}`
1027
+ );
1028
+ }
1029
+ }
1030
+ }
1031
+ });
1032
+ }
1033
+ async registerCommand() {
1034
+ if (this._registeredCommand) return;
1035
+ this._registeredCommand = true;
1036
+ this.na.subcommand("cxGame").action(async ({ session }) => {
1037
+ await this.execCommand(session, "cx", (handler) => handler.server());
1038
+ });
1039
+ this.na.subcommand("status").alias("stats").alias("状态").action(async ({ session }) => {
1040
+ await this.execCommand(session, "status", async (handler) => {
1041
+ const status2 = await handler.status();
1042
+ await session?.send(
1043
+ session?.bot.adapterName == "qq" ? (0, import_koishi4.h)("qq:markdown", {
1044
+ content: session?.text(status2["success"] == 0 ? ".msg-md" : "failed-md", status2)
1045
+ }) : session?.text(status2["success"] == 0 ? ".msg" : "failed", status2)
1046
+ );
1047
+ return status2["success"] == 0 ? 0 : 1;
1048
+ });
1049
+ });
1050
+ this.na.subcommand("random [最小数:number] [最大数:number]").alias("随机数").action(async ({ session }, min, max) => {
1051
+ await this.execCommand(session, "random", async (handler) => {
1052
+ const random2 = await handler.random(min, max);
1053
+ await session?.send(
1054
+ session?.bot.adapterName == "qq" ? (0, import_koishi4.h)("qq:markdown", {
1055
+ content: session?.text(".msg-md", random2)
1056
+ }) : session?.text(".msg", random2)
1057
+ );
1058
+ });
1059
+ });
1060
+ this.na.subcommand("info").action(async ({ session }) => {
1061
+ await this.execCommand(session, "info", async (handler) => {
1062
+ const info = await handler.info();
1063
+ await session?.send(
1064
+ session?.bot.adapterName == "qq" ? (0, import_koishi4.h)("qq:markdown", {
1065
+ content: session?.text(info["success"] == 0 ? ".msg-md" : "failed-md", info)
1066
+ }) : session?.text(info["success"] == 0 ? ".msg" : "failed", info)
1067
+ );
1068
+ return info["success"] == 0 ? 0 : 1;
1069
+ });
1070
+ });
1071
+ this.na.subcommand("rw").action(async ({ session }) => {
1072
+ await this.execCommand(session, "rw", async (handler) => {
1073
+ const rw = await handler.randomWord();
1074
+ await session?.send(
1075
+ session?.bot.adapterName == "qq" ? (0, import_koishi4.h)("qq:markdown", {
1076
+ content: session?.text(rw["success"] == 0 ? "failed-md" : "failed-md", rw)
1077
+ }) : session?.text(rw["success"] == 0 ? "failed" : "failed", rw)
1078
+ );
1079
+ return rw["success"] == 0 ? 0 : 1;
1080
+ });
1081
+ });
1082
+ this.na.subcommand("randomBA").alias("随机ba图").action(async ({ session }) => {
1083
+ await this.execCommand(session, "ba", (handler) => handler.blueArchive());
1084
+ });
1085
+ this.na.subcommand("randomCat").alias("随机猫猫图").alias("随机猫猫").action(async ({ session }) => {
1086
+ await this.execCommand(session, "cat", (handler) => handler.cat());
1087
+ });
1088
+ }
1089
+ };
1217
1090
  // Annotate the CommonJS export names for ESM import in node:
1218
1091
  0 && (module.exports = {
1219
1092
  Config,
1093
+ NodeAsyncBot,
1220
1094
  apply,
1221
1095
  inject,
1222
1096
  name,