From 0dfed3019ef30005bdf29bcba097e6a84dd8311a Mon Sep 17 00:00:00 2001 From: Georgios Atheridis Date: Tue, 22 Mar 2022 12:36:39 +0200 Subject: [PATCH] added basic structure and functionality --- aptbot/__main__.py | 64 ++++++++++++++++++++++++++- aptbot/args.py | 24 ++++++++++ aptbot/bot.py | 108 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 aptbot/args.py create mode 100644 aptbot/bot.py diff --git a/aptbot/__main__.py b/aptbot/__main__.py index 3339ef2..d01dfbd 100644 --- a/aptbot/__main__.py +++ b/aptbot/__main__.py @@ -1,5 +1,67 @@ +import socket +import aptbot.args +import time +import aptbot.bot +import os +import sys +from threading import Thread +from dotenv import load_dotenv + +load_dotenv() + +PORT = 26538 +LOCALHOST = "127.0.0.1" + + +def loop(bot: aptbot.bot.Bot): + while True: + messages = bot.receive_messages() + for message in messages: + pass + time.sleep(0.001) + + +def listener(): + NICK = os.getenv("APTBOT_NICK") + OAUTH = os.getenv("APTBOT_OAUTH") + CLIENT_ID = os.getenv("APTBOT_CLIENT_ID") + print(NICK) + print(OAUTH) + print(CLIENT_ID) + if NICK and OAUTH and CLIENT_ID: + bot = aptbot.bot.Bot(NICK, OAUTH, CLIENT_ID) + else: + sys.exit(1) + bot.connect() + bot.join_channel("skgyorugo") + Thread(target=loop, args=(bot,)).start() + s = socket.socket() + s.bind(("", PORT)) + s.listen(5) + + while True: + c, addr = s.accept() + msg = c.recv(1024).decode() + bot.send_privmsg("skgyorugo", msg) + time.sleep(1) + + +def send(acc: str): + s = socket.socket() + s.connect(("", PORT)) + print("Socket connected") + s.send(acc.encode()) + s.close() + + def main(): - pass + argsv = aptbot.args.parse_arguments() + if argsv.enable: + listener() + if argsv.add_account: + send(argsv.add_account) + print("hi") + if __name__ == "__main__": main() diff --git a/aptbot/args.py b/aptbot/args.py new file mode 100644 index 0000000..c292819 --- /dev/null +++ b/aptbot/args.py @@ -0,0 +1,24 @@ +import argparse + + +def parse_arguments() -> argparse.Namespace: + arg_parser = argparse.ArgumentParser( + prog="aptbot", + description="A chat bot for twitch.tv" + ) + + arg_parser.add_argument( + "-a", + "--add-account", + type=str, + help=f"Add an account to connect with the bot" + ) + + arg_parser.add_argument( + "--enable", + default=False, + action="store_true", + help=f"Enable the bot" + ) + + return arg_parser.parse_args() diff --git a/aptbot/bot.py b/aptbot/bot.py new file mode 100644 index 0000000..71f59ed --- /dev/null +++ b/aptbot/bot.py @@ -0,0 +1,108 @@ +import socket +from enum import Enum +from dataclasses import dataclass +from typing import Optional + + +class Commands(Enum): + CLEARCHAT = "CLEARCHAT" + CLEARMSG = "CLEARMSG" + HOSTTARGET = "HOSTTARGET" + NOTICE = "NOTICE" + RECONNECT = "RECONNECT" + ROOMSTATE = "ROOMSTATE" + USERNOTICE = "USERNOTICE" + USERSTATE = "USERSTATE" + GLOBALUSERSTATE = "GLOBALUSERSTATE" + PRIVMSG = "PRIVMSG" + JOIN = "JOIN" + PART = "PART" + + +@dataclass +class Message: + tags: dict + nick: str + command: Optional[Commands] + channel: str + value: str + + +class Bot: + def __init__(self, nick: str, oauth_token: str, client_id: str): + self.irc = socket.socket() + self.server = "irc.twitch.tv" + self.port = 6667 + self.nick = nick + self.oauth_token = oauth_token + self.client_id = client_id + + def send_command(self, command: str): + self.irc.send((command + "\r\n").encode()) + + def connect(self): + self.irc.connect((self.server, self.port)) + self.send_command(f"PASS oauth:{self.oauth_token}") + self.send_command(f"NICK {self.nick}") + self.send_command(f"CAP REQ :twitch.tv/membership") + self.send_command(f"CAP REQ :twitch.tv/tags") + self.send_command(f"CAP REQ :twitch.tv/commands") + + def join_channel(self, channel: str): + self.send_command(f"{Commands.JOIN.value} #{channel}") + + def leave_channel(self, channel: str): + self.send_command(f"{Commands.PART.value} #{channel}") + + def send_privmsg(self, channel: str, text: str): + self.send_command(f"{Commands.PRIVMSG.value} #{channel} :{text}") + + @staticmethod + def parse_message(received_msg: str) -> Message: + message = Message({}, "", None, "", "") + + value_start = received_msg.find( + ':', + received_msg.find(' ', received_msg.find(' ') + 1) + ) + if value_start != -1: + message.value = received_msg[value_start:][1:] + received_msg = received_msg[:value_start - 1] + + parts = received_msg.split(' ') + + for part in parts: + if part.startswith('@'): + part = part[1:] + for tag in part.split(';'): + tag = tag.split('=') + try: + message.tags[tag[0]] = tag[1] + except IndexError: + message.tags[tag[0]] = "" + elif part.startswith(':'): + part = part[1:] + if '!' in part: + message.nick = part.split('!')[0] + elif part in set(command.value for command in Commands): + message.command = Commands(part) + elif part.startswith('#'): + part = part[1:] + message.channel = part + + return message + + def _handle_message(self, received_msg: str) -> Message: + if received_msg == "PING :tmi.twitch.tv": + self.send_command("PONG :tmi.twitch.tv") + return Message({}, "", None, "", "") + elif not received_msg: + return Message({}, "", None, "", "") + return Bot.parse_message(received_msg) + + def receive_messages(self) -> list: + messages = [] + received_msgs = self.irc.recv(2048).decode() + for received_msgs in received_msgs.split("\r\n"): + messages.append(self._handle_message(received_msgs)) + return messages -- 2.30.2