From 453c1de0ccafd1d5a0a072dc020312e2d95e1c1c Mon Sep 17 00:00:00 2001 From: dtookey Date: Sun, 20 Sep 2020 11:40:51 -0400 Subject: [PATCH 1/5] Let PEP8 do it's thing and reformat all the files. Removed bots.py and slurs.py and moved them into config.py. twitch_script_class.py has been updated to handle this added a test harness for twitch_script_class.py contains_url and contains_slur are both validated refactored contains_url to use a simple(ish) regex instead of an if cascade --- bots.py | 1 - config.py | 3 + db.py | 35 ++++---- db_cred.py | 2 +- hotkey_script.py | 1 + main.py | 15 +--- requirements.txt | 8 ++ slurs.py | 1 - tests/test_twitch_script_class.py | 35 ++++++++ tts.py | 18 ++-- twitch_cred.py | 9 +- twitch_script_class.py | 140 +++++++++++++++--------------- utilities_script.py | 3 +- 13 files changed, 155 insertions(+), 116 deletions(-) delete mode 100644 bots.py create mode 100644 config.py create mode 100644 requirements.txt delete mode 100644 slurs.py create mode 100644 tests/test_twitch_script_class.py 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') From 3e24942d545b8f13dee2fb399337082670b103b8 Mon Sep 17 00:00:00 2001 From: dtookey Date: Sun, 20 Sep 2020 11:40:51 -0400 Subject: [PATCH 2/5] Let PEP8 do it's thing and reformat all the files. Removed bots.py and slurs.py and moved them into config.py. twitch_script_class.py has been updated to handle this added a test harness for twitch_script_class.py contains_url and contains_slur are both validated refactored contains_url to use a simple(ish) regex instead of an if cascade Let PEP8 do it's thing and reformat all the files. Removed bots.py and slurs.py and moved them into config.py. twitch_script_class.py has been updated to handle this added a test harness for twitch_script_class.py contains_url and contains_slur are both validated refactored contains_url to use a simple(ish) regex instead of an if cascade --- bots.py | 1 - config.py | 3 + db.py | 35 ++++----- db_cred.py | 2 +- hotkey_script.py | 1 + main.py | 15 +--- requirements.txt | 8 ++ slurs.py | 1 - tests/test_twitch_script_class.py | 35 +++++++++ tts.py | 18 ++--- twitch_cred.py | 9 ++- twitch_script_class.py | 125 ++++++++++++++---------------- utilities_script.py | 3 +- 13 files changed, 140 insertions(+), 116 deletions(-) delete mode 100644 bots.py create mode 100644 config.py create mode 100644 requirements.txt delete mode 100644 slurs.py create mode 100644 tests/test_twitch_script_class.py 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..1590311 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,70 @@ 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 = 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 +150,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 +172,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 +183,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') From 17e1a092bee17d3a198ce410663e3d7c304bc293 Mon Sep 17 00:00:00 2001 From: dtookey Date: Sun, 20 Sep 2020 13:35:53 -0400 Subject: [PATCH 3/5] updated tts.py support both gtts and aws polly (we borrow from the streamlabs api) moved some configuration stuff around added one test method for creating file names, but it doesn't have any assertions, so it's useless added enums for different configuration properties like tts engine, file naming, and poly voices --- config.py | 80 ++++++++++++++++++++++++++++++ requirements.txt | 3 +- tests/test_tts.py | 12 +++++ tests/test_twitch_script_class.py | 2 +- tts.py | 82 ++++++++++++++++++++++++++----- twitch_script_class.py | 24 +++++---- 6 files changed, 179 insertions(+), 24 deletions(-) create mode 100644 tests/test_tts.py diff --git a/config.py b/config.py index 84c2c11..e4899e4 100644 --- a/config.py +++ b/config.py @@ -1,3 +1,83 @@ +from enum import Enum + + +class Speaker(Enum): + GOOGLE_TEXT_TO_SPEECH = 1 + STREAMLABS_API = 2 + + +class FileNameStrategy(Enum): + TIME_BASED = 1 + CONTENT_BASED = 2 + + +class PollyVoices(Enum): + Aditi = "Aditi" + Amy = "Amy" + Astrid = "Astrid" + Bianca = "Bianca" + Brian = "Brian" + Camila = "Camila" + Carla = "Carla" + Carmen = "Carmen" + Celine = "Celine" + Chantal = "Chantal" + Conchita = "Conchita" + Cristiano = "Cristiano" + Dora = "Dora" + Emma = "Emma" + Enrique = "Enrique" + Ewa = "Ewa" + Filiz = "Filiz" + Geraint = "Geraint" + Giorgio = "Giorgio" + Gwyneth = "Gwyneth" + Hans = "Hans" + Ines = "Ines" + Ivy = "Ivy" + Jacek = "Jacek" + Jan = "Jan" + Joanna = "Joanna" + Joey = "Joey" + Justin = "Justin" + Karl = "Karl" + Kendra = "Kendra" + Kimberly = "Kimberly" + Lea = "Lea" + Liv = "Liv" + Lotte = "Lotte" + Lucia = "Lucia" + Lupe = "Lupe" + Mads = "Mads" + Maja = "Maja" + Marlene = "Marlene" + Mathieu = "Mathieu" + Matthew = "Matthew" + Maxim = "Maxim" + Mia = "Mia" + Miguel = "Miguel" + Mizuki = "Mizuki" + Naja = "Naja" + Nicole = "Nicole" + Penelope = "Penelope" + Raveena = "Raveena" + Ricardo = "Ricardo" + Ruben = "Ruben" + Russell = "Russell" + Salli = "Salli" + Seoyeon = "Seoyeon" + Takumi = "Takumi" + Tatyana = "Tatyana" + Vicki = "Vicki" + Vitoria = "Vitoria" + Zeina = "Zeina" + Zhiyu = "Zhiyu" + + botList = ("Nightbot", "StreamElements", "Moobot", "praxis_bot") slurList = ("fag", "faggot", "niga", "nigga", "nigger", "retard", "tard", "rtard", "coon") + +currentSpeaker = Speaker.STREAMLABS_API +fileNameStrategy = FileNameStrategy.CONTENT_BASED +streamlabsVoice = PollyVoices.Justin diff --git a/requirements.txt b/requirements.txt index d052841..0e8c8c3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,4 +5,5 @@ SQLAlchemy pandas numpy gTTS -playsound \ No newline at end of file +playsound +pyglet \ No newline at end of file diff --git a/tests/test_tts.py b/tests/test_tts.py new file mode 100644 index 0000000..faf992e --- /dev/null +++ b/tests/test_tts.py @@ -0,0 +1,12 @@ +import unittest + +import tts + +class TTSTest(unittest.TestCase): + + def test_file_name(self): + tts.create_file_name("test", "mp3") + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_twitch_script_class.py b/tests/test_twitch_script_class.py index eba485c..63a6f52 100644 --- a/tests/test_twitch_script_class.py +++ b/tests/test_twitch_script_class.py @@ -4,7 +4,7 @@ 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'] +testInvalidUrls = ['this is just a sentence. With a period', 'gotta have some other stuff', 'bad punctuation.does not produces false positives'] class TwitchBotTest(unittest.TestCase): diff --git a/tts.py b/tts.py index 7eff716..b4d3bf5 100644 --- a/tts.py +++ b/tts.py @@ -1,31 +1,89 @@ +import datetime +import hashlib import os -import datetime - +import requests +from gtts import gTTS from playsound import playsound +import config + +streamLabsUrl = "https://streamlabs.com/polly/speak" 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" + outpath = create_speech_file(inputText) + playsound(outpath) - if len(args) == 1: - fileName = args[0] + "_tts.mp3" - # tts = gTTS(text=inputText, lang='en') - # tts.save(destPath + fileName) +def create_speech_gtts(input_text: str): + path = os.path.join(get_tts_dir(), create_file_name(input_text, "mp3")) + if not os.path.exists(path): + sound_digest = gTTS(text=input_text, lang='en') + sound_digest.save(path) + return path - playsound(destPath + fileName) - # os.system(filename) +def create_speech_streamlabs(text: str): + path = os.path.join(get_tts_dir(), create_file_name(text, "ogg")) + if not os.path.exists(path): + body = {"voice": config.streamlabsVoice.value, "text": text} + resp = requests.post(streamLabsUrl, data=body).json() + sound_file_url = resp["speak_url"] + if sound_file_url is not None: + sound_bytes = requests.get(sound_file_url, stream=True) + f = open(path, "+wb") + f.write(sound_bytes.content) + f.close() + return path + + +speechCreationFunctions = { # this is a mapping of the Speaker enum to function pointers + config.Speaker.STREAMLABS_API: create_speech_streamlabs, + config.Speaker.GOOGLE_TEXT_TO_SPEECH: create_speech_gtts +} + + +def create_speech_file(text: str): + text_creation_function = speechCreationFunctions.get(config.currentSpeaker) + output_path = text_creation_function(text) + return output_path + + +def create_file_name(text: str, ext: str): + """ + :param text: the content of the message. using the CONTENT_BASED FileNameStrategy, this will (ostensibly) produce a + unique file name based on the content of the message. Two messages of equal content will produce the same name + :param ext: the desired file extension i.e. mp3, ogg, wav, etc... + :return: returns the formatted filename i.e. 01-01-20_01-01-01_tts.mp3 + """ + if config.fileNameStrategy == config.FileNameStrategy.CONTENT_BASED: + unique_id = hashlib.md5(bytes(text, 'utf-8')).hexdigest() + return "%s_tts.%s" % (unique_id, ext) + + elif config.fileNameStrategy == config.FileNameStrategy.CONTENT_BASED: + time = datetime.datetime.now() + return "%s_tts.%s" % (time.strftime("%m-%d-%Y_%H-%M-%S"), ext) + + else: + return "unconfigured_tts.%s" % ext def play_speech(fileName): - destPath = os.getcwd() + "\\tts\\" + destPath = get_tts_dir() playsound(destPath + fileName) +def get_tts_dir(): + """ + Checks for the tts directory, and will create it if it does not exist + :return: the relative file path of the tts dir + """ + dir = os.path.join(os.getcwd(), "tts") # this is platform-agnostic + if not os.path.exists(dir): + os.mkdir(dir) + return dir + + if __name__ == "__main__": print("Enter Text: ") textInput = str(input()) diff --git a/twitch_script_class.py b/twitch_script_class.py index 1590311..fe6cd5f 100644 --- a/twitch_script_class.py +++ b/twitch_script_class.py @@ -1,13 +1,13 @@ import random +import re + import twitch import twitch.chat -import twitch_cred as twitch_credentials import config as config -import tts - import db -import re +import tts +import twitch_cred as twitch_credentials class Twitch_Module(): @@ -19,7 +19,8 @@ class Twitch_Module(): 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))") + 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 @@ -81,14 +82,17 @@ class Twitch_Module(): 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 not self.contains_slur(message): + if self.tts_enabled: + if not message.text.startswith('!'): + text_to_say: str = "%s says, %s" % (message.sender, message.text) + channel_text = "%s user msg" % message.channel + if message.sender.lower() == message.channel: - tts.tts(message.sender + " says, " + message.text) + tts.tts(text_to_say) else: # tts.tts(message.sender + " says, " + message.text) - tts.tts(message.sender + " says, " + message.text, message.channel + " user msg") + tts.tts(text_to_say, channel_text) def contains_url(self, message: twitch.chat.Message): containsURL = re.search(self._urlMatcher, message.text.lower()) is not None From 0c3733e2c06d89484e734eb9eb0fa024ce03c5a0 Mon Sep 17 00:00:00 2001 From: dtookey Date: Sun, 20 Sep 2020 13:51:14 -0400 Subject: [PATCH 4/5] removed pyglet because playsound appears to work just fine added documentation to several functions in tty.py --- requirements.txt | 3 +-- tts.py | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 0e8c8c3..d052841 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,5 +5,4 @@ SQLAlchemy pandas numpy gTTS -playsound -pyglet \ No newline at end of file +playsound \ No newline at end of file diff --git a/tts.py b/tts.py index b4d3bf5..522d21e 100644 --- a/tts.py +++ b/tts.py @@ -16,6 +16,11 @@ def tts(inputText: str, *args): def create_speech_gtts(input_text: str): + """ + Will create a sound file for the provided text by using gTTS + :param input_text: any reasonable english text + :return: returns the path of the file for the sound + """ path = os.path.join(get_tts_dir(), create_file_name(input_text, "mp3")) if not os.path.exists(path): sound_digest = gTTS(text=input_text, lang='en') @@ -24,6 +29,11 @@ def create_speech_gtts(input_text: str): def create_speech_streamlabs(text: str): + """ + Will create a sound file for the provided text by querying and downloading a file from streamlabs + :param text: any reasonable english text + :return: returns the path of the file for the sound + """ path = os.path.join(get_tts_dir(), create_file_name(text, "ogg")) if not os.path.exists(path): body = {"voice": config.streamlabsVoice.value, "text": text} @@ -44,6 +54,12 @@ speechCreationFunctions = { # this is a mapping of the Speaker enum to function def create_speech_file(text: str): + """ + Helper function that will create a sound file for the provided text. This will use the configuration in config.py + to use TTS engines and name the file + :param text: the text you would like to turn into a sound file + :return: returns the path of the sound file + """ text_creation_function = speechCreationFunctions.get(config.currentSpeaker) output_path = text_creation_function(text) return output_path From 68674de54eda8fe773aacf6923ffe6e493ec7061 Mon Sep 17 00:00:00 2001 From: dtookey Date: Sun, 20 Sep 2020 13:51:14 -0400 Subject: [PATCH 5/5] removed pyglet because playsound appears to work just fine added documentation to several functions in tty.py --- requirements.txt | 3 +-- tts.py | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/requirements.txt b/requirements.txt index 0e8c8c3..d052841 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,5 +5,4 @@ SQLAlchemy pandas numpy gTTS -playsound -pyglet \ No newline at end of file +playsound \ No newline at end of file diff --git a/tts.py b/tts.py index b4d3bf5..3223b76 100644 --- a/tts.py +++ b/tts.py @@ -16,6 +16,11 @@ def tts(inputText: str, *args): def create_speech_gtts(input_text: str): + """ + Will create a sound file for the provided text by using gTTS + :param input_text: any reasonable english text + :return: returns the path of the file for the sound + """ path = os.path.join(get_tts_dir(), create_file_name(input_text, "mp3")) if not os.path.exists(path): sound_digest = gTTS(text=input_text, lang='en') @@ -24,6 +29,11 @@ def create_speech_gtts(input_text: str): def create_speech_streamlabs(text: str): + """ + Will create a sound file for the provided text by querying and downloading a file from streamlabs + :param text: any reasonable english text + :return: returns the path of the file for the sound + """ path = os.path.join(get_tts_dir(), create_file_name(text, "ogg")) if not os.path.exists(path): body = {"voice": config.streamlabsVoice.value, "text": text} @@ -44,6 +54,12 @@ speechCreationFunctions = { # this is a mapping of the Speaker enum to function def create_speech_file(text: str): + """ + Helper function that will create a sound file for the provided text. This will use the configuration in config.py + to use TTS engines and name the file + :param text: the text you would like to turn into a sound file + :return: returns the path of the sound file + """ text_creation_function = speechCreationFunctions.get(config.currentSpeaker) output_path = text_creation_function(text) return output_path @@ -60,7 +76,7 @@ def create_file_name(text: str, ext: str): unique_id = hashlib.md5(bytes(text, 'utf-8')).hexdigest() return "%s_tts.%s" % (unique_id, ext) - elif config.fileNameStrategy == config.FileNameStrategy.CONTENT_BASED: + elif config.fileNameStrategy == config.FileNameStrategy.TIME_BASED: time = datetime.datetime.now() return "%s_tts.%s" % (time.strftime("%m-%d-%Y_%H-%M-%S"), ext)