mirror of
https://github.com/qwerinope/qweribot.git
synced 2025-12-18 22:41:38 +01:00
fix #3, now tracking cheers and cheerEvents in database, minor tweaks to existing code
This commit is contained in:
@@ -17,7 +17,7 @@ They can however use items.
|
|||||||
The intended use for invulns is for when you need to talk to a chatter, or for using other bots.
|
The intended use for invulns is for when you need to talk to a chatter, or for using other bots.
|
||||||
Invulns don't need moderator or vip status in the channel.
|
Invulns don't need moderator or vip status in the channel.
|
||||||
The chatterbot and streamer always are invuln and cannot be stripped of this status.
|
The chatterbot and streamer always are invuln and cannot be stripped of this status.
|
||||||
Only the streamer and chatterbot have the power to add and remove invulns.
|
Admins can add and remove invulns.
|
||||||
|
|
||||||
### Commands
|
### Commands
|
||||||
|
|
||||||
@@ -105,8 +105,8 @@ COMMAND|FUNCTION|USER|ALIASES|DISABLEABLE
|
|||||||
`getadmins`|Get a list of every admin in the channel|anyone|`getadmins`|:x:
|
`getadmins`|Get a list of every admin in the channel|anyone|`getadmins`|:x:
|
||||||
`itemlock {target}`|Toggle the itemlock on the specified target|admins|`itemlock`|:x:
|
`itemlock {target}`|Toggle the itemlock on the specified target|admins|`itemlock`|:x:
|
||||||
`testcheer {amount} [args]`|Create a fake cheering event|streamer/chatterbot|`testcheer`|:x:
|
`testcheer {amount} [args]`|Create a fake cheering event|streamer/chatterbot|`testcheer`|:x:
|
||||||
`addinvuln {target}`|Adds an invuln user|streamer/chatterbot|`addinvuln`|:x:
|
`addinvuln {target}`|Adds an invuln user|admins|`addinvuln`|:x:
|
||||||
`removeinvuln {target}`|Removes an invuln user| streamer/chatterbot|`removeinvuln`|:x:
|
`removeinvuln {target}`|Removes an invuln user|admins|`removeinvuln`|:x:
|
||||||
`addadmin {target}`|Adds an admin|streamer/chatterbot|`addadmin`|:x:
|
`addadmin {target}`|Adds an admin|streamer/chatterbot|`addadmin`|:x:
|
||||||
`removeadmin {target}`|Removes an admin|streamer/chatterbot|`removeadmin`|:x:
|
`removeadmin {target}`|Removes an admin|streamer/chatterbot|`removeadmin`|:x:
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ 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 { parseCheerArgs } from "lib/parseCommandArgs";
|
import { parseCheerArgs } from "lib/parseCommandArgs";
|
||||||
|
import { createCheerEventRecord } from "db/dbCheerEvents";
|
||||||
|
|
||||||
const ITEMNAME = 'silverbullet';
|
const ITEMNAME = 'silverbullet';
|
||||||
|
|
||||||
@@ -19,6 +20,7 @@ export default new Cheer('execute', 6666, async (msg, user) => {
|
|||||||
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, ITEMNAME),
|
createTimeoutRecord(user, target, ITEMNAME),
|
||||||
|
createCheerEventRecord(user, ITEMNAME)
|
||||||
]);
|
]);
|
||||||
else {
|
else {
|
||||||
await handleNoTarget(msg, user, ITEMNAME);
|
await handleNoTarget(msg, user, ITEMNAME);
|
||||||
|
|||||||
@@ -4,11 +4,12 @@ import { timeout } from "lib/timeout";
|
|||||||
import User from "user";
|
import User from "user";
|
||||||
import { getUserRecord } from "db/dbUser";
|
import { getUserRecord } from "db/dbUser";
|
||||||
import { createTimeoutRecord } from "db/dbTimeouts";
|
import { createTimeoutRecord } from "db/dbTimeouts";
|
||||||
|
import { createCheerEventRecord } from "db/dbCheerEvents";
|
||||||
import { Cheer, handleNoTarget } from "cheers";
|
import { Cheer, handleNoTarget } from "cheers";
|
||||||
|
|
||||||
const ITEMNAME = 'grenade';
|
const ITEMNAME = 'grenade';
|
||||||
|
|
||||||
export default new Cheer(ITEMNAME, 99, async (msg, user) => {
|
export default new Cheer('grenade', 99, async (msg, user) => {
|
||||||
const targets = await redis.keys(`user:*:vulnerable`);
|
const targets = await redis.keys(`user:*:vulnerable`);
|
||||||
if (targets.length === 0) { await sendMessage('No vulnerable chatters to blow up!', msg.messageId); await handleNoTarget(msg, user, ITEMNAME); return; };
|
if (targets.length === 0) { await sendMessage('No vulnerable chatters to blow up!', msg.messageId); await handleNoTarget(msg, user, ITEMNAME); return; };
|
||||||
const selection = targets[Math.floor(Math.random() * targets.length)]!;
|
const selection = targets[Math.floor(Math.random() * targets.length)]!;
|
||||||
@@ -20,6 +21,7 @@ export default new Cheer(ITEMNAME, 99, async (msg, user) => {
|
|||||||
timeout(target!, `You got hit by ${user.displayName}'s grenade!`, 60),
|
timeout(target!, `You got hit by ${user.displayName}'s grenade!`, 60),
|
||||||
redis.del(selection),
|
redis.del(selection),
|
||||||
sendMessage(`wybuh ${target?.displayName} got hit by ${user.displayName}'s grenade wybuh`),
|
sendMessage(`wybuh ${target?.displayName} got hit by ${user.displayName}'s grenade wybuh`),
|
||||||
createTimeoutRecord(user, target!, ITEMNAME)
|
createTimeoutRecord(user, target!, ITEMNAME),
|
||||||
|
createCheerEventRecord(user, ITEMNAME)
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ 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 { createCheerEventRecord } from "db/dbCheerEvents";
|
||||||
import { parseCheerArgs } from "lib/parseCommandArgs";
|
import { parseCheerArgs } from "lib/parseCommandArgs";
|
||||||
|
|
||||||
const ITEMNAME = 'blaster';
|
const ITEMNAME = 'blaster';
|
||||||
@@ -18,7 +19,8 @@ export default new Cheer('timeout', 100, async (msg, user) => {
|
|||||||
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, ITEMNAME)
|
createTimeoutRecord(user, target, ITEMNAME),
|
||||||
|
createCheerEventRecord(user, ITEMNAME)
|
||||||
]);
|
]);
|
||||||
else {
|
else {
|
||||||
await handleNoTarget(msg, user, ITEMNAME);
|
await handleNoTarget(msg, user, ITEMNAME);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ 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 { createCheerEventRecord } from "db/dbCheerEvents";
|
||||||
import { getTNTTargets } from "items/tnt";
|
import { getTNTTargets } from "items/tnt";
|
||||||
import { redis } from "bun";
|
import { redis } from "bun";
|
||||||
|
|
||||||
@@ -22,6 +23,7 @@ export default new Cheer('tnt', 1000, async (msg, user) => {
|
|||||||
redis.del(`user:${targetid}:vulnerable`),
|
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),
|
||||||
|
createCheerEventRecord(user, ITEMNAME)
|
||||||
]);
|
]);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { addInvuln } from "lib/invuln";
|
|||||||
import parseCommandArgs from "lib/parseCommandArgs";
|
import parseCommandArgs from "lib/parseCommandArgs";
|
||||||
import User from "user";
|
import User from "user";
|
||||||
|
|
||||||
export default new Command('addinvuln', ['addinvuln'], 'streamer', async msg => {
|
export default new Command('addinvuln', ['addinvuln'], 'admin', async msg => {
|
||||||
const args = parseCommandArgs(msg.messageText);
|
const args = parseCommandArgs(msg.messageText);
|
||||||
if (!args[0]) { await sendMessage('Please specify a target', msg.messageId); return; };
|
if (!args[0]) { await sendMessage('Please specify a target', msg.messageId); return; };
|
||||||
const target = await User.initUsername(args[0].toLowerCase());
|
const target = await User.initUsername(args[0].toLowerCase());
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { removeInvuln } from "lib/invuln";
|
|||||||
import parseCommandArgs from "lib/parseCommandArgs";
|
import parseCommandArgs from "lib/parseCommandArgs";
|
||||||
import User from "user";
|
import User from "user";
|
||||||
|
|
||||||
export default new Command('removeinvuln', ['removeinvuln'], 'streamer', async msg => {
|
export default new Command('removeinvuln', ['removeinvuln'], 'admin', async msg => {
|
||||||
const args = parseCommandArgs(msg.messageText);
|
const args = parseCommandArgs(msg.messageText);
|
||||||
if (!args[0]) { await sendMessage('Please specify a target', msg.messageId); return; };
|
if (!args[0]) { await sendMessage('Please specify a target', msg.messageId); return; };
|
||||||
const target = await User.initUsername(args[0].toLowerCase());
|
const target = await User.initUsername(args[0].toLowerCase());
|
||||||
|
|||||||
@@ -34,11 +34,26 @@ export type timeoutRecord = {
|
|||||||
created: string;
|
created: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type cheerEventRecord = {
|
||||||
|
id?: string;
|
||||||
|
user: string;
|
||||||
|
cheer: string;
|
||||||
|
created: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type cheerRecord = {
|
||||||
|
id?: string;
|
||||||
|
user?: string;
|
||||||
|
amount: number;
|
||||||
|
};
|
||||||
|
|
||||||
interface TypedPocketBase extends PocketBase {
|
interface TypedPocketBase extends PocketBase {
|
||||||
collection(idOrName: 'auth'): RecordService<authRecord>;
|
collection(idOrName: 'auth'): RecordService<authRecord>;
|
||||||
collection(idOrName: 'users'): RecordService<userRecord>;
|
collection(idOrName: 'users'): RecordService<userRecord>;
|
||||||
collection(idOrName: 'usedItems'): RecordService<usedItemRecord>;
|
collection(idOrName: 'usedItems'): RecordService<usedItemRecord>;
|
||||||
collection(idOrName: 'timeouts'): RecordService<timeoutRecord>;
|
collection(idOrName: 'timeouts'): RecordService<timeoutRecord>;
|
||||||
|
collection(idOrName: 'cheerEvents'): RecordService<cheerEventRecord>;
|
||||||
|
collection(idOrName: 'cheers'): RecordService<cheerRecord>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default new PocketBase(pocketbaseurl).autoCancellation(false) as TypedPocketBase;
|
export default new PocketBase(pocketbaseurl).autoCancellation(false) as TypedPocketBase;
|
||||||
|
|||||||
26
src/db/dbCheerEvents.ts
Normal file
26
src/db/dbCheerEvents.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import pocketbase from "db/connection";
|
||||||
|
import User from "user";
|
||||||
|
import logger from "lib/logger";
|
||||||
|
const pb = pocketbase.collection('cheerEvents');
|
||||||
|
|
||||||
|
export async function createCheerEventRecord(user: User, cheer: string): Promise<void> {
|
||||||
|
try {
|
||||||
|
await pb.create({ user: user.id, cheer });
|
||||||
|
} catch (e) {
|
||||||
|
logger.err(`Failed to create cheerEvent record in database: user: ${user.id}, cheer: ${cheer}`);
|
||||||
|
logger.err(e as string);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function getCheerEvents(user: User, monthData?: string) {
|
||||||
|
try {
|
||||||
|
const monthquery = monthData ? ` && created~"${monthData}"` : '';
|
||||||
|
const data = await pb.getFullList({
|
||||||
|
filter: `user="${user.id}"${monthquery}`
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
} catch (e) {
|
||||||
|
logger.err(`Failed to get cheerEvents for user: ${user.id}, month: ${monthData}`);
|
||||||
|
logger.err(e as string);
|
||||||
|
};
|
||||||
|
};
|
||||||
26
src/db/dbCheers.ts
Normal file
26
src/db/dbCheers.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import pocketbase from "db/connection";
|
||||||
|
import User from "user";
|
||||||
|
import logger from "lib/logger";
|
||||||
|
const pb = pocketbase.collection('cheers');
|
||||||
|
|
||||||
|
export async function createCheerRecord(user: User, amount: number): Promise<void> {
|
||||||
|
try {
|
||||||
|
await pb.create({ user: user.id, amount })
|
||||||
|
} catch (e) {
|
||||||
|
logger.err(`Failed to create cheer record in database: user: ${user.id}, amount: ${amount}`);
|
||||||
|
logger.err(e as string);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function getCheers(user: User, monthData?: string) {
|
||||||
|
try {
|
||||||
|
const monthquery = monthData ? ` && created~"${monthData}"` : '';
|
||||||
|
const data = await pb.getFullList({
|
||||||
|
filter: `user="${user.id}"${monthquery}`
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
} catch (e) {
|
||||||
|
logger.err(`Failed to get cheers for user: ${user.id}, month: ${monthData}`);
|
||||||
|
logger.err(e as string);
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -8,6 +8,8 @@ import cheers from "cheers";
|
|||||||
import logger from "lib/logger";
|
import logger from "lib/logger";
|
||||||
import { addMessageToChatWidget } from "web/chatWidget/message";
|
import { addMessageToChatWidget } from "web/chatWidget/message";
|
||||||
import { isInvuln, setTemporaryInvuln } from "lib/invuln";
|
import { isInvuln, setTemporaryInvuln } from "lib/invuln";
|
||||||
|
import { getUserRecord } from "db/dbUser";
|
||||||
|
import { createCheerRecord } from "db/dbCheers";
|
||||||
|
|
||||||
logger.info(`Loaded the following commands: ${commands.keys().toArray().join(', ')}`);
|
logger.info(`Loaded the following commands: ${commands.keys().toArray().join(', ')}`);
|
||||||
|
|
||||||
@@ -65,6 +67,11 @@ async function handleChatMessage(msg: EventSubChannelChatMessageEvent, user: Use
|
|||||||
};
|
};
|
||||||
|
|
||||||
export async function handleCheer(msg: EventSubChannelChatMessageEvent, bits: number, user: User) {
|
export async function handleCheer(msg: EventSubChannelChatMessageEvent, bits: number, user: User) {
|
||||||
|
if (msg.isCheer) {
|
||||||
|
await getUserRecord(user); // ensure they exist in the database
|
||||||
|
await createCheerRecord(user, bits);
|
||||||
|
}; // If this is not triggered it's because of the testcheer command. these fake bits should not be added to the database
|
||||||
|
|
||||||
const selection = cheers.get(bits);
|
const selection = cheers.get(bits);
|
||||||
if (!selection) return;
|
if (!selection) return;
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { getCheerEvents } from "db/dbCheerEvents";
|
||||||
import { getTimeoutsAsTarget, getTimeoutsAsUser } from "db/dbTimeouts";
|
import { getTimeoutsAsTarget, getTimeoutsAsUser } from "db/dbTimeouts";
|
||||||
import { getItemsUsed } from "db/dbUsedItems";
|
import { getItemsUsed } from "db/dbUsedItems";
|
||||||
import type { inventory } from "items";
|
import type { inventory } from "items";
|
||||||
@@ -33,12 +34,22 @@ export async function getTimeoutStats(target: User, thismonth: boolean) {
|
|||||||
export async function getItemStats(target: User, thismonth: boolean) {
|
export async function getItemStats(target: User, thismonth: boolean) {
|
||||||
const monthdata = thismonth ? new Date().toISOString().slice(0, 7) : undefined;
|
const monthdata = thismonth ? new Date().toISOString().slice(0, 7) : undefined;
|
||||||
|
|
||||||
const data = await getItemsUsed(target, monthdata);
|
const [items, cheers] = await Promise.all([
|
||||||
if (!data) return;
|
getItemsUsed(target, monthdata),
|
||||||
|
getCheerEvents(target, monthdata)
|
||||||
|
]);
|
||||||
|
if (!items || !cheers) return;
|
||||||
|
|
||||||
const returnObj: inventory = {
|
const returnObj: inventory = {};
|
||||||
grenade: data.filter(use => use.item === 'grenade').length,
|
|
||||||
tnt: data.filter(use => use.item === 'tnt').length
|
for (const item of items) {
|
||||||
|
if (!returnObj[item.item]) returnObj[item.item] = 0;
|
||||||
|
returnObj[item.item]! += 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const cheer of cheers) {
|
||||||
|
if (!returnObj[cheer.cheer]) returnObj[cheer.cheer] = 0;
|
||||||
|
returnObj[cheer.cheer]! += 1
|
||||||
};
|
};
|
||||||
|
|
||||||
return returnObj;
|
return returnObj;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export async function addInvuln(userid: string) {
|
|||||||
export async function removeInvuln(userid: string) {
|
export async function removeInvuln(userid: string) {
|
||||||
return await redis.del(`user:${userid}:invulnerable`);
|
return await redis.del(`user:${userid}:invulnerable`);
|
||||||
};
|
};
|
||||||
export async function setTemporaryInvuln(userid: string) {
|
export async function setTemporaryInvuln(userid: string, duration = 600) {
|
||||||
await redis.set(`user:${userid}:invulnerable`, '1');
|
await redis.set(`user:${userid}:invulnerable`, '1');
|
||||||
await redis.expire(`user:${userid}:invulnerable`, 600);
|
await redis.expire(`user:${userid}:invulnerable`, duration);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user