From cc9f833c4e58014dd71920f0670b797284e5f7e9 Mon Sep 17 00:00:00 2001 From: liyunze <50455574+liyunze-coding@users.noreply.github.com> Date: Thu, 2 May 2024 20:34:53 +0800 Subject: [PATCH] first commit --- .gitignore | 1 + README.md | 48 +++++++++++++++++++++++++++++ functions.py | 79 ++++++++++++++++++++++++++++++++++++++++++++++++ main.py | 54 +++++++++++++++++++++++++++++++++ requirements.txt | 1 + 5 files changed, 183 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 functions.py create mode 100644 main.py create mode 100644 requirements.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ed8ebf5 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +__pycache__ \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..6608521 --- /dev/null +++ b/README.md @@ -0,0 +1,48 @@ +# Twitch Plays X (by RythonDev) + +> (Credits to [TwitchPlaysPokemon] and [TwitchPlayX by hzoo](https://github.com/hzoo/TwitchPlaysX)) + +Allows your Twitch chat to play games such as Pokemon! + +![Python Badge](https://img.shields.io/badge/Python-3776AB?logo=python&logoColor=fff&style=for-the-badge) +![Windows 11 Badge](https://img.shields.io/badge/Windows%2011-0078D4?logo=windows11&logoColor=fff&style=for-the-badge) +![Linux Badge](https://img.shields.io/badge/Linux-FCC624?logo=linux&logoColor=000&style=for-the-badge) + +## How it works + +1. Connects to your Twitch chat +2. Reads messages +3. Check if messages contains controls only: + - `up up down down left right` - pass + - `what's up` - fail +4. Executes keyboard controls + +## Installation + +1. Install [Python](https://python.org) onto your machine +2. Download zip file or Clone the repo via: + ``` + git clone https://github.com/liyunze-coding/TwitchPlaysX.git + ``` + +3. Modify `CHANNEL_NAME` in `main.py`: + ``` + CHANNEL_NAME = "rythondev" + ``` + +4. Install the requirements: + + Windows: + ``` + pip install pywin32 + ``` + + Linux: + ``` + sudo apt-get install xdotool + ``` + +5. Run the script: + ``` + py main.py + ``` \ No newline at end of file diff --git a/functions.py b/functions.py new file mode 100644 index 0000000..4729943 --- /dev/null +++ b/functions.py @@ -0,0 +1,79 @@ +import time +import subprocess +import platform +import socket +import win32api # Windows only +import win32con # Windows only + + +class TwitchPlaysX: + def __init__(self, key_delay, keymap, channel_name) -> None: + self.os = self.get_os() + self.key_delay = key_delay + self.keymap = keymap + self.channel_name = channel_name + + # not tested + def sendKeyLinux(self, button): + subprocess.run(["xdotool", "key", button]) + time.sleep(self.key_delay) + + def sendKeyWindows(self, button): + win32api.keybd_event(self.keymap[button], 0, 0, 0) + time.sleep(self.key_delay) + win32api.keybd_event(self.keymap[button], 0, win32con.KEYEVENTF_KEYUP, 0) + + def get_os(self): + os_name = platform.system() + if os_name == "Windows": + return "Windows" + elif os_name == "Linux": + return "Linux" + else: + return "Unknown" + + def sendKey(self, button, os_type): + if os_type.lower() == "windows": + self.sendKeyWindows(button) + else: + self.sendKeyLinux(button) + + def all_valid_chars(self, char_array): + return all(char in self.keymap for char in char_array) + + def process_message(self, author, message): + characters = message.lower().split(" ") + + os_type = self.get_os() + + if self.all_valid_chars(characters): + for char in characters: + print(f"{author}: {char}") + self.sendKey(char, os_type) + + def twitch_chat_listener(self, channel): + server = "irc.chat.twitch.tv" + port = 6667 + nick = "justinfan123" # Twitch allows anonymous users with 'justinfan' prefix + channel = f"#{channel}" + + sock = socket.socket() + sock.connect((server, port)) + sock.send(f"NICK {nick}\r\n".encode("utf-8")) + sock.send(f"JOIN {channel}\r\n".encode("utf-8")) + + while True: + resp = sock.recv(2048).decode("utf-8") + + if resp.startswith("PING"): + sock.send("PONG\n".encode("utf-8")) + + # Check if message is not empty + elif len(resp) > 0: + # Extract author from response + author = resp.split("!", 1)[0].split(":", 1)[-1] + + # Extract message from response + msg = resp.split(channel, 1)[-1].split(":", 1)[-1].strip() + + self.process_message(author, msg) diff --git a/main.py b/main.py new file mode 100644 index 0000000..7a84448 --- /dev/null +++ b/main.py @@ -0,0 +1,54 @@ +import win32con # Windows only +from functions import TwitchPlaysX +import platform + +# SETTINGS +CHANNEL_NAME = "rythondev" +KEYDELAY = 0.3 + +# Keymap for Windows +windowsKeyMap = { + "up": win32con.VK_UP, + "left": win32con.VK_LEFT, + "down": win32con.VK_DOWN, + "right": win32con.VK_RIGHT, + "a": ord("X"), + "b": ord("Z"), + "l": ord("A"), + "r": ord("S"), + "start": ord("S"), + "select": ord("E"), +} + +# Keymap for Linux +linuxKeyMap = { + "up": "Up", + "left": "Left", + "down": "Down", + "right": "Right", + "a": "x", + "b": "z", + "l": "a", + "r": "s", + "start": "s", + "select": "e", +} +### + + +def main(): + if CHANNEL_NAME == "CHANNEL_NAME": + print("Please set the CHANNEL_NAME variable in the main.py file") + else: + os_type = platform.system() + + keymap = windowsKeyMap if os_type == "Windows" else linuxKeyMap + + twitchPlaysX = TwitchPlaysX(KEYDELAY, keymap, CHANNEL_NAME) + + print(f"Starting TwitchPlaysX for channel: {CHANNEL_NAME}") + twitchPlaysX.twitch_chat_listener(CHANNEL_NAME) + + +if __name__ == "__main__": + main() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..864f63b --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +pywin32==306