diff --git a/.gitignore b/.gitignore index d344ba6..c26f084 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ config.json +docker-compose.yml \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..bfa9eee --- /dev/null +++ b/Dockerfile @@ -0,0 +1,22 @@ +FROM python:3.9-slim + +RUN useradd --create-home --shell /bin/bash bot + +WORKDIR /home/bot + +ENV PATH="/home/bot:${PATH}" + +# Prepare environment +RUN python -m pip install --upgrade pip +RUN pip install pipenv +COPY Pipfile.lock . +RUN pipenv sync && pipenv run pip freeze > requirements.txt + +# Add files +RUN pip install -r requirements.txt && mkdir config +COPY _twitchbot/ _twitchbot/ +COPY bot.py . + +USER bot + +CMD ["python", "bot.py", "--config=config/config.json"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..3cc8394 --- /dev/null +++ b/README.md @@ -0,0 +1,68 @@ +# Twason - The KISS Twitch bot + +Twason is an opinionated Twitch chatbot created with the [KISS principle](https://en.wikipedia.org/wiki/KISS_principle) in mind. +It is based on the [IRC](https://en.wikipedia.org/wiki/Internet_Relay_Chat) protocol and is configurable in just one JSON file. + +## What the hell is that name!? + +Twason is an umbrella name based on two words: _Twitch_ (the platform the bot is designed for) and _Jason_ (as the JSON file that you use to wonfigure it). + +## What features does it provide? + +Currently, Twason has the following features: + +- **Commands:** automatically answer to messages that start with a given command + - Customizable commands prefix (useful if you're using multiple bots) + - Mention the user who invoked the command in the answer + - Help command auto-generation +- **Timer:** automatically send pre-defined messages + - Only one timer to keep the bot from spamming in the chat + - Configurable time and number of messages between each automatic message + - Two strategies available: + - _round-robin_: send the messages in the same order they have been set in the configuration file + - _shuffle_: send the messages in a random order + +More features will be available in the future. + +## How do I use it? + +Twason is currently in development and may contain bugs, but it is globally usable. Actually, I'm using it on [my Twitch channel](https://twitch.tv/jdeuchnord). +The simplest (and safest) way to use it is to use the Docker image: `deuchnord/twason`. +A Docker-Compose file is also available for facility. + +### About the Twitch token + +To enable the bot to connect to Twitch chat, you will need to generate a token. Head to the [Twitch Chat OAuth Password Generator](https://twitchapps.com/tmi/) and follow the instructions to generate it. +Then, you will need to give it to the bot through the `TWITCH_TOKEN` environment variable. + +### The JSON configuration file + +To configure the bot, you will need to create a JSON file in `config/config.json` as defined in the `docker-compose.yml` file. +You can find a minimal configuration in the `config.json.dist` file in this repository. + +Below is the complete configuration reference: + +```json5 +{ + "nickname": "yourbot", // the Twitch name of your bot + "channel": "yourchannel", // the channel the bot must follow + "command_prefix": "!", // the prefix the commands will have (defaults to '!') + "help": true, // if true, a help command will be automatically generated (defaults to true) + "commands": [ // a list of commands that your bot will recognize and respond to (empty by default) + { + "name": "ping", // the command name - spaces are not recommended here (even though they are technically accepted) + "message": "Pong @{author} Kappa" // the message the bot must send when someone invokes this command ('{author}' will be replaced with the user who invoked the command) + } + ], + "timer": { // the configuration of the automatically sent messages + "between": { + "time": 10, // the minimum time that must have passed between two messages (defaults to 10) + "messages": 10 // the minimum number of messages that the chat members must have sent between two messages (defaults to 10) + }, + "strategy": "round-robin", // the strategy used to send the messages: "round-robin" or "shuffle" (defaults to "round-robin") + "messages": [ // the list of messages to send (empty by default) + "Hello World! HeyGuys", + ] + } +} +``` diff --git a/_twitchbot/config.py b/_twitchbot/config.py index 1691e35..f29ce47 100644 --- a/_twitchbot/config.py +++ b/_twitchbot/config.py @@ -33,12 +33,12 @@ class Timer: time_between: int = 10, msgs_between: int = 10, strategy: TimerStrategy = TimerStrategy.ROUND_ROBIN, - messages: [str] = [] + messages: [str] = None ): self.time_between = time_between self.msgs_between = msgs_between self.strategy = strategy - self.messages = messages + self.messages = messages if messages else [] @classmethod def from_dict(cls, param: dict): @@ -98,7 +98,7 @@ class Config: ) -def get_config(): - with open('config.json', 'r') as config_file: +def get_config(file_path: str): + with open(file_path, 'r') as config_file: token = environ['TWITCH_TOKEN'] - return Config.from_dict(json.loads(config_file.read()), token) \ No newline at end of file + return Config.from_dict(json.loads(config_file.read()), token) diff --git a/_twitchbot/twitchbot.py b/_twitchbot/twitchbot.py index ea97749..d4f0850 100644 --- a/_twitchbot/twitchbot.py +++ b/_twitchbot/twitchbot.py @@ -4,11 +4,13 @@ from .config import get_config, TimerStrategy from random import shuffle from datetime import datetime, timedelta +config = None + @irc3.plugin class TwitchBot: def __init__(self, bot): - self.config = get_config() + self.config = config self.messages_stack = [] self.bot = bot self.log = self.bot.log diff --git a/bot.py b/bot.py index ebf574b..a7ad74c 100644 --- a/bot.py +++ b/bot.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 +import argparse import irc3 from _twitchbot.config import get_config @@ -11,12 +12,14 @@ TWITCH_IRC_PORT = 6697 def main() -> int: - config = get_config() - print(config.timer.messages) + args = get_arguments() + + twitchbot.config = get_config(args.config) + print(twitchbot.config.timer.messages) bot = irc3.IrcBot.from_config({ - 'nick': config.nickname, - 'password': config.token, - 'autojoins': [config.channel], + 'nick': twitchbot.config.nickname, + 'password': twitchbot.config.token, + 'autojoins': [twitchbot.config.channel], 'host': TWITCH_IRC_SERVER, 'port': TWITCH_IRC_PORT, 'ssl': True, @@ -28,5 +31,12 @@ def main() -> int: return 0 +def get_arguments(): + parser = argparse.ArgumentParser() + parser.add_argument('--config', '-c', type=str, default='config.json') + + return parser.parse_args() + + if __name__ == '__main__': exit(main()) diff --git a/config.json.dist b/config.json.dist new file mode 100644 index 0000000..100002c --- /dev/null +++ b/config.json.dist @@ -0,0 +1,22 @@ +{ + "nickname": "yourbot", + "channel": "yourchannel", + "command_prefix": "!", + "help": true, + "commands": [ + { + "name": "ping", + "message": "Pong @{author} Kappa" + } + ], + "timer": { + "between": { + "time": 10, + "messages": 10 + }, + "strategy": "round-robin", + "messages": [ + "Hello World! HeyGuys", + ] + } +} \ No newline at end of file diff --git a/docker-compose.yml.dist b/docker-compose.yml.dist new file mode 100644 index 0000000..fb058c7 --- /dev/null +++ b/docker-compose.yml.dist @@ -0,0 +1,11 @@ +version: '3.8' + +services: + bot: + build: + dockerfile: Dockerfile + context: . + env: + TWITCH_TOKEN: 'SET_THIS_TOKEN' + volumes: + - './config:/home/bot/config' \ No newline at end of file