small refactor and small lootbox rebalance SMILERS

This commit is contained in:
2025-11-15 02:35:39 +01:00
parent a205daacb7
commit 977082f38e
89 changed files with 300 additions and 203 deletions

View File

@@ -1,5 +1,5 @@
import { Cheer, handleNoTarget } from "cheers";
import { sendMessage } from "commands";
import { sendMessage } from "lib/commandUtils";
import { getUserRecord } from "db/dbUser";
import User from "user";
import { timeout } from "lib/timeout";

View File

@@ -1,5 +1,5 @@
import { redis } from "bun";
import { sendMessage } from "commands";
import { redis } from "lib/redis";
import { sendMessage } from "lib/commandUtils";
import { timeout } from "lib/timeout";
import User from "user";
import { getUserRecord } from "db/dbUser";

View File

@@ -30,7 +30,7 @@ for (const file of files) {
export default cheers;
export { namedcheers };
import { sendMessage } from 'commands';
import { sendMessage } from 'lib/commandUtils';
import { getUserRecord } from 'db/dbUser';
import { changeItemCount, type items } from 'items';

View File

@@ -1,10 +1,10 @@
import { Cheer } from "cheers";
import { sendMessage } from "commands";
import { sendMessage } from "lib/commandUtils";
import { getUserRecord, updateUserRecord } from "db/dbUser";
import itemMap, { type inventory, type items } from "items";
import { createGetLootRecord } from "db/dbGetLoot";
import { timeout } from "lib/timeout";
import { redis } from "bun";
import { redis } from "lib/redis";
export default new Cheer('superloot', 150, async (msg, user) => {
if (!await redis.exists('streamIsLive')) { await sendMessage(`No loot while stream is offline`, msg.messageId); return; };
@@ -38,7 +38,7 @@ export default new Cheer('superloot', 150, async (msg, user) => {
if (Math.floor(Math.random() * 5) === 0) itemDiff.grenade! += 1; // 1 in 5
if (Math.floor(Math.random() * 5) === 0) itemDiff.blaster! += 1; // 1 in 5
if (Math.floor(Math.random() * 50) === 0) itemDiff.tnt! += 1; // 1 in 50
if (Math.floor(Math.random() * 250) === 0) itemDiff.silverbullet! += 1; // 1 in 250
if (Math.floor(Math.random() * 50) === 0) itemDiff.silverbullet! += 1; // 1 in 50
};
for (const [item, amount] of Object.entries(itemDiff) as [items, number][]) {

View File

@@ -1,5 +1,5 @@
import { Cheer, handleNoTarget } from "cheers";
import { sendMessage } from "commands";
import { sendMessage } from "lib/commandUtils";
import { getUserRecord } from "db/dbUser";
import User from "user";
import { timeout } from "lib/timeout";

View File

@@ -1,12 +1,12 @@
import { Cheer, handleNoTarget } from "cheers";
import { sendMessage } from "commands";
import { sendMessage } from "lib/commandUtils";
import { getUserRecord } from "db/dbUser";
import User from "user";
import { timeout } from "lib/timeout";
import { createTimeoutRecord } from "db/dbTimeouts";
import { createCheerEventRecord } from "db/dbCheerEvents";
import { getTNTTargets } from "items/tnt";
import { redis } from "bun";
import { redis } from "lib/redis";
import { playAlert } from "web/alerts/serverFunctions";
const ITEMNAME = 'tnt';

View File

@@ -1,4 +1,4 @@
import { Command, sendMessage } from "commands";
import { Command, sendMessage } from "lib/commandUtils";
import { addAdmin } from "lib/admins";
import parseCommandArgs from "lib/parseCommandArgs";
import User from "user";

View File

@@ -1,5 +1,5 @@
import { redis } from "bun";
import { Command, sendMessage } from "commands";
import { redis } from "lib/redis";
import { Command, sendMessage } from "lib/commandUtils";
import parseCommandArgs from "lib/parseCommandArgs";
import { streamerUsers } from "main";
import User from "user";

View File

@@ -1,5 +1,5 @@
import { Command, sendMessage } from "commands";
import { addInvuln } from "lib/invuln";
import { Command, sendMessage } from "lib/commandUtils";
import parseCommandArgs from "lib/parseCommandArgs";
import User from "user";

View File

@@ -1,4 +1,4 @@
import { Command, sendMessage } from "commands";
import { Command, sendMessage } from "lib/commandUtils";
import { getUserRecord } from "db/dbUser";
import { changeBalance } from "lib/changeBalance";
import parseCommandArgs from "lib/parseCommandArgs";

View File

@@ -1,4 +1,4 @@
import { Command, sendMessage } from "commands";
import { Command, sendMessage } from "lib/commandUtils";
import { getUserRecord } from "db/dbUser";
import items, { changeItemCount } from "items";
import parseCommandArgs from "lib/parseCommandArgs";

View File

@@ -1,4 +1,4 @@
import { Command, sendMessage } from "commands";
import { Command, sendMessage } from "lib/commandUtils";
import { getKDLeaderboard } from "db/dbUser";
import User from "user";

View File

@@ -1,4 +1,4 @@
import { Command, sendMessage } from "commands";
import { Command, sendMessage } from "lib/commandUtils";
import { getTimeoutStats, getItemStats } from "lib/getStats";
import parseCommandArgs from "lib/parseCommandArgs";
import User from "user";

View File

@@ -1,4 +1,4 @@
import { Command, sendMessage } from "commands";
import { Command, sendMessage } from "lib/commandUtils";
import { getAnivTimeouts } from "db/dbAnivTimeouts";
import parseCommandArgs from "lib/parseCommandArgs";
import User from "user";

View File

@@ -1,6 +1,6 @@
import { Command, sendMessage } from "commands";
import { Command, sendMessage } from "lib/commandUtils";
import User from "user";
import { redis } from "bun";
import { redis } from "lib/redis";
export default new Command({
name: 'backshot',

View File

@@ -1,4 +1,4 @@
import { Command, sendMessage } from "commands";
import { Command, sendMessage } from "lib/commandUtils";
import parseCommandArgs from "lib/parseCommandArgs";
import items from "items";
import { getUserRecord, updateUserRecord } from "db/dbUser";

View File

@@ -1,5 +1,5 @@
import { redis } from "bun";
import { Command, sendMessage } from "commands";
import { redis } from "lib/redis";
import { Command, sendMessage } from "lib/commandUtils";
import parseCommandArgs from "lib/parseCommandArgs";
import { namedcheers } from "cheers";

View File

@@ -1,5 +1,6 @@
import { redis } from "bun";
import commands, { Command, sendMessage } from "commands";
import { redis } from "lib/redis";
import commands from "commands";
import { Command, sendMessage } from "lib/commandUtils";
import parseCommandArgs from "lib/parseCommandArgs";
export default new Command({

View File

@@ -1,4 +1,4 @@
import { Command, sendMessage } from "commands";
import { Command, sendMessage } from "lib/commandUtils";
import parseCommandArgs from "lib/parseCommandArgs";
import { disableRedeem, idMap, namedRedeems, sfxRedeems } from "pointRedeems";
import logger from "lib/logger";

View File

@@ -1,4 +1,4 @@
import { Command, sendMessage } from "commands";
import { Command, sendMessage } from "lib/commandUtils";
import { getUserRecord } from "db/dbUser";
import parseCommandArgs from "lib/parseCommandArgs";
import { changeBalance } from "lib/changeBalance";

View File

@@ -1,5 +1,5 @@
import { redis } from "bun";
import { Command, sendMessage } from "commands";
import { redis } from "lib/redis";
import { Command, sendMessage } from "lib/commandUtils";
import parseCommandArgs from "lib/parseCommandArgs";
import { namedcheers } from "cheers";

View File

@@ -1,5 +1,6 @@
import { redis } from "bun";
import commands, { Command, sendMessage } from "commands";
import { redis } from "lib/redis";
import { Command, sendMessage } from "lib/commandUtils";
import commands from "commands";
import parseCommandArgs from "lib/parseCommandArgs";
export default new Command({

View File

@@ -1,4 +1,4 @@
import { Command, sendMessage } from "commands";
import { Command, sendMessage } from "lib/commandUtils";
import logger from "lib/logger";
import parseCommandArgs from "lib/parseCommandArgs";
import { enableRedeem, idMap, namedRedeems, sfxRedeems } from "pointRedeems";

View File

@@ -1,4 +1,4 @@
import { Command, sendMessage } from "commands";
import { Command, sendMessage } from "lib/commandUtils";
import { timeout } from "lib/timeout";
export default new Command({

View File

@@ -1,4 +1,4 @@
import { Command, sendMessage } from "commands";
import { Command, sendMessage } from "lib/commandUtils";
import { getAdmins } from "lib/admins";
import User from "user";

View File

@@ -1,4 +1,4 @@
import { Command, sendMessage } from "commands";
import { Command, sendMessage } from "lib/commandUtils";
import { getUserRecord } from "db/dbUser";
import parseCommandArgs from "lib/parseCommandArgs";
import User from "user";

View File

@@ -1,5 +1,5 @@
import { redis } from "bun";
import { Command, sendMessage } from "commands";
import { redis } from "lib/redis";
import { Command, sendMessage } from "lib/commandUtils";
import parseCommandArgs from "lib/parseCommandArgs";
import { namedcheers } from "cheers";

View File

@@ -1,5 +1,6 @@
import { redis } from "bun";
import { basecommands, Command, sendMessage } from "commands";
import { redis } from "lib/redis";
import { Command, sendMessage } from "lib/commandUtils";
import { basecommands } from "commands";
import parseCommandArgs from "lib/parseCommandArgs";
export default new Command({

View File

@@ -1,4 +1,4 @@
import { Command, sendMessage } from "commands";
import { Command, sendMessage } from "lib/commandUtils";
import { getUserRecord } from "db/dbUser";
import parseCommandArgs from "lib/parseCommandArgs";
import User from "user";

View File

@@ -1,4 +1,4 @@
import { Command, sendMessage } from "commands";
import { Command, sendMessage } from "lib/commandUtils";
import { getInvulns } from "lib/invuln";
import User from "user";

View File

@@ -1,5 +1,5 @@
import { redis } from "bun";
import { Command, sendMessage } from "commands";
import { redis } from "lib/redis";
import { Command, sendMessage } from "lib/commandUtils";
import { getUserRecord, updateUserRecord } from "db/dbUser";
import itemMap, { type inventory, type items } from "items";
import { buildTimeString } from "lib/dateManager";
@@ -57,7 +57,7 @@ export default new Command({
if (Math.floor(Math.random() * 5) === 0) itemDiff.grenade! += 1; // 1 in 5
if (Math.floor(Math.random() * 5) === 0) itemDiff.blaster! += 1; // 1 in 5
if (Math.floor(Math.random() * 50) === 0) itemDiff.tnt! += 1; // 1 in 50
if (Math.floor(Math.random() * 250) === 0) itemDiff.silverbullet! += 1; // 1 in 250
if (Math.floor(Math.random() * 50) === 0) itemDiff.silverbullet! += 1; // 1 in 50
};
for (const [item, amount] of Object.entries(itemDiff) as [items, number][]) {

View File

@@ -1,4 +1,4 @@
import { Command, sendMessage } from "commands";
import { Command, sendMessage } from "lib/commandUtils";
import { itemObjectArray } from "items";
export default new Command({

View File

@@ -1,4 +1,4 @@
import { Command, sendMessage } from "commands";
import { Command, sendMessage } from "lib/commandUtils";
import { buildTimeString } from "lib/dateManager";
import parseCommandArgs from "lib/parseCommandArgs";
import User from "user";

View File

@@ -1,4 +1,4 @@
import { Command, sendMessage } from "commands";
import { Command, sendMessage } from "lib/commandUtils";
import { getUserRecord } from "db/dbUser";
import items, { changeItemCount } from "items";
import parseCommandArgs from "lib/parseCommandArgs";

View File

@@ -1,39 +1,4 @@
import { EventSubChannelChatMessageEvent } from "@twurple/eventsub-base";
import User from "user";
export type userType = 'chatter' | 'admin' | 'streamer' | 'moderator';
export type specialExecuteArgs = {
activation?: string;
};
export type commandOptions = {
name: string;
aliases: string[];
usertype: userType;
execution: (message: EventSubChannelChatMessageEvent, sender: User, args?: specialExecuteArgs) => Promise<void>;
disableable?: boolean;
specialaliases?: string[];
};
/** The Command class represents a command */
export class Command {
public readonly name: string;
public readonly aliases: string[];
public readonly usertype: userType;
public readonly disableable: boolean;
public readonly specialaliases: string[];
public readonly execute: (message: EventSubChannelChatMessageEvent, sender: User, args?: specialExecuteArgs) => Promise<void>;
constructor(options: commandOptions) {
this.name = options.name.toLowerCase();
this.aliases = options.aliases;
this.usertype = options.usertype;
this.execute = options.execution;
this.disableable = options.disableable ?? true;
this.specialaliases = options.specialaliases ?? [];
};
};
import { Command } from 'lib/commandUtils';
import { readdir } from 'node:fs/promises';
const commands = new Map<string, Command>; // This map has all command/item aliases mapped to commands/items (many-to-one)
const specialAliasCommands = new Map<string, Command>; // This map has all special command/item aliases mapped to commands/items (just like commands map)
@@ -63,14 +28,3 @@ for (const [alias, item] of Array.from(specialAliasItems)) {
export default commands;
export { specialAliasCommands, basecommands };
import { chatterApi, chatterId, streamerId } from "main";
/** Helper function to send a message to the stream */
export const sendMessage = async (message: string, replyParentMessageId?: string) => {
try {
return await chatterApi.chat.sendChatMessageAsApp(chatterId, streamerId, message, { replyParentMessageId });
} catch (e) {
return await chatterApi.chat.sendChatMessageAsApp(chatterId, streamerId, message);
};
};

View File

@@ -1,4 +1,4 @@
import { Command, sendMessage } from "commands";
import { Command, sendMessage } from "lib/commandUtils";
import items from "items";
import parseCommandArgs from "lib/parseCommandArgs";

View File

@@ -1,4 +1,4 @@
import { Command, sendMessage } from "commands";
import { Command, sendMessage } from "lib/commandUtils";
import parseCommandArgs from "lib/parseCommandArgs";
import User from "user";

View File

@@ -1,4 +1,4 @@
import { Command, sendMessage } from "commands";
import { Command, sendMessage } from "lib/commandUtils";
import { getKDLeaderboard } from "db/dbUser";
import User from "user";

View File

@@ -1,4 +1,4 @@
import { Command, sendMessage } from "commands";
import { Command, sendMessage } from "lib/commandUtils";
import { getTimeoutStats, getItemStats } from "lib/getStats";
import parseCommandArgs from "lib/parseCommandArgs";
import User from "user";

View File

@@ -1,4 +1,4 @@
import { Command, sendMessage } from "commands";
import { Command, sendMessage } from "lib/commandUtils";
import { getBalanceLeaderboard } from "db/dbUser";
import User from "user";

View File

@@ -1,4 +1,4 @@
import { Command, sendMessage } from "commands";
import { Command, sendMessage } from "lib/commandUtils";
import logger from "lib/logger";
import { streamerId } from "main";
import User from "user";

View File

@@ -1,4 +1,4 @@
import { Command, sendMessage } from "commands";
import { Command, sendMessage } from "lib/commandUtils";
import { streamerUsers } from "main";
import { removeAdmin } from "lib/admins";
import parseCommandArgs from "lib/parseCommandArgs";

View File

@@ -1,6 +1,6 @@
import { Command, sendMessage } from "commands";
import { Command, sendMessage } from "lib/commandUtils";
import { streamerUsers } from "main";
import { redis } from "bun";
import { redis } from "lib/redis";
import parseCommandArgs from "lib/parseCommandArgs";
import User from "user";

View File

@@ -1,4 +1,4 @@
import { Command, sendMessage } from "commands";
import { Command, sendMessage } from "lib/commandUtils";
import { streamerUsers } from "main";
import { removeInvuln } from "lib/invuln";
import parseCommandArgs from "lib/parseCommandArgs";

View File

@@ -1,5 +1,5 @@
import { Command, sendMessage } from "commands";
import { redis } from "bun";
import { Command, sendMessage } from "lib/commandUtils";
import { redis } from "lib/redis";
import { timeout } from "lib/timeout";
const barrelCount = 6;

View File

@@ -1,4 +1,4 @@
import { Command, sendMessage } from "commands";
import { Command, sendMessage } from "lib/commandUtils";
import { timeout } from "lib/timeout";
export default new Command({
@@ -8,7 +8,7 @@ export default new Command({
execution: async (msg, user) => {
const rand = Math.floor(Math.random() * 101);
if (rand > 75) await sendMessage(`${rand}% seiso YAAAA`, msg.messageId);
else if (rand > 51) await sendMessage(`${rand}% seiso POGGERS`, msg.messageId);
else if (rand > 50) await sendMessage(`${rand}% seiso POGGERS`, msg.messageId);
else if (rand === 50) await sendMessage(`${rand}% seiso ok`, msg.messageId);
else if (rand > 30) await sendMessage(`${rand}% seiso SWEAT`, msg.messageId);
else if (rand > 10) await sendMessage(`${rand}% seiso catErm`, msg.messageId);

View File

@@ -1,5 +1,5 @@
import { redis } from "bun";
import { Command, sendMessage } from "commands";
import { redis } from "lib/redis";
import { Command, sendMessage } from "lib/commandUtils";
import { isAdmin } from "lib/admins";
import parseCommandArgs from "lib/parseCommandArgs";

View File

@@ -1,4 +1,4 @@
import { Command, sendMessage } from "commands";
import { Command, sendMessage } from "lib/commandUtils";
import { handleCheer } from "events/message";
import parseCommandArgs from "lib/parseCommandArgs";

View File

@@ -1,9 +1,9 @@
import { redis } from "bun";
import { Command, sendMessage } from "commands";
import { redis } from "lib/redis";
import { Command, sendMessage } from "lib/commandUtils";
import items from "items";
import { isInvuln, removeInvuln } from "lib/invuln";
import { streamerUsers } from "main";
import getloot from "./getloot";
import getloot from "commands/getloot";
export default new Command({
name: 'use',
@@ -11,8 +11,8 @@ export default new Command({
usertype: 'chatter',
disableable: false,
specialaliases: ['i'],
execution: async (msg, user) => {
const messagequery = msg.messageText.trim().split(' ').slice(1);
execution: async (msg, user, specialargs) => {
const messagequery = msg.messageText.trim().split(' ').slice(1); // This selects the item, so on "i blast mrockstar20" it would pick ["blast", "mrockstar20"]
const silent = msg.messageText.toLowerCase().startsWith('i');
if (!messagequery[0]) { if (!silent) { await sendMessage('Please specify an item you would like to use', msg.messageId); }; return; };
const selection = items.get(messagequery[0].toLowerCase());
@@ -20,6 +20,6 @@ export default new Command({
if (!selection) { if (!silent) { await sendMessage(`'${messagequery[0]}' is not an item`, msg.messageId); }; return; };
if (await redis.sismember('disabledcommands', selection.name)) { await sendMessage(`The ${selection.prettyName} item is disabled`, msg.messageId); return; };
if (await isInvuln(msg.chatterId) && !streamerUsers.includes(msg.chatterId)) { await sendMessage(`You're no longer an invuln because you used an item.`, msg.messageId); await removeInvuln(msg.chatterId); };
await selection.execute(msg, user);
await selection.execute(msg, user, specialargs);
}
});

View File

@@ -1,5 +1,5 @@
import { redis } from "bun";
import { Command, sendMessage } from "commands";
import { redis } from "lib/redis";
import { Command, sendMessage } from "lib/commandUtils";
export default new Command({
name: 'vulnchatters',

View File

@@ -1,4 +1,4 @@
import { Command, sendMessage } from "commands";
import { Command, sendMessage } from "lib/commandUtils";
import { timeout } from "lib/timeout";
// Remake of the !yabai command in ttv/kiara_tv

View File

@@ -1,15 +1,10 @@
import * as schema from "db/schema";
import logger from "lib/logger";
const host = process.env.POSTGRES_HOST ?? "";
if (!host) { logger.enverr("POSTGRES_HOST"); process.exit(1); };
const user = process.env.POSTGRES_USER ?? "";
if (!user) { logger.enverr("POSTGRES_USER"); process.exit(1); };
const password = process.env.POSTGRES_PASSWORD ?? "";
if (!password) { logger.enverr("POSTGRES_USER"); process.exit(1); };
const database = process.env.POSTGRES_DB ?? "";
if (!database) { logger.enverr("POSTGRES_DB"); process.exit(1); };
const url = `postgresql://${user}:${password}@${host}/${database}`;
export const host = process.env.POSTGRES_HOST ?? "";
export const user = process.env.POSTGRES_USER ?? "";
export const password = process.env.POSTGRES_PASSWORD ?? "";
export const database = process.env.POSTGRES_DB ?? "";
export const url = `postgresql://${user}:${password}@${host}/${database}`;
import { drizzle } from 'drizzle-orm/bun-sql';
export default drizzle(url, { schema });
export default drizzle(url, { schema })

View File

@@ -1,8 +1,8 @@
import db from "db/connection";
import { timeouts, users } from "db/schema";
import { itemarray, type inventory } from "items";
import { itemarray } from "items";
import type User from "user";
import { count, desc, eq, inArray, sql, ne, between, and, SQL, type InferInsertModel, type InferSelectModel } from "drizzle-orm";
import { count, desc, eq, inArray, sql, ne, between, and, SQL, type InferSelectModel } from "drizzle-orm";
/** Use this function to both ensure existance and to retreive data */
export async function getUserRecord(user: User) {

View File

@@ -1,6 +1,7 @@
import { eventSub, streamerApi, streamerId } from "main";
import { streamerId } from "main";
import { deleteBannedUserMessagesFromChatWidget } from "web/chatWidget/message";
import { redis } from "bun";
import { eventSub, streamerApi } from "index";
import { redis } from "lib/redis";
eventSub.onChannelBan(streamerId, async msg => {
deleteBannedUserMessagesFromChatWidget(msg);

View File

@@ -1,6 +1,7 @@
import { sendMessage } from "commands";
import { sendMessage } from "lib/commandUtils";
import { eventSub } from "index";
import logger from "lib/logger";
import { eventSub, streamerId } from "main";
import { streamerId } from "main";
import { activeRedeems } from "pointRedeems";
import User from "user";

View File

@@ -1,4 +1,5 @@
import { eventSub, streamerId } from "main";
import { eventSub } from "index";
import { streamerId } from "main";
import { deleteMessageFromChatWidget } from "web/chatWidget/message";
eventSub.onChannelChatMessageDelete(streamerId, streamerId, async msg => {

View File

@@ -1,7 +1,8 @@
import { eventSub, chatterEventSub, streamerApi, streamerId, chatterApi, chatterId } from "main";
import { streamerId, chatterId } from "main";
import { HelixEventSubSubscription } from "@twurple/api";
import kleur from "kleur";
import logger from "lib/logger";
import { chatterApi, chatterEventSub, eventSub, streamerApi } from "index";
// This file is such a fucking disaster lmaooooo

View File

@@ -1,4 +1,4 @@
import { eventSub, chatterEventSub } from "main";
import { eventSub, chatterEventSub } from "index";
import { readdir } from 'node:fs/promises';
const files = await readdir(import.meta.dir);

View File

@@ -1,8 +1,8 @@
import { EventSubChannelChatMessageEvent } from "@twurple/eventsub-base"
import { streamerId, eventSub, commandPrefix, streamerUsers } from "main";
import { streamerId, commandPrefix, streamerUsers } from "main";
import User from "user";
import commands, { Command, sendMessage, specialAliasCommands } from "commands";
import { redis } from "bun";
import commands, { specialAliasCommands } from "commands";
import { Command, sendMessage } from "lib/commandUtils";
import { isAdmin } from "lib/admins";
import cheers from "cheers";
import logger from "lib/logger";
@@ -12,6 +12,8 @@ import { getUserRecord } from "db/dbUser";
import { createCheerRecord } from "db/dbCheers";
import handleAnivMessage from "lib/handleAnivMessage";
import { Item } from "items";
import { eventSub } from "index";
import { redis } from "lib/redis";
eventSub.onChannelChatMessage(streamerId, streamerId, parseChatMessage);

View File

@@ -1,5 +1,6 @@
import { redis } from "bun";
import { eventSub, streamerId } from "main";
import { eventSub } from "index";
import { redis } from "lib/redis";
import { streamerId } from "main";
eventSub.onChannelModeratorAdd(streamerId, async mod => {
await redis.set(`user:${mod.userId}:mod`, '1');

View File

@@ -1,10 +1,11 @@
import { redis } from "bun";
import { sendMessage } from "commands";
import { sendMessage } from "lib/commandUtils";
import { getUserRecord } from "db/dbUser";
import { eventSub, streamerApi } from "index";
import { changeItemCount } from "items";
import logger from "lib/logger";
import { eventSub, streamerApi, streamerId } from "main";
import { streamerId } from "main";
import User from "user";
import { redis } from "lib/redis";
eventSub.onChannelRaidTo(streamerId, async msg => {
if (await redis.exists(`user:${msg.raidingBroadcasterId}:recentraid`)) { await sendMessage(`Another raid from ${msg.raidedBroadcasterDisplayName}??? SMH`); return; };

View File

@@ -1,10 +1,13 @@
import { redis } from "bun";
import { sendMessage } from "commands";
import { eventSub, streamerId } from "main";
import { sendMessage } from "lib/commandUtils";
import { eventSub } from "index";
import { streamerId } from "main";
import { sendDiscordMessage } from "web/discordConnection";
import { redis } from "lib/redis";
eventSub.onStreamOnline(streamerId, async msg => {
await redis.set('streamIsLive', '1');
await sendMessage(`${msg.broadcasterDisplayName.toUpperCase()} IS LIVE! START DIGGING!`);
await sendDiscordMessage({ message: 'live' });
});
eventSub.onStreamOffline(streamerId, async msg => {

View File

@@ -1,9 +1,10 @@
import { redis } from "bun";
import { sendMessage } from "commands";
import { sendMessage } from "lib/commandUtils";
import { getUserRecord, updateUserRecord } from "db/dbUser";
import { eventSub } from "index";
import { changeBalance } from "lib/changeBalance";
import { eventSub, streamerId } from "main";
import { streamerId } from "main";
import User from "user";
import { redis } from "lib/redis";
eventSub.onChannelSubscription(streamerId, async msg => {
await redis.set(`user:${msg.userId}:subbed`, msg.tier.slice(0, 1));

View File

@@ -1,7 +1,8 @@
import { redis } from "bun";
import { sendMessage } from "commands";
import { sendMessage } from "lib/commandUtils";
import { chatterApi, chatterEventSub } from "index";
import { buildTimeString } from "lib/dateManager";
import { chatterEventSub, chatterApi, chatterId } from "main";
import { chatterId } from "main";
import { redis } from "lib/redis";
const WHISPERCOOLDOWN = 60 * 5; // 5 minutes

View File

@@ -1,25 +1,17 @@
import { createAuthProvider } from "./auth";
import { chatterId, streamerId, singleUserMode, streamerUsers } from "main";
import { ApiClient } from "@twurple/api";
import { EventSubWsListener } from "@twurple/eventsub-ws";
import { addAdmin } from "lib/admins";
import logger from "lib/logger";
import { addInvuln } from "lib/invuln";
import { redis } from "bun";
import { remodMod, timeoutDuration } from "lib/timeout";
import User from "user";
import { connectionCheck } from "connectionCheck";
import logger from "lib/logger";
import { redis } from "lib/redis";
import { createAuthProvider } from "auth";
import { EventSubWsListener } from "@twurple/eventsub-ws";
import { user, password, database, host } from "db/connection";
await connectionCheck();
const CHATTERINTENTS = ["user:read:chat", "user:write:chat", "user:bot", "user:manage:whispers"];
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", "channel:read:subscriptions", "channel:manage:redemptions"];
export const singleUserMode = process.env.CHATTER_IS_STREAMER === 'true';
export const chatterId = process.env.CHATTER_ID ?? "";
if (chatterId === "") { logger.enverr('CHATTER_ID'); process.exit(1); };
export const streamerId = process.env.STREAMER_ID ?? "";
if (streamerId === "") { logger.enverr('STREAMER_ID'); process.exit(1); };
export const chatterAuthProvider = await createAuthProvider(chatterId, singleUserMode ? CHATTERINTENTS.concat(STREAMERINTENTS) : CHATTERINTENTS);
export const streamerAuthProvider = singleUserMode ? undefined : await createAuthProvider(streamerId, STREAMERINTENTS, true);
@@ -34,11 +26,20 @@ export const eventSub = new EventSubWsListener({ apiClient: streamerApi });
export const chatterEventSub = singleUserMode ? eventSub : new EventSubWsListener({ apiClient: chatterApi });
export const commandPrefix = process.env.COMMAND_PREFIX ?? "!";
if (chatterId === "") { logger.enverr('CHATTER_ID'); process.exit(1); };
if (streamerId === "") { logger.enverr('STREAMER_ID'); process.exit(1); };
if (!user) { logger.enverr("POSTGRES_USER"); process.exit(1); };
if (!password) { logger.enverr("POSTGRES_USER"); process.exit(1); };
if (!database) { logger.enverr("POSTGRES_DB"); process.exit(1); };
if (!host) { logger.enverr("POSTGRES_HOST"); process.exit(1); };
if (!singleUserMode) await redis.set(`user:${chatterId}:bot`, '1');
export const streamerUsers = [chatterId, streamerId];
import { addAdmin } from "lib/admins";
import { addInvuln } from "lib/invuln";
import User from "user";
import { remodMod, timeoutDuration } from "lib/timeout";
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);
@@ -88,3 +89,4 @@ await import("./events");
await import("./pointRedeems");
await import("./web");

View File

@@ -1,5 +1,5 @@
import { changeItemCount, Item } from "items";
import { sendMessage } from "commands";
import { sendMessage } from "lib/commandUtils";
import { createTimeoutRecord } from "db/dbTimeouts";
import { createUsedItemRecord } from "db/dbUsedItems";
import { getUserRecord } from "db/dbUser";
@@ -17,8 +17,8 @@ export default new Item({
description: 'Times a specific person out for 60 seconds',
aliases: ['blaster', 'blast'],
price: 100,
execution: async (msg, user) => {
const messagequery = parseCommandArgs(msg.messageText);
execution: async (msg, user, specialargs) => {
const messagequery = parseCommandArgs(msg.messageText, specialargs?.activation);
if (!messagequery[0]) { await sendMessage('Please specify a target'); return; };
const target = await User.initUsername(messagequery[0].toLowerCase());
if (!target) { await sendMessage(`${messagequery[0]} doesn't exist`); return; };

View File

@@ -1,5 +1,5 @@
import { redis } from "bun";
import { sendMessage } from "commands";
import { redis } from "lib/redis";
import { sendMessage } from "lib/commandUtils";
import { timeout } from "lib/timeout";
import { changeItemCount, Item } from "items";
import User from "user";

View File

@@ -1,6 +1,6 @@
import { EventSubChannelChatMessageEvent } from "@twurple/eventsub-base";
import User from "user";
import { type userType, type specialExecuteArgs } from "commands";
import { type userType, type specialExecuteArgs } from "lib/commandUtils";
type itemOptions = {
name: items;

View File

@@ -1,5 +1,5 @@
import { changeItemCount, Item } from "items";
import { sendMessage } from "commands";
import { sendMessage } from "lib/commandUtils";
import { createTimeoutRecord } from "db/dbTimeouts";
import { createUsedItemRecord } from "db/dbUsedItems";
import { getUserRecord } from "db/dbUser";

View File

@@ -1,5 +1,5 @@
import { redis } from "bun";
import { sendMessage } from "commands";
import { redis } from "lib/redis";
import { sendMessage } from "lib/commandUtils";
import { timeout } from "lib/timeout";
import { changeItemCount, Item } from "items";
import User from "user";

View File

@@ -1,4 +1,4 @@
import { redis } from "bun";
import { redis } from "lib/redis";
export async function getAdmins() {
const data = await redis.keys('user:*:admin');

46
src/lib/commandUtils.ts Normal file
View File

@@ -0,0 +1,46 @@
import { EventSubChannelChatMessageEvent } from "@twurple/eventsub-base";
import User from "user";
import { chatterId, streamerId } from "main";
export type userType = 'chatter' | 'admin' | 'streamer' | 'moderator';
export type specialExecuteArgs = {
activation?: string;
};
export type commandOptions = {
name: string;
aliases: string[];
usertype: userType;
execution: (message: EventSubChannelChatMessageEvent, sender: User, args?: specialExecuteArgs) => Promise<void>;
disableable?: boolean;
specialaliases?: string[];
};
/** The Command class represents a command */
export class Command {
public readonly name: string;
public readonly aliases: string[];
public readonly usertype: userType;
public readonly disableable: boolean;
public readonly specialaliases: string[];
public readonly execute: (message: EventSubChannelChatMessageEvent, sender: User, args?: specialExecuteArgs) => Promise<void>;
constructor(options: commandOptions) {
this.name = options.name.toLowerCase();
this.aliases = options.aliases;
this.usertype = options.usertype;
this.execute = options.execution;
this.disableable = options.disableable ?? true;
this.specialaliases = options.specialaliases ?? [];
};
};
/** Helper function to send a message to the stream */
export const sendMessage = async (message: string, replyParentMessageId?: string) => {
const chatterApi = await import("index").then(m => m.chatterApi);
try {
return await chatterApi.chat.sendChatMessageAsApp(chatterId, streamerId, message, { replyParentMessageId });
} catch (e) {
return await chatterApi.chat.sendChatMessageAsApp(chatterId, streamerId, message);
};
};

View File

@@ -1,8 +1,8 @@
import { EventSubChannelChatMessageEvent } from "@twurple/eventsub-base"
import { redis } from "bun";
import { redis } from "lib/redis";
import type User from "user";
import { timeout } from "lib/timeout";
import { sendMessage } from "commands";
import { sendMessage } from "lib/commandUtils";
import { createAnivTimeoutRecord } from "db/dbAnivTimeouts";
const ANIVNAMES: anivBots[] = ['a_n_e_e_v', 'a_n_i_v'];

View File

@@ -1,4 +1,4 @@
import { redis } from "bun";
import { redis } from "lib/redis";
import { streamerUsers } from "main";
export async function getInvulns() {

View File

@@ -6,6 +6,7 @@ export default function parseCommandArgs(input: string, specialAlias?: string) {
let sliceLength = 0;
if (specialAlias) {
nice = input.toLowerCase().slice(specialAlias.length).replace(/[^\x00-\x7F]/g, '').trim();
sliceLength = input.toLowerCase().startsWith('i') ? 1 : 0;
} else {
nice = input.toLowerCase().slice(commandPrefix.length).replace(/[^\x00-\x7F]/g, '').trim();
sliceLength = nice.startsWith('use') ? 2 : 1;

3
src/lib/redis.ts Normal file
View File

@@ -0,0 +1,3 @@
import { RedisClient } from "bun";
export const redis = new RedisClient();

View File

@@ -1,8 +1,9 @@
import { streamerApi, streamerId } from "main";
import { streamerId } from "main";
import logger from "lib/logger";
import User from "user";
import { isInvuln } from "lib/invuln";
import { redis } from "bun";
import { streamerApi } from "index";
import { redis } from "lib/redis";
type SuccessfulTimeout = { status: true; };
type UnSuccessfulTimeout = { status: false; reason: 'banned' | 'unknown' | 'illegal'; };

5
src/main.ts Normal file
View File

@@ -0,0 +1,5 @@
export const singleUserMode = process.env.CHATTER_IS_STREAMER === 'true';
export const chatterId = process.env.CHATTER_ID ?? "";
export const streamerId = process.env.STREAMER_ID ?? "";
export const commandPrefix = process.env.COMMAND_PREFIX ?? "!";
export const streamerUsers = [chatterId, streamerId];

View File

@@ -54,8 +54,9 @@ const activeRedeems = new Map<string, PointRedeem>;
/** Map of redeemname to twitch redeem ID */
const idMap = new Map<string, string>;
import { streamerApi, streamerId } from "main";
import { streamerId } from "main";
import logger from "lib/logger";
import { streamerApi } from "index";
const currentRedeems = new Map<string, string>;
await streamerApi.channelPoints.getCustomRewards(streamerId).then(a => a.map(b => currentRedeems.set(b.title, b.id)));

View File

@@ -1,4 +1,4 @@
import { sendMessage } from "commands";
import { sendMessage } from "lib/commandUtils";
import { getUserRecord } from "db/dbUser";
import { changeBalance } from "lib/changeBalance";
import PointRedeem from "pointRedeems";

View File

@@ -1,5 +1,5 @@
import { redis } from "bun";
import { chatterApi } from "main";
import { redis } from "lib/redis";
import { chatterApi } from "index";
import { HelixUser } from "@twurple/api"
import logger from "lib/logger";

View File

@@ -1,5 +1,6 @@
import { streamerId, chatterApi } from "main";
import { redis } from "bun";
import { streamerId } from "main";
import { chatterApi } from "index";
import { redis } from "lib/redis";
type badgeObject = {
[key: string]: {

View File

@@ -0,0 +1,17 @@
import server from "web";
type liveMessage = {
message: 'live';
};
type offlineMessage = {
message: 'offline';
};
export type discordMessage =
| liveMessage
| offlineMessage;
export async function sendDiscordMessage(message: discordMessage) {
server.publish('discordbot', JSON.stringify(message));
};

View File

@@ -60,4 +60,3 @@ export default Bun.serve({
return new Response("Internal Server Error", { status: 500 })
},
});