From 3e373056c93a0104fe1ca1f337f1194bbae39759 Mon Sep 17 00:00:00 2001 From: qwerinope Date: Thu, 11 Sep 2025 14:44:26 +0200 Subject: [PATCH] jank fixes --- src/commands/banclanker.ts | 20 ++++++++++++++++++++ src/commands/getloot.ts | 2 +- src/commands/index.ts | 4 ++-- src/events/bans.ts | 4 +++- src/events/message.ts | 9 +++++++-- src/index.ts | 4 ++-- src/lib/dateManager.ts | 4 ++-- src/lib/timeout.ts | 2 +- 8 files changed, 38 insertions(+), 11 deletions(-) create mode 100644 src/commands/banclanker.ts diff --git a/src/commands/banclanker.ts b/src/commands/banclanker.ts new file mode 100644 index 0000000..691bb7f --- /dev/null +++ b/src/commands/banclanker.ts @@ -0,0 +1,20 @@ +import { Command, sendMessage } from "commands"; +import parseCommandArgs from "lib/parseCommandArgs"; +import { timeout } from "lib/timeout"; +import User from "user"; +import { playAlert } from "web/alerts/serverFunctions"; + +export default new Command('banclanker', ['banclanker', 'banbot'], 'moderator', async msg => { + const args = parseCommandArgs(msg.messageText); + if (!args[0]) { await sendMessage(`Specify a clanker to ban`, msg.messageId); return; }; + const target = await User.initUsername(args[0]); + if (!target) { await sendMessage(`Clanker ${args[0]} doesn't exist`, msg.messageId); return; }; + await Promise.all([ + timeout(target, `get fucked`), + playAlert({ + name: 'userExecution', + user: msg.chatterDisplayName, + target: target.displayName + }) + ]); +}); diff --git a/src/commands/getloot.ts b/src/commands/getloot.ts index c9f1631..7559d09 100644 --- a/src/commands/getloot.ts +++ b/src/commands/getloot.ts @@ -17,7 +17,7 @@ export default new Command('getloot', ['getloot', 'dig', 'loot'], 'chatter', asy if (await user.greedy()) { await Promise.all([ sendMessage(`${user.displayName} STOP BEING GREEDY!!! UltraMad UltraMad UltraMad`), - timeout(user, 'STOP BEING GREEDY!!!', 60) + timeout(user, `Wait ${buildTimeString(now - COOLDOWN, lastlootbox)}`, 60) ]); return; } else { diff --git a/src/commands/index.ts b/src/commands/index.ts index d46dd22..c2b7db1 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -1,7 +1,7 @@ import { EventSubChannelChatMessageEvent } from "@twurple/eventsub-base"; import User from "user"; -export type userType = 'chatter' | 'admin' | 'streamer'; +export type userType = 'chatter' | 'admin' | 'streamer' | 'moderator'; /** The Command class represents a command */ export class Command { @@ -46,5 +46,5 @@ import { chatterApi, chatterId, streamerId } from "main"; /** Helper function to send a message to the stream */ export const sendMessage = async (message: string, replyParentMessageId?: string) => { - await chatterApi.chat.sendChatMessageAsApp(chatterId, streamerId, message, { replyParentMessageId }) + return await chatterApi.chat.sendChatMessageAsApp(chatterId, streamerId, message, { replyParentMessageId }) }; diff --git a/src/events/bans.ts b/src/events/bans.ts index 3de026a..d57b7d1 100644 --- a/src/events/bans.ts +++ b/src/events/bans.ts @@ -1,9 +1,11 @@ -import { eventSub, streamerId } from "main"; +import { eventSub, streamerApi, streamerId } from "main"; import { deleteBannedUserMessagesFromChatWidget } from "web/chatWidget/message"; import { redis } from "bun"; eventSub.onChannelBan(streamerId, async msg => { deleteBannedUserMessagesFromChatWidget(msg); + const welcomemessageid = await redis.get(`user:${msg.userId}:welcomemessageid`); + if (welcomemessageid) { await streamerApi.moderation.deleteChatMessages(streamerId, welcomemessageid); await redis.del(`user:${msg.userId}:welcomemessageid`); }; await redis.set(`user:${msg.userId}:timeout`, '1'); if (msg.endDate) await redis.expire(`user:${msg.userId}:timeout`, Math.floor((msg.endDate.getTime() - Date.now()) / 1000)); }); diff --git a/src/events/message.ts b/src/events/message.ts index 3748071..82f8fdf 100644 --- a/src/events/message.ts +++ b/src/events/message.ts @@ -30,9 +30,11 @@ async function parseChatMessage(msg: EventSubChannelChatMessageEvent) { if (!await isInvuln(user?.id!)) user?.setVulnerable(); // Make the user vulnerable to explosions if not marked as invuln if (!await redis.exists(`user:${user?.id}:haschatted`) && !msg.sourceMessageId) { - await sendMessage(`Welcome ${user?.displayName}. Please note: This chat has PvP, if you get timed out that's part of the qwerinope experience. You have 10 minutes of invincibility. A full list of commands and items can be found here: https://github.com/qwerinope/qweribot/#qweribot`); + const message = await sendMessage(`Welcome ${user?.displayName}. Please note: This chat has PvP, if you get timed out that's part of the qwerinope experience. You have 10 minutes of invincibility. A full list of commands and items can be found here: https://github.com/qwerinope/qweribot/#qweribot`); await redis.set(`user:${user?.id}:haschatted`, "1"); - if (!streamerUsers.includes(msg.chatterId)) await setTemporaryInvuln(user?.id!); // This would set the invuln expiration lmao + await redis.set(`user:${user?.id}:welcomemessageid`, message.id); + await redis.expire(`user:${user?.id}:welcomemessageid`, 600); + if (!await isInvuln(msg.chatterId)) await setTemporaryInvuln(user?.id!); // This would set the invuln expiration lmao }; if (!msg.isCheer && !msg.isRedemption) await handleChatMessage(msg, user!) @@ -57,6 +59,9 @@ async function handleChatMessage(msg: EventSubChannelChatMessageEvent, user: Use case "streamer": if (!streamerUsers.includes(msg.chatterId)) return; break; + case "moderator": + if (!await redis.exists(`user:${user.id}:mod`)) return; + break; }; try { await selected.execute(msg, user); } diff --git a/src/index.ts b/src/index.ts index 09022a7..0024262 100644 --- a/src/index.ts +++ b/src/index.ts @@ -10,7 +10,7 @@ import User from "user"; import { buildTimeString } from "lib/dateManager"; const CHATTERINTENTS = ["user:read:chat", "user:write:chat", "user:bot"]; -const STREAMERINTENTS = ["channel:bot", "user:read:chat", "moderation:read", "channel:manage:moderators", "moderator:manage:banned_users", "bits:read", "channel:moderate", "moderator:manage:shoutouts"]; +const STREAMERINTENTS = ["channel:bot", "user:read:chat", "moderation:read", "channel:manage:moderators", "moderator:manage:chat_messages", "moderator:manage:banned_users", "bits:read", "channel:moderate", "moderator:manage:shoutouts"]; export const singleUserMode = process.env.CHATTER_IS_STREAMER === 'true'; export const chatterId = process.env.CHATTER_ID ?? ""; @@ -33,7 +33,7 @@ export const eventSub = new EventSubWsListener({ apiClient: streamerApi }); export const commandPrefix = process.env.COMMAND_PREFIX ?? "!"; export const streamerUsers = [chatterId, streamerId]; -streamerUsers.forEach(async id => await Promise.all([addAdmin(id), addInvuln(id)])); +streamerUsers.forEach(async id => await Promise.all([addAdmin(id), addInvuln(id), redis.set(`user:${id}:mod`, '1')])); const banned = await streamerApi.moderation.getBannedUsers(streamerId).then(a => a.data); for (const ban of banned) { diff --git a/src/lib/dateManager.ts b/src/lib/dateManager.ts index 5ca57cf..8a8ed94 100644 --- a/src/lib/dateManager.ts +++ b/src/lib/dateManager.ts @@ -1,4 +1,4 @@ -export function buildTimeString(time1: number, time2: number) { +export function buildTimeString(time1: number, time2: number): string { const diff = Math.abs(time1 - time2); const timeobj = { day: Math.floor(diff / (1000 * 60 * 60 * 24)), @@ -13,5 +13,5 @@ export function buildTimeString(time1: number, time2: number) { stringarray.push(`${value} ${unit}${value === 1 ? '' : 's'}`); }; const last = stringarray.pop(); - return stringarray.length === 0 ? last : stringarray.join(', ') + " and " + last; + return stringarray.length === 0 ? last! : stringarray.join(', ') + " and " + last; }; diff --git a/src/lib/timeout.ts b/src/lib/timeout.ts index 2a96e76..37d36e8 100644 --- a/src/lib/timeout.ts +++ b/src/lib/timeout.ts @@ -13,7 +13,7 @@ type TimeoutResult = SuccessfulTimeout | UnSuccessfulTimeout; * @param reason - reason for timeout/ban * @param duration - duration of timeout. don't specifiy for ban */ export const timeout = async (user: User, reason: string, duration?: number): Promise => { - if (await isInvuln(user.id)) return { status: false, reason: 'illegal' }; // Don't timeout invulnerable chatters + if (await isInvuln(user.id) && duration) return { status: false, reason: 'illegal' }; // Don't timeout invulnerable chatters // Check if user already has a timeout and handle stacking const banStatus = await timeoutDuration(user);