446 lines
11 KiB
Markdown
446 lines
11 KiB
Markdown
Customizable Twitch chat bot written in rust
|
|
|
|
# Quick Start
|
|
|
|
Run a Simple bot with Built in functionality
|
|
|
|
1. Generate a twitch access token
|
|
|
|
- Get a Bot Chat Token here - https://twitchtokengenerator.com
|
|
- More Info - https://dev.twitch.tv/docs/authentication
|
|
|
|
2. Define an `.env` file with the following
|
|
|
|
```
|
|
login_name=BOTNAME
|
|
access_token=ACCESS_TOKEN
|
|
bot_channels=BOTNAME
|
|
prefix=`
|
|
bot_admins=ADMIN
|
|
```
|
|
|
|
3. Build & run
|
|
|
|
```
|
|
cargo run -p forcebot_core
|
|
```
|
|
|
|
# Features
|
|
|
|
## Built In Chat Commands
|
|
|
|
- `quiet on` / `quiet off` - Moderators & Broadcasters can quiet the bot
|
|
|
|
- `enable $module$` / `disable $module$` - Moderators & Broadcasters can enable or disable `Modules` of bot functionality through chat `Commands`
|
|
|
|
|
|
## Custom Modules can be coded to load additional functionality
|
|
|
|
Developers an create Modules that add more bot functionality
|
|
|
|
The main `forcebot_core` Binary crate includes the following Custom `Modules`
|
|
|
|
- `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` Bot Library
|
|
|
|
- `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`
|
|
|
|
## Workspaces
|
|
|
|
|
|
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
|
|
```
|
|
|
|
## Full Featured Forcebot
|
|
|
|
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
|
|
```
|
|
|
|
2. 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"
|
|
```
|
|
|
|
3. Copy `main.rs` from the `new_empty_bot` package into your package
|
|
|
|
4. Optionally, customize your `main()` to load modules before starting the bot
|
|
|
|
5. 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
|
|
|
|
```rust
|
|
use forcebot_core::Bot;
|
|
|
|
#[tokio::main]
|
|
pub async fn main() {
|
|
|
|
/* 1. Create the bot using env */
|
|
let bot = Bot::new().await;
|
|
|
|
/* 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
|
|
|
|
```rust
|
|
use forcebot_core::{custom_mods::{debug, guest_badge, pyramid}, Bot};
|
|
|
|
|
|
|
|
#[tokio::main]
|
|
pub async fn main() {
|
|
|
|
/* Create the bot using env */
|
|
let bot = Bot::new().await;
|
|
|
|
/* 1. Load the module into the bot */
|
|
bot.load_module(funbot_objs::create_module()).await;
|
|
|
|
/* 2. Load Custom Modules */
|
|
bot.load_module(guest_badge::create_module()).await;
|
|
bot.load_module(pyramid::create_module()).await;
|
|
bot.load_module(debug::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
|
|
|
|
|
|
```rust
|
|
|
|
use forcebot_core::Bot;
|
|
|
|
#[tokio::main]
|
|
pub async fn main() {
|
|
|
|
/* Create the bot using env */
|
|
let bot = Bot::new().await;
|
|
|
|
/* 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.chat.lock().await.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::Vip);
|
|
|
|
cmd
|
|
}
|
|
}
|
|
```
|
|
|
|
## Simple Debug Listener
|
|
Bot with a simple listener that listens for all messages and prints in output
|
|
|
|
```rust
|
|
|
|
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 bot = Bot::new().await;
|
|
|
|
/* 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).await;
|
|
|
|
/* 4. Run the bot */
|
|
bot.run().await;
|
|
|
|
}
|
|
|
|
```
|
|
|
|
## Moderator Reactor
|
|
|
|
Example listener listens for a moderator badge and reply in chat
|
|
|
|
```rust
|
|
|
|
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 bot = Bot::new().await;
|
|
|
|
/* 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.chat.lock().await.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).await;
|
|
|
|
/* Run the bot */
|
|
bot.run().await;
|
|
|
|
}
|
|
|
|
```
|
|
|
|
## Simple Test Command
|
|
|
|
```rust
|
|
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 bot = Bot::new().await;
|
|
|
|
/* 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.chat.lock().await.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).await;
|
|
|
|
/* 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
|
|
```
|
|
|
|
|