Merge pull request 'Discord Script + Threading' (#11) from Discord-Script into master

Reviewed-on: #11
This commit is contained in:
alex_orid 2020-11-17 10:35:19 +00:00
commit 979c8dd2e9
14 changed files with 355 additions and 35 deletions

View File

@ -19,8 +19,15 @@ Oauth = `https://twitchapps.com/tmi/`
V5 Client ID = `https://twitchtokengenerator.com/`
### For Database Credentials
Nickname = `Anything You Want`
Engine = `"mysql+mysqlconnector://root:password@localhost:3306/DatabaseName"`
### For Discord Credentials
Nickname = `Anything You Want`
Token = `https://discord.com/developers/`
## Credential Usage:
Place json credentials in the `/credentials/` folder.

View File

@ -0,0 +1,75 @@
from abc import ABCMeta
from discord import message
from commands.command_base import AbstractCommand
import random
import discord
import discord.message
import discord.channel
class CommandRoll(AbstractCommand, metaclass=ABCMeta):
"""
this is the roll command.
"""
command = "!roll"
def __init__(self):
super().__init__(CommandRoll.command, n_args=1, command_type=AbstractCommand.CommandType.DISCORD)
async def do_command(self, bot, discord_message: discord.Message):
print("!roll Detected")
#twitch_message.chat.send("test acknowledged")
diceRoll: str = ""
await bot.send_message(discord_message, "Rolling Dice...")
#await discord_message.channel.send("Rolling Dice...")
print("Rolling Dice...")
temp_preParsedMessage = discord_message.content.split("+")
tempParsedMessage = temp_preParsedMessage[0].split(" ")
temp_dice_stmt: str = tempParsedMessage[1]
parsedMessage = temp_dice_stmt.lower().split("d")
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 loopBool == True:
rolls: list = []
for x in range(int(parsedMessage[0])):
rolls.append(random.randint(1, int(parsedMessage[1])))
rollTotal = 0
for roll in rolls:
rollTotal = rollTotal + roll
diceRoll = diceRoll + str(roll) + ", "
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]))
else:
diceRoll = diceRoll + " = " + str(rollTotal)
# If roll is in dx+x format
if loopBool == False:
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]))
else:
diceRoll = str(roll)
diceRoll = discord_message.author.mention + " rolled: " + diceRoll
print(diceRoll)
await bot.send_message(discord_message, diceRoll)
#await discord_message.channel.send(diceRoll)

View File

@ -18,5 +18,5 @@ class CommandTTS(AbstractCommand, metaclass=ABCMeta):
bot.tts_enabled = True
elif args[1] == "stop":
if twitch_message.sender.lower() == twitch_message.channel:
bot.send_message("tts activated on #%s" % twitch_message.channel)
bot.send_message("tts deactivated on #%s" % twitch_message.channel)
bot.tts_enabled = False

View File

@ -0,0 +1,30 @@
from abc import ABCMeta
from commands.command_base import AbstractCommand
import discord
import discord.message
class CommandTTS(AbstractCommand, metaclass=ABCMeta):
command = "!tts"
def __init__(self):
super().__init__(CommandTTS.command, n_args=1, command_type=AbstractCommand.CommandType.DISCORD)
async def do_command(self, bot, discord_message: discord.message):
args = self.get_args(discord_message.content)
if args[1] == "start":
print(discord_message.author.top_role)
print("start detected")
if str(discord_message.author.top_role) == "Admin":
print("Admin Check")
response = str("tts activated on %s" % discord_message.guild.name)
await bot.send_message(discord_message, response)
bot.tts_enabled = True
elif args[1] == "stop":
print("stop detected")
if str(discord_message.author.top_role) == "Admin":
print("Admin Check")
response = str("tts deactivated on %s" % discord_message.guild.name)
await bot.send_message(discord_message, response)
bot.tts_enabled = False

View File

@ -12,6 +12,9 @@ def load_commands() -> Dict[str, AbstractCommand]:
commands = compile_and_load()
return commands
def load_commands_new(commandType: AbstractCommand.CommandType) -> Dict[str, AbstractCommand]:
commands = compile_and_load_new(commandType)
return commands
def compile_and_load_file(path: str) -> (str, AbstractCommand):
module_name = os.path.split(path)[1].replace(".py", "")
@ -41,6 +44,18 @@ def compile_and_load() -> Dict[str, AbstractCommand]:
break
return dic
def compile_and_load_new(commandType: AbstractCommand.CommandType) -> Dict[str, AbstractCommand]:
dic = {}
implementations = get_implementations_dir()
for dirName, subdirList, fileList in os.walk(implementations):
for file in fileList:
name = os.path.join(dirName, file)
print("compiling %s" % name)
name, command = compile_and_load_file(name)
if command is not None and command.command_type is commandType:
dic[name] = command
break
return dic
def get_base_dir() -> str:
cwd = os.getcwd()
@ -52,7 +67,7 @@ def get_base_dir() -> str:
return check_dir(os.path.join(cwd, "commands"))
else:
print("could not find working directory for Praxis_Bot/commands")
raise
raise Exception
def get_implementations_dir() -> str:

View File

@ -74,7 +74,7 @@ class PollyVoices(Enum):
Zhiyu = "Zhiyu"
botList = ("Nightbot", "StreamElements", "Moobot", "praxis_bot")
botList = ("Nightbot", "StreamElements", "Moobot", "Praxis Bot", "praxis_bot", "MEE6 +", "Nerdy", "Rythm", "Groovy")
slurList = ("fag", "faggot", "niga", "nigga", "nigger", "retard", "tard", "rtard", "coon")

View File

@ -1,6 +1,4 @@
{
"username": "discord",
"helix": "secret discord",
"oauth": "token discord",
"v5_client": "I have no idea here"
"nickname": "AnythingYouWant",
"token": ""
}

View File

@ -146,8 +146,8 @@ class Credentials_Module():
foundSomething = False
tempCert: Discord_Credential = None
for cert in self.Discord_Credentials_List:
if cert.username == searchParam:
print("Discord Credential Found: {" + cert.username + "}")
if cert.nickname == searchParam:
print("Discord Credential Found: {" + cert.nickname + "}")
tempCert = cert
foundSomething = True
if foundSomething:

2
db.py
View File

@ -13,7 +13,7 @@ class db_module():
self.currentWorkingDB: str
self.engine = None
def setup_engine(self, credential: credentials.DB_Credential):
def setup_engine(self, credential: credentials.DB_Credential = None):
createEngine = True
if credential is None:
if self.dbCredential is None:

152
discord_script.py Normal file
View File

@ -0,0 +1,152 @@
import random
import re
from discord import message
from discord.client import Client
import asyncio
import config as config
import db
import tts
import commands.loader as command_loader
from commands.command_base import AbstractCommand
import credentials
import discord
import discord.message
import discord.channel
from cooldowns import Cooldown_Module
class Discord_Module(discord.Client):
def __init__(self):
super().__init__()
self.loop = asyncio.get_event_loop()
self.dbCredential: credentials.DB_Credential
self.discordCredential: credentials.Discord_Credential
self.cooldownModule:Cooldown_Module = Cooldown_Module()
self.cooldownModule.setupCooldown("discordRateLimit", 10, 1)
self.commands = command_loader.load_commands_new(AbstractCommand.CommandType.DISCORD)
self.tts_enabled: bool = False
async def startup(self):
await self.start(self.discordCredential.token)
def main(self):
print("starting loop")
self.loop.create_task(self.startup())
self.loop.run_forever()
async def on_ready(self):
print('Logged on as', self.user)
async def on_message(self, message: discord.Message):
print("{" + message.guild.name + "}[ " + str(message.channel) + " ](" + message.author.display_name + ")> ")
print(message.content)
#Message ID
#print(str(message.id))
#Channel ID
#print(str(message.channel.id))
if message.content == "//test":
await message.channel.send('test response')
if not await self.isSenderBot(message):
if self.cooldownModule.isCooldownActive("discordRateLimit") == False:
await self.eval_commands(message)
await self.tts_message(message)
async def eval_commands(self, message: discord.Message):
# containsURL: bool = self.contains_url(message)
try:
#first_space_idx = message.text.index(' ')
# This fixes a error where if you send a command without arguments it fails because
# it cant find the substring.
if message.content.find(" ") != -1:
first_space_idx = message.content.index(' ')
else:
first_space_idx = -1
command_text = ' '
if first_space_idx > -1:
command_text = message.content[0:first_space_idx]
else:
command_text = message.content
command = self.commands[command_text]
if command is not None and command.command_type is AbstractCommand.CommandType.DISCORD:
await command.do_command(self, message)
except Exception as e:
# Undo the following for debug stuff
#print(e)
pass # we don't care
async def send_message(self, message, response):
if self.cooldownModule.isCooldownActive("discordRateLimit") == False:
await message.channel.send(response)
self.cooldownModule.actionTrigger("discordRateLimit")
async def tts_message(self, message: discord.Message):
if not await self.contains_slur(message):
if self.tts_enabled:
if not message.content.startswith('!'):
text_to_say: str = "%s says, %s" % (message.author.display_name, message.content)
channel_text = "%s user msg" % message.channel
tts.tts(text_to_say)
# Checks for basic slurs.
async def contains_slur(self, message: discord.Message):
containsSlur: bool = False
if await self.slur_check(message.content) or await self.slur_check(message.author.display_name):
containsSlur = True
return containsSlur
async def slur_check(self, text):
containsSlur: bool = False
parsedMessage = text.split(" ")
for word in parsedMessage:
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:
print("<{ slur detected! }>")
#print("<{ slur detected! }> " + " [#" + message.channel + "](" + message.author.display_name + ") used a slur in chat")
return containsSlur
# Checks if Sender is bot.
async def isSenderBot(self, message: discord.Message):
isBot = False
for bot in config.botList:
if message.author.display_name.lower() == bot.lower():
isBot = True
print("<{ bot detected! }> ")
return isBot
if __name__ == "__main__":
testModule = Discord_Module()
credentials_manager = credentials.Credentials_Module()
credentials_manager.load_credentials()
testModule.dbCredential = credentials_manager.find_DB_Credential("praxis_bot")
testModule.discordCredential = credentials_manager.find_Discord_Credential("praxis_bot")
testModule.main()
testModule.main()

61
main.py
View File

@ -5,31 +5,72 @@ import sys
import time
import twitch_script
import discord_script
import utilities_script as utility
import credentials
import threading
twitch_chat: twitch_script.Twitch_Module
credentials_manager: credentials.Credentials_Module
discord_connection: discord_script.Discord_Module
def main():
global twitch_chat
global credentials_manager
credentials_manager = credentials.Credentials_Module()
credentials_manager.load_credentials()
pass
dbCert: credentials.DB_Credential = credentials_manager.find_Credential(credentials.DB_Credential, "praxis_bot")
twitchCert: credentials.Twitch_Credential = credentials_manager.find_Twitch_Credential("praxis_bot")
twitch_chat = twitch_script.Twitch_Module()
def new_main(inputArg):
args = utility.get_args(inputArg)
def twitch_module_init(dbCert, twitchCert):
twitch_chat.db_manager.setup_engine(dbCert)
twitch_chat.twitchCredential = twitchCert
twitch_chat.join_channel(None, "thecuriousnerd")
# twitch_chat.send_message("activated")
def discord_module_init(dbCert, discordCert):
discord_connection.dbCredential = dbCert
discord_connection.discordCredential = discordCert
discord_connection.main()
def thread_main():
global twitch_chat
global discord_connection
global credentials_manager
twitch_chat = twitch_script.Twitch_Module()
discord_connection = discord_script.Discord_Module()
credentials_manager = credentials.Credentials_Module()
credentials_manager.load_credentials()
dbCert: credentials.DB_Credential = credentials_manager.find_Credential(credentials.DB_Credential, "praxis_bot")
twitchCert: credentials.Twitch_Credential = credentials_manager.find_Twitch_Credential("praxis_bot")
discordCert: credentials.Discord_Credential = credentials_manager.find_Discord_Credential("praxis_bot")
threads = []
twitch = threading.Thread(target=twitch_module_init, args=(dbCert, twitchCert))
threads.append(twitch)
twitch.start()
discord = threading.Thread(target=discord_module_init, args=(dbCert, discordCert))
threads.append(discord)
discord.start()
print("---Post Thread Creation Test---")
for t in threads:
t.join()
print("---Point of no return---")
if __name__ == "__main__":
main()
thread_main()

View File

@ -5,4 +5,5 @@ SQLAlchemy
pandas
numpy
gTTS
playsound
playsound
discord.py

View File

@ -23,7 +23,7 @@ class Twitch_Module():
self.db_manager: db.db_module = db.db_module()
self.chat: twitch.Chat
self.commands = command_loader.load_commands()
self.commands = command_loader.load_commands_new(AbstractCommand.CommandType.TWITCH)
self.tts_enabled: bool = False
self.tts_whitelist_enabled: bool = False
self.links_allowed: bool = True
@ -34,8 +34,8 @@ class Twitch_Module():
# Default Twitch Chat limit is 20 per 30 seconds
# If Mod or Op, Twitch Chat limit is 100 per 30 seconds
self.twitchChat_cooldown:Cooldown_Module = Cooldown_Module()
self.twitchChat_cooldown.setupCooldown("twitchChat", 20, 32)
self.cooldownModule:Cooldown_Module = Cooldown_Module()
self.cooldownModule.setupCooldown("twitchChat", 20, 32)
def join_channel(self, credential: credentials.Twitch_Credential, channel_name:str):
channel_name = "#" + channel_name
@ -60,9 +60,9 @@ class Twitch_Module():
self.chat.irc.socket.close()
def send_message(self, message):
if self.twitchChat_cooldown.isCooldownActive("twitchChat") == False:
if self.cooldownModule.isCooldownActive("twitchChat") == False:
self.chat.send(message)
self.twitchChat_cooldown.actionTrigger("twitchChat")
self.cooldownModule.actionTrigger("twitchChat")
def send_whisper(self, user, message):
pass
@ -73,13 +73,12 @@ class Twitch_Module():
if message.channel == "thecuriousnerd":
if not self.isSenderBot(message):
if self.twitchChat_cooldown.isCooldownActive("twitchChat") == False:
if self.cooldownModule.isCooldownActive("twitchChat") == False:
self.eval_commands(message)
#elif message.channel == message.sender:
#self.eval_commands(message)
self.tts_message(message)
def eval_commands(self, message: twitch.chat.Message):
print("evaling command")
# containsURL: bool = self.contains_url(message)
try:
#first_space_idx = message.text.index(' ')
@ -99,9 +98,12 @@ class Twitch_Module():
command = self.commands[command_text]
if command is not None and command.command_type is AbstractCommand.CommandType.TWITCH:
print("evaling command")
command.do_command(self, message)
except Exception as e:
print(e)
# Undo the following for debug stuff
#print(e)
print("failed command")
pass # we don't care
@ -112,11 +114,7 @@ class Twitch_Module():
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(text_to_say)
else:
# tts.tts(message.sender + " says, " + message.text)
tts.tts(text_to_say, channel_text)
tts.tts(text_to_say)
def contains_url(self, message: twitch.chat.Message):
containsURL = re.search(self._urlMatcher, message.text.lower()) is not None

View File

@ -1,3 +1,6 @@
import os
clearScreen = lambda: os.system('cls' if os.name == 'nt' else 'clear')
def get_args(text: str) -> list:
return text.split(" ")