From 528b76303e11455d334393514881bfd5c751ee56 Mon Sep 17 00:00:00 2001 From: hanshino Date: Sun, 10 Nov 2024 14:44:50 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E6=A9=9F=E5=99=A8?= =?UTF-8?q?=E4=BA=BA=E4=BA=92=E5=8B=95=E5=8A=9F=E8=83=BD=EF=BC=8C=E5=8C=85?= =?UTF-8?q?=E5=90=AB=E8=AA=B0=E7=9A=84=E5=95=8F=E9=A1=8C=E7=9A=84=E5=9B=9E?= =?UTF-8?q?=E6=87=89=E5=8F=8A=E6=9C=80=E6=96=B0=E7=BE=A4=E7=B5=84=E7=94=A8?= =?UTF-8?q?=E6=88=B6=E7=B4=80=E9=8C=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/locales/zh_tw.json | 17 ++++++++ app/src/app.js | 91 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) diff --git a/app/locales/zh_tw.json b/app/locales/zh_tw.json index 1718f61..7c37fb0 100644 --- a/app/locales/zh_tw.json +++ b/app/locales/zh_tw.json @@ -64,6 +64,23 @@ "lottery_ticket_auto_buy": "快選" }, "message": { + "whos_problem": [ + "{user} 在搞吧...", + "{user} 這個人在搞什麼...", + "{user} 這個人在搞什麼鬼...", + "{user} 的鍋!!!", + "{user} 出來背鍋", + "{user} 好了啦", + "{user} 超級可悲,就是你", + "{user} you", + "都 {user} 的錯", + "{user} 你是不是有點太過分了" + ], + "whos_problem_only_one": [ + "好了啦,就你在搞", + "就你在講話而已", + "老哥,就你在這而已" + ], "error_contact_admin": "如發現此訊息,請向管理員報告此問題\n使用者ID: {{ user_id }}\n錯誤類型: {{ error_key }}", "user_own_god_stone": "你擁有的女神石: {{ god_stone }}", "user_own_character_count": "你擁有的角色數量: {{ character_count }}", diff --git a/app/src/app.js b/app/src/app.js index 3c73cff..cd1ba0b 100644 --- a/app/src/app.js +++ b/app/src/app.js @@ -39,6 +39,7 @@ const NumberController = require("./controller/application/NumberController"); const JobController = require("./controller/application/JobController"); const { transfer } = require("./middleware/dcWebhook"); const redis = require("./util/redis"); +const i18n = require("./util/i18n"); const traffic = require("./util/traffic"); const { showManagePlace } = require("./templates/application/Admin"); const { pushMessage } = require("./util/LineNotify"); @@ -46,9 +47,36 @@ const AdminModel = require("./model/application/Admin"); const axios = require("axios"); const pConfig = require("config"); const FetchGameData = require("../bin/FetchGameData"); +const { get, sample } = require("lodash"); axios.defaults.timeout = 5000; +const askBot = (keyword, action) => + route(context => { + if (context.event.isText === false) return false; + const mentionees = get(context, "event.message.mention.mentionees", []); + const isAskingBot = mentionees.some(mentionee => mentionee.isSelf === true); + if (!isAskingBot) return false; + + if (keyword === undefined) { + throw new Error("Missing keyword"); + } + + if (typeof keyword === "string") { + return context.event.text.includes(keyword); + } + + if (Array.isArray(keyword)) { + return keyword.some(k => context.event.text.includes(k)); + } + + if (keyword instanceof RegExp) { + return keyword.test(context.event.text); + } + + return false; + }, action); + function showState(context) { context.replyText(JSON.stringify(context.state)); } @@ -339,6 +367,67 @@ async function CustomerOrderBased(context, { next }) { if (detectResult === false) return next; } +function interactWithBot(context) { + return router([ + askBot("你好", context => context.replyText("你好啊!")), + askBot(["誰的問題", "誰在搞"], whosProblem), + ]); +} + +const recordLatestGroupUser = async (context, { next }) => { + if (context.event.source.type !== "group") return; + const { userId, groupId } = context.event.source; + const key = `latestGroupUser:${groupId}`; + await redis.zAdd(key, [ + { + score: Date.now(), + value: userId, + }, + ]); + // 保留 timestamp 在 30 分鐘內的資料 + await redis.zRemRangeByScore(key, 0, Date.now() - 30 * 60 * 1000); + return next; +}; + +/** + * 誰的問題 + * @param {import("bottender").LineContext} context + */ +async function whosProblem(context) { + if (context.event.source.type !== "group") return; + const { groupId } = context.event.source; + const key = `latestGroupUser:${groupId}`; + const users = await redis.zRange(key, 0, -1); + const { quoteToken } = context.event.message; + + if (users.length === 1) { + return context.replyText(sample(i18n.__("message.whos_problem_only_one")), { quoteToken }); + } + + const target = sample(users); + const replyMessage = [ + { + type: "textV2", + text: sample(i18n.__("message.whos_problem")), + sender: { + name: "裁決者", + }, + substitution: { + user: { + type: "mention", + mentionee: { + type: "user", + userId: target, + }, + }, + }, + quoteToken, + }, + ]; + + context.reply(replyMessage); +} + function Nothing(context) { switch (context.platform) { case "line": @@ -359,6 +448,7 @@ async function App(context) { return chain([ setProfile, // 設置各式用戶資料 statistics, // 數據蒐集 + recordLatestGroupUser, // 紀錄最近群組用戶 lineEvent, // 事件處理 config, // 設置群組設定檔 transfer, // Discord Webhook轉發 @@ -368,6 +458,7 @@ async function App(context) { GlobalOrderBase, // 全群指令分析 OrderBased, // 指令分析 CustomerOrderBased, // 自訂指令分析 + interactWithBot, // 標記機器人回應 Nothing, // 無符合事件 ]); }