Last active
March 23, 2024 08:16
-
-
Save PCDSandwichMan/24576752644d12a81cc07b29a0bc7d39 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Description: | |
This is a simple Twitch bot script that allows users to enter a giveaway, | |
pick a winner, and view the list of entered users. | |
Usage: | |
1. Locally install tmi.js and ts-node via npm (or similar package manager) | |
2. Replace <ADD_USERNAME_HERE> with your Twitch username that will act as the bot | |
3. Replace <ADD_TOKEN_HERE> with your oauth token (https://twitchapps.com/tmi/) | |
4. Run the script with ts-node - ts-node giveaway-bot.ts | |
Faq: | |
Q: How do I get my oauth token? | |
A: The easiest way to get your oauth token is to go to https://twitchapps.com/tmi/ | |
*/ | |
import tmi, { ChatUserstate } from "tmi.js"; | |
/** | |
* ---------------------------------- | |
* INITIALIZE THE TWITCH CONNECTION | |
* ---------------------------------- | |
**/ | |
const clientConfig = { | |
identity: { | |
username: "<ADD_USERNAME_HERE>", // Your Twitch username | |
password: "<ADD_TOKEN_HERE>", // The easiest way to get your oauth token is to go to https://twitchapps.com/tmi/ | |
}, | |
channels: ["thevioletneko"], | |
}; | |
const client = new tmi.client(clientConfig); | |
// @ts-ignore | |
client.on("connected", onConnectedHandler); | |
client.connect(); | |
/** | |
* ---------------------- | |
* INITIALIZE THE BOT | |
* ---------------------- | |
**/ | |
client.on("chat", async (_channel, userState, message, self) => { | |
if (self) return; | |
console.log(`${userState.username}: ${message}`); | |
const args = message.trim().split(/\s+/); | |
const command = args.shift()?.toLowerCase(); | |
switch (command) { | |
case "!misc": | |
await handleMiscCommand(_channel, args, userState); | |
break; | |
case "!help": | |
await handleHelpCommand(_channel); | |
break; | |
case "!enter": | |
await handleEnterCommand(_channel, userState); | |
break; | |
case "!pick": | |
await handlePickCommand(_channel, userState); | |
break; | |
case "!user-pool": | |
await handleUserPoolCommand(_channel); | |
break; | |
case "!clear": | |
await handleClearCommand(_channel, userState); | |
break; | |
} | |
}); | |
/** | |
* ------------------- | |
* HELPER FUNCTIONS | |
* ------------------- | |
**/ | |
const enteredUsers = new Set<string>(); | |
/** | |
* Handles when the client connects to Twitch. | |
* | |
* @param {string} addr - The server address. | |
* @param {number} port - The server port. | |
*/ | |
function onConnectedHandler(addr: string, port: string) { | |
console.log(`* Connected to ${addr}:${port}`); | |
} | |
/** | |
* Handles miscellaneous commands based on the given subCommand. | |
* | |
* @param {string} channel - The channel where the command is executed. | |
* @param {string} subCommand - The subcommand to handle. | |
* @param {ChatUserstate} userState - The user state object. | |
* @returns {Promise<void>} - A promise that resolves when the command handling is complete. | |
*/ | |
async function handleMiscCommand( | |
channel: string, | |
args: string[], | |
userState: ChatUserstate | |
) { | |
const subCommand = args.shift()?.toLowerCase(); | |
switch (subCommand) { | |
case "ping": | |
await client.say(channel, `Hello ${userState.username} 🥪`); | |
break; | |
} | |
} | |
/** | |
* Handles the help command by sending a message with the available commands to the specified channel. | |
* | |
* @param {string} channel - The channel where the command is executed. | |
* @returns {Promise<void>} - A promise that resolves when the help message is sent. | |
*/ | |
async function handleHelpCommand(channel: string) { | |
await client.say( | |
channel, | |
`Available commands: !misc, !enter, !pick, !user-pool, !clear` | |
); | |
} | |
/** | |
* Handles the enter command for the giveaway. | |
* | |
* @param {string} channel - The channel where the command is executed. | |
* @param {ChatUserstate} userState - The user state object containing information about the user. | |
* @returns {Promise<void>} - A promise that resolves when the command is handled. | |
*/ | |
async function handleEnterCommand(channel: string, userState: ChatUserstate) { | |
enteredUsers.add(userState.username!); | |
await client.say(channel, `${userState.username} has entered the giveaway!`); | |
} | |
/** | |
* Handles the pick command to select a winner for the giveaway. | |
* Only the broadcaster or moderators can pick a winner. | |
* | |
* @param {string} channel - The channel where the command is executed. | |
* @param {ChatUserstate} userState - The user state of the command executor. | |
* @returns {Promise<void>} - A promise that resolves when the winner is announced. | |
*/ | |
async function handlePickCommand(channel: string, userState: ChatUserstate) { | |
if ( | |
userState.mod || | |
userState["user-type"] === "mod" || | |
userState.username === channel.replace("#", "") | |
) { | |
if (enteredUsers.size > 0) { | |
const randomUser = | |
Array.from(enteredUsers)[Math.floor(Math.random() * enteredUsers.size)]; | |
await client.say( | |
channel, | |
`🎉 Congratulations ${randomUser}, you won the giveaway!` | |
); | |
} else { | |
await client.say(channel, "No users have entered the giveaway yet."); | |
} | |
} else { | |
await client.say( | |
channel, | |
"Sorry, only the broadcaster or moderators can pick a winner." | |
); | |
} | |
} | |
/** | |
* Handles the user pool command by sending a message to the specified channel | |
* with the list of entered users or a message indicating that no users have entered yet. | |
* | |
* @param {string} channel - The channel to send the message to. | |
* @returns {Promise<void>} - A promise that resolves when the message is sent. | |
*/ | |
async function handleUserPoolCommand(channel: string) { | |
if (enteredUsers.size > 0) { | |
const userList = Array.from(enteredUsers).join(", "); | |
await client.say(channel, `Entered users: ${userList}`); | |
} else { | |
await client.say(channel, "No users have entered the giveaway yet."); | |
} | |
} | |
/** | |
* Clears the entered users list and sends a message in the channel. | |
* Only the broadcaster or moderators can clear the entered users. | |
* | |
* @param {string} channel - The channel name. | |
* @param {ChatUserstate} userState - The user state object. | |
* @returns {Promise<void>} - A promise that resolves when the entered users list is cleared. | |
*/ | |
async function handleClearCommand(channel: string, userState: ChatUserstate) { | |
if ( | |
userState.mod || | |
userState["user-type"] === "mod" || | |
userState.username === channel.replace("#", "") | |
) { | |
enteredUsers.clear(); | |
await client.say(channel, "The entered users list has been cleared."); | |
} else { | |
await client.say( | |
channel, | |
"Sorry, only the broadcaster or moderators can clear the entered users." | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment