diff --git a/CalBot/__init__.py b/CalBot/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/CalBot/discord/__init__.py b/CalBot/discord/__init__.py new file mode 100644 index 0000000..11921e9 --- /dev/null +++ b/CalBot/discord/__init__.py @@ -0,0 +1,3 @@ +from .discord_client import DiscordClient + +__all__ = ["DiscordClient"] diff --git a/CalBot/discord/discord_client.py b/CalBot/discord/discord_client.py new file mode 100644 index 0000000..84168f6 --- /dev/null +++ b/CalBot/discord/discord_client.py @@ -0,0 +1,85 @@ +import discord +from asyncio import Queue, create_task +import concurrent.futures + +""" +Abstraction around the Discord client library +""" + + +class DiscordClient(discord.Client): + + def __init__(self): + super().__init__() + self._commands = {} + self._queue = Queue() + self.bg_task = self.loop.create_task(self._send_loop()) + + def add_command(self, command, responder): + """ + Add a command. + + :param command: The command prefix. For example, '!command'. + :param responder: The function that responds to the message. This can return either a string, an embed or None. + """ + self._commands[command] = responder + + async def on_message(self, message): + """ + Called whenever a message is sent to a Discord channel that ButlerBot can read. + This overrides on_message() from discord.py. + + :param message: The message sent by the user. + """ + # Don't listen to messages coming from ButlerBot. + if message.author == self.user: + return + + # Check if message matches any of the supported command prefixes. + for command, responder in self._commands.items(): + command_prefix = message.content.split(' ')[0] + if command_prefix == command: + await self._do_command(responder, message) + + async def _do_command(self, responder, message): + """ + Respond to a command. + + :param responder: The function that responds to the message. + :param message: The message sent by the user. + """ + # Some commands take a while. Let users know by showing the Discord typing indicator. + with concurrent.futures.ThreadPoolExecutor() as pool: + response_placeholder = await message.channel.send(content=":hourglass: **Command in progress...**") + await message.channel.trigger_typing() + response = await self.loop.run_in_executor(pool, responder, message) + await response_placeholder.delete() + if response is None: + pass + elif isinstance(response, discord.Embed): + await message.channel.send(embed=response) + else: + await message.channel.send(content=response) + + def queue_message(self, channel, message): + """ + Queues a message to be sent. + + :param channel: The channel in which the message will be sent. + :param message: The message to be sent. This can be eiher a string or an embed. + """ + self._queue.put_nowait((channel, message)) + + async def _send_loop(self): + """ + Sends queued messages. + """ + await self.wait_until_ready() + while True: + channel, message = await self._queue.get() + if channel is not None and message is not None: + if isinstance(message, discord.Embed): + await channel.send(embed=message) + else: + await channel.send(content=message) + self._queue.task_done() diff --git a/CalBot/main.py b/CalBot/main.py new file mode 100644 index 0000000..8844b79 --- /dev/null +++ b/CalBot/main.py @@ -0,0 +1,14 @@ +from CalBot.discord import DiscordClient +from CalBot.reminder import Reminder + + +def main(): + client = DiscordClient() + + Reminder(client) + + client.run("YOURDISCORDBOTTOKENYy.XlQ5bA.PvDElVz0dzxiSfMHb693WBuOb2E") + + +if __name__ == "__main__": + main() diff --git a/CalBot/reminder/__init__.py b/CalBot/reminder/__init__.py new file mode 100644 index 0000000..7ed41b5 --- /dev/null +++ b/CalBot/reminder/__init__.py @@ -0,0 +1 @@ +from .reminder import * diff --git a/CalBot/reminder/reminder.py b/CalBot/reminder/reminder.py new file mode 100644 index 0000000..8a01f51 --- /dev/null +++ b/CalBot/reminder/reminder.py @@ -0,0 +1,15 @@ +import discord +import socket +from CalBot.discord import DiscordClient + + +class Reminder(): + + def __init__(self, client): + self._discord = client + self._discord.add_command('!reminder', self._parse_command) + + def _parse_command(self, command): + embed = discord.Embed(color=0x00ff00) + embed.set_image(url='https://media.discordapp.net/attachments/506852356898422797/715690132883111996/Capture.PNG') + return embed diff --git a/README.md b/README.md index 71372ee..0bafeb0 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,13 @@ # CalBot +Use a Python 3.8 venv. Install using... +```bash +python38 -m venv venv +source venv/bin/activate +pip install . +``` + +Run using... +``` +calbot +``` \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..945c9b4 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +. \ No newline at end of file diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..d18fc45 --- /dev/null +++ b/setup.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 + +from setuptools import setup, find_packages + +with open('LICENSE') as f: + license = f.read() + +setup( + name='calbot', + version='0.1', + description='A Discord bot for Callum', + author='Jack Hadrill', + author_email='', + url='https://git.jacknet.io/jackhadrill/CalBot', + license=license, + packages=[ + 'CalBot', + 'CalBot.discord', + 'CalBot.reminder', + ], + entry_points={ + 'console_scripts' : [ + 'calbot = CalBot.main:main' + ] + }, + install_requires=[ + 'discord.py>=1.3.1', + ] +)