diff --git a/commands/command_base.py b/commands/command_base.py index 27cf842..761c602 100644 --- a/commands/command_base.py +++ b/commands/command_base.py @@ -53,5 +53,5 @@ class AbstractCommand(metaclass=ABCMeta): return self.isCommandEnabled @abstractmethod - def do_command(self, bot, command, rest): + def do_command(self, bot, user, command, rest): pass \ No newline at end of file diff --git a/commands/implemented/Command_test_v2.py b/commands/implemented/Command_test_v2.py index 1c910b3..09cba73 100644 --- a/commands/implemented/Command_test_v2.py +++ b/commands/implemented/Command_test_v2.py @@ -16,8 +16,8 @@ class Command_test_v2(AbstractCommand, metaclass=ABCMeta): "\nExample:","testerino"] self.isCommandEnabled = True - def do_command(self, source = AbstractCommand.CommandSource.default, command = "", rest = ""): - returnString = command + " is and rest is " + rest + def do_command(self, source = AbstractCommand.CommandSource.default, user = "User", command = "", rest = ""): + returnString = user + " sent: [ " + command + " ] with: " + rest #print(returnString) return returnString diff --git a/discord_script_standalone.py b/discord_script_standalone.py new file mode 100644 index 0000000..3a7d316 --- /dev/null +++ b/discord_script_standalone.py @@ -0,0 +1,165 @@ +import random +import re +import utilities_script as utility +from json import loads +from urllib.parse import urlencode + +import requests + +from discord import message +from discord.client import Client +import asyncio + +import config + +import commands.command_base +import commands.loader as command_loader +from commands.command_base import AbstractCommand + +import credentials + +import discord +import discord.message +import discord.channel +import discord.abc + +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) + + # 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))") + + + 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.author.mention) + print(message.content) + + if not await self.isSenderBot(message): + # This will check for the praxis_bot-tts channel and will TTS stuff from there. + #await self.eval_triggeredEvents(message) + + await self.eval_commands(message) + #await self.tts_message(message) + + + async def eval_triggeredEvents(self, message: discord.Message): + # This will check for the selected channels and will TTS stuff from there. + #await self.tts_message(message) + foundChannel = False + + for channel in self.selected_ttsChannels: + if channel == message.channel.id: + # await self.tts_message(message) + pass + + async def eval_commands(self, message: discord.Message): + command, rest = utility.parse_line(message.content) + + is_actionable = await self.is_command(command) + if is_actionable: + if self.cooldownModule.isCooldownActive("discordRateLimit") == False: + await self.exec_command(message, command, rest) + + async def is_command(self, word: str) -> bool: + # todo need to url-escape word + clean_param = urlencode({'name': word}) + url = "http://localhost:5000/api/v1/command?%s" % clean_param + resp = requests.get(url) + return resp.status_code == 200 + + async def exec_command(self, realMessage: discord.Message, command: str, rest: str): + # todo need to url-escape command and rest + params = urlencode({'command_source': commands.command_base.AbstractCommand.CommandSource.Discord, 'user_name': realMessage.author.mention, 'command_name': command, 'rest': rest}) + url = "http://localhost:5000/api/v1/exec?%s" % params + resp = requests.get(url) + if resp.status_code == 200: + print("Got the following message: %s" % resp.text) + data = loads(resp.text) + msg = data['message'] + if msg is not None: + await self.send_message(realMessage, msg) + else: + # todo handle failed requests + pass + + + async def send_message(self, message: discord.Message, response): + isBlocked = await self.isChannel_inConfigList(str(message.channel.id), config.block_DiscordChannelsMessaging) + if self.cooldownModule.isCooldownActive("discordRateLimit") == False and not isBlocked and not config.blockAll_DiscordChannelsMessaging: + if not await self.contains_slur(response): + await message.channel.send(response) + + self.cooldownModule.actionTrigger("discordRateLimit") + + + # Checks for basic slurs. + async def contains_slur(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 + + async def isChannel_inConfigList(self, selectedChannel, selectedList): + #print(channel) + #print(selectedList) + is_Self = False + for discordChannel in selectedList: + #print("isSelf: " + str(discordChannel) + " vs " + str(selectedChannel)) + if discordChannel == selectedChannel: + is_Self = True + + return is_Self + + + + +if __name__ == "__main__": + testModule = Discord_Module() + + credentials_manager = credentials.Credentials_Module() + credentials_manager.load_credentials() + testModule.dbCredential = credentials_manager.find_DB_Credential(config.credentialsNickname) + testModule.discordCredential = credentials_manager.find_Discord_Credential(config.credentialsNickname) + + testModule.main() \ No newline at end of file diff --git a/standalone_command.py b/standalone_command.py index 9419921..8553195 100644 --- a/standalone_command.py +++ b/standalone_command.py @@ -32,7 +32,7 @@ def is_command(command: str) -> bool: else: return False -def handle_command(source, command, rest): +def handle_command(source, username, command, rest): if command == "!echo": message = "Got payload [%s]" % rest #print(message) @@ -40,7 +40,7 @@ def handle_command(source, command, rest): cmd:AbstractCommand = loadedCommands[command] if cmd is not None: - cmd_response = cmd.do_command(source, command, rest) + cmd_response = cmd.do_command(source, username, command, rest) return flask.make_response("{\"message\":\"%s\"}" % cmd_response, 200, {"Content-Type": "application/json"}) #print("Doing a command") @@ -65,7 +65,12 @@ def exec_command(): if 'command_source' not in request.args: return flask.make_response('{\"text\":"Argument \'command_source\' not in request"}', 400) - return handle_command(request.args['command_source'], request.args['command_name'], request.args['rest']) + if 'user_name' not in request.args: + username = "User" + else: + username = request.args['user_name'] + + return handle_command(request.args['command_source'], username, request.args['command_name'], request.args['rest']) if __name__ == '__main__': diff --git a/twitch_script_standalone.py b/twitch_script_standalone.py index f01f9ba..187c0a4 100644 --- a/twitch_script_standalone.py +++ b/twitch_script_standalone.py @@ -10,7 +10,7 @@ import config as config import credentials from cooldowns import Cooldown_Module import commands.command_base - +import utilities_script as utility class Twitch_Module(): def __init__(self): @@ -58,7 +58,7 @@ class Twitch_Module(): isBlocked = self.isChannel_inConfigList(self.chat.channel, config.block_TwitchChannelsMessaging) # print("isBlocked: " + str(isBlocked) + " for: " + self.chat.channel) #if self. - if self.contains_slur(message): isBlocked = True + if utility.contains_slur(message): isBlocked = True if self.cooldownModule.isCooldownActive( "twitchChat") == False and not isBlocked and not config.blockAll_TwitchChatChannelsMessaging: @@ -66,31 +66,6 @@ class Twitch_Module(): # print("Sent ChatMSG") self.cooldownModule.actionTrigger("twitchChat") - def parse_line(self, message: str): - first_space = False - start = -1 - idx = -1 - for x in range(0, len(message)): - c = message[x] - if c == ' ': - if first_space: - idx = x - break - else: - first_space = True - pass - else: - first_space = True - if start == -1: - start = x - - if idx == -1: - idx = len(message) - - command = message[start:idx] - rest = message[idx + 1:] - return command, rest - def is_command(self, word: str) -> bool: # todo need to url-escape word clean_param = urlencode({'name': word}) @@ -98,9 +73,9 @@ class Twitch_Module(): resp = requests.get(url) return resp.status_code == 200 - def exec_command(self, command: str, rest: str): + def exec_command(self, username, command: str, rest: str): # todo need to url-escape command and rest - params = urlencode({'command_source': commands.command_base.AbstractCommand.CommandSource.default, 'command_name': command, 'rest': rest}) + params = urlencode({'command_source': commands.command_base.AbstractCommand.CommandSource.Twitch,'user_name': username, 'command_name': command, 'rest': rest}) url = "http://localhost:5000/api/v1/exec?%s" % params resp = requests.get(url) if resp.status_code == 200: @@ -119,25 +94,12 @@ class Twitch_Module(): # This reacts to messages def twitch_chat(self, message: twitch.chat.Message) -> None: print("[#" + message.channel + "](" + message.sender + ")> " + message.text) - command, rest = self.parse_line(message.text) + command, rest = utility.parse_line(message.text) is_actionable = self.is_command(command) if is_actionable: - self.exec_command(command, rest) - - # Checks for basic slurs. - def contains_slur(self, message): - containsSlur: bool = False - parsedMessage = message.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 - - return containsSlur + if self.cooldownModule.isCooldownActive("twitchChat") == False: + self.exec_command(message.sender ,command, rest) def isChannel_inConfigList(self, selectedChannel, selectedList): # print(channel) diff --git a/utilities_script.py b/utilities_script.py index fdf5a81..4cfb4d0 100644 --- a/utilities_script.py +++ b/utilities_script.py @@ -65,6 +65,31 @@ def contains_slur(input: str): print("<{ slur detected! }> ") return containsSlur +def parse_line(message: str): + first_space = False + start = -1 + idx = -1 + for x in range(0, len(message)): + c = message[x] + if c == ' ': + if first_space: + idx = x + break + else: + first_space = True + pass + else: + first_space = True + if start == -1: + start = x + + if idx == -1: + idx = len(message) + + command = message[start:idx] + rest = message[idx + 1:] + return command, rest + def isRunningInDocker(): isD = os.getenv('ISDOCKER') if isD is None: