Add a IRC wrapper for Discord command implementations
This commit is contained in:
parent
78f30b19fe
commit
5dccc2d4bb
5 changed files with 145 additions and 4 deletions
115
ircbot.py
Executable file
115
ircbot.py
Executable file
|
@ -0,0 +1,115 @@
|
|||
import asyncio
|
||||
import os
|
||||
import sys
|
||||
|
||||
import pydle
|
||||
from discord_webhook import DiscordEmbed
|
||||
|
||||
import commands as botcommands
|
||||
|
||||
|
||||
class DiscordAuthor:
|
||||
def __init__(self, nick):
|
||||
self.nick = nick
|
||||
self.global_name = nick
|
||||
|
||||
|
||||
class DiscordContext:
|
||||
def __init__(self, bot, target, source, message):
|
||||
self._bot = bot
|
||||
self._target = target
|
||||
self._source = source
|
||||
self._message = message
|
||||
self.author = DiscordAuthor(source)
|
||||
|
||||
def typing(self):
|
||||
class NilTyping:
|
||||
async def __aenter__(self):
|
||||
return self
|
||||
|
||||
async def __aexit__(self, *exc):
|
||||
return None
|
||||
|
||||
return NilTyping()
|
||||
|
||||
async def reply(self, m):
|
||||
lines = m.strip().split("\n")
|
||||
lines = [f"{self._source}: {line}" for line in lines]
|
||||
await self._bot.message(self._target, "\n".join(lines))
|
||||
|
||||
|
||||
class DiscordImplBot(pydle.Client):
|
||||
def __init__(self, channel, nickname, *, push_messages=None, prefix="!"):
|
||||
super().__init__(nickname, realname=nickname)
|
||||
self._channel = channel
|
||||
self._cmd_prefix = prefix
|
||||
self._cmds = {}
|
||||
self._push_messages = push_messages
|
||||
self._push_messages_task = None
|
||||
|
||||
async def on_connect(self):
|
||||
await self.join(self._channel)
|
||||
if self._push_messages is not None:
|
||||
self._push_messages_task = asyncio.create_task(self._handle_push_messages())
|
||||
|
||||
async def on_disconnect(self):
|
||||
if self._push_messages_task is not None:
|
||||
self._push_messages_task.cancel()
|
||||
self._push_messages_task = None
|
||||
|
||||
async def _handle_push_messages(self):
|
||||
async for message in self._push_messages():
|
||||
if isinstance(message, DiscordEmbed):
|
||||
await self.message(self._channel, f"{message.title} {message.url}")
|
||||
else:
|
||||
await self.message(self._channel, message)
|
||||
|
||||
async def on_message(self, target, source, message):
|
||||
# Don't respond to our own messages, as this leads to a positive feedback loop.
|
||||
if source == self.nickname:
|
||||
return
|
||||
if not message.startswith(self._cmd_prefix):
|
||||
return
|
||||
|
||||
cmd_fn = self._cmds.get(message.removeprefix(self._cmd_prefix))
|
||||
if not cmd_fn:
|
||||
return
|
||||
|
||||
ctx = DiscordContext(self, target, source, message)
|
||||
await cmd_fn(ctx)
|
||||
|
||||
# Discord API: Register a new command
|
||||
def command(self, *, name=None, description=None):
|
||||
def _reg_cmd(handler):
|
||||
nonlocal name
|
||||
name = name or handler.__name__
|
||||
self._cmds[name] = handler
|
||||
|
||||
return _reg_cmd
|
||||
|
||||
|
||||
def main(*, server, channel, nick, mqtt_host):
|
||||
def push_messages():
|
||||
return botcommands.run_events(mqtt_host)
|
||||
|
||||
bot = DiscordImplBot(
|
||||
channel,
|
||||
nick,
|
||||
push_messages=push_messages,
|
||||
)
|
||||
botcommands.setup(bot, mqtt_host)
|
||||
bot.run(server, tls=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
mqtt_host = os.getenv("MQTT_HOST")
|
||||
if not mqtt_host:
|
||||
print("MQTT_HOST unset")
|
||||
sys.exit(1)
|
||||
|
||||
main(
|
||||
server="irc.libera.chat",
|
||||
channel="#bitlair-bot-test",
|
||||
nick="Bitlair",
|
||||
mqtt_host=mqtt_host,
|
||||
)
|
Loading…
Add table
Add a link
Reference in a new issue