diff --git a/bots.py b/bots.py deleted file mode 100644 index cc3ef55..0000000 --- a/bots.py +++ /dev/null @@ -1 +0,0 @@ -botList = ["Nightbot", "StreamElements", "Moobot", "praxis_bot"] \ No newline at end of file diff --git a/config.py b/config.py new file mode 100644 index 0000000..84c2c11 --- /dev/null +++ b/config.py @@ -0,0 +1,3 @@ +botList = ("Nightbot", "StreamElements", "Moobot", "praxis_bot") + +slurList = ("fag", "faggot", "niga", "nigga", "nigger", "retard", "tard", "rtard", "coon") diff --git a/db.py b/db.py index c028711..253afb1 100644 --- a/db.py +++ b/db.py @@ -1,10 +1,9 @@ -import mysql.connector -import os import db_cred as db_credentials import pandas as pd from sqlalchemy import create_engine + class db_module(): def __init__(self): super().__init__() @@ -15,27 +14,26 @@ class db_module(): self.engine = create_engine(db_credentials.engine_url) print("Engine Created") - def create_table(self, tableName:str = ""): + def create_table(self, tableName: str = ""): pass - def does_table_exist(self, tableName:str = ""): + def does_table_exist(self, tableName: str = ""): pass - def delete_table(self, tableName:str = ""): + def delete_table(self, tableName: str = ""): pass - - #This was a old function used prior to the creation of this class. I need to remake it. - def get_data_old(self, tableName:str = "", key:str = ""): + + # This was a old function used prior to the creation of this class. I need to remake it. + def get_data_old(self, tableName: str = "", key: str = ""): table = '_channel_commands' table = tableName - - - df = pd.read_sql_query('SELECT * FROM '+ table, engine) + + df = pd.read_sql_query('SELECT * FROM ' + table, engine) stmt = "trigger == '" + key + "'" temp = df.query(stmt) result = temp.get("response") - #print(result) + # print(result) i = len(temp.index.values) if i == 1: @@ -45,20 +43,19 @@ class db_module(): output = "$$None$$" return output - def get_data(self, tableName:str = "", key:str = ""): + def get_data(self, tableName: str = "", key: str = ""): pass - def insert_data(self, tableName:str = "", param:str = ""): + def insert_data(self, tableName: str = "", param: str = ""): pass - def edit_data(self, tableName:str = "", key:str = "", param:str = ""): + def edit_data(self, tableName: str = "", key: str = "", param: str = ""): pass - def delete_data(self, tableName:str = "", key:str = ""): + def delete_data(self, tableName: str = "", key: str = ""): pass - if __name__ == "__main__": - db_connection = db_module() - db_connection.setup_engine() \ No newline at end of file + db_connection = db_module() + db_connection.setup_engine() diff --git a/db_cred.py b/db_cred.py index 382ad5b..13fc233 100644 --- a/db_cred.py +++ b/db_cred.py @@ -1 +1 @@ -engine_url = "mysql+mysqlconnector://" \ No newline at end of file +engine_url = "mysql+mysqlconnector://" diff --git a/hotkey_script.py b/hotkey_script.py index 560dd3c..eebe3fa 100644 --- a/hotkey_script.py +++ b/hotkey_script.py @@ -1,6 +1,7 @@ import pygetwindow as gw from pynput.keyboard import Key, Controller import time + keyboard = Controller() diff --git a/main.py b/main.py index 373f60c..173bb9f 100644 --- a/main.py +++ b/main.py @@ -1,12 +1,5 @@ -# Install these: -# pip install mysql-connector-python -# pip install pynput -# pip install twitch-python -# pip install SQLAlchemy -# pip install pandas -# pip install numpy -# pip install gTTS -# pip install playsound +# I moved all the requirements into requirements.txt. +# you can install everything with pip install -r requirements.txt while you're in the directory import sys import time @@ -17,6 +10,7 @@ import utilities_script as utility twitch_chat: twitch_script_class.Twitch_Module + def main(): print("Connecting to Channels...") @@ -24,9 +18,8 @@ def main(): twitch_chat = twitch_script_class.Twitch_Module() twitch_chat.join_channel("thecuriousnerd") - #twitch_chat.send_message("activated") + # twitch_chat.send_message("activated") if __name__ == "__main__": main() - \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..d052841 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,8 @@ +mysql-connector-python +pynput +twitch-python +SQLAlchemy +pandas +numpy +gTTS +playsound \ No newline at end of file diff --git a/slurs.py b/slurs.py deleted file mode 100644 index 4743cbd..0000000 --- a/slurs.py +++ /dev/null @@ -1 +0,0 @@ -slurList = ["fag", "faggot", "niga", "nigga", "nigger", "retard", "tard", "rtard", "coon"] diff --git a/tests/test_twitch_script_class.py b/tests/test_twitch_script_class.py new file mode 100644 index 0000000..eba485c --- /dev/null +++ b/tests/test_twitch_script_class.py @@ -0,0 +1,35 @@ +import unittest +import twitch_script_class +import twitch + + +testValidUrls = ['https://shady.ru', 'http://stolencards.zn', 'https://i.imgur.com/FL6slHd.jpg'] +testInvalidUrls = ['this is just a sentence. With a period', 'gotta have some other stuff', 'bad punctuation produces false positives'] + + +class TwitchBotTest(unittest.TestCase): + def setUp(self): + self.bot = twitch_script_class.Twitch_Module() + + def test_find_url(self): + bot = self.bot + for link in testInvalidUrls: + msg = twitch.chat.Message("", "", link) + t = bot.contains_url(msg) + assert not t + + for link in testValidUrls: + msg = twitch.chat.Message("", "", link) + t = bot.contains_url(msg) + assert t + + def test_find_slur(self): + nonSlurMessage = twitch.chat.Message("", "", "hey look, a normal sentence") + slurMessage = twitch.chat.Message("", "", "fag is a hateful word that shouldn't be used anymore") + assert not self.bot.contains_slur(nonSlurMessage) + assert self.bot.contains_slur(slurMessage) + + +if __name__ == '__main__': + unittest.main() + diff --git a/tts.py b/tts.py index af4b554..7eff716 100644 --- a/tts.py +++ b/tts.py @@ -1,4 +1,3 @@ -from gtts import gTTS import os import datetime @@ -6,30 +5,31 @@ import datetime from playsound import playsound -def tts(inputText:str, *args): - +def tts(inputText: str, *args): destPath = os.getcwd() + "\\tts\\" time = datetime.datetime.now() - fileName:str = time.strftime("%m-%d-%Y_%H-%M-%S") + "_tts.mp3" + fileName: str = time.strftime("%m-%d-%Y_%H-%M-%S") + "_tts.mp3" if len(args) == 1: fileName = args[0] + "_tts.mp3" - tts = gTTS(text=inputText, lang='en') - tts.save(destPath + fileName) + # tts = gTTS(text=inputText, lang='en') + # tts.save(destPath + fileName) playsound(destPath + fileName) - #os.system(filename) + # os.system(filename) + def play_speech(fileName): destPath = os.getcwd() + "\\tts\\" playsound(destPath + fileName) + if __name__ == "__main__": print("Enter Text: ") textInput = str(input()) - print("Custom FileName? y/n: ") + print("Custom FileName? y/n: ") bool_string = str(input()) if bool_string == "y": @@ -37,4 +37,4 @@ if __name__ == "__main__": fileName = str(input()) tts(textInput, fileName) else: - tts(textInput) \ No newline at end of file + tts(textInput) diff --git a/twitch_cred.py b/twitch_cred.py index e5d27a6..c30aab1 100644 --- a/twitch_cred.py +++ b/twitch_cred.py @@ -1,10 +1,11 @@ +# So I'm a little conflicted here. My nit-picky self says that this should be a class you have to instantiate rather +# than static variables... I'll leave this alone for now, but you may wish to refactor this in future username = "" helix = "" oauth = "oauth:" v5_Client = "" - -#Helix ID https://dev.twitch.tv/console/apps -#Oauth https://twitchapps.com/tmi/ -#V5 Client ID https://twitchtokengenerator.com/ +# Helix ID https://dev.twitch.tv/console/apps +# Oauth https://twitchapps.com/tmi/ +# V5 Client ID https://twitchtokengenerator.com/ diff --git a/twitch_script_class.py b/twitch_script_class.py index 9a4eeda..4340584 100644 --- a/twitch_script_class.py +++ b/twitch_script_class.py @@ -3,20 +3,23 @@ import twitch import twitch.chat import twitch_cred as twitch_credentials -import bots as botList -import slurs as slurList +import config as config import tts import db +import re + class Twitch_Module(): def __init__(self): super().__init__() self.chat: twitch.Chat - self.tts_enabled:bool = False - self.tts_whitelist_enabled:bool = False - self.links_allowed:bool = True - self.whitelisted_users:list = ["thecuriousnerd", "theredpoint", "lakotor"] + self.tts_enabled: bool = False + self.tts_whitelist_enabled: bool = False + self.links_allowed: bool = True + self.whitelisted_users: list = ["thecuriousnerd", "theredpoint", "lakotor"] + # don't freak out, this is *merely* a regex for matching urls that will hit just about everything + self._urlMatcher = re.compile("(https?:(/{1,3}|[a-z0-9%])|[a-z0-9.-]+[.](com|net|org|edu|gov|mil|aero|asia|biz|cat|coop|info|int|jobs|mobi|museum|name|post|pro|tel|travel|xxx|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cs|cu|cv|cx|cy|cz|dd|de|dj|dk|dm|do|dz|ec|ee|eg|eh|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|Ja|sk|sl|sm|sn|so|sr|ss|st|su|sv|sx|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw))") def join_channel(self, channel_name): channel_name = "#" + channel_name @@ -28,35 +31,32 @@ class Twitch_Module(): helix=twitch.Helix(twitch_credentials.helix, use_cache=True) ) self.chat.subscribe(self.twitch_chat) - - print("Connected to Channel: ", channel_name) - + print("Connected to Channel: ", channel_name) def leave_channel(self): - print("Leaving Channel",self.chat.channel) + print("Leaving Channel", self.chat.channel) self.chat.irc.leave_channel(self.chat.channel) self.chat.irc.socket.close() def send_message(self, message): - self.chat.send(message) + self.chat.send(message) def send_whisper(self, user, message): pass - #This reacts to messages + # This reacts to messages def twitch_chat(self, message: twitch.chat.Message) -> None: - print("[#"+ message.channel + "](" + message.sender + ")> " + message.text) + print("[#" + message.channel + "](" + message.sender + ")> " + message.text) if message.channel == "thecuriousnerd": - if self.isSenderBot(message) == False: + if not self.isSenderBot(message): if message.sender.lower() == "thecuriousnerd": self.eval_commands(message) self.tts_message(message) - def eval_commands(self, message: twitch.chat.Message): - containsURL:bool = self.contains_url(message) + containsURL: bool = self.contains_url(message) if message.text.startswith('!tts start'): print("tts activated on #" + message.channel) @@ -67,11 +67,11 @@ class Twitch_Module(): print("tts deactivated on #" + message.channel) self.send_message("tts deactivated") self.tts_enabled = True - + if message.text.startswith('!test'): print("!test Detected") message.chat.send("test acknowledged") - #message.chat.send(f'@{message.user().display_name}, you have {message.user().view_count} views.') + # message.chat.send(f'@{message.user().display_name}, you have {message.user().view_count} views.') if message.text.startswith('!roll'): try: @@ -79,82 +79,85 @@ class Twitch_Module(): except Exception: self.send_message("{something went wrong}") print("{something went wrong}") - def tts_message(self, message: twitch.chat.Message): if self.contains_slur(message) == False: - if self.tts_enabled == True: - if message.text.startswith('!') == False: - if message.sender.lower() == message.channel: - tts.tts(message.sender + " says, " + message.text) - else: - #tts.tts(message.sender + " says, " + message.text) - tts.tts(message.sender + " says, " + message.text, message.channel + " user msg") + if self.tts_enabled == True: + if message.text.startswith('!') == False: + if message.sender.lower() == message.channel: + tts.tts(message.sender + " says, " + message.text) + else: + # tts.tts(message.sender + " says, " + message.text) + tts.tts(message.sender + " says, " + message.text, message.channel + " user msg") def contains_url(self, message: twitch.chat.Message): - containsURL:bool = False - if message.text.lower().find("http") != -1: - containsURL = True - if message.text.lower().find("https") != -1: - containsURL = True - if message.text.lower().find(".com") != -1: - containsURL = True - if message.text.lower().find(".net") != -1: - containsURL = True - if message.text.lower().find(".org") != -1: - containsURL = True - if message.text.lower().find(".tv") != -1: - containsURL = True - if message.text.lower().find(".io") != -1: - containsURL = True - if containsURL == True: - print("<{ link detected! }> " + " [#"+ message.channel + "](" + message.sender + ") sent a link in chat") + # containsURL: bool = False + # if message.text.lower().find("http") != -1: + # containsURL = True + # if message.text.lower().find("https") != -1: + # containsURL = True + # if message.text.lower().find(".com") != -1: + # containsURL = True + # if message.text.lower().find(".net") != -1: + # containsURL = True + # if message.text.lower().find(".org") != -1: + # containsURL = True + # if message.text.lower().find(".tv") != -1: + # containsURL = True + # if message.text.lower().find(".io") != -1: + # containsURL = True + containsURL = re.search(self._urlMatcher, message.text.lower()) is not None + if containsURL: + print("<{ link detected! }> " + " [#" + message.channel + "](" + message.sender + ") sent a link in chat") return containsURL - - #Checks if Sender is bot. + + # Checks if Sender is bot. def isSenderBot(self, message: twitch.chat.Message): isBot = False - for bot in botList.botList: + for bot in config.botList: if message.sender.lower() == bot.lower(): isBot = True - print("<{ bot detected! }> " + " [#"+ message.channel + "](" + message.sender + ") is a bot") + print("<{ bot detected! }> " + " [#" + message.channel + "](" + message.sender + ") is a bot") return isBot - #Checks for basic slurs. + # Checks for basic slurs. def contains_slur(self, message: twitch.chat.Message): - containsSlur:bool = False + containsSlur: bool = False parsedMessage = message.text.split(" ") for word in parsedMessage: - for slur in slurList.slurList: + for slur in config.slurList: if word.lower() == slur: containsSlur = True + break # we want to immediately escape if we found a slur + if containsSlur: + break - if containsSlur == True: - print("<{ slur detected! }> " + " [#"+ message.channel + "](" + message.sender + ") used a slur in chat") + if containsSlur: + print("<{ slur detected! }> " + " [#" + message.channel + "](" + message.sender + ") used a slur in chat") return containsSlur - #Rolls Dice. + # Rolls Dice. def dice_roll(self, message: twitch.chat.Message): - diceRoll:str = "" + diceRoll: str = "" self.send_message("Rolling Dice...") print("Rolling Dice...") temp_preParsedMessage = message.text.split("+") tempParsedMessage = temp_preParsedMessage[0].split(" ") - temp_dice_stmt:str = tempParsedMessage[1] + temp_dice_stmt: str = tempParsedMessage[1] parsedMessage = temp_dice_stmt.lower().split("d") - loopBool:bool = False + loopBool: bool = False if parsedMessage[0] != "": loopBool = True if loopBool == True: if int(parsedMessage[0]) == 1: loopBool = False - #If roll is in xdx+x format + # If roll is in xdx+x format if loopBool == True: - rolls:list = [] + rolls: list = [] for x in range(int(parsedMessage[0])): rolls.append(random.randint(1, int(parsedMessage[1]))) @@ -162,18 +165,20 @@ class Twitch_Module(): for roll in rolls: rollTotal = rollTotal + roll diceRoll = diceRoll + str(roll) + ", " - diceRoll = diceRoll[:-2] #This removes the last two characters in the string + diceRoll = diceRoll[:-2] # This removes the last two characters in the string if len(temp_preParsedMessage) == 2: - diceRoll = diceRoll + " + " + temp_preParsedMessage[1] + " = " + str(rollTotal + int(temp_preParsedMessage[1])) + diceRoll = diceRoll + " + " + temp_preParsedMessage[1] + " = " + str( + rollTotal + int(temp_preParsedMessage[1])) else: diceRoll = diceRoll + " = " + str(rollTotal) - #If roll is in dx+x format + # If roll is in dx+x format if loopBool == False: - roll:int = random.randint(1, int(parsedMessage[1])) - + roll: int = random.randint(1, int(parsedMessage[1])) + if len(temp_preParsedMessage) == 2: - diceRoll = str(roll) + " + " + temp_preParsedMessage[1] + " = " + str(roll + int(temp_preParsedMessage[1])) + diceRoll = str(roll) + " + " + temp_preParsedMessage[1] + " = " + str( + roll + int(temp_preParsedMessage[1])) else: diceRoll = str(roll) @@ -182,8 +187,8 @@ class Twitch_Module(): self.send_message(diceRoll) -#This is a old function used prior to the creation of the Twitch_Module class above. -#I need to make a new one for the class. +# This is a old function used prior to the creation of the Twitch_Module class above. +# I need to make a new one for the class. def main_chat_commands_check(channel, sender, text): response = db.basic_command_trigger(channel, sender, text) if response == "$$None$$": @@ -193,7 +198,6 @@ def main_chat_commands_check(channel, sender, text): print(response) - if __name__ == "__main__": testChat = Twitch_Module() - testChat.join_channel("thecuriousnerd") \ No newline at end of file + testChat.join_channel("thecuriousnerd") diff --git a/utilities_script.py b/utilities_script.py index bbedaf0..dc1f6b6 100644 --- a/utilities_script.py +++ b/utilities_script.py @@ -1,4 +1,3 @@ import os -clearScreen = lambda : os.system('cls' if os.name == 'nt' else 'clear') - +clearScreen = lambda: os.system('cls' if os.name == 'nt' else 'clear')