Customizable Rust Twitch Bot
Find a file
2025-02-03 21:34:57 -05:00
forcebot_core debug module and fix issue with modules 2025-02-03 21:34:57 -05:00
moderator_reactor debug module and fix issue with modules 2025-02-03 21:34:57 -05:00
new_empty_bot debug module and fix issue with modules 2025-02-03 21:34:57 -05:00
simple_command_bot debug module and fix issue with modules 2025-02-03 21:34:57 -05:00
simple_debug_listener debug module and fix issue with modules 2025-02-03 21:34:57 -05:00
simple_module_example debug module and fix issue with modules 2025-02-03 21:34:57 -05:00
.gitignore custom pyramid 2025-01-31 13:25:09 -05:00
Cargo.lock reorg workspaces 2025-02-02 17:01:54 -05:00
Cargo.toml reorg workspaces 2025-02-02 17:01:54 -05:00
readme.md debug module and fix issue with modules 2025-02-03 21:34:57 -05:00

Customizable Twitch chat bot written in rust

Quick Start

Run a Simple bot with Built in functionality

  1. Generate a twitch access token

  2. Define an .env file with the following

login_name=BOTNAME
access_token=ACCESS_TOKEN
bot_channels=BOTNAME
prefix=`
bot_admins=ADMIN
  1. Build & run
cargo run -p forcebot_core 

Features

  • Quick Start to use full feature set bot
  • Moderators & Broadcasters can disable or enable Modules of bot functionality through chat Commands
  • Full Feature Set forcebot_core bot has the following modules loaded
    • debug - outputs to console messages from the channel where it was enabled. Toggle debug with the Commands debug on or debug off
    • guest_badge - Temporary badges can be issued to chatters
    • besty - Tomfoolery
    • pyramid - for detecting & handling pyramids
  • forcebot_core library API provides Custom package developers a way to add functionality by adding Modules that contain Bot Objects like Commands and Listeners
  • Listeners and Commands listen for a defined callback trigger condition and run an defined execution callback
  • Commands are similar to Listeners with refined trigger conditions including using bot prefix with the Command , triggers based on Badge , and more
  • Workspace for package developers to independently code their own Modules
  • Workspace comes with binary crates with working or example bots that use forcebot_core library
    • moderator_reactor - bot kneels to all moderator messages
    • simple_module_example - bot has a test Module with a test Command .Moderators & Broadcasters can manage the Module in chat with enable / disable Commands
    • new_empty_bot - while empty, has disable and enable chat Commands . This is an example of the bot without any loaded modules
    • simple_command_bot - bot responds to a test Command. As the command was not loaded through a Module, disable & enable commands don't work on the test command. This could be a Global Command
    • simple_debug_listener - bot outputs all twitch ServerMessages received to terminal

Example Bots

Use the following to build and run built-in bots. No coding required!

New Empty Bot

Run an empty simple bot that logs into chat and has minimum built in functions

cargo run -p new_empty_bot

Run a forcebot with fun catered customizations

cargo run -p forcebot_core 

Simple Debug Listener

Run a bot that listens to all messages and output to console

cargo run -p simple_debug_listener

Simple Command Bot

Run a bot that uses the test chat Command . Commands are prefixed and must be ran by a chatter with a vip badge or above

cargo run -p simple_command_bot

Moderator Reactor

Run a bot that listens for messages with the moderator badge, and replies to that mod with an emote

cargo run -p moderator_reactor

Module loaded Bot

Run a bot that has a test chat Command. As the command was loaded through a module, moderators or broadcastors can enable or disable the module through chat commands

cargo run -p simple_module_example

Workspace packages

Source is a workspace of packages . In particular, forcebot_core is the main library crate to use

TIP : if you want to start customizing you own bot, create a binary package in the workspace for your bot's binary crate

More info about workspaces - https://doc.rust-lang.org/book/ch14-03-cargo-workspaces.html

Creating a new package

To create a new package

  1. Create a new package

For example, to create a new binary crate in the workspace

cargo new my_new_bot
  1. In the newly created directory for your package, adjust the Cargo.toml to the following
[dependencies]
forcebot_core = {path = "../forcebot_core"}
dotenv = "0.15.0"
lazy_static = "1.5.0"
tokio = { version = "1.33.0", features = ["full"] }
twitch-irc = "5.0.1"
  1. Copy main.rs from the new_empty_bot package into your package

  2. Optionally, customize your main() to load modules before starting the bot

  3. Build and run your package

cargo run -p my_new_bot

Example Code

New Bot

Uses Env defined variables to create and run the bot

use forcebot_core::Bot;

#[tokio::main]
pub async fn main() {

    /* 1. Create the bot using env */
    let bot = Bot::new();

    /* 2. Run the bot */
    bot.run().await;

}

Customize by Loading Custom Modules

A Module is a group of bot objects (eg Command) that elevated users can manage through built in disable and enable commands

Custom Modules can be loaded into a new bot with minimum coding : just load the modules and run the bot

use forcebot_core::{custom_mods::{guest_badge, pyramid}, Bot};


#[tokio::main]
pub async fn main() {

    /* 1. Create the bot using env */
    let mut bot = Bot::new();

    /* 2. Load Custom Modules */
    bot.load_module(guest_badge::create_module()).await;
    bot.load_module(pyramid::create_module()).await;
    
    /* 3. Run the bot */
    bot.run().await;

}

Create your own Custom Modules

Create a custom Module by :

  1. Defining Functions that create the Custom Bot Objects (eg Command)

  2. Define a function that creates a Module with the Custom Bot Objects loaded

use forcebot_core::Bot;

#[tokio::main]
pub async fn main() {

    /* Create the bot using env */
    let mut bot = Bot::new();

    /* load the Module */
    bot.load_module(custom_mod::new()).await;

    /* Run the bot */
    bot.run().await;

}

pub mod custom_mod {
    use std::sync::Arc;

    use forcebot_core::{execution_async, Badge, Bot, Command, Module};
    use twitch_irc::message::ServerMessage;


    /// Module definition with a loaded command
    pub fn new() -> Module {
        /* 1. Create a new module */
        let mut custom_mod = Module::new(
            vec!["test".to_string()], 
            "".to_string());

        /* 2. Load the cmd into a new module */
        custom_mod.load_command(cmd_test());

        custom_mod

    }

    /// Command definition 
    pub fn cmd_test() -> Command {
        /* 1. Create a new cmd */
        let mut cmd = Command::new(vec!["test".to_string()],"".to_string());

        /* 2. Define exec callback  */
        async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
            if let ServerMessage::Privmsg(msg) = message {
                let _= bot.client.say_in_reply_to(
                    &msg, "test return".to_string()).await;
            }
            Result::Err("Not Valid message type".to_string()) 
        }

        /* 3. Set Command flags */
        cmd.set_exec_fn(execution_async(execbody));
        cmd.set_admin_only(false);
        cmd.set_min_badge(Badge::Moderator);

        cmd
    }
}

Simple Debug Listener

Bot with a simple listener that listens for all messages and prints in output

use std::sync::Arc;

use forcebot_core::{execution_async, Bot, Listener};
use twitch_irc::message::ServerMessage;

#[tokio::main]
pub async fn main() {

    /* 1. Create the bot using env */
    let mut bot = Bot::new();

    /* 2a. Create a new blank Listener */
    let mut listener = Listener::new();

    /* 2b. Set a trigger condition function for listener */
    listener.set_trigger_cond_fn(
        |_:Arc<Bot>,_:ServerMessage| true
    );

    /* 2c. Define an async fn callback execution */
    async fn execbody(_:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
        dbg!(message); /* outputs message to debug */
        Result::Ok("Success".to_string()) 
    }

    /* 2d. Set and Store the execution body using `execution_async()`  */
    listener.set_exec_fn(execution_async(execbody));

    /* 3. Load the listener into the bot */
    bot.load_listener(listener);

    /* 4. Run the bot */
    bot.run().await;

}

Moderator Reactor

Example listener listens for a moderator badge and reply in chat

use std::sync::Arc;

use forcebot_core::Bot;
use forcebot_core::execution_async;
use forcebot_core::Listener;
use twitch_irc::message::ServerMessage;


#[tokio::main]
pub async fn main() {

    /* Create the bot using env */
    let mut bot = Bot::new();

    /* 1. Create a new blank Listener */
    let mut listener = Listener::new();

    /* 2. Set a trigger condition function for listener */

    listener.set_trigger_cond_fn(
        |_:Arc<Bot>,message:ServerMessage| 
            if let ServerMessage::Privmsg(msg) = message {
                
                for badge in msg.badges {
                    if matches!(badge, x if x.name == "moderator") {
                        // dbg!("moderator found");
                        return true;
                    }
                } 
                false
            } else { false }
    );

    /* 3. Define an async fn callback execution */
    async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
        if let ServerMessage::Privmsg(msg) = message {
            let _ = bot.client.say_in_reply_to(&msg, "pepeKneel".to_string()).await ;
            return Result::Ok("Success".to_string()) ;
        }
        Result::Err("Not Valid message type".to_string()) 
    }

    /* 4. Set and Store the execution body using `execution_async()`  */
    listener.set_exec_fn(execution_async(execbody));

    /* 5. Load the listener into the bot */
    bot.load_listener(listener);

    /* Run the bot */
    bot.run().await;

}

Simple Test Command

use std::sync::Arc;

use forcebot_core::Badge;
use forcebot_core::Bot;
use forcebot_core::execution_async;
use forcebot_core::Command;
use twitch_irc::message::ServerMessage;

#[tokio::main]
pub async fn main() {

    /* Create the bot using env */
    let mut bot = Bot::new();

    /* 1. Create a new blank cmd */
    let mut cmd = Command::new(vec!["test".to_string()],"".to_string());

    /* 2. Define an async fn callback execution */
    async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
        if let ServerMessage::Privmsg(msg) = message {
            let _ = bot.client.say_in_reply_to(&msg, String::from("test success")).await;
            return Result::Ok("Success".to_string()) ;
        }
        Result::Err("Not Valid message type".to_string()) 
    }

    /* 3. Set and Store the execution body using `execution_async()`  */
    cmd.set_exec_fn(execution_async(execbody));

    /* 4. optionally, remove admin only default flag */
    cmd.set_admin_only(false);

    /* 5. optionally, set min badge*/
    cmd.set_min_badge(Badge::Moderator);

    /* 6. Load the cmd into the bot */
    bot.load_command(cmd);

    /* Run the bot */
    bot.run().await;

}

Crate Rust API Documentation

Create forcebot_rs_v2 Rust Crate documentation

Documentation - Clean Build & Open in Default Browser

cargo clean && cargo doc --open