UNPKG

koishi-plugin-mizuki-bot

Version:
1,386 lines (1,366 loc) 79 kB
var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); var __export = (target, all) => { for (var name3 in all) __defProp(target, name3, { get: all[name3], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { Config: () => Config, apply: () => apply2, inject: () => inject, name: () => name2 }); module.exports = __toCommonJS(src_exports); var import_koishi5 = require("koishi"); // src/database.ts var database_exports = {}; __export(database_exports, { apply: () => apply, name: () => name }); var name = "Database"; function apply(ctx) { ctx.model.extend("mzk_user", { id: "unsigned", platform: "string", user_id: "string", nickname: "string", skland_cred: "string", skland_uid: "string", skland_token: "string", skland_last_refresh: "timestamp" }, { primary: "id", autoInc: true }); ctx.model.extend("mzk_jellyfish_box", { user_id: "unsigned", last_catch_time: "timestamp", last_refresh_time: "timestamp", jellyfish: "json", decoration: "json", salinity: "double", temperature: "double", draw_style: "string" }, { primary: "user_id", autoInc: true, foreign: { user_id: ["mzk_user", "entity_id"] } }); ctx.model.extend("mzk_jellyfish_meta", { id: "string", name: "string", group: "string", description: "string", reproductive_rate: "double", living_location: "json", protected: "boolean", draw: "json" }); ctx.model.extend("mzk_jellyfish_event_meta", { id: "string", name: "string", description: "string", type: "string", probability: "double", relation: "json" }); } __name(apply, "apply"); // src/commands/jellyfish_box.tsx var import_koishi2 = require("koishi"); var import_lodash5 = __toESM(require("lodash")); // src/utils.ts var import_lodash = __toESM(require("lodash")); function NormalizeProbabilities(probabilities) { const total = probabilities.reduce((sum, prob) => sum + prob, 0); return probabilities.map((prob) => prob / total); } __name(NormalizeProbabilities, "NormalizeProbabilities"); function RandomChooseWithWeights(weights, choices) { if (choices.length !== weights.length) { throw new Error("weights and choices arrays must have the same length."); } const normalizedProbabilities = NormalizeProbabilities(weights); const cumulativeProbabilities = normalizedProbabilities.reduce((acc, prob, index) => { acc.push((acc[index - 1] || 0) + prob); return acc; }, []); const random3 = Math.random(); return choices[cumulativeProbabilities.findIndex((p) => p > random3)]; } __name(RandomChooseWithWeights, "RandomChooseWithWeights"); function RandomChoose(choices) { return choices[import_lodash.default.random(choices.length - 1)]; } __name(RandomChoose, "RandomChoose"); // src/draw/default.ts var import_koishi = require("koishi"); var import_path = __toESM(require("path")); // src/draw/utils.tsx var import_lodash2 = __toESM(require("lodash")); var import_jsx_runtime = require("@satorijs/element/jsx-runtime"); var ImageBuffer = /* @__PURE__ */ __name(async ({ buffer }) => { return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { src: "data:image/png;base64," + buffer.toString("base64") }); }, "ImageBuffer"); var ProcessJellyfishImage = /* @__PURE__ */ __name(async (ctx, image_path) => { const { Canvas, loadImage } = ctx.skia; const image = await loadImage(image_path); const canvas = new Canvas(image.width, image.height); const skia_ctx = canvas.getContext("2d"); skia_ctx.drawImage(image, 0, 0); const image_data = skia_ctx.getImageData(0, 0, canvas.width, canvas.height); const { width, height, data } = image_data; let top = height, bottom = 0, left = width, right = 0; for (let y = 0; y < height; y++) { for (let x = 0; x < width; x++) { const alpha = data[(y * width + x) * 4 + 3]; if (alpha > 0) { if (x < left) left = x; if (x > right) right = x; if (y < top) top = y; if (y > bottom) bottom = y; } } } const crop_width = right - left + 1; const crop_height = bottom - top + 1; const max = import_lodash2.default.max([crop_width, crop_height]); const dx = (max - crop_width) / 2; const dy = (max - crop_height) / 2; const crop_canvas = new Canvas(max, max); const crop_ctx = crop_canvas.getContext("2d"); crop_ctx.drawImage(image, left, top, crop_width, crop_height, dx, dy, crop_width, crop_height); return crop_canvas; }, "ProcessJellyfishImage"); // src/draw/default.ts var import_lodash3 = __toESM(require("lodash")); var logger = new import_koishi.Logger("mizuki-bot-draw-normal"); var drawRoundRect = /* @__PURE__ */ __name((ctx, x, y, width, height, radius) => { ctx.save(); ctx.beginPath(); ctx.roundRect(x, y, width, height, radius); ctx.closePath(); ctx.clip(); ctx.fillRect(x, y, width, height); ctx.restore(); }, "drawRoundRect"); var drawPacman = /* @__PURE__ */ __name(async (koishiCtx, dotCount) => { const { Canvas } = koishiCtx.skia; const canvas = new Canvas(240, 24); const ctx = canvas.getContext("2d"); ctx.fillStyle = "#e0e97d"; const centerX = 12; const centerY = 12; const radius = 12; const eyeX = centerX + 2; const eyeY = centerY - 7; const eyeRadius = 1.5; ctx.beginPath(); ctx.moveTo(centerX, centerY); ctx.arc(centerX, centerY, radius, 0.2 * Math.PI, 1.8 * Math.PI, false); ctx.closePath(); ctx.fill(); ctx.globalCompositeOperation = "destination-out"; ctx.beginPath(); ctx.arc(eyeX, eyeY, eyeRadius, 0, 2 * Math.PI, false); ctx.fill(); ctx.globalCompositeOperation = "source-over"; const dotRadius = 6; const dotSpacing = 15; ctx.fillStyle = "#8aabfd"; for (let i = 1; i <= dotCount; i++) { const dotX = centerX + radius + i * dotSpacing; const dotY = centerY; ctx.beginPath(); ctx.arc(dotX, dotY, dotRadius, 0, 2 * Math.PI, false); ctx.fill(); } return canvas; }, "drawPacman"); var DrawDefaultThemeBox = /* @__PURE__ */ __name(async (koishiCtx, config, session, jellyfishBox, newJelly, events, isCatch = false) => { const { Canvas, loadImage, FontLibrary } = koishiCtx.skia; const root = import_path.default.join(koishiCtx.baseDir, "data/mizuki-bot"); const imageRoot = import_path.default.join(root, "image"); const fontRoot = import_path.default.join(root, "font"); const jellyRoot = import_path.default.join(imageRoot, "jellyfish/default"); const themeRoot = import_path.default.join(imageRoot, "/theme/default"); const help = [ { id: "help1", name: "水母箱 -h", description: "查看水母箱指令介绍" }, !isCatch ? { id: "help2", name: "水母箱 抓水母", description: "抓几只水母进水母箱" } : null ].filter(Boolean); FontLibrary.use("unifont", import_path.default.join(fontRoot, "unifont-16.0.02.otf")); FontLibrary.use("fusion-pixel-12px", import_path.default.join(fontRoot, "fusion-pixel-12px-proportional-zh_hans.otf")); FontLibrary.use("noto-sans-sc-regular", import_path.default.join(fontRoot, "NotoSansSC-Regular.ttf")); FontLibrary.use("noto-sans-sc-medium", import_path.default.join(fontRoot, "NotoSansSC-Medium.ttf")); FontLibrary.use("noto-sans-sc-bold", import_path.default.join(fontRoot, "NotoSansSC-Bold.ttf")); const newJellyCanvas = await DrawNewJellyfishCardCanvas(koishiCtx, config, newJelly, jellyRoot); const eventsCanvas = await DrawGeneralCardCanvas(koishiCtx, config, "事件列表", events); const helpCanvas = await DrawGeneralCardCanvas(koishiCtx, config, "指令帮助", help); const height = 608 + (newJellyCanvas ? newJellyCanvas.height + 16 : 0) + (eventsCanvas ? eventsCanvas.height + 16 : 0) + (helpCanvas ? helpCanvas.height + 16 : 0) + 16; const canvas = new Canvas(768, height); const ctx = canvas.getContext("2d"); ctx.fillStyle = config.theme.backgroundColor; ctx.fillRect(0, 0, 768, height); const backgroundJelly = await loadImage(import_path.default.join(themeRoot, "background_jelly.png")); for (let y = 0; y < height; y += backgroundJelly.height) { for (let x = 0; x < 768; x += backgroundJelly.width) { ctx.drawImage(backgroundJelly, x, y, backgroundJelly.width, backgroundJelly.height); } } const trDeco = await loadImage(import_path.default.join(themeRoot, "tr_deco.png")); ctx.drawImage(trDeco, 768 - trDeco.width, 0); const defaultUserAvatar = import_path.default.join(themeRoot, "default_avatar.png"); const avatarImage = await loadImage(session.event.user.avatar || defaultUserAvatar); const avatarSize = 96; const avatarCanvas = new Canvas(avatarSize, avatarSize); const avatarCtx = avatarCanvas.getContext("2d"); const radius = avatarCanvas.width / 2; avatarCtx.beginPath(); avatarCtx.arc(radius, radius, radius, 0, Math.PI * 2); avatarCtx.closePath(); avatarCtx.clip(); avatarCtx.drawImage(avatarImage, 0, 0, avatarSize, avatarSize); ctx.drawCanvas(avatarCanvas, 80, 64); const user = await koishiCtx.database.get("mzk_user", jellyfishBox.user_id); const username = user[0].nickname || session.event.user.name; ctx.font = "48px noto-sans-sc-bold"; ctx.fillStyle = config.theme.name; ctx.textAlign = "left"; const nameMetrics = ctx.measureText(username); ctx.fillText(username, 80 + avatarSize + 24, 64 + nameMetrics.actualBoundingBoxAscent); const pacmanX = 80 + avatarSize + 24; const pacmanY = 64 + nameMetrics.actualBoundingBoxAscent + 8; const jellyCount = jellyfishBox.jellyfish.reduce((sum, jelly) => sum + jelly.number, 0); const pacmanCount = Math.floor(jellyCount / 20); const pacmanCanvas = await drawPacman(koishiCtx, pacmanCount); ctx.drawImage(pacmanCanvas, pacmanX, pacmanY); ctx.fillStyle = "#7986cb"; ctx.font = "24px noto-sans-sc-medium"; ctx.textAlign = "right"; const date = "〇 " + (/* @__PURE__ */ new Date()).toLocaleDateString(); const dateMetrics = ctx.measureText(date); ctx.fillText(date, 688, 150 + dateMetrics.actualBoundingBoxAscent); const boxCanvas = new Canvas(672, 416); const { width: backW, height: backH } = boxCanvas; const boxCtx = boxCanvas.getContext("2d"); boxCtx.fillStyle = config.theme.boxBackground; drawRoundRect(boxCtx, 4, 4, backW - 8, backH - 8, 8); const centerX = backW / 2; const centerY = backH / 2; ctx.fillStyle = config.theme.boxOutline; drawRoundRect(ctx, 48, 192, 672, 416, 12); const meta = await koishiCtx.database.get("mzk_jellyfish_meta", {}); const jellys = jellyfishBox.jellyfish; for (let i = 0; i < jellys.length; i++) { const jelly = jellys[i]; const { id, number } = jelly; const jellyImagePath = import_path.default.join(jellyRoot, `${id}.png`); try { const jellyCanvas = await ProcessJellyfishImage(koishiCtx, jellyImagePath); const jellyMeta = meta.find((meta2) => meta2.id === id); const drawSize = jellyMeta.draw.size; for (let j = 0; j < number; j++) { const w = jellyCanvas.width; const h = jellyCanvas.height; const ratio = 32 / Math.max(w, h) || drawSize; const drawW = w * ratio; const drawH = h * ratio; const x = centerX + import_lodash3.default.random(-centerX + drawW, centerX - drawW); const y = centerY + import_lodash3.default.random(-centerY + drawH, centerY - drawH); const direction = import_lodash3.default.random(-180, 180) * (Math.PI / 180); boxCtx.save(); boxCtx.translate(x, y); boxCtx.rotate(direction); boxCtx.drawCanvas(jellyCanvas, -drawW / 2, -drawH / 2, drawW, drawH); boxCtx.restore(); } } catch (error) { logger.error("打开水母图片失败", error); continue; } } ctx.drawCanvas(boxCanvas, 48, 192); let currentHeight = 608 + 16; if (newJellyCanvas) { ctx.drawCanvas(newJellyCanvas, 48, currentHeight); currentHeight += newJellyCanvas.height + 16; } if (eventsCanvas) { ctx.drawCanvas(eventsCanvas, 48, currentHeight); currentHeight += eventsCanvas.height + 16; } if (helpCanvas) { ctx.drawCanvas(helpCanvas, 48, currentHeight); currentHeight += helpCanvas.height + 16; } await canvas.saveAs(import_path.default.join(root, "/temp/output.png")); return await canvas.toBuffer("png"); }, "DrawDefaultThemeBox"); var DrawCardCanvas = /* @__PURE__ */ __name(async (koishiCtx, config, width, height, title, content) => { const { Canvas } = koishiCtx.skia; const canvas = new Canvas(width, height); const ctx = canvas.getContext("2d"); ctx.fillStyle = config.theme.cardBackground; drawRoundRect(ctx, 0, 0, width, height, 16); ctx.fillStyle = config.theme.title; ctx.font = "30px noto-sans-sc-medium"; ctx.textAlign = "left"; ctx.fillText(title, 24, 36 + 2); ctx.drawCanvas(content, 0, 38); return canvas; }, "DrawCardCanvas"); var DrawJellyfishCardContent = /* @__PURE__ */ __name(async (koishiCtx, config, newJelly, jellyRoot, withBackground = false, showNumber = true) => { const { Canvas } = koishiCtx.skia; if (!newJelly || !jellyRoot) { return null; } const width = 768 - 48 * 2; const height = 162; const contentCanvas = new Canvas(width, height); const ctx = contentCanvas.getContext("2d"); if (withBackground) { ctx.fillStyle = config.theme.cardBackground; drawRoundRect(ctx, 0, 0, width, height, 16); } const newJellyImage = await ProcessJellyfishImage(koishiCtx, import_path.default.join(jellyRoot, `${newJelly.id}.png`)); const meta = await koishiCtx.database.get("mzk_jellyfish_meta", { id: newJelly.id }); const name3 = meta[0].name; const iconCanvas = new Canvas(128, 128); const iconCtx = iconCanvas.getContext("2d"); iconCtx.fillStyle = config.theme.jellyIconBorder; drawRoundRect(iconCtx, 0, 0, 128, 128, 8); iconCtx.fillStyle = config.theme.jellyIconBackground; drawRoundRect(iconCtx, 4, 4, 120, 120, 4); iconCtx.drawCanvas(newJellyImage, 0, 0, newJellyImage.width, newJellyImage.height, 12, 12, 104, 104); ctx.drawCanvas(iconCanvas, 24, 16); ctx.save(); ctx.beginPath(); ctx.roundRect(0, 0, width, height, 16); ctx.closePath(); ctx.clip(); ctx.globalAlpha = 0.3; ctx.translate(width - 100, height / 2); ctx.rotate(Math.PI / -4); const tx = -100, ty = -60; const tw = 220, th = 220; ctx.fillStyle = "red"; ctx.drawCanvas(newJellyImage, 0, 0, newJellyImage.width, newJellyImage.height, tx, ty, tw, th); ctx.restore(); ctx.fillStyle = config.theme.jellyName; ctx.font = "30px noto-sans-sc-medium"; ctx.textAlign = "left"; ctx.fillText(name3, 24 + 128 + 16, 46); ctx.fillStyle = config.theme.eventDescription; ctx.font = "22px noto-sans-sc-regular"; ctx.textAlign = "left"; const description = meta[0].description; const maxWidth = width - (24 + 128 + 16 + 24); const lineHeight = 26; const maxLines = 2; const lines = []; let currentLine = ""; const chars = description; for (let i = 0; i < chars.length; i++) { const potentialLine = currentLine + chars[i]; const metrics = ctx.measureText(potentialLine); if (metrics.width > maxWidth) { if (lines.length >= maxLines) { currentLine += "..."; lines.push(currentLine); break; } lines.push(currentLine); currentLine = chars[i]; } else { currentLine = potentialLine; if (i === chars.length - 1) { lines.push(currentLine); } } } lines.forEach((line, index) => { ctx.fillText(line, 24 + 128 + 16, 72 + index * lineHeight + 4); }); ctx.fillStyle = showNumber ? config.theme.jellyName : config.theme.eventDescription; ctx.font = "24px noto-sans-sc-medium"; ctx.textAlign = "left"; const number = showNumber ? `×${newJelly.number}` : "稀有度:"; ctx.fillText(number, 24 + 128 + 16, 72 + lines.length * lineHeight + 4); const group = meta[0].group; const groupColor = config.theme.groups[group]; ctx.fillStyle = groupColor; ctx.font = "24px noto-sans-sc-medium"; ctx.textAlign = "left"; const groupDx = 24 + 128 + 16 + ctx.measureText(number).width + 8; ctx.fillText(`${group.toUpperCase()}`, groupDx, 72 + lines.length * lineHeight + 4); return contentCanvas; }, "DrawJellyfishCardContent"); var DrawNewJellyfishCardCanvas = /* @__PURE__ */ __name(async (koishiCtx, config, newJelly, jellyRoot) => { if (!newJelly || !jellyRoot) { return null; } const contentCanvas = await DrawJellyfishCardContent(koishiCtx, config, newJelly, jellyRoot); return await DrawCardCanvas(koishiCtx, config, 672, 200, "新增", contentCanvas); }, "DrawNewJellyfishCardCanvas"); var DrawGeneralCardCanvas = /* @__PURE__ */ __name(async (koishiCtx, config, title, events) => { const { Canvas } = koishiCtx.skia; if (!events || events.length === 0) { return null; } const width = 768 - 48 * 2; const height = 38 + events.length * (26 + 36) + 16; const canvas = new Canvas(width, height); const ctx = canvas.getContext("2d"); ctx.fillStyle = config.theme.cardBackground; drawRoundRect(ctx, 0, 0, width, height, 16); ctx.fillStyle = config.theme.title; ctx.font = "30px noto-sans-sc-medium"; ctx.textAlign = "left"; ctx.fillText(title, 24, 38); let currentHeight = 38 + 30 + 8; for (let i = 0; i < events.length; i++) { const event = events[i]; ctx.fillStyle = config.theme.eventTitle; ctx.font = "30px noto-sans-sc-medium"; ctx.textAlign = "left"; ctx.fillText(event.name, 24, currentHeight); currentHeight += 30 - 4; ctx.fillStyle = config.theme.eventDescription; ctx.font = "22px noto-sans-sc-regular"; ctx.textAlign = "left"; ctx.fillText(event.description, 24, currentHeight); currentHeight += 24 + 12; } return canvas; }, "DrawGeneralCardCanvas"); var DrawDefaultThemeStatistics = /* @__PURE__ */ __name(async (koishiCtx, config, session, jellyfishBox) => { const { Canvas, loadImage, FontLibrary } = koishiCtx.skia; const meta = await koishiCtx.database.get("mzk_jellyfish_meta", {}, ["id", "group"]); const flag = jellyfishBox ? true : false; const jellies = flag ? import_lodash3.default.clone(jellyfishBox.jellyfish) : meta.map((meta2) => ({ id: meta2.id, number: 0 })); const selectMeta = /* @__PURE__ */ __name((id) => meta.find((meta2) => meta2.id === id), "selectMeta"); const groupPriority = { perfect: 5, great: 4, good: 3, normal: 2, special: 1 }; jellies.sort((a, b) => { const aMeta = selectMeta(a.id); const bMeta = selectMeta(b.id); return (groupPriority[bMeta.group] || 0) - (groupPriority[aMeta.group] || 0); }); const jellySpeciesCount = import_lodash3.default.size(jellies); const singleCol = jellySpeciesCount <= 10; const width = 708 * import_lodash3.default.ceil(jellySpeciesCount / 10) + (singleCol ? 12 : 0); const height = 84 + 24 + 24 + (162 + 8) * import_lodash3.default.min([10, jellySpeciesCount]); const root = import_path.default.join(koishiCtx.baseDir, "data/mizuki-bot"); const imageRoot = import_path.default.join(root, "image"); const fontRoot = import_path.default.join(root, "font"); const jellyRoot = import_path.default.join(imageRoot, "jellyfish/default"); const themeRoot = import_path.default.join(imageRoot, "/theme/default"); FontLibrary.use("noto-sans-sc-regular", import_path.default.join(fontRoot, "NotoSansSC-Regular.ttf")); FontLibrary.use("noto-sans-sc-medium", import_path.default.join(fontRoot, "NotoSansSC-Medium.ttf")); FontLibrary.use("noto-sans-sc-bold", import_path.default.join(fontRoot, "NotoSansSC-Bold.ttf")); const canvas = new Canvas(width, height); const ctx = canvas.getContext("2d"); ctx.fillStyle = config.theme.backgroundColor; ctx.fillRect(0, 0, width, height); const backgroundImage = await loadImage(import_path.default.join(themeRoot, "background_jelly.png")); for (let y = 0; y < height; y += backgroundImage.height) { for (let x = 0; x < width; x += backgroundImage.width) { ctx.drawImage(backgroundImage, x, y, backgroundImage.width, backgroundImage.height); } } const date = "〇 " + (/* @__PURE__ */ new Date()).toLocaleDateString(); ctx.fillStyle = config.theme.date; ctx.font = "24px noto-sans-sc-medium"; ctx.textAlign = "left"; ctx.fillText(date, 48, 54); let username = ""; if (flag) { const user = await koishiCtx.database.get("mzk_user", jellyfishBox.user_id); username = user[0].nickname || session.event.user.name; } ctx.fillStyle = config.theme.title; ctx.font = "32px noto-sans-sc-bold"; ctx.textAlign = "left"; const title = flag ? "水母统计表@" + username : "水母图鉴"; ctx.fillText(title, 48, 54 + 32); for (let i = 0; i < jellies.length; i++) { const row = i % 10; const col = import_lodash3.default.floor(i / 10); const jelly = jellies[i]; const jellyCanvas = await DrawJellyfishCardContent(koishiCtx, config, jelly, jellyRoot, true, flag); const dx = 24 + col * (672 + 24); const dy = 84 + 24 + row * (162 + 8); ctx.drawCanvas(jellyCanvas, dx, dy); } return canvas.toBuffer("png"); }, "DrawDefaultThemeStatistics"); // src/user/user.ts var import_lodash4 = __toESM(require("lodash")); var GetUser = /* @__PURE__ */ __name(async (ctx, id, platform) => { const user = await ctx.database.get("mzk_user", { platform, user_id: id }); if (import_lodash4.default.size(user) === 0) { return await ctx.database.create("mzk_user", { platform, user_id: id }); } return user[0]; }, "GetUser"); // src/commands/jellyfish_box.tsx var import_jsx_runtime2 = require("@satorijs/element/jsx-runtime"); var logger2 = new import_koishi2.Logger("mizuki-bot-jellyfish"); var PromptNickname = /* @__PURE__ */ __name(async (ctx, session) => { if (session.platform === "qq" && !session.event.user.name) { const user = await GetUser(ctx, session.event.user.id, session.platform); if (!user.nickname) { session.send(` 检测到这是你第一次认领水母箱,请先@我输入昵称,让机器人知道如何称呼你 例如:@${session.bot.user.name} 海月离 设置完成后你可以通过“/叫我 xx”来更新`); let name3 = await session.prompt(); if (!name3) return { success: false }; if (name3.startsWith("/叫我 ")) { name3 = name3.slice(4); } await ctx.database.set("mzk_user", user.id, { nickname: name3 }); return { success: true, name: name3 }; } } return { success: true, name: session.event.user.name }; }, "PromptNickname"); async function CommandJellyfishBox(config, ctx, session) { const uid = session.event.user.id; const { success } = await PromptNickname(ctx, session); if (!success) return "输入超时或取消,已退出"; const jellyfish_box = await GetJellyfishBox(ctx, uid, session.platform); const events = await CalculateBoxEvents(ctx, jellyfish_box); const buffer = await DrawDefaultThemeBox(ctx, config, session, jellyfish_box, null, events); return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ImageBuffer, { buffer }) }); } __name(CommandJellyfishBox, "CommandJellyfishBox"); async function CommandJellyfishBoxCatch(config, ctx, session) { const { success } = await PromptNickname(ctx, session); if (!success) return "输入超时或取消,已退出"; const uid = session.event.user.id; const platform = session.platform; let jellyfish_box = await GetJellyfishBox(ctx, uid, platform); const last_catch_time = jellyfish_box.last_catch_time; if (uid !== config.test_account && last_catch_time.getTime() + 2 * 60 * 60 * 1e3 > Date.now()) { const remain = (last_catch_time.getTime() + 2 * 60 * 60 * 1e3 - Date.now()) / 1e3; const hours = Math.floor(remain / 3600); const minutes = Math.floor(remain % 3600 / 60); const seconds = Math.floor(remain % 60); return `别抓啦,过${hours ? hours + "小时" : ""}${minutes ? minutes + "分" : ""}${seconds}秒再来吧!`; } const jellyfish_num = GetJellyfishInBoxCount(jellyfish_box); if (jellyfish_num >= 256) { return "别抓啦,水母箱里的水母太多了!"; } const events = await CalculateBoxEvents(ctx, jellyfish_box); jellyfish_box = await GetJellyfishBox(ctx, uid, platform); let added = { id: "", number: 0 }; let catch_num = 0; if (jellyfish_box.jellyfish.length === 0) { catch_num = import_lodash5.default.random(4, 6); } else { if (jellyfish_num < 10) catch_num = import_lodash5.default.random(3, 4); else if (jellyfish_num < 20) catch_num = import_lodash5.default.random(2, 3); else if (jellyfish_num < 50) catch_num = import_lodash5.default.random(1, 2); else catch_num = 1; } const group = ["perfect", "great", "good", "normal", "special"]; let group_probability = [0.02, 0.08, 0.5, 0.4, 0]; if ((/* @__PURE__ */ new Date()).getMonth() === 3 && (/* @__PURE__ */ new Date()).getDate() === 22) { group_probability = [0.02, 0.08, 0.45, 0.25, 0.2]; } const selected_group = RandomChooseWithWeights(group_probability, group); const group_meta = await ctx.database.get("mzk_jellyfish_meta", { group: selected_group }); const selected_jellyfish = RandomChoose(group_meta); const jellyfish_index = jellyfish_box.jellyfish.findIndex((jelly) => jelly.id === selected_jellyfish.id); if (jellyfish_index === -1) { jellyfish_box.jellyfish.push({ id: selected_jellyfish.id, number: catch_num }); } else { jellyfish_box.jellyfish[jellyfish_index].number += catch_num; } added = { id: selected_jellyfish.id, number: catch_num }; jellyfish_box.last_catch_time = new Date(Date.now()); await ctx.database.set("mzk_jellyfish_box", jellyfish_box.user_id, { last_catch_time: jellyfish_box.last_catch_time, jellyfish: jellyfish_box.jellyfish }); logger2.info(`用户${uid}在${platform}抓到了${catch_num}只${selected_jellyfish.name}`); const buffer = await DrawDefaultThemeBox(ctx, config, session, jellyfish_box, added, events, true); return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ImageBuffer, { buffer }) }); } __name(CommandJellyfishBoxCatch, "CommandJellyfishBoxCatch"); var CommandJellyfishBoxStatistics = /* @__PURE__ */ __name(async (config, ctx, session) => { const uid = session.event.user.id; const platform = session.platform; const jellyfish_box = await GetJellyfishBox(ctx, uid, platform); const buffer = await DrawDefaultThemeStatistics(ctx, config, session, jellyfish_box); return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ImageBuffer, { buffer }); }, "CommandJellyfishBoxStatistics"); var CommandJellyfishBoxCatalogue = /* @__PURE__ */ __name(async (config, ctx, session) => { const buffer = await DrawDefaultThemeStatistics(ctx, config, session); return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ImageBuffer, { buffer }); }, "CommandJellyfishBoxCatalogue"); var CommandJellyfishBoxSetStyle = /* @__PURE__ */ __name(async (config, ctx, session, style) => { return "暂不支持更换样式"; const uid = session.event.user.id; const platform = session.platform; const jellyfish_box = await GetJellyfishBox(ctx, uid, platform); if (style === "normal" || style === "默认") { await ctx.database.set("mzk_jellyfish_box", jellyfish_box.user_id, { draw_style: "normal" }); return "已切换为默认样式"; } else if (style === "pixel" || style === "像素") { await ctx.database.set("mzk_jellyfish_box", jellyfish_box.user_id, { draw_style: "pixel" }); return "已切换为像素样式"; } else { return "找不到该样式,请检查名称"; } }, "CommandJellyfishBoxSetStyle"); var GetJellyfishBox = /* @__PURE__ */ __name(async (ctx, id, platform) => { let query = []; const user = await GetUser(ctx, id, platform); query = await ctx.database.get("mzk_jellyfish_box", { user_id: user.id }); if (query.length === 0) { query.push(await ctx.database.create("mzk_jellyfish_box", { user_id: user.id, last_catch_time: new Date(Date.now() - 2 * 60 * 60 * 1e3), last_refresh_time: new Date(Date.now() - 2 * 60 * 60 * 1e3), jellyfish: [], decoration: [], salinity: 25, temperature: 25, draw_style: "normal" })); } return query[0]; }, "GetJellyfishBox"); var GetJellyfishInBoxCount = /* @__PURE__ */ __name((jellyfish_box) => { return jellyfish_box.jellyfish.reduce((pre, cur) => pre + cur.number, 0); }, "GetJellyfishInBoxCount"); var CalculateBoxEvents = /* @__PURE__ */ __name(async (ctx, jellyfish_box) => { let refresh = false; let refresh_number = 0; const last_time = jellyfish_box.last_refresh_time; if (last_time.getTime() + 1 * 60 * 60 * 1e3 < Date.now()) { refresh = true; refresh_number = Math.floor(Date.now() - last_time.getTime() / (1 * 60 * 60 * 1e3)); if (refresh_number > 168) refresh_number = 24; else if (refresh_number > 72) refresh_number = 12; } if (jellyfish_box.user_id === ctx.config.test_account) { refresh = true; refresh_number = 10; } if (!refresh) return []; const events = []; const jellyfish_num = GetJellyfishInBoxCount(jellyfish_box); const ids = jellyfish_box.jellyfish.map((jellyfish) => jellyfish.id); const jellyfish_meta = await ctx.database.get("mzk_jellyfish_meta", { id: { $in: ids } }); for (const item of jellyfish_box.jellyfish) { let num_to_add = 0; const meta = jellyfish_meta.find((m) => m.id === item.id); if (meta.reproductive_rate === 0) return; const reproductive_rate = meta.reproductive_rate; let rate = reproductive_rate / 30 / 24 * item.number * refresh_number; if (jellyfish_num > 50) { rate = rate / jellyfish_num; } if (rate > 1) { num_to_add = Math.floor(rate); rate -= num_to_add; } if (rate > 0 && RandomChooseWithWeights([rate, 1 - rate], [true, false])) { num_to_add += 1; } if (num_to_add > 0) { item.number += num_to_add; events.push({ "id": "reproductive", "name": "繁殖", "description": `在水母箱中繁殖出了${num_to_add}只新的${meta.name}` }); } } ; const event_meta = await ctx.database.get("mzk_jellyfish_event_meta", {}); const event_probabilities = event_meta.map((item) => item.probability); let event_probabilities_sum = event_probabilities.reduce((pre, cur) => pre + cur, 0) * refresh_number; let event_number = 0; if (event_probabilities_sum > 1) { event_number += Math.floor(event_probabilities_sum); } event_probabilities_sum -= event_number; if (event_probabilities_sum > 0 && RandomChooseWithWeights([event_probabilities_sum, 1 - event_probabilities_sum], [true, false])) { event_number += 1; } if (event_number > 0) { for (let i = 0; i < event_number; i++) { const event = RandomChoose(event_meta); switch (event.type) { case "reduce": break; case "add": break; case "change": break; default: break; } events.push({ "id": event.id, "name": event.name, "description": event.description }); } } if (import_lodash5.default.size(events) !== 0) jellyfish_box.last_refresh_time = new Date(Date.now()); await ctx.database.set("mzk_jellyfish_box", jellyfish_box.user_id, { last_refresh_time: jellyfish_box.last_refresh_time, jellyfish: jellyfish_box.jellyfish }); return events; }, "CalculateBoxEvents"); var parseListParams = /* @__PURE__ */ __name((params) => { const result = []; let i = 0; const all_values = /* @__PURE__ */ new Set(["all", "全部", "所有"]); while (i < params.length) { const name3 = params[i]; let num = 1; if (i + 1 < params.length) { const next = params[i + 1]; if (!isNaN(Number(next))) { num = Number(next); i += 1; } else if (all_values.has(next.toLowerCase())) { num = "all"; i += 1; } } result.push({ name: name3, number: num }); i += 1; } return result; }, "parseListParams"); var validateAndGenerateDropList = /* @__PURE__ */ __name(async (ctx, drop_list, jellyfish_box) => { const group_values = /* @__PURE__ */ new Set(["normal", "good", "great", "perfect", "special"]); const meta = await ctx.database.get("mzk_jellyfish_meta", {}); const all_jellyfish_id_set = new Set(meta.map((jelly) => jelly.id)); const all_jellyfish_id_to_name = new Map(meta.map((jelly) => [jelly.id, jelly.name])); const errors = []; const result = []; for (const item of drop_list) { if (group_values.has(item.name)) { if (item.number !== "all") { errors.push(new Error(`要放生${item.name}时数量必须为all`)); continue; } const searched_meta_id = meta.filter((jelly) => jelly.group === item.name).map((jelly) => jelly.id); const meta_search = new Set(searched_meta_id); const jelly_search = jellyfish_box.jellyfish.filter((jelly) => meta_search.has(jelly.id)); if (import_lodash5.default.size(jelly_search) === 0) { errors.push(new Error(`水母箱里没有稀有度为${item.name}的水母`)); continue; } else { result.push(...jelly_search.map((jelly) => ({ id: jelly.id, name: all_jellyfish_id_to_name.get(jelly.id), num: jelly.number }))); } } else { let item_id = item.name; if (all_jellyfish_id_set.has(item.name)) { item_id = item.name; } else { const jellyfish_meta = meta.find((jelly) => jelly.name === item.name); if (!jellyfish_meta) { errors.push(new Error(`这片大地(hai)没有名为${item.name}的水母`)); continue; } item_id = jellyfish_meta.id; } const index = jellyfish_box.jellyfish.findIndex((jelly) => jelly.id === item_id); if (index === -1) { errors.push(new Error(`水母箱里没有${item.name}`)); continue; } if (item.number !== "all" && jellyfish_box.jellyfish[index].number < item.number) { errors.push(new Error(`水母箱里的${item.name}数量不够`)); continue; } result.push({ id: item_id, name: all_jellyfish_id_to_name.get(item_id), num: item.number }); } } return { errors, result }; }, "validateAndGenerateDropList"); async function CommandJellyfishBoxDrop(config, ctx, session, params) { const uid = session.event.user.id; const platform = session.platform; logger2.info(params); if (!params[0]) { return "请添加水母名称以及数量\n例:“水母箱 放生 普通水母 10”"; } const drop_list = parseListParams(params); logger2.info(JSON.stringify(drop_list)); const jellyfish_box = await GetJellyfishBox(ctx, uid, platform); const { errors: validate_errors, result: drop_result } = await validateAndGenerateDropList(ctx, drop_list, jellyfish_box); if (import_lodash5.default.size(validate_errors) > 0) { return `放生失败,请检查输入的信息: ${validate_errors.map((error) => error.message).join("\n")}`; } for (const item of drop_result) { const index = jellyfish_box.jellyfish.findIndex((jelly) => jelly.id === item.id); if (index === -1) { continue; } const num_has = jellyfish_box.jellyfish[index].number; jellyfish_box.jellyfish[index].number -= item.num === "all" ? num_has : item.num; } for (let i = jellyfish_box.jellyfish.length - 1; i >= 0; i--) { if (jellyfish_box.jellyfish[i].number === 0) { jellyfish_box.jellyfish.splice(i, 1); } } await ctx.database.set("mzk_jellyfish_box", jellyfish_box.user_id, { jellyfish: jellyfish_box.jellyfish }); const message = `成功放生${drop_result.map((item) => item.num === "all" ? `全部${item.name}` : `${item.name}×${item.num}`).join("、")}`; return message; } __name(CommandJellyfishBoxDrop, "CommandJellyfishBoxDrop"); // src/commands/testCommand.tsx var CommandTest = /* @__PURE__ */ __name(async (ctx, session) => { return "测试"; }, "CommandTest"); // src/index.ts var fs4 = __toESM(require("fs/promises")); var path5 = __toESM(require("path")); // src/commands/callme.tsx var CommandCallMe = /* @__PURE__ */ __name(async (ctx, session, newName) => { try { const uid = session.event.user.id; const platform = session.platform; const user = await GetUser(ctx, uid, platform); await ctx.database.set("mzk_user", user.id, { nickname: newName }); return `已将你的昵称更新为 ${newName}`; } catch (error) { return `更新昵称失败,请检查输入的信息。 错误信息:${error.message}`; } }, "CommandCallMe"); // src/skland/api.ts var import_axios = __toESM(require("axios")); var import_koishi4 = require("koishi"); var import_qrcode = __toESM(require("qrcode")); // src/skland/helper.ts var import_node_crypto2 = require("node:crypto"); var import_pako = __toESM(require("pako")); var import_date_fns = require("date-fns"); // src/skland/constant.ts var SKLAND_SM_CONFIG = { organization: "UWXspnCCJN4sfYlNfqps", appId: "default", publicKey: "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCmxMNr7n8ZeT0tE1R9j/mPixoinPkeM+k4VGIn/s0k7N5rJAfnZ0eMER+QhwFvshzo0LNmeUkpR8uIlU/GEVr8mN28sKmwd2gpygqj0ePnBmOW4v0ZVwbSYK+izkhVFk2V/doLoMbWy6b+UnA8mkjvg0iYWRByfRsK2gdl7llqCwIDAQAB", protocol: "https", apiHost: "fp-it.portal101.cn", apiPath: "/deviceprofile/v4" }; var DES_RULE = { appId: { cipher: "DES", is_encrypt: 1, key: "uy7mzc4h", obfuscated_name: "xx" }, box: { is_encrypt: 0, obfuscated_name: "jf" }, canvas: { cipher: "DES", is_encrypt: 1, key: "snrn887t", obfuscated_name: "yk" }, clientSize: { cipher: "DES", is_encrypt: 1, key: "cpmjjgsu", obfuscated_name: "zx" }, organization: { cipher: "DES", is_encrypt: 1, key: "78moqjfc", obfuscated_name: "dp" }, os: { cipher: "DES", is_encrypt: 1, key: "je6vk6t4", obfuscated_name: "pj" }, platform: { cipher: "DES", is_encrypt: 1, key: "pakxhcd2", obfuscated_name: "gm" }, plugins: { cipher: "DES", is_encrypt: 1, key: "v51m3pzl", obfuscated_name: "kq" }, pmf: { cipher: "DES", is_encrypt: 1, key: "2mdeslu3", obfuscated_name: "vw" }, protocol: { is_encrypt: 0, obfuscated_name: "protocol" }, referer: { cipher: "DES", is_encrypt: 1, key: "y7bmrjlc", obfuscated_name: "ab" }, res: { cipher: "DES", is_encrypt: 1, key: "whxqm2a7", obfuscated_name: "hf" }, rtype: { cipher: "DES", is_encrypt: 1, key: "x8o2h2bl", obfuscated_name: "lo" }, sdkver: { cipher: "DES", is_encrypt: 1, key: "9q3dcxp2", obfuscated_name: "sc" }, status: { cipher: "DES", is_encrypt: 1, key: "2jbrxxw4", obfuscated_name: "an" }, subVersion: { cipher: "DES", is_encrypt: 1, key: "eo3i2puh", obfuscated_name: "ns" }, svm: { cipher: "DES", is_encrypt: 1, key: "fzj3kaeh", obfuscated_name: "qr" }, time: { cipher: "DES", is_encrypt: 1, key: "q2t3odsk", obfuscated_name: "nb" }, timezone: { cipher: "DES", is_encrypt: 1, key: "1uv05lj5", obfuscated_name: "as" }, tn: { cipher: "DES", is_encrypt: 1, key: "x9nzj1bp", obfuscated_name: "py" }, trees: { cipher: "DES", is_encrypt: 1, key: "acfs0xo4", obfuscated_name: "pi" }, ua: { cipher: "DES", is_encrypt: 1, key: "k92crp1t", obfuscated_name: "bj" }, url: { cipher: "DES", is_encrypt: 1, key: "y95hjkoo", obfuscated_name: "cf" }, version: { is_encrypt: 0, obfuscated_name: "version" }, vpw: { cipher: "DES", is_encrypt: 1, key: "r9924ab5", obfuscated_name: "ca" } }; var BROWSER_ENV = { plugins: "MicrosoftEdgePDFPluginPortableDocumentFormatinternal-pdf-viewer1,MicrosoftEdgePDFViewermhjfbmdgcfjbbpaeojofohoefgiehjai1", ua: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 Edg/129.0.0.0", canvas: "259ffe69", // 基于浏览器的canvas获得的值,不知道复用行不行 timezone: -480, // 时区,应该是固定值吧 platform: "Win32", url: "https://www.skland.com/", // 固定值 referer: "", res: "1920_1080_24_1.25", // 屏幕宽度_高度_色深_window.devicePixelRatio clientSize: "0_0_1080_1920_1920_1080_1920_1080", status: "0011" // 不知道在干啥 }; // src/skland/crypto.ts var import_node_crypto = require("node:crypto"); var import_crypto_js = __toESM(require("crypto-js")); var import_node_forge = __toESM(require("node-forge")); var crypto = import_node_crypto.webcrypto; async function md5(string) { return import_crypto_js.default.MD5(string).toString(); } __name(md5, "md5"); async function hmacSha256(key, data) { return import_crypto_js.default.HmacSHA256(data, key).toString(); } __name(hmacSha256, "hmacSha256"); async function encryptAES(message, key) { const iv = new TextEncoder().encode("0102030405060708"); const data = new TextEncoder().encode(message); const cryptoKey = await crypto.subtle.importKey( "raw", new TextEncoder().encode(key), { name: "AES-CBC" }, false, ["encrypt"] ); const encrypted = await crypto.subtle.encrypt( { name: "AES-CBC", iv }, cryptoKey, data ); return Array.from(new Uint8Array(encrypted)).map((b) => b.toString(16).padStart(2, "0")).join(""); } __name(encryptAES, "encryptAES"); function padData(data) { const blockSize = 8; const padLength = blockSize - data.length % blockSize; return data + "\0".repeat(padLength); } __name(padData, "padData"); async function encryptDES(message, key) { const inputStr = padData(String(message)); const keyWordArray = import_crypto_js.default.enc.Utf8.parse(key); const dataWordArray = import_crypto_js.default.enc.Utf8.parse(inputStr); const encrypted = import_crypto_js.default.TripleDES.encrypt(dataWordArray, keyWordArray, { mode: import_crypto_js.default.mode.ECB, padding: import_crypto_js.default.pad.NoPadding }); return encrypted.toString(); } __name(encryptDES, "encryptDES"); async function encryptObjectByDESRules(object, rules) { const result = {}; for (const i in object) { if (i in rules) { const rule = rules[i]; if (rule.is_encrypt === 1) result[rule.obfuscated_name] = await encryptDES(object[i], rule.key); else result[rule.obfuscated_name] = object[i]; } else { result[i] = object[i]; } } return result; } __name(encryptObjectByDESRules, "encryptObjectByDESRules"); async function encryptRSA(message, publicKey) { const formatPublickey = publicKey.match(/.{1,64}/g)?.join("\n") || ""; const pk = `-----BEGIN PUBLIC KEY----- ${formatPublickey} -----END PUBLIC KEY-----`; const publicKeyForge = import_node_forge.default.pki.publicKeyFromPem(pk); const encrypted = publicKeyForge.encrypt(message, "RSAES-PKCS1-V1_5"); return import_node_forge.default.util.encode64(encrypted); } __name(encryptRSA, "encryptRSA"); // src/skland/helper.ts var import_koishi3 = require("koishi"); var crypto2 = import_node_crypto2.webcrypto; var stringify = /* @__PURE__ */ __name((obj) => JSON.stringify(obj).replace(/":"/g, '": "').replace(/","/g, '", "'), "stringify"); function gzipObject(o) { const jsonStr = stringify(o); const encoded = new TextEncoder().encode(jsonStr); const compressed = import_pako.default.gzip(encoded, { level: 2 }); compressed.set([19], 9); return btoa(String.fromCharCode(...compressed)); } __name(gzipObject, "gzipObject"); async function getSmId() { const now = /* @__PURE__ */ new Date(); const _time = (0, import_date_fns.format)(now, "yyyyMMddHHmmss"); const uid = crypto2.randomUUID(); const uidMd5 = md5(uid); const v = `${_time + uidMd5}00`; const smsk_web = (await md5(`smsk_web_${v}`)).substring(0, 14); return `${v + smsk_web}0`; } __name(getSmId, "getSmId"); function getTn(o) { const sortedKeys = Object.keys(o).sort(); const resultList = []; for (const key of sortedKeys) { let v = o[key]; if (typeof v === "number") v = String(v * 1e4); else if (typeof v === "object" && v !== null) v = getTn(v); resultList.push(v); } return resultList.join(""); } __name(getTn, "getTn"); var SM_CONFIG = SKLAND_SM_CONFIG; var devices_info_url = `${SKLAND_SM_CONFIG.protocol}://${SKLAND_SM_CONFIG.apiHost}${SKLAND_SM_CONFIG.apiPath}`; async function getDid() { const uid = crypto2.randomUUID(); const priId = (await md5(uid)).substring(0, 16); const ep = await encryptRSA(uid, SM_CONFIG.publicKey); const browser = { ...BROWSER_ENV, vpw: crypto2.randomUUID(), svm: Date.now(), trees: crypto2.randomUUID(), pmf: Date.now() }; const desTarget = { ...browser, protocol: 102, organization: SM_CONFIG.organization, appId: SM_CONFIG.appId, os: "web", version: "3.0.0", sdkver: "3.0.0", box: "", // 首次请求为空 rtype: "all", smid: await getSmId(), subVersion: "1.0.0", time: 0 }; desTarget.tn = await md5(getTn(desTarget)); const desResult = await encryptObjectByDESRules(desTarget, DES_RULE); const gzipResult = gzipObject(desResult); const aesResult = await encryptAES(gzipResult, priId); const body = { appId: "default", compress: 2, data: aesResult, encode: 5, ep, organization: SM_CONFIG.organization, os: "web" }; const response = await fetch(devices_info_url, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) }); const resp = await response.json(); if (resp.code !== 1100) { console.log(resp); throw new Error("did计算失败,请联系作者"); } return `B${resp.detail.deviceId}`; } __name(getDid, "getDid"); var Attendent = /* @__PURE__ */ __name(async (cred, token) => { const logger4 = new import_koishi3.Logger("mizuki-bot-skland"); const getPrivacyName = /* @__PURE__ */ __name((name3) => { return name3.split("").map((s, i) => i > 0 && i < name3.length - 1 ? "*" : s).join(""); }, "getPrivacyName"); try { const bindings = await GetBinding(cred, token); logger4.info(bindings); const characters = bindings.data.list.filter((i) => !["exa"].includes(i.appCode)).map((i) => i.bindingList).flat(); let successAttendance = 0; let allMsg = "【森空岛每日签到】\n"; for (const character of characters) { try { const data = await GameAttendance(cred, token, character.uid, character.channelMasterId); if (data) { if (data.code === 0 && data.message === "OK") { const msg = `${Number(character.channelMasterId) - 1 ? "B 服" : "官服"}角色 ${getPrivacyName(character.nickName)} 签到成功${`, 获得了${data.data.awards.map((a) => `「${a.resource.name}」${a.count}个`).join(",")}`}`; allMsg += `${msg} `; successAttendance++; } else { const msg = `${Number(character.channelMasterId) - 1 ? "B 服" : "官服"}角色 ${getPrivacyName(character.nickName)} 签到失败${`, 错误消息: ${data.message} \`\`\`json ${JSON.stringify(data, null, 2)} \`\`\``}`; allMsg += `${msg} `; } } else { const msg = `${Number(character.channelMasterId) - 1 ? "B 服" : "官服"}角色 ${getPrivacyName(character.nickName)} 今天已经签到过了`; allMsg += `${msg} `; } } catch (error) { if (error.response && error.response.status === 403) { allMsg += `${Number(character.channelMasterId) - 1 ? "B 服" : "官服"}角色 ${getPrivacyName(character.nickName)} 今天已经签到过了 `; } else { allMsg += `签到过程中出现未知错误: ${error.message} `; logger4.error(`签到过程中出现未知错误: ${error.message} ${error.stack}`); return; } } } ; if (successAttendance !== 0) { allMsg += `成功签到 ${successAttendance} 个角色`; } else { allMsg += "一个都没签到成功"; } return allMsg; } catch (error) { logger4.error(`每日签到 error:${error}`); return error.message; } }, "Attendent"); // src/skland/api.ts var import_ufo = require("ufo"); var import_async_mutex = require("async-mutex"); var logger3 = new import_koishi4.Logger("mizuki-bot-skland"); var appCode = "4ca99fa6b56cc2ba"; var WHITE_LIST = [ "/web/v1/user/auth/generate_cred_by_code", "/api/v1/auth/refresh", "/api/v1/user/check" ]; var mutex = new import_async_mutex.Mutex(); var axiosInstance = import_axios.default.create({ headers: { "Content-Type": "application/json", "Origin": "https://www.skland.com", "Referer": "https://www.skland.com/", "Cache-Control": "no-cache", "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:134.0) Gecko/20100101 Firefox/134.0" } }); axiosInstance.interceptors.request.use(async (config) => { const MILLISECOND_PER_SECOND = 1e3; const { url, headers, data, params } = config; const baseURL = url?.split("?")[0]?.split("/").slice(0, 3).join("/"); if (baseURL !== "https://zonai.skland.com") return config; const pathname = url?.replace(baseURL || "", "") || ""; if (WHITE_LIST.includes(pathname)) return config; const token = hea