feat: add multi-reaction user listing and improve emoji handling in interaction responses
This commit is contained in:
parent
63de53b655
commit
903b33885a
74
src/index.ts
74
src/index.ts
@ -1,5 +1,5 @@
|
||||
import { Hono } from "hono";
|
||||
import nacl from "tweetnacl";
|
||||
import * as nacl from "tweetnacl";
|
||||
|
||||
/** ====== Env ====== */
|
||||
const BOT_TOKEN = process.env.BOT_TOKEN!;
|
||||
@ -24,8 +24,8 @@ console.log("[BOOT] Discord Audit Bot starting…");
|
||||
/** ====== Constants ====== */
|
||||
const API = "https://discord.com/api/v10";
|
||||
const DECIDER_USER_ID = "311380871901085707";
|
||||
const EMOJI_RENAME = "✏️";
|
||||
const EMOJI_ROLE = "😭";
|
||||
const RENAME_EMOJIS = ["✏️", "✏"]; // VS16 + no-VS16
|
||||
const ROLE_EMOJIS = ["😭"];
|
||||
|
||||
/** ====== Helpers ====== */
|
||||
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
|
||||
@ -164,6 +164,21 @@ async function listReactionUsers(
|
||||
return Array.isArray(users) ? users : [];
|
||||
}
|
||||
|
||||
async function listReactionUsersMulti(
|
||||
channelId: string,
|
||||
messageId: string,
|
||||
emojis: string[]
|
||||
) {
|
||||
const results = await Promise.all(
|
||||
emojis.map((e) => listReactionUsers(channelId, messageId, e))
|
||||
);
|
||||
const byId = new Map<string, any>();
|
||||
for (const arr of results) {
|
||||
for (const u of arr) byId.set(u.id, u); // de-dupe across variants
|
||||
}
|
||||
return Array.from(byId.values());
|
||||
}
|
||||
|
||||
async function fetchNewMessagesAfter(
|
||||
channelId: string,
|
||||
afterMessageId: string
|
||||
@ -198,12 +213,7 @@ async function removeRole(guildId: string, userId: string, roleId: string) {
|
||||
|
||||
/** ====== OpenRouter /talk ====== */
|
||||
const randomSystem = () => {
|
||||
const pool = [
|
||||
"You are a terse analyst. Answer with precision.",
|
||||
"You are a sarcastic librarian. Be clear, mildly dry.",
|
||||
"You are a pragmatic engineer. Prefer bullet points and tradeoffs.",
|
||||
"You are a security reviewer. Be skeptical and concrete.",
|
||||
];
|
||||
const pool = ["คุณเป็นคนพูดจาเกรียนๆ"];
|
||||
return pool[Math.floor(Math.random() * pool.length)];
|
||||
};
|
||||
|
||||
@ -220,7 +230,7 @@ async function callOpenRouterChat(userPrompt: string) {
|
||||
{ role: "system", content: randomSystem() },
|
||||
{
|
||||
role: "user",
|
||||
content: userPrompt || "Say something useful in 3–5 bullet points.",
|
||||
content: userPrompt || "ผมชื่อว่าเนก ตอบคำถามผมเสมอ. ผมเป็นคนไม่ดี",
|
||||
},
|
||||
],
|
||||
stream: false,
|
||||
@ -332,7 +342,7 @@ app.post("/interactions", async (c) => {
|
||||
const kind = hit.kind === "deafen" ? "ปิดหู" : "ปิดไมค์";
|
||||
|
||||
// Decision message
|
||||
const intro = `มีคนโดนทำร้าย😭😭 ${kind}\nคนทำ!: <@${executorId}> → คนโดน: <@${targetId}>\nเลือกการลงโทษโดยการกดส่งอีโมจิ:\n${EMOJI_RENAME} = เปลี่ยนชื่อเล่น, ${EMOJI_ROLE} = ลบ Role`;
|
||||
const intro = `มีคนโดนทำร้าย😭😭 ${kind}\nคนทำ!: <@${executorId}> → คนโดน: <@${targetId}>\nเลือกการลงโทษโดยการกดส่งอีโมจิ:\n${RENAME_EMOJIS[0]} = เปลี่ยนชื่อเล่น, ${ROLE_EMOJIS[0]} = ลบ Role`;
|
||||
const sent = await sendMessage(channelId, intro);
|
||||
if (!sent.ok) {
|
||||
await editOriginal(token, "Cannot post decision message.");
|
||||
@ -341,32 +351,50 @@ app.post("/interactions", async (c) => {
|
||||
const msgId = sent.data.id as string;
|
||||
|
||||
// Seed reactions so users can tap
|
||||
await addReaction(channelId, msgId, EMOJI_RENAME);
|
||||
await addReaction(channelId, msgId, EMOJI_ROLE);
|
||||
for (const e of RENAME_EMOJIS) await addReaction(channelId, msgId, e);
|
||||
for (const e of ROLE_EMOJIS) await addReaction(channelId, msgId, e);
|
||||
|
||||
// Identify the bot user ID (same as application_id for bot apps)
|
||||
const botUserId = String(interaction.application_id);
|
||||
|
||||
// Poll reactions up to timeout
|
||||
const deadline = Date.now() + REACTION_TIMEOUT_SEC * 1000;
|
||||
let chosen: "rename" | "role" | null = null;
|
||||
|
||||
while (Date.now() < deadline && !chosen) {
|
||||
const [renameUsers, roleUsers] = await Promise.all([
|
||||
listReactionUsers(channelId, msgId, EMOJI_RENAME),
|
||||
listReactionUsers(channelId, msgId, EMOJI_ROLE),
|
||||
const [renameUsersAll, roleUsersAll] = await Promise.all([
|
||||
listReactionUsersMulti(channelId, msgId, RENAME_EMOJIS),
|
||||
listReactionUsersMulti(channelId, msgId, ROLE_EMOJIS),
|
||||
]);
|
||||
// Priority: decider user
|
||||
const deciderRename = renameUsers.find(
|
||||
|
||||
// Exclude the bot itself from counts
|
||||
const renameUsers = renameUsersAll.filter(
|
||||
(u: any) => u?.id !== botUserId
|
||||
);
|
||||
const roleUsers = roleUsersAll.filter(
|
||||
(u: any) => u?.id !== botUserId
|
||||
);
|
||||
|
||||
// Priority: specific decider
|
||||
const deciderRename = renameUsers.some(
|
||||
(u: any) => u?.id === DECIDER_USER_ID
|
||||
);
|
||||
const deciderRole = roleUsers.find(
|
||||
const deciderRole = roleUsers.some(
|
||||
(u: any) => u?.id === DECIDER_USER_ID
|
||||
);
|
||||
|
||||
console.log(
|
||||
`[VOTE] rename=${renameUsers.length} role=${roleUsers.length} deciderRename=${deciderRename} deciderRole=${deciderRole}`
|
||||
);
|
||||
|
||||
if (deciderRename) chosen = "rename";
|
||||
else if (deciderRole) chosen = "role";
|
||||
else {
|
||||
// Otherwise first to 2 votes
|
||||
if ((renameUsers?.length || 0) >= 2) chosen = "rename";
|
||||
else if ((roleUsers?.length || 0) >= 2) chosen = "role";
|
||||
// Otherwise: first path to reach 2 human votes
|
||||
if (renameUsers.length >= 2) chosen = "rename";
|
||||
else if (roleUsers.length >= 2) chosen = "role";
|
||||
}
|
||||
|
||||
if (!chosen) await sleep(2000);
|
||||
}
|
||||
|
||||
@ -380,7 +408,7 @@ app.post("/interactions", async (c) => {
|
||||
// Ask for new nickname
|
||||
const ask = await sendMessage(
|
||||
channelId,
|
||||
`เลือก: เปลี่ยนชื่อเล่น\nพิมพ์ชื่อใหม่ในข้อความถัดไปภายใน ${RENAME_TIMEOUT_SEC} วินาที`
|
||||
`เลือก: เปลี่ยนชื่อเล่นให้ <@${executorId}>\nพิมพ์ชื่อใหม่ (≤32 ตัวอักษร) ภายใน ${RENAME_TIMEOUT_SEC} วินาที`
|
||||
);
|
||||
if (!ask.ok) {
|
||||
await sendMessage(channelId, "ถามชื่อไม่ได้ ทำไมอ่า");
|
||||
|
||||
Loading…
Reference in New Issue
Block a user