diff --git a/README.md b/README.md index e3d895e..12f8c36 100644 --- a/README.md +++ b/README.md @@ -161,7 +161,7 @@ COMMAND|FUNCTION|USER|ALIASES|DISABLEABLE NAME|COMMAND|FUNCTION|ALIASES|COST -|-|-|-|- Blaster|`blaster {target}`|Times targeted user out for 60 seconds|`blaster` `blast`|100 -Silver Bullet|`silverbullet {target}`|Times targeted user out for 24 hours|`silverbullet` `execute` `{blastin}`|6666 +Silver Bullet|`silverbullet {target}`|Times targeted user out for 30 minutes|`silverbullet` `execute` `{blastin}`|666 Grenade|`grenade`|Times a random vulnerable chatter out for 60 seconds|`grenade`|99 TNT|`tnt`|Give 5-10 random chatters 60 second timeouts|`tnt`|1000 @@ -171,5 +171,5 @@ NAME|AMOUNT|USAGE|FUNCTION -|-|-|- `grenade`|99|`cheer99`|Times a random vulnerable chatter out for 60 seconds. Of failure gives cheerer a grenade `timeout`|100|`cheer100 {target}`|Times specified user out for 1 minute. On failure gives cheerer a blaster +`execute`|666|`cheer666 {target}`|Times specified user out for 30 minutes. On failure gives cheerer a silver bullet `tnt`|1000|`cheer1000`|Gives 5-10 random vulnerable chatters 60 second timeouts. On failure gives cheerer a TNT -`execute`|6666|`cheer6666 {target}`|Times specified user out for 24 hours. On failure gives cheerer a silver bullet diff --git a/src/cheers/execute.ts b/src/cheers/execute.ts index 8ec6db9..0e57832 100644 --- a/src/cheers/execute.ts +++ b/src/cheers/execute.ts @@ -10,14 +10,14 @@ import { playAlert } from "web/alerts/serverFunctions"; const ITEMNAME = 'silverbullet'; -export default new Cheer('execute', 6666, async (msg, user) => { +export default new Cheer('execute', 666, async (msg, user) => { const args = parseCheerArgs(msg.messageText); if (!args[0]) { await handleNoTarget(msg, user, ITEMNAME, false); return; }; const target = await User.initUsername(args[0].toLowerCase()); if (!target) { await handleNoTarget(msg, user, ITEMNAME, false); return; }; 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 * 30); if (result.status) await Promise.all([ sendMessage(`${target.displayName} RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO`), createTimeoutRecord(user, target, ITEMNAME), diff --git a/src/connectionCheck.ts b/src/connectionCheck.ts index 856852b..f305748 100644 --- a/src/connectionCheck.ts +++ b/src/connectionCheck.ts @@ -10,7 +10,7 @@ export async function connectionCheck() { pgstatus = true; } catch { }; const tempclient = new RedisClient(undefined, { - connectionTimeout: 100, + connectionTimeout: 200, maxRetries: 1, }); let redisstatus = false; diff --git a/src/events/channelPoints.ts b/src/events/channelPoints.ts new file mode 100644 index 0000000..6644a09 --- /dev/null +++ b/src/events/channelPoints.ts @@ -0,0 +1,18 @@ +import { sendMessage } from "commands"; +import logger from "lib/logger"; +import { eventSub, streamerId } from "main"; +import { activeRedeems } from "pointRedeems"; +import User from "user"; + +eventSub.onChannelRedemptionAdd(streamerId, async msg => { + const selection = activeRedeems.get(msg.rewardId); + if (!selection) { logger.warn(`Can't find the ${msg.rewardTitle} redeem`); return; }; + const user = await User.initUsername(msg.userName); + try { + await selection.execute(msg, user!); + await msg.updateStatus('FULFILLED'); + } catch (err) { + await sendMessage(`[ERROR]: Something went wrong with ${user?.displayName}'s redeem!`); + logger.err(err as string); + }; +}); diff --git a/src/index.ts b/src/index.ts index f835ee3..065c8b2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -12,7 +12,7 @@ import { connectionCheck } from "connectionCheck"; 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"]; +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 ?? ""; @@ -72,4 +72,6 @@ if (streamdata) await redis.set('streamIsLive', '1'); await import("./events"); +await import("./pointRedeems"); + await import("./web"); diff --git a/src/items/silverbullet.ts b/src/items/silverbullet.ts index 32b6b30..a92fc5d 100644 --- a/src/items/silverbullet.ts +++ b/src/items/silverbullet.ts @@ -14,10 +14,10 @@ export default new Item({ name: ITEMNAME, prettyName: 'Silver bullet', plural: 's', - description: 'Times a specific person out for 24 hours', + description: 'Times a specific person out for 30 minutes', aliases: ['execute', 'silverbullet'], specialaliases: ['blastin'], - price: 6666, + price: 666, execution: async (msg, user, specialargs) => { const messagequery = parseCommandArgs(msg.messageText, specialargs?.activation); if (!messagequery[0]) { await sendMessage('Please specify a target'); return; }; @@ -31,7 +31,7 @@ export default new Item({ const userObj = await getUserRecord(user); if (userObj.inventory[ITEMNAME]! < 1) { await sendMessage(`You don't have any silver bullets!`, msg.messageId); await user.clearLock(); return; }; - const result = await timeout(target, `You got blasted by ${user.displayName}!`, 60 * 60 * 24); + const result = await timeout(target, `You got blasted by ${user.displayName}!`, 60 * 30); if (result.status) await Promise.all([ sendMessage(`${target.displayName} RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO`), changeItemCount(user, userObj, ITEMNAME), diff --git a/src/pointRedeems/index.ts b/src/pointRedeems/index.ts new file mode 100644 index 0000000..3de1564 --- /dev/null +++ b/src/pointRedeems/index.ts @@ -0,0 +1,77 @@ +import { EventSubChannelRedemptionAddEvent } from "@twurple/eventsub-base"; +import User from "user"; + +export type pointRedeemOptions = { + name: string; + title: string; + prompt?: string; + cost: number; + color?: string; + execution: (message: EventSubChannelRedemptionAddEvent, sender: User) => Promise; +}; + +/** The Command class represents a command */ +export default class PointRedeem { + public readonly name: string; + public readonly title: string; + public readonly prompt?: string; + public readonly cost: number; + public readonly color?: string; + public readonly execute: (message: EventSubChannelRedemptionAddEvent, sender: User) => Promise; + constructor(options: pointRedeemOptions) { + this.name = options.name + this.title = options.title; + this.prompt = options.prompt; + this.cost = options.cost; + this.color = options.color; + this.execute = options.execution; + }; +}; + +import { readdir } from 'node:fs/promises'; + +const pointRedeems = new Map; + +/** A map of all (including inactive) redeems mapped to names */ +const namedRedeems = new Map; + +const files = await readdir(import.meta.dir); +for (const file of files) { + if (!file.endsWith('.ts')) continue; + if (file === import.meta.file) continue; + const redeem: PointRedeem = await import(import.meta.dir + '/' + file.slice(0, -3)).then(a => a.default); + pointRedeems.set(redeem.cost, redeem); + namedRedeems.set(redeem.name, redeem); +}; + +export { namedRedeems }; + +const activeRedeems = new Map; + +import { streamerApi, streamerId } from "main"; +import logger from "lib/logger"; + +const currentRedeems = new Map; +await streamerApi.channelPoints.getCustomRewards(streamerId).then(a => a.map(b => currentRedeems.set(b.title, b.id))); +for (const [_, redeem] of Array.from(pointRedeems)) { + const selection = currentRedeems.get(redeem.title); + if (selection) { + currentRedeems.delete(redeem.title); + activeRedeems.set(selection, redeem); + } else { + const creation = await streamerApi.channelPoints.createCustomReward(streamerId, { + title: redeem.title, + prompt: redeem.prompt, + cost: redeem.cost, + backgroundColor: redeem.color + }); + logger.ok(`Created custom point redeem ${redeem.title}`); + activeRedeems.set(creation.id, redeem); + }; +}; + +Array.from(currentRedeems).map(async ([title, redeem]) => { await streamerApi.channelPoints.deleteCustomReward(streamerId, redeem); logger.ok(`Deleted custom point redeem ${title}`); }); + +logger.ok("Successfully synced all custom point redeems"); + +export { activeRedeems }; diff --git a/src/pointRedeems/qbucksredeem.ts b/src/pointRedeems/qbucksredeem.ts new file mode 100644 index 0000000..713be35 --- /dev/null +++ b/src/pointRedeems/qbucksredeem.ts @@ -0,0 +1,16 @@ +import { sendMessage } from "commands"; +import { getUserRecord } from "db/dbUser"; +import { changeBalance } from "lib/changeBalance"; +import PointRedeem from "pointRedeems"; + +export default new PointRedeem({ + name: "qbucksredeem", + title: "FREE MONEY", + prompt: "GET 100 QBUCKS!", + color: '#00FF00', + cost: 1000, + execution: async (_msg, user) => { + await changeBalance(user, await getUserRecord(user), 100); + await sendMessage(`${user.displayName} got 100 qbucks for their point redeem`); + } +}) diff --git a/tsconfig.json b/tsconfig.json index a43e69e..faf5091 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,18 +3,41 @@ "compilerOptions": { "baseUrl": "./src", "paths": { - "lib/*": ["./lib/*"], - "main": ["./index.ts"], - "user": ["./user.ts"], - "commands": ["./commands/index.ts"], - "items": ["./items/index.ts"], - "cheers": ["./cheers/index.ts"], - "events": ["./events/index.ts"], - "web/*": ["./web/*"] + "lib/*": [ + "./lib/*" + ], + "main": [ + "./index.ts" + ], + "user": [ + "./user.ts" + ], + "commands": [ + "./commands/index.ts" + ], + "items": [ + "./items/index.ts" + ], + "cheers": [ + "./cheers/index.ts" + ], + "events": [ + "./events/index.ts" + ], + "web/*": [ + "./web/*" + ], + "pointRedeems": [ + "./pointRedeems/index.ts" + ] } }, "references": [ - { "path": "./tsconfig.bot.json" }, - { "path": "./tsconfig.web.json" } + { + "path": "./tsconfig.bot.json" + }, + { + "path": "./tsconfig.web.json" + } ] }