mirror of
https://gitlab.com/qwerinope/qweribot.git
synced 2026-02-04 12:06:58 +01:00
handle user bans on widget, add tnt cheer, bugfixes
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
import { EventSubChannelChatMessageEvent, EventSubChannelChatMessageDeleteEvent } from "@twurple/eventsub-base";
|
import { EventSubChannelChatMessageEvent, EventSubChannelChatMessageDeleteEvent, EventSubChannelBanEvent } from "@twurple/eventsub-base";
|
||||||
import { sendTwitchEvent } from ".";
|
import { sendTwitchEvent } from ".";
|
||||||
|
|
||||||
export async function addMessageToChatWidget(msg: EventSubChannelChatMessageEvent) {
|
export async function addMessageToChatWidget(msg: EventSubChannelChatMessageEvent) {
|
||||||
sendTwitchEvent({
|
await sendTwitchEvent({
|
||||||
function: 'createMessage',
|
function: 'createMessage',
|
||||||
messageParts: msg.messageParts,
|
messageParts: msg.messageParts,
|
||||||
displayName: msg.chatterDisplayName,
|
displayName: msg.chatterDisplayName,
|
||||||
@@ -14,8 +14,15 @@ export async function addMessageToChatWidget(msg: EventSubChannelChatMessageEven
|
|||||||
};
|
};
|
||||||
|
|
||||||
export async function deleteMessageFromChatWidget(msg: EventSubChannelChatMessageDeleteEvent) {
|
export async function deleteMessageFromChatWidget(msg: EventSubChannelChatMessageDeleteEvent) {
|
||||||
sendTwitchEvent({
|
await sendTwitchEvent({
|
||||||
function: 'deleteMessage',
|
function: 'deleteMessage',
|
||||||
messageId: msg.messageId
|
messageId: msg.messageId
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export async function deleteBannedUserMessagesFromChatWidget(msg: EventSubChannelBanEvent) {
|
||||||
|
sendTwitchEvent({
|
||||||
|
function: 'userBan',
|
||||||
|
chatterId: msg.userId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,14 +12,20 @@ export type deleteMessageEvent = {
|
|||||||
function: 'deleteMessage';
|
function: 'deleteMessage';
|
||||||
messageId: string;
|
messageId: string;
|
||||||
};
|
};
|
||||||
|
export type userBanEvent = {
|
||||||
|
function: 'userBan';
|
||||||
|
chatterId: string;
|
||||||
|
};
|
||||||
export type serverNotificationEvent = {
|
export type serverNotificationEvent = {
|
||||||
function: 'serverNotification';
|
function: 'serverNotification';
|
||||||
message: string;
|
message: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type twitchEventData = createMessageEvent |
|
export type twitchEventData =
|
||||||
deleteMessageEvent |
|
createMessageEvent
|
||||||
serverNotificationEvent;
|
| deleteMessageEvent
|
||||||
|
| userBanEvent
|
||||||
|
| serverNotificationEvent;
|
||||||
|
|
||||||
// The types below are taken straight from @twurple/eventsub-base
|
// The types below are taken straight from @twurple/eventsub-base
|
||||||
// I would import this from the package, but that's impossible
|
// I would import this from the package, but that's impossible
|
||||||
|
|||||||
@@ -18,10 +18,14 @@ socket.onmessage = event => {
|
|||||||
case 'createMessage':
|
case 'createMessage':
|
||||||
const newMessageElement = parseMessage(data);
|
const newMessageElement = parseMessage(data);
|
||||||
newMessageElement.id = data.messageId;
|
newMessageElement.id = data.messageId;
|
||||||
|
newMessageElement.classList.add(data.chatterId);
|
||||||
document.querySelector("#message-container")?.appendChild(newMessageElement);
|
document.querySelector("#message-container")?.appendChild(newMessageElement);
|
||||||
break;
|
break;
|
||||||
case 'deleteMessage':
|
case 'deleteMessage':
|
||||||
document.querySelector(`#${CSS.escape(data.messageId)}`)?.remove();
|
document.querySelectorAll(`#${CSS.escape(data.messageId)}`).forEach(msg => msg.remove());
|
||||||
|
break;
|
||||||
|
case 'userBan':
|
||||||
|
document.querySelectorAll(`.${CSS.escape(data.chatterId)}`).forEach(msg => msg.remove());
|
||||||
break;
|
break;
|
||||||
case 'serverNotification':
|
case 'serverNotification':
|
||||||
console.log(data.message);
|
console.log(data.message);
|
||||||
|
|||||||
@@ -1,28 +1,27 @@
|
|||||||
import { Cheer } from ".";
|
import { Cheer, handleNoTarget } from ".";
|
||||||
import { EventSubChannelChatMessageEvent } from "@twurple/eventsub-base"
|
|
||||||
import { changeItemCount } from "../items";
|
|
||||||
import { sendMessage } from "../commands";
|
import { sendMessage } from "../commands";
|
||||||
import { getUserRecord } from "../db/dbUser";
|
import { getUserRecord } from "../db/dbUser";
|
||||||
import { User } from "../user";
|
import { User } from "../user";
|
||||||
import { timeout } from "../lib/timeout";
|
import { timeout } from "../lib/timeout";
|
||||||
import { createTimeoutRecord } from "../db/dbTimeouts";
|
import { createTimeoutRecord } from "../db/dbTimeouts";
|
||||||
import logger from "../lib/logger";
|
|
||||||
import { parseCheerArgs } from "../lib/parseCommandArgs";
|
import { parseCheerArgs } from "../lib/parseCommandArgs";
|
||||||
|
|
||||||
|
const ITEMNAME = 'silverbullet';
|
||||||
|
|
||||||
export default new Cheer('execute', 6666, async (msg, user) => {
|
export default new Cheer('execute', 6666, async (msg, user) => {
|
||||||
const args = parseCheerArgs(msg.messageText);
|
const args = parseCheerArgs(msg.messageText);
|
||||||
if (!args[0]) { await handleNoExecuteTarget(msg, user, false); return; };
|
if (!args[0]) { await handleNoTarget(msg, user, ITEMNAME, false); return; };
|
||||||
const target = await User.initUsername(args[0].toLowerCase());
|
const target = await User.initUsername(args[0].toLowerCase());
|
||||||
if (!target) { await handleNoExecuteTarget(msg, user, false); return; };
|
if (!target) { await handleNoTarget(msg, user, ITEMNAME, false); return; };
|
||||||
await getUserRecord(target);
|
await getUserRecord(target);
|
||||||
|
|
||||||
const result = await timeout(target, `You got executed by ${user.displayName}!`, 60 * 60 * 24);
|
const result = await timeout(target, `You got executed by ${user.displayName}!`, 60 * 60 * 24);
|
||||||
if (result.status) await Promise.all([
|
if (result.status) await Promise.all([
|
||||||
sendMessage(`${target.displayName} RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO`),
|
sendMessage(`${target.displayName} RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO`),
|
||||||
createTimeoutRecord(user, target, 'silverbullet'),
|
createTimeoutRecord(user, target, ITEMNAME),
|
||||||
]);
|
]);
|
||||||
else {
|
else {
|
||||||
await handleNoExecuteTarget(msg, user);
|
await handleNoTarget(msg, user, ITEMNAME);
|
||||||
switch (result.reason) {
|
switch (result.reason) {
|
||||||
case "banned":
|
case "banned":
|
||||||
await sendMessage(`${target.displayName} is already timed out/banned`, msg.messageId);
|
await sendMessage(`${target.displayName} is already timed out/banned`, msg.messageId);
|
||||||
@@ -40,15 +39,3 @@ export default new Cheer('execute', 6666, async (msg, user) => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
async function handleNoExecuteTarget(msg: EventSubChannelChatMessageEvent, user: User, silent = true) {
|
|
||||||
if (await user.itemLock()) {
|
|
||||||
await sendMessage(`Cannot give ${user.displayName} a silver bullet`, msg.messageId);
|
|
||||||
logger.err(`Failed to give ${user.displayName} a silver bullet for their cheer`);
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
await user.setLock();
|
|
||||||
const userRecord = await getUserRecord(user);
|
|
||||||
if (!silent) await sendMessage('No (valid) target specified. You got a silver bullet!', msg.messageId);
|
|
||||||
await changeItemCount(user, userRecord, 'silverbullet', 1);
|
|
||||||
await user.clearLock();
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -27,3 +27,21 @@ for (const file of files) {
|
|||||||
|
|
||||||
export default cheers;
|
export default cheers;
|
||||||
export { namedcheers };
|
export { namedcheers };
|
||||||
|
|
||||||
|
import { sendMessage } from '../commands';
|
||||||
|
import logger from '../lib/logger';
|
||||||
|
import { getUserRecord } from '../db/dbUser';
|
||||||
|
import { changeItemCount } from '../items';
|
||||||
|
|
||||||
|
export async function handleNoTarget(msg: EventSubChannelChatMessageEvent, user: User, itemname: string, silent = true) {
|
||||||
|
if (await user.itemLock()) {
|
||||||
|
await sendMessage(`Cannot give ${user.displayName} a ${itemname}`, msg.messageId);
|
||||||
|
logger.err(`Failed to give ${user.displayName} a ${itemname} for their cheer`);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
await user.setLock();
|
||||||
|
const userRecord = await getUserRecord(user);
|
||||||
|
if (!silent) await sendMessage(`No (valid) target specified. You got a ${itemname}!`, msg.messageId);
|
||||||
|
await changeItemCount(user, userRecord, itemname, 1);
|
||||||
|
await user.clearLock();
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,28 +1,27 @@
|
|||||||
import { Cheer } from ".";
|
import { Cheer, handleNoTarget } from ".";
|
||||||
import { EventSubChannelChatMessageEvent } from "@twurple/eventsub-base"
|
|
||||||
import { changeItemCount } from "../items";
|
|
||||||
import { sendMessage } from "../commands";
|
import { sendMessage } from "../commands";
|
||||||
import { getUserRecord } from "../db/dbUser";
|
import { getUserRecord } from "../db/dbUser";
|
||||||
import { User } from "../user";
|
import { User } from "../user";
|
||||||
import { timeout } from "../lib/timeout";
|
import { timeout } from "../lib/timeout";
|
||||||
import { createTimeoutRecord } from "../db/dbTimeouts";
|
import { createTimeoutRecord } from "../db/dbTimeouts";
|
||||||
import logger from "../lib/logger";
|
|
||||||
import { parseCheerArgs } from "../lib/parseCommandArgs";
|
import { parseCheerArgs } from "../lib/parseCommandArgs";
|
||||||
|
|
||||||
|
const ITEMNAME = 'blaster';
|
||||||
|
|
||||||
export default new Cheer('timeout', 100, async (msg, user) => {
|
export default new Cheer('timeout', 100, async (msg, user) => {
|
||||||
const args = parseCheerArgs(msg.messageText);
|
const args = parseCheerArgs(msg.messageText);
|
||||||
if (!args[0]) { await handleNoBlasterTarget(msg, user, false); return; };
|
if (!args[0]) { await handleNoTarget(msg, user, ITEMNAME, false); return; };
|
||||||
const target = await User.initUsername(args[0].toLowerCase());
|
const target = await User.initUsername(args[0].toLowerCase());
|
||||||
if (!target) { await handleNoBlasterTarget(msg, user, false); return; };
|
if (!target) { await handleNoTarget(msg, user, ITEMNAME, false); return; };
|
||||||
await getUserRecord(target);
|
await getUserRecord(target);
|
||||||
|
|
||||||
const result = await timeout(target, `You got blasted by ${user.displayName}!`, 60);
|
const result = await timeout(target, `You got blasted by ${user.displayName}!`, 60);
|
||||||
if (result.status) await Promise.all([
|
if (result.status) await Promise.all([
|
||||||
sendMessage(`GOTTEM ${target.displayName} got BLASTED by ${user.displayName} GOTTEM`),
|
sendMessage(`GOTTEM ${target.displayName} got BLASTED by ${user.displayName} GOTTEM`),
|
||||||
createTimeoutRecord(user, target, 'blaster'),
|
createTimeoutRecord(user, target, ITEMNAME)
|
||||||
]);
|
]);
|
||||||
else {
|
else {
|
||||||
await handleNoBlasterTarget(msg, user);
|
await handleNoTarget(msg, user, ITEMNAME);
|
||||||
switch (result.reason) {
|
switch (result.reason) {
|
||||||
case "banned":
|
case "banned":
|
||||||
await sendMessage(`${target.displayName} is already timed out/banned`, msg.messageId);
|
await sendMessage(`${target.displayName} is already timed out/banned`, msg.messageId);
|
||||||
@@ -39,16 +38,3 @@ export default new Cheer('timeout', 100, async (msg, user) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
async function handleNoBlasterTarget(msg: EventSubChannelChatMessageEvent, user: User, silent = true) {
|
|
||||||
if (await user.itemLock()) {
|
|
||||||
await sendMessage(`Cannot give ${user.displayName} a blaster`, msg.messageId);
|
|
||||||
logger.err(`Failed to give ${user.displayName} a blaster for their cheer`);
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
await user.setLock();
|
|
||||||
const userRecord = await getUserRecord(user);
|
|
||||||
if (!silent) await sendMessage('No (valid) target specified. You got a blaster!', msg.messageId);
|
|
||||||
await changeItemCount(user, userRecord, 'blaster', 1);
|
|
||||||
await user.clearLock();
|
|
||||||
};
|
|
||||||
|
|||||||
30
src/cheers/tnt.ts
Normal file
30
src/cheers/tnt.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import { Cheer, handleNoTarget } from ".";
|
||||||
|
import { sendMessage } from "../commands";
|
||||||
|
import { getUserRecord } from "../db/dbUser";
|
||||||
|
import { User } from "../user";
|
||||||
|
import { timeout } from "../lib/timeout";
|
||||||
|
import { createTimeoutRecord } from "../db/dbTimeouts";
|
||||||
|
import { getTNTTargets } from "../items/tnt";
|
||||||
|
import { redis } from "bun";
|
||||||
|
|
||||||
|
const ITEMNAME = 'tnt';
|
||||||
|
|
||||||
|
export default new Cheer('tnt', 1000, async (msg, user) => {
|
||||||
|
const vulntargets = await redis.keys('user:*:vulnerable').then(a => a.map(b => b.slice(5, -11)));
|
||||||
|
if (vulntargets.length === 0) { await sendMessage('No vulnerable chatters to blow up', msg.messageId); handleNoTarget(msg, user, ITEMNAME); return; };
|
||||||
|
const targets = getTNTTargets(vulntargets);
|
||||||
|
|
||||||
|
await Promise.all(targets.map(async targetid => {
|
||||||
|
const target = await User.initUserId(targetid);
|
||||||
|
await getUserRecord(target!); // make sure the user record exist in the database
|
||||||
|
await Promise.all([
|
||||||
|
timeout(target!, `You got hit by ${user.displayName}'s TNT!`, 60),
|
||||||
|
redis.del(`user:${targetid}:vulnerable`),
|
||||||
|
sendMessage(`wybuh ${target?.displayName} got hit by ${user.displayName}'s TNT wybuh`),
|
||||||
|
createTimeoutRecord(user, target!, ITEMNAME),
|
||||||
|
]);
|
||||||
|
}));
|
||||||
|
|
||||||
|
await sendMessage(`RIPBOZO ${user.displayName} exploded ${targets.length} chatter${targets.length === 1 ? '' : 's'} with their TNT RIPBOZO`);
|
||||||
|
});
|
||||||
|
|
||||||
6
src/events/banned.ts
Normal file
6
src/events/banned.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { eventSub, streamerId } from "..";
|
||||||
|
import { deleteBannedUserMessagesFromChatWidget } from "../chatwidget/message";
|
||||||
|
|
||||||
|
eventSub.onChannelBan(streamerId, async msg => {
|
||||||
|
deleteBannedUserMessagesFromChatWidget(msg);
|
||||||
|
});
|
||||||
@@ -62,7 +62,7 @@ export async function handleCheer(msg: EventSubChannelChatMessageEvent, bits: nu
|
|||||||
const selection = cheers.get(bits);
|
const selection = cheers.get(bits);
|
||||||
if (!selection) return;
|
if (!selection) return;
|
||||||
|
|
||||||
if (await redis.sismember('disabledcheers', selection.name)) { await sendMessage(`The ${selection.name} cheer is disabled`); return; };
|
if (await redis.sismember('disabledcheers', selection.name)) { await sendMessage(`The ${selection.name} cheer is disabled! Sorry!`, msg.messageId); return; };
|
||||||
try {
|
try {
|
||||||
selection.execute(msg, user);
|
selection.execute(msg, user);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import logger from "./lib/logger";
|
|||||||
import { addInvuln } from "./lib/invuln";
|
import { addInvuln } from "./lib/invuln";
|
||||||
|
|
||||||
const CHATTERINTENTS = ["user:read:chat", "user:write:chat", "user:bot"];
|
const CHATTERINTENTS = ["user:read:chat", "user:write:chat", "user:bot"];
|
||||||
const STREAMERINTENTS = ["user:read:chat", "moderation:read", "channel:manage:moderators", "moderator:manage:banned_users", "bits:read"];
|
const STREAMERINTENTS = ["user:read:chat", "moderation:read", "channel:manage:moderators", "moderator:manage:banned_users", "bits:read", "channel:moderate"];
|
||||||
|
|
||||||
export const singleUserMode = process.env.CHATTER_IS_STREAMER === 'true';
|
export const singleUserMode = process.env.CHATTER_IS_STREAMER === 'true';
|
||||||
export const chatterId = process.env.CHATTER_ID ?? "";
|
export const chatterId = process.env.CHATTER_ID ?? "";
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export default new Item(ITEMNAME, 'TNT', 's',
|
|||||||
await getUserRecord(target!); // make sure the user record exist in the database
|
await getUserRecord(target!); // make sure the user record exist in the database
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
timeout(target!, `You got hit by ${user.displayName}'s TNT!`, 60),
|
timeout(target!, `You got hit by ${user.displayName}'s TNT!`, 60),
|
||||||
redis.del(targetid),
|
redis.del(`user:${targetid}:vulnerable`),
|
||||||
sendMessage(`wybuh ${target?.displayName} got hit by ${user.displayName}'s TNT wybuh`),
|
sendMessage(`wybuh ${target?.displayName} got hit by ${user.displayName}'s TNT wybuh`),
|
||||||
createTimeoutRecord(user, target!, ITEMNAME),
|
createTimeoutRecord(user, target!, ITEMNAME),
|
||||||
]);
|
]);
|
||||||
@@ -42,7 +42,7 @@ export default new Item(ITEMNAME, 'TNT', 's',
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
function getTNTTargets<T>(arr: T[]): T[] {
|
export function getTNTTargets<T>(arr: T[]): T[] {
|
||||||
if (arr.length <= 5) {
|
if (arr.length <= 5) {
|
||||||
return arr;
|
return arr;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user