koishi-plugin-onebot-tool
Version:
OneBot 工具集,带有点赞、打卡、拍一拍、表情回应和 AI 语音等功能,可独立开关和自由配置
1,513 lines (1,501 loc) • 51.2 kB
JavaScript
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
var __export = (target, all) => {
for (var name2 in all)
__defProp(target, name2, { get: all[name2], 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 __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
Config: () => Config4,
PokeMode: () => PokeMode,
SignMode: () => SignMode,
StickMode: () => StickMode,
ZanwoMode: () => ZanwoMode,
apply: () => apply,
inject: () => inject,
name: () => name,
usage: () => usage
});
module.exports = __toCommonJS(index_exports);
var import_koishi5 = require("koishi");
// src/utils.ts
var import_koishi = require("koishi");
var import_promises = require("fs/promises");
var import_fs = require("fs");
var import_path = require("path");
var utils = {
/**
* 解析目标用户ID (支持@元素、@数字格式或纯数字)
*/
parseTarget(target) {
if (!target) return null;
try {
const at = import_koishi.h.select(import_koishi.h.parse(target), "at")[0]?.attrs?.id;
if (at) return at;
} catch {
}
const m = target.match(/@?(\d{5,10})/);
return m ? m[1] : null;
},
/**
* 自动撤回消息
*/
async autoRecall(session, message, delay = 1e4) {
if (!message) return;
setTimeout(() => session.bot?.deleteMessage(session.channelId, message.toString()), delay);
},
/**
* 读取所有模块数据
*/
async getAllModuleData(baseDir, logger) {
const filePath = (0, import_path.resolve)(baseDir, "data", "onebot-tool.json");
if (!(0, import_fs.existsSync)(filePath)) return {};
try {
const data = JSON.parse(await (0, import_promises.readFile)(filePath, "utf8"));
return typeof data === "object" && data ? data : {};
} catch (e) {
logger.error("读取数据文件失败:", e);
return {};
}
},
/**
* 保存所有模块数据
*/
async saveAllModuleData(baseDir, data, logger) {
try {
await (0, import_promises.writeFile)((0, import_path.resolve)(baseDir, "data", "onebot-tool.json"), JSON.stringify(data, null, 2));
return true;
} catch (e) {
logger.error("保存数据文件失败:", e);
return false;
}
},
/**
* 加载指定模块的数据
*/
async loadModuleData(baseDir, moduleName, logger) {
return (await this.getAllModuleData(baseDir, logger))[moduleName] ?? [];
},
/**
* 保存指定模块的数据
*/
async saveModuleData(baseDir, moduleName, data, logger) {
const allData = await this.getAllModuleData(baseDir, logger);
allData[moduleName] = data;
return this.saveAllModuleData(baseDir, allData, logger);
},
/**
* 检查文件是否为图片
*/
isImageFile(filename) {
const ext = (0, import_path.extname)(filename).toLowerCase();
return [".jpg", ".jpeg", ".png", ".gif", ".webp"].includes(ext);
},
/**
* 获取本地目录中的图片文件列表
*/
async getLocalImages(dirPath, logger) {
try {
if (!(0, import_fs.existsSync)(dirPath) || !(0, import_fs.statSync)(dirPath).isDirectory()) return [];
const files = await (0, import_promises.readdir)(dirPath);
const imagePaths = files.filter((file) => this.isImageFile(file)).map((file) => (0, import_path.resolve)(dirPath, file));
return imagePaths;
} catch (e) {
logger.error(`读取图片目录失败: ${e.message}`);
return [];
}
},
/**
* 获取Pixiv图片链接数组(支持网络JSON或本地目录)
*/
async getPixivLinks(baseDir, path, logger) {
if (path.startsWith("http://") || path.startsWith("https://")) {
const filePath = (0, import_path.resolve)(baseDir, "data", "pixiv.json");
if (!(0, import_fs.existsSync)(filePath)) {
try {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 3e4);
const res = await fetch(path, { signal: controller.signal });
clearTimeout(timeout);
if (!res.ok) throw new Error(`下载失败: ${res.status}`);
await (0, import_promises.writeFile)(filePath, await res.text(), "utf8");
} catch (e) {
logger.error("下载JSON文件失败:", e);
return [];
}
}
try {
const arr = JSON.parse(await (0, import_promises.readFile)(filePath, "utf8"));
return Array.isArray(arr) ? arr : [];
} catch (e) {
logger.error("读取Pixiv链接失败:", e);
return [];
}
} else {
return this.getLocalImages(path, logger);
}
}
};
// src/zanwo.ts
var Zanwo = class {
static {
__name(this, "Zanwo");
}
targets = /* @__PURE__ */ new Set();
moduleName = "zanwo";
logger;
ctx;
cronJob;
timer;
config;
/**
* 构造函数
* @param ctx Koishi 上下文
* @param config 插件配置
* @param logger 日志记录器
*/
constructor(ctx, config, logger) {
this.ctx = ctx;
this.config = config;
this.logger = logger;
this.loadTargetsFromFile().catch((err) => this.logger.error("加载点赞列表失败:", err));
if (this.config.zanwoMode === "auto" /* Auto */) this.startAutoLikeTimer();
}
/**
* 从文件加载点赞目标列表
* @private
*/
async loadTargetsFromFile() {
this.targets = new Set(await utils.loadModuleData(this.ctx.baseDir, this.moduleName, this.logger));
}
/**
* 启动自动点赞定时器
* @private
*/
startAutoLikeTimer() {
this.cronJob?.dispose();
this.timer && clearInterval(this.timer);
this.cronJob = this.timer = null;
if (this.config.zanwoMode !== "auto" /* Auto */ || !this.targets.size) return;
if (typeof this.ctx.cron === "function") {
this.cronJob = this.ctx.cron("0 0 * * *", () => this.executeAutoLike());
this.logger.info("已设置每日自动点赞定时任务");
} else {
this.timer = setInterval(() => this.executeAutoLike(), 864e5);
this.logger.info("已设置每日自动点赞定时器");
}
}
/**
* 执行自动点赞
* @param session 可选,Koishi 会话对象
* @private
*/
async executeAutoLike(session) {
const targets = [...this.targets];
if (!targets.length) return;
try {
let successCount = 0;
for (const userId of targets) {
if (await this.sendLike(session, userId)) successCount++;
await new Promise((r) => setTimeout(r, 1e3));
}
this.logger.info(`自动点赞完成:成功 ${successCount}/${targets.length} 人`);
} catch (error) {
this.logger.error("自动点赞出错:", error);
}
}
/**
* 处理点赞目标列表的增删查清
* @param action 操作类型:'add'添加, 'remove'移除, 'get'获取, 'clear'清空
* @param userId 用户ID,用于add和remove操作
* @returns 操作结果。get返回目标数组,其他返回布尔值表示成功与否
*/
async handleTargets(action, userId) {
if (action === "get") return [...this.targets];
if (action === "clear") {
const isEmpty = !this.targets.size;
if (!isEmpty) {
this.targets.clear();
await utils.saveModuleData(this.ctx.baseDir, this.moduleName, [], this.logger);
}
return !isEmpty;
}
if (!userId || !/^\d+$/.test(userId)) return false;
const result = action === "add" ? !!this.targets.add(userId) : this.targets.delete(userId);
if (result) await utils.saveModuleData(this.ctx.baseDir, this.moduleName, [...this.targets], this.logger);
return result;
}
/**
* 发送点赞请求
* @param session Koishi 会话对象
* @param userId QQ用户ID
* @returns 是否点赞成功
*/
async sendLike(session, userId) {
let success = false;
for (let i = 0; i < 5; i++) {
try {
await session.bot.internal.sendLike(userId, 10);
success = true;
} catch {
break;
}
}
return success;
}
/**
* 注册点赞相关命令
* @param parentCmd 父命令对象
*/
registerCommands(parentCmd) {
const handleReply = /* @__PURE__ */ __name(async (session, message) => {
const msg = await session.send(message);
await utils.autoRecall(session, Array.isArray(msg) ? msg[0] : msg);
return "";
}, "handleReply");
const zanwo = parentCmd.subcommand("zanwo", "点赞功能").alias("赞我").usage("点赞自己 50 下").action(async ({ session }) => handleReply(session, await this.sendLike(session, session.userId) ? `点赞完成,记得回赞哦~` : "点赞失败,请尝试添加好友"));
zanwo.subcommand(".list", "查看列表", { authority: 3 }).usage("查看自动点赞用户列表").action(async () => {
const targets = await this.handleTargets("get");
return targets.length ? `当前点赞列表(共${targets.length}人):${targets.join(", ")}` : "点赞列表为空";
});
zanwo.subcommand(".add <target:text>", "添加用户", { authority: 2 }).usage("添加用户到点赞列表").action(async ({ session }, target) => {
const userId = utils.parseTarget(target);
return handleReply(session, userId && await this.handleTargets("add", userId) ? `已添加 ${userId} 到点赞列表` : "添加失败");
});
zanwo.subcommand(".remove <target:text>", "移除用户", { authority: 2 }).usage("从列表移除指定用户").action(async ({ session }, target) => {
const userId = utils.parseTarget(target);
return handleReply(session, userId && await this.handleTargets("remove", userId) ? `已从点赞列表移除 ${userId}` : "移除失败");
});
zanwo.subcommand(".user <target:text>", "点赞用户").usage("给指定用户点赞").action(async ({ session }, target) => {
const userId = utils.parseTarget(target);
return handleReply(session, userId && await this.sendLike(session, userId) ? `点赞完成,记得回赞哦~` : "点赞失败,请尝试添加好友");
});
zanwo.subcommand(".all", "全部点赞", { authority: 3 }).usage("点赞列表中所有用户").action(async ({ session }) => (this.executeAutoLike(session), "已开始点赞"));
zanwo.subcommand(".clear", "清空列表", { authority: 4 }).usage("清空点赞列表").action(async () => (this.handleTargets("clear"), "已清空点赞列表"));
}
/**
* 释放资源
*/
dispose() {
this.cronJob?.dispose();
this.cronJob = null;
if (this.timer) clearInterval(this.timer);
this.timer = null;
}
};
// src/poke.ts
var import_koishi2 = require("koishi");
var import_promises2 = require("fs/promises");
var import_fs2 = require("fs");
var import_path2 = require("path");
var Poke = class {
/**
* 构造函数
* @param ctx Koishi 上下文
* @param config 插件配置
* @param logger 日志记录器
*/
constructor(ctx, config, logger) {
this.ctx = ctx;
this.config = config;
this.logger = logger;
if (config?.responses?.length) {
this.totalWeight = config.responses.reduce((sum, resp) => sum + resp.weight, 0);
if (this.totalWeight > 100) {
const scale = 100 / this.totalWeight;
config.responses.forEach((resp) => resp.weight *= scale);
this.totalWeight = 100;
}
}
this.imagesPath = config.imagesPath;
}
static {
__name(this, "Poke");
}
cache = /* @__PURE__ */ new Map();
totalWeight = 0;
imagesPath;
logger;
/**
* 释放资源
*/
dispose() {
this.cache.clear();
}
/**
* 获取一言内容
* @param params 可选参数
* @returns 一言内容字符串
* @private
*/
async getHitokoto(params) {
try {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 3e3);
const url = `https://v1.hitokoto.cn/${params ? `?${params}` : ""}`;
const response = await fetch(url, { signal: controller.signal });
clearTimeout(timeout);
if (!response.ok) return "";
const data = await response.json();
if (!data?.hitokoto) return "";
if (!data.from) return data.hitokoto;
const showAuthor = data.from_who && data.from_who !== data.from;
const citation = `——${showAuthor ? ` ${data.from_who}` : ""}《${data.from}》`;
const getTextWidth = /* @__PURE__ */ __name((text) => [...text].reduce((w, c) => w + (/[\u4e00-\u9fa5\u3000-\u30ff\u3130-\u318f\uac00-\ud7af]/.test(c) ? 2 : 1), 0), "getTextWidth");
const contentWidth = getTextWidth(data.hitokoto), citationWidth = getTextWidth(citation), maxWidth = 36;
const spaces = Math.max(0, Math.min(contentWidth, maxWidth) - citationWidth);
return `${data.hitokoto}
${" ".repeat(spaces)}${citation}`;
} catch {
return "";
}
}
/**
* 替换响应内容中的占位符
* @param content 响应内容
* @param session Koishi 会话对象
* @returns 替换后的内容
* @private
*/
async replacePlaceholders(content, session) {
if (!content.includes("{")) return content;
const hitokotoMatches = [...content.matchAll(/{hitokoto(?::([^}]*))?}/g)];
const pixivMatches = [...content.matchAll(/{pixiv}/g)];
let hitokotoContents = hitokotoMatches.length ? await Promise.all(hitokotoMatches.map((m) => this.getHitokoto(m[1]).then((content2) => ({ pattern: m[0], content: content2 })))) : [];
let pixivContents = [];
if (pixivMatches.length) {
const arr = await utils.getPixivLinks(this.ctx.baseDir, this.imagesPath, this.logger);
pixivContents = await Promise.all(pixivMatches.map(async (m) => {
let content2 = "";
if (Array.isArray(arr) && arr.length) {
const imagePath = arr[Math.floor(Math.random() * arr.length)];
try {
if (!imagePath.startsWith("http")) {
if ((0, import_fs2.existsSync)(imagePath)) {
const buffer = await (0, import_promises2.readFile)(imagePath);
const ext = (0, import_path2.extname)(imagePath).toLowerCase().substring(1) || "jpg";
const mime = ext === "png" ? "image/png" : ext === "gif" ? "image/gif" : ext === "webp" ? "image/webp" : "image/jpeg";
content2 = `<image src="base64://${buffer.toString("base64")}" type="${mime}"/>`;
} else {
this.logger.warn(`图片文件不存在: ${imagePath}`);
}
} else {
const res = await fetch(imagePath, { headers: { "Referer": "https://www.pixiv.net/" } });
if (res.ok) {
const buffer = Buffer.from(await res.arrayBuffer());
const ext = imagePath.split(".").pop()?.toLowerCase() || "jpg";
const mime = ext === "png" ? "image/png" : ext === "gif" ? "image/gif" : "image/jpeg";
content2 = `<image src="base64://${buffer.toString("base64")}" type="${mime}"/>`;
}
}
} catch (e) {
this.logger.error("图片发送失败:", e);
}
}
return { pattern: m[0], content: content2 };
}));
}
let result = content.replace(/{at}/g, `<at id="${session.userId}"/>`).replace(/{username}/g, session.username).replace(/{image:([^}]+)}/g, '<image url="$1"/>');
hitokotoContents.forEach(({ pattern, content: content2 }) => result = result.replace(pattern, content2));
pixivContents.forEach(({ pattern, content: content2 }) => result = result.replace(pattern, content2));
return result;
}
/**
* 注册拍一拍命令
* @param parentCmd 父命令对象
*/
registerCommand(parentCmd) {
parentCmd.subcommand("poke [times:number] [target:string]", "拍一拍").usage("发送拍一拍,可指定次数和目标").example("poke - 拍自己一次").example("poke 3 @12345 - 拍用户@12345三次").action(async ({ session }, times, target) => {
try {
if (typeof times === "string" && !target) [target, times] = [times, 1];
times = Math.max(1, Math.floor(Number(times)));
if (isNaN(times)) times = 1;
if (times > this.config.maxTimes) {
const msgId = await session.send(`单次拍一拍请求不能超过${this.config.maxTimes}次哦~`);
utils.autoRecall(session, Array.isArray(msgId) ? msgId[0] : msgId);
return;
}
const parsedId = target ? utils.parseTarget(target) : null;
const targetId = !target || !parsedId ? session.userId : parsedId;
for (let i = 0; i < times; i++) {
await session.onebot._request("send_poke", {
user_id: targetId,
group_id: session.isDirect ? void 0 : session.guildId
});
if (times > 1 && i < times - 1) await new Promise((r) => setTimeout(r, this.config.actionInterval));
}
return "";
} catch {
return;
}
});
}
/**
* 处理拍一拍通知事件
* @param session Koishi 会话对象
* @returns 是否已响应
*/
async processNotice(session) {
if (session.subtype !== "poke" || session.targetId !== session.selfId) return false;
const lastTime = this.cache.get(session.userId);
if (lastTime && session.timestamp - lastTime < 1e3) return false;
this.cache.set(session.userId, session.timestamp);
if (!this.config?.responses?.length) return false;
const response = this.randomResponse();
if (!response) return false;
try {
if (response.type === "command") {
session._responseTriggered = true;
await session.execute(response.content);
delete session._responseTriggered;
} else {
for (const seg of response.content.split("{~}")) {
await session.sendQueued(import_koishi2.h.parse(await this.replacePlaceholders(seg, session), session));
}
}
return true;
} catch {
return false;
}
}
/**
* 随机选择一个拍一拍响应
* @returns 响应对象
* @private
*/
randomResponse() {
if (!this.config?.responses?.length) return null;
const responses = this.config.responses;
let sum = 0, random = Math.random() * this.totalWeight;
for (const response of responses) if ((sum += response.weight) > random) return response;
return responses[0];
}
};
// src/stick.ts
var import_koishi3 = require("koishi");
// src/emojimap.ts
var EMOJI_MAP = {
"惊讶": "0",
"撇嘴": "1",
"色": "2",
"发呆": "3",
"得意": "4",
"流泪": "5",
"害羞": "6",
"闭嘴": "7",
"睡": "8",
"大哭": "9",
"尴尬": "10",
"发怒": "11",
"调皮": "12",
"呲牙": "13",
"微笑": "14",
"难过": "15",
"酷": "16",
"抓狂": "18",
"吐": "19",
"偷笑": "20",
"可爱": "21",
"白眼": "22",
"傲慢": "23",
"饥饿": "24",
"困": "25",
"惊恐": "26",
"流汗": "27",
"憨笑": "28",
"悠闲": "29",
"奋斗": "30",
"咒骂": "31",
"疑问": "32",
"嘘": "33",
"晕": "34",
"折磨": "35",
"衰": "36",
"骷髅": "37",
"敲打": "38",
"再见": "39",
"发抖": "41",
"爱情": "42",
"跳跳": "43",
"猪头": "46",
"拥抱": "49",
"蛋糕": "53",
"55": "55",
"刀": "56",
"便便": "59",
"咖啡": "60",
"玫瑰": "63",
"凋谢": "64",
"爱心": "66",
"心碎": "67",
"太阳": "74",
"月亮": "75",
"赞": "76",
"踩": "77",
"握手": "78",
"胜利": "79",
"飞吻": "85",
"怄火": "86",
"西瓜": "89",
"冷汗": "96",
"擦汗": "97",
"抠鼻": "98",
"鼓掌": "99",
"糗大了": "100",
"坏笑": "101",
"左哼哼": "102",
"右哼哼": "103",
"哈欠": "104",
"鄙视": "105",
"委屈": "106",
"快哭了": "107",
"阴险": "108",
"左亲亲": "109",
"吓": "110",
"可怜": "111",
"菜刀": "112",
"篮球": "114",
"示爱": "116",
"抱拳": "118",
"勾引": "119",
"拳头": "120",
"差劲": "121",
"122": "122",
"NO": "123",
"OK": "124",
"转圈": "125",
"挥手": "129",
"鞭炮": "137",
"喝彩": "144",
"爆筋": "146",
"棒棒糖": "147",
"148": "148",
"手枪": "169",
"茶": "171",
"眨眼睛": "172",
"泪奔": "173",
"无奈": "174",
"卖萌": "175",
"小纠结": "176",
"喷血": "177",
"斜眼笑": "178",
"doge": "179",
"180": "180",
"戳一戳": "181",
"笑哭": "182",
"我最美": "183",
"羊驼": "185",
"幽灵": "187",
"194": "194",
"198": "198",
"200": "200",
"点赞": "201",
"202": "202",
"203": "203",
"204": "204",
"206": "206",
"210": "210",
"211": "211",
"托腮": "212",
"214": "214",
"215": "215",
"216": "216",
"217": "217",
"218": "218",
"219": "219",
"221": "221",
"222": "222",
"223": "223",
"224": "224",
"225": "225",
"226": "226",
"227": "227",
"229": "229",
"230": "230",
"231": "231",
"232": "232",
"233": "233",
"235": "235",
"237": "237",
"238": "238",
"239": "239",
"240": "240",
"241": "241",
"243": "243",
"244": "244",
"脑阔疼": "262",
"沧桑": "263",
"捂脸": "264",
"辣眼睛": "265",
"哦哟": "266",
"头秃": "267",
"问号脸": "268",
"暗中观察": "269",
"emm": "270",
"吃瓜": "271",
"呵呵哒": "272",
"我酸了": "273",
"汪汪": "277",
"279": "279",
"无眼笑": "281",
"敬礼": "282",
"狂笑": "283",
"面无表情": "284",
"摸鱼": "285",
"魔鬼笑": "286",
"哦": "287",
"288": "288",
"睁眼": "289",
"290": "290",
"292": "292",
"摸锦鲤": "293",
"期待": "294",
"拿到红包": "295",
"拜谢": "297",
"元宝": "298",
"牛啊": "299",
"胖三斤": "300",
"301": "301",
"左拜年": "302",
"右拜年": "303",
"右亲亲": "305",
"牛气冲天": "306",
"喵喵": "307",
"打call": "311",
"变形": "312",
"仔细分析": "314",
"菜汪": "317",
"崇拜": "318",
"比心": "319",
"庆祝": "320",
"322": "322",
"嫌弃": "323",
"吃糖": "324",
"惊吓": "325",
"生气": "326",
"举牌牌": "332",
"烟花": "333",
"虎虎生威": "334",
"335": "335",
"豹富": "336",
"花朵脸": "337",
"我想开了": "338",
"舔屏": "339",
"打招呼": "341",
"酸Q": "342",
"我方了": "343",
"大怨种": "344",
"红包多多": "345",
"你真棒棒": "346",
"大展宏兔": "347",
"348": "348",
"坚强": "349",
"贴贴": "350",
"敲敲": "351",
"咦": "352",
"拜托": "353",
"尊嘟假嘟": "354",
"耶": "355",
"666": "356",
"裂开": "357",
"358": "358",
"359": "359",
"360": "360",
"361": "361",
"362": "362",
"363": "363",
"364": "364",
"365": "365",
"366": "366",
"367": "367",
"368": "368",
"369": "369",
"370": "370",
"371": "371",
"372": "372",
"373": "373",
"374": "374",
"375": "375",
"376": "376",
"377": "377",
"378": "378",
"379": "379",
"380": "380",
"381": "381",
"382": "382",
"383": "383",
"384": "384",
"385": "385",
"386": "386",
"387": "387",
"388": "388",
"389": "389",
"390": "390",
"391": "391",
"龙年快乐": "392",
"新年中龙": "393",
"新年大龙": "394",
"略略略": "395",
"396": "396",
"397": "397",
"398": "398",
"399": "399",
"400": "400",
"401": "401",
"402": "402",
"403": "403",
"404": "404",
"405": "405",
"406": "406",
"407": "407",
"408": "408",
"409": "409",
"410": "410",
"411": "411",
"412": "412",
"413": "413",
"划龙舟": "415",
"划龙舟2": "416",
"划龙舟3": "417",
"火车": "419",
"火车2": "420",
"火车3": "421",
"龙舟": "422",
"复兴号": "423",
"424": "424",
"425": "425",
"426": "426",
"427": "427",
"428": "428",
"灵蛇献瑞": "432",
"嘿嘿": "😊",
"羞涩": "😌",
"亲亲": "😚",
"汗": "😓",
"紧张": "😰",
"吐舌": "😝",
"呲牙2": "😁",
"淘气": "😜",
"花痴": "😍",
"失落": "😔",
"高兴": "😄",
"哼哼": "😏",
"不屑": "😒",
"瞪眼": "😳",
"大哭2": "😭",
"害怕": "😱",
"激动": "😂",
"肌肉": "💪",
"厉害": "👍",
"合十": "🙏",
"好的": "👌",
"向上": "👆",
"眼睛": "👀",
"拉面": "🍜",
"刨冰": "🍧",
"面包": "🍞",
"啤酒": "🍺",
"干杯": "🍻",
"苹果": "🍎",
"草莓": "🍓",
"吸烟": "🚬",
"庆祝2": "🎉",
"礼物": "💝",
"炸弹": "💣",
"闪光": "✨",
"吹气": "💨",
"水": "💦",
"火": "🔥",
"睡觉": "💤",
"打针": "💉",
"邮箱": "📫",
"骑马": "🐎",
"女孩": "👧",
"男孩": "👦",
"猴": "🐵",
"猪": "🐷",
"牛": "🐮",
"公鸡": "🐔",
"青蛙": "🐸",
"虫": "🐛",
"狗": "🐶",
"鲸鱼": "🐳",
"靴子": "👢",
"晴天": "☀",
"问号": "❔",
"手枪2": "🔫",
"爱心2": "💓",
"便利店": "🏪",
"默认表情": "default"
};
var COMMON_EMOJIS = [
"😊",
"😌",
"😚",
"😓",
"😰",
"😝",
"😁",
"😜",
"😍",
"😔",
"😄",
"😏",
"😒",
"😳",
"😭",
"😱",
"😂",
"💪",
"👍",
"🙏",
"👌",
"👆",
"👀",
"🍜",
"🍧",
"🍞",
"🍺",
"🍻",
"🍎",
"🍓",
"🚬",
"🎉",
"💝",
"💣",
"✨",
"💨",
"💦",
"🔥",
"💤",
"💉",
"📫",
"🐎",
"👧",
"👦",
"🐵",
"🐷",
"🐮",
"🐔",
"🐸",
"🐛",
"🐶",
"🐳",
"👢",
"☀",
"❔",
"🔫",
"💓",
"🏪"
];
// src/stick.ts
var Stick = class {
static {
__name(this, "Stick");
}
logger;
numericEmojiIds;
keywordMap = /* @__PURE__ */ new Map();
mode;
/**
* 构造函数
* @param ctx Koishi 上下文
* @param config 插件配置
* @param logger 日志记录器
*/
constructor(ctx, config, logger) {
this.logger = logger || ctx.logger("stick");
this.numericEmojiIds = Object.values(EMOJI_MAP).filter((id) => /^\d+$/.test(id));
this.mode = config?.stickMode || "off" /* Off */;
config?.keywordEmojis?.forEach((item) => {
const emojiId = this.resolveEmojiId(item.emojiId);
emojiId ? this.keywordMap.set(item.keyword, emojiId) : this.logger.warn(`无效的表情ID或名称: ${item.emojiId}`);
});
}
/**
* 解析表情ID - 将名称或ID转换为有效的表情ID
* @param input 表情名称或ID
* @returns 有效的表情ID或null
* @private
*/
resolveEmojiId(input) {
if (EMOJI_MAP[input]) return EMOJI_MAP[input];
if (/^\d+$/.test(input) || input === "default" || COMMON_EMOJIS.some((e) => input.startsWith(e))) return input;
return null;
}
/**
* 处理消息中的表情回应
* @param session Koishi 会话对象
* @returns 是否已作出表情回应
*/
async processMessage(session) {
if (session.userId === session.selfId) return false;
try {
let responded = false;
for (const [keyword, emojiId] of this.keywordMap)
if (session.content.includes(keyword)) {
await this.addReaction(session, session.messageId, emojiId);
responded = true;
}
if (this.mode === "keyword" /* KeywordOnly */) return responded;
for (const element of import_koishi3.h.select(import_koishi3.h.parse(session.content), "face"))
if (element.attrs?.id) {
await this.addReaction(session, session.messageId, element.attrs.id);
responded = true;
}
return responded;
} catch (error) {
this.logger.warn("表情处理失败:", error);
return false;
}
}
/**
* 格式化表情列表
* @param emojiList 表情列表
* @param page 页码
* @param keyword 搜索关键词
* @returns 格式化后的表情列表字符串
* @private
*/
formatEmojiList(emojiList, page = 1, keyword = "") {
emojiList.sort((a, b) => {
const numA = parseInt(a[1]), numB = parseInt(b[1]);
if (!isNaN(numA) && !isNaN(numB)) return numA - numB;
if (!isNaN(numA)) return -1;
if (!isNaN(numB)) return 1;
return a[1].localeCompare(b[1]);
});
const total = emojiList.length;
if (!total) return keyword ? `没有找到表情"${keyword}"` : "没有可用的表情";
const itemsPerRow = 4, rowsPerPage = 9, pageSize = itemsPerRow * rowsPerPage;
const totalPages = Math.ceil(total / pageSize) || 1;
const validPage = Math.min(Math.max(1, page), totalPages);
const startIdx = (validPage - 1) * pageSize;
const current = emojiList.slice(startIdx, startIdx + pageSize);
const rows = [];
for (let i = 0; i < current.length; i += itemsPerRow)
rows.push(current.slice(i, i + itemsPerRow).map(([n, id]) => `${n}-${id}`).join("|"));
const header = keyword ? `表情"${keyword}"(共${total}个)` : `表情列表(第${validPage}/${totalPages}页)`;
return header + "\n" + rows.join("\n");
}
/**
* 注册表情回应命令
* @param parentCmd 父命令对象
*/
registerCommand(parentCmd) {
const handleError = /* @__PURE__ */ __name((e, msg) => (this.logger.warn(msg, e), msg.replace(":", "")), "handleError");
const stick = parentCmd.subcommand("stick [faceId:string]", "表情回应").usage("对消息进行表情回应,默认点赞").example("stick 76,77 - 使用表情ID 76和77回应").example('stick 赞,踩 - 使用"赞"和"踩"表情回应').action(async ({ session }, faceId) => {
try {
const targetId = session.quote?.messageId || session.messageId;
if (!faceId) return this.addReaction(session, targetId, "76");
const ids = faceId.split(",").map((s) => this.resolveEmojiId(s.trim())).filter(Boolean);
if (!ids.length) return this.addReaction(session, targetId, "76");
for (const id of ids.slice(0, 20)) {
await this.addReaction(session, targetId, id);
await new Promise((r) => setTimeout(r, 500));
}
} catch (e) {
return handleError(e, "表情回应失败:");
}
});
stick.subcommand(".random [count:number]", "随机表情").usage("使用随机表情回应消息").action(async ({ session }, count = 1) => {
try {
const targetId = session.quote?.messageId || session.messageId;
return this.sendRandomFaces(session, Math.min(count, 20), targetId);
} catch (e) {
return handleError(e, "随机表情发送失败:");
}
});
stick.subcommand(".search [keyword:string]", "搜索表情").usage("搜索指定关键词的表情").action(({}, keyword) => {
try {
if (!keyword) return "请输入要搜索的关键词";
return this.formatEmojiList(Object.entries(EMOJI_MAP).filter(([n]) => n.includes(keyword)), 1, keyword);
} catch (e) {
return handleError(e, "表情搜索失败:");
}
});
stick.subcommand(".list [page:number]", "表情列表").usage("分页查看表情列表").action(({}, page = 1) => {
try {
return this.formatEmojiList(Object.entries(EMOJI_MAP), page);
} catch (e) {
return handleError(e, "表情列表获取失败:");
}
});
}
/**
* 添加表情回应
* @param session Koishi 会话对象
* @param messageId 消息ID
* @param emojiId 表情ID
* @private
*/
async addReaction(session, messageId, emojiId) {
await session.onebot._request("set_msg_emoji_like", { message_id: messageId, emoji_id: emojiId });
await new Promise((r) => setTimeout(r, 100));
}
/**
* 发送多个随机表情
* @param session Koishi 会话对象
* @param count 数量
* @param messageId 消息ID
* @private
*/
async sendRandomFaces(session, count, messageId) {
if (!this.numericEmojiIds.length) return;
const shuffled = [...this.numericEmojiIds];
for (let i = shuffled.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
}
for (const id of shuffled.slice(0, Math.min(count, 20, shuffled.length))) {
await this.addReaction(session, messageId, id);
await new Promise((r) => setTimeout(r, 500));
}
}
};
// src/sign.ts
var Sign = class {
static {
__name(this, "Sign");
}
/** 打卡目标群ID集合 */
targets = /* @__PURE__ */ new Set();
/** 模块名称,用于数据存储 */
moduleName = "sign";
/** 日志记录器 */
logger;
/** Koishi上下文 */
ctx;
/** 定时任务对象 */
cronJob = null;
/** 定时器 */
timer = null;
/** 插件配置 */
config;
/**
* 创建群打卡管理实例
* @param ctx Koishi上下文
* @param config 插件配置
* @param logger 日志记录器
*/
constructor(ctx, config, logger) {
this.ctx = ctx;
this.config = config;
this.logger = logger;
this.loadTargetsFromFile().catch((err) => this.logger.error("加载群打卡列表失败:", err));
if (this.config.signMode === "auto" /* Auto */) this.startAutoSignTimer();
}
/**
* 从文件加载打卡目标列表
* @private
*/
async loadTargetsFromFile() {
this.targets = new Set(await utils.loadModuleData(this.ctx.baseDir, this.moduleName, this.logger));
}
/**
* 启动自动打卡定时器
* @private
*/
startAutoSignTimer() {
this.cronJob?.dispose();
this.timer && clearInterval(this.timer);
this.cronJob = this.timer = null;
if (this.config.signMode !== "auto" /* Auto */) return;
if (typeof this.ctx.cron === "function") {
this.cronJob = this.ctx.cron("0 0 * * *", () => this.executeAutoSign());
this.logger.info("已设置每日自动群打卡定时任务");
} else {
this.timer = setInterval(() => this.executeAutoSign(), 864e5);
this.logger.info("已设置每日自动群打卡定时器");
}
}
/**
* 获取所有群列表
* @param session Koishi 会话对象
* @returns 群ID数组
* @private
*/
async getAllGroups(session) {
try {
return (await session.bot.internal.getGroupList()).map((g) => String(g.group_id));
} catch (e) {
this.logger.error("获取群列表失败:", e);
return [];
}
}
/**
* 执行自动群打卡
* @param session 可选,Koishi 会话对象
* @private
*/
async executeAutoSign(session) {
try {
let targets = [];
if (this.config.signMode === "auto" /* Auto */) {
if (!session?.bot) return;
targets = await this.getAllGroups(session);
} else {
targets = [...this.targets];
}
if (!targets.length) return;
let successCount = 0;
for (const groupId of targets)
if (await this.sendGroupSign(session, groupId)) successCount++;
else this.logger.warn(`群 ${groupId} 打卡失败`);
this.logger.info(`自动群打卡完成:成功 ${successCount}/${targets.length} 个群`);
} catch (e) {
this.logger.error("自动群打卡出错:", e);
}
}
/**
* 处理打卡目标列表的增删查清
* @param action 操作类型:'add'添加, 'remove'移除, 'get'获取, 'clear'清空
* @param groupId 群ID,用于add和remove操作
* @returns 操作结果
*/
async handleTargets(action, groupId) {
if (action === "get") return [...this.targets];
if (action === "clear") {
const changed2 = !!this.targets.size;
this.targets.clear();
if (changed2) await utils.saveModuleData(this.ctx.baseDir, this.moduleName, [], this.logger);
return changed2;
}
if (!groupId || !/^\d+$/.test(groupId)) return false;
const changed = action === "add" ? this.targets.add(groupId) : this.targets.delete(groupId);
if (changed) await utils.saveModuleData(this.ctx.baseDir, this.moduleName, [...this.targets], this.logger);
return changed;
}
/**
* 发送群打卡请求
* @param session Koishi 会话对象
* @param groupId 群ID
* @returns 是否打卡成功
*/
async sendGroupSign(session, groupId) {
try {
await session.bot.internal.sendGroupSign(groupId);
return true;
} catch {
return false;
}
}
/**
* 注册群打卡相关命令
* @param parentCmd 父命令对象
*/
registerCommands(parentCmd) {
const handleReply = /* @__PURE__ */ __name(async (session, message) => {
const msg = await session.send(message);
await utils.autoRecall(session, Array.isArray(msg) ? msg[0] : msg);
return "";
}, "handleReply");
const sign = parentCmd.subcommand("gsign", "群打卡").usage("在当前群进行打卡").action(async ({ session }) => {
if (!session.guildId) return handleReply(session, "请在群内使用该命令");
const success = await this.sendGroupSign(session, session.guildId);
return handleReply(session, success ? `群 ${session.guildId} 打卡成功~` : "群打卡失败");
});
sign.subcommand(".list", "查看列表", { authority: 3 }).usage("查看打卡群列表").action(async () => {
const targets = await this.handleTargets("get");
return targets.length ? `手动模式 - 当前群打卡列表(共${targets.length}个群)` : "手动模式 - 群打卡列表为空";
});
sign.subcommand(".group <target:text>", "指定打卡").usage("打卡指定群").action(async ({ session }, target) => {
const groupId = target.trim();
if (!groupId || !/^\d+$/.test(groupId)) return handleReply(session, "请输入有效的群号");
const success = await this.sendGroupSign(session, groupId);
return handleReply(session, success ? `群 ${groupId} 打卡成功~` : "群打卡失败");
});
sign.subcommand(".all", "全部打卡", { authority: 3 }).usage("打卡所有列表中的群").action(async ({ session }) => {
await handleReply(session, `已开始群打卡,请稍候...`);
await this.executeAutoSign(session);
return "群打卡完成";
});
sign.subcommand(".add <target:text>", "添加群", { authority: 2 }).usage("添加群到打卡列表").action(async ({ session }, target) => {
const groupId = target.trim();
if (!groupId || !/^\d+$/.test(groupId)) return handleReply(session, "请输入有效的群号");
const success = await this.handleTargets("add", groupId);
return handleReply(session, success ? `已添加群 ${groupId} 到打卡列表` : "添加失败");
});
sign.subcommand(".remove <target:text>", "移除群", { authority: 2 }).usage("从打卡列表移除群").action(async ({ session }, target) => {
const groupId = target.trim();
if (!groupId || !/^\d+$/.test(groupId)) return handleReply(session, "请输入有效的群号");
const success = await this.handleTargets("remove", groupId);
return handleReply(session, success ? `已从打卡列表移除群 ${groupId}` : "移除失败");
});
sign.subcommand(".clear", "清空列表", { authority: 4 }).usage("清空打卡列表").action(async () => {
await this.handleTargets("clear");
return "已清空群打卡列表";
});
}
/**
* 释放资源,清理定时任务和计时器
*/
dispose() {
this.cronJob?.dispose();
this.cronJob = null;
this.timer && clearInterval(this.timer);
this.timer = null;
}
};
// src/voice.ts
var import_koishi4 = require("koishi");
var Voice = class {
static {
__name(this, "Voice");
}
ctx;
logger;
/**
* 构造函数
* @param ctx Koishi 上下文
* @param logger 日志记录器
*/
constructor(ctx, logger) {
this.ctx = ctx;
this.logger = logger;
}
/**
* 注册AI语音相关命令
* @param parentCmd 父命令对象
*/
registerCommands(parentCmd) {
const fetchAllCharacters = /* @__PURE__ */ __name(async (session) => {
const typeMap = {};
for (const type of [1, 2]) {
try {
const res = await session.onebot._request("get_ai_characters", {
group_id: session.guildId,
chat_type: type
});
res?.data?.forEach((group) => {
if (!group.characters?.length) return;
typeMap[group.type] ??= [];
group.characters.forEach((c) => {
if (!typeMap[group.type].some((x) => x.character_id === c.character_id)) {
typeMap[group.type].push(c);
}
});
});
} catch (e) {
this.logger.warn("获取AI语音角色失败:", e);
}
}
return typeMap;
}, "fetchAllCharacters");
const checkParams = /* @__PURE__ */ __name(async (session, ...params) => {
if (params.some((p) => !p)) {
const m = await session.send("请输入正确的参数");
await utils.autoRecall(session, Array.isArray(m) ? m[0] : m);
return false;
}
return true;
}, "checkParams");
const voice = parentCmd.subcommand("aisay <character:string> <text:text>", "AI语音").channelFields(["guildId"]).usage("使用指定角色发送AI语音").action(async ({ session }, character, text) => {
if (!await checkParams(session, character, text)) return "";
try {
await session.onebot._request("send_group_ai_record", {
character: character.startsWith("lucy-voice-") ? character : "lucy-voice-" + character,
group_id: Number(session.guildId),
text
});
} catch (e) {
this.logger.warn("发送AI语音失败:", e);
}
return "";
});
voice.subcommand(".list", "角色列表").channelFields(["guildId"]).usage("显示所有AI语音角色").action(async ({ session }) => {
try {
const typeMap = await fetchAllCharacters(session);
return Object.entries(typeMap).map(
([type, characters]) => `${type}:
${characters.map((c) => `${c.character_name}[${c.character_id.replace(/^lucy-voice-/, "")}]`).join("、")}`
).join("\n").trim();
} catch (e) {
this.logger.warn("获取语音角色列表失败:", e);
return "";
}
});
voice.subcommand(".text <character:string> <text:text>", "转换语音").channelFields(["guildId"]).usage("将文字转换为语音消息").action(async ({ session }, character, text) => {
if (!await checkParams(session, character, text)) return "";
try {
const res = await session.onebot._request("get_ai_record", {
character: character.startsWith("lucy-voice-") ? character : "lucy-voice-" + character,
group_id: Number(session.guildId),
text
});
return (0, import_koishi4.h)("audio", { src: res.data });
} catch (e) {
this.logger.warn("文字转AI语音失败:", e);
return "语音生成失败";
}
});
voice.subcommand(".view <key:string>", "角色预览").channelFields(["guildId"]).usage("发送指定角色的预览音频").action(async ({ session }, key) => {
if (!key) {
const m = await session.send("请输入角色ID或名称");
await utils.autoRecall(session, Array.isArray(m) ? m[0] : m);
return "";
}
try {
const typeMap = await fetchAllCharacters(session);
let found;
for (const characters of Object.values(typeMap)) {
found = characters.find(
(c) => c.character_id === key || c.character_id.replace(/^lucy-voice-/, "") === key || c.character_name === key
);
if (found) break;
}
if (!found) {
const m = await session.send("未找到该角色");
await utils.autoRecall(session, Array.isArray(m) ? m[0] : m);
return "";
}
await session.send((0, import_koishi4.h)("audio", { src: found.preview_url }));
} catch (e) {
this.logger.warn("语音角色预览失败:", e);
}
return "";
});
}
};
// src/index.ts
var name = "onebot-tool";
var inject = { optional: ["cron"] };
var usage = `
<div style="border-radius: 10px; border: 1px solid #ddd; padding: 16px; margin-bottom: 20px; box-shadow: 0 2px 5px rgba(0,0,0,0.1);">
<h2 style="margin-top: 0; color: #4a6ee0;">📌 插件说明</h2>
<p>📖 <strong>使用文档</strong>:请点击左上角的 <strong>插件主页</strong> 查看插件使用文档</p>
<p>🔍 <strong>更多插件</strong>:可访问 <a href="https://github.com/YisRime" style="color:#4a6ee0;text-decoration:none;">苡淞的 GitHub</a> 查看本人的所有插件</p>
</div>
<div style="border-radius: 10px; border: 1px solid #ddd; padding: 16px; margin-bottom: 20px; box-shadow: 0 2px 5px rgba(0,0,0,0.1);">
<h2 style="margin-top: 0; color: #e0574a;">❤️ 支持与反馈</h2>
<p>🌟 喜欢这个插件?请在 <a href="https://github.com/YisRime" style="color:#e0574a;text-decoration:none;">GitHub</a> 上给我一个 Star!</p>
<p>🐛 遇到问题?请通过 <strong>Issues</strong> 提交反馈,或加入 QQ 群 <a href="https://qm.qq.com/q/PdLMx9Jowq" style="color:#e0574a;text-decoration:none;"><strong>855571375</strong></a> 进行交流</p>
</div>
`;
var StickMode = /* @__PURE__ */ ((StickMode2) => {
StickMode2["Off"] = "off";
StickMode2["KeywordOnly"] = "keyword";
StickMode2["EmojiOnly"] = "emoji";
StickMode2["All"] = "all";
StickMode2["Manual"] = "manual";
return StickMode2;
})(StickMode || {});
var SignMode = /* @__PURE__ */ ((SignMode2) => {
SignMode2["Off"] = "off";
SignMode2["Manual"] = "manual";
SignMode2["Auto"] = "auto";
return SignMode2;
})(SignMode || {});
var ZanwoMode = /* @__PURE__ */ ((ZanwoMode2) => {
ZanwoMode2["Off"] = "off";
ZanwoMode2["Manual"] = "manual";
ZanwoMode2["Auto"] = "auto";
return ZanwoMode2;
})(ZanwoMode || {});
var PokeMode = /* @__PURE__ */ ((PokeMode2) => {
PokeMode2["Off"] = "off";
PokeMode2["Manual"] = "manual";
PokeMode2["Auto"] = "auto";
return PokeMode2;
})(PokeMode || {});
var Config4 = import_koishi5.Schema.intersect([
import_koishi5.Schema.object({
enableVoice: import_koishi5.Schema.boolean().description("启用 AI 语音").default(true),
zanwoMode: import_koishi5.Schema.union([
import_koishi5.Schema.const("off" /* Off */).description("关闭"),
import_koishi5.Schema.const("manual" /* Manual */).description("手动"),
import_koishi5.Schema.const("auto" /* Auto */).description("自动")
]).description("点赞模式").default("manual" /* Manual */),
signMode: import_koishi5.Schema.union([
import_koishi5.Schema.const("off" /* Off */).description("关闭"),
import_koishi5.Schema.const("manual" /* Manual */).description("手动"),
import_koishi5.Schema.const("auto" /* Auto */).description("自动")
]).description("群打卡模式").default("manual" /* Manual */),
pokeMode: import_koishi5.Schema.union([
import_koishi5.Schema.const("off" /* Off */).description("关闭"),
import_koishi5.Schema.const("manual" /* Manual */).description("手动"),
import_koishi5.Schema.const("auto" /* Auto */).description("自动")
]).description("拍一拍模式").default("manual" /* Manual */),
stickMode: import_koishi5.Schema.union([
import_koishi5.Schema.const("off" /* Off */).description("关闭"),
import_koishi5.Schema.const("manual" /* Manual */).description("手动"),
import_koishi5.Schema.const("all" /* All */).description("二者"),
import_koishi5.Schema.const("keyword" /* KeywordOnly */).description("仅关键词"),
import_koishi5.Schema.const("emoji" /* EmojiOnly */).description("仅同表情")
]).description("表情回应模式").default("manual" /* Manual */)
}).description("功能配置"),
import_koishi5.Schema.object({
maxTimes: import_koishi5.Schema.number().description("拍一拍单次限制").default(3).min(1).max(200),
actionInterval: import_koishi5.Schema.number().description("拍一拍单次间隔(毫秒)").default(500).min(100),
imagesPath: import_koishi5.Schema.string().description('占位符"{pixiv}"数据地址').default("https://raw.githubusercontent.com/YisRime/koishi-plugin-onebot-tool/main/resource/pixiv.json"),
responses: import_koishi5.Schema.array(import_koishi5.Schema.object({
type: import_koishi5.Schema.union([
import_koishi5.Schema.const("command").description("执行命令"),
import_koishi5.Schema.const("message").description("发送消息")
]).description("响应类型"),
content: import_koishi5.Schema.string().description("响应内容"),
weight: import_koishi5.Schema.number().description("触发权重").default(50).min(0).max(100)
})).default([
{ type: "message", content: "{at}你干嘛~!", weight: 0 },
{ type: "message", content: "{hitokoto}", weight: 0 },
{ type: "message", content: "稍等哦~插画一会就来~{~}{pixiv}", weight: 100 },
{ type: "command", content: "poke", weight: 0 }
]).description("拍一拍响应列表").role("table"),
keywordEmojis: import_koishi5.Schema.array(import_koishi5.Schema.object({
keyword: import_koishi5.Schema.string().description("触发关键词"),
emojiId: import_koishi5.Schema.string().description("表情名称/ID")
})).default([{ keyword: "点赞", emojiId: "76" }]).description("表情回应关键词列表").role("table")
}).description("响应配置")
]);
function apply(ctx, config) {
const logger = ctx.logger("onebot-tool");
const zanwo = new Zanwo(ctx, config, logger);
const poke = new Poke(ctx, config, logger);
const stick = new Stick(ctx, config, logger);
const sign = new Sign(ctx, config, logger);
const voice = new Voice(ctx, logger);
const qtool = ctx.command("qtool", "QQ 工具").usage("点赞、打卡、拍一拍、表情回应和AI语音");
config.enableVoice !== false && voice.registerCommands(qtool);
if (config.zanwoMode !== "off" /* Off */) zanwo.registerCommands(qtool);
if (config.pokeMode !== "off" /* Off */) poke.registerCommand(qtool);
if (config.stickMode !== "off" /* Off */) stick.registerCommand(qtool);
if (config.signMode !== "off" /* Off */) sign.registerCommands(qtool);
if (config.pokeMode === "auto" /* Auto */) ctx.on("notice", poke.processNotice.bind(poke));
if (config.stickMode !== "off" /* Off */ && config.stickMode !== "manual" /* Manual */) {
ctx.middleware(async (session, next) => {
await stick.processMessage(session);
return next();
});
}
ctx.on("dispose", () => {
zanwo.dispose();
poke.dispose();
sign.dispose();
});
}
__name(apply, "apply");
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Config,
PokeMode,
SignMode,
StickMode,
ZanwoMode,
apply,
inject,
name,
usage
});