# Example: https://github.com/Rapptz/discord.py/blob/master/examples/app_commands/basic.py import os, re, random, logging, asyncio, discord from discord import app_commands from functools import reduce from dotenv import load_dotenv from typing import Optional # TODO: Reenable and extend scraper # from models import Models # We're fancy today from rich.traceback import install install(show_locals=True) # DONE: Migrate back to discord.py # TODO: Rewrite bot with slash commands (and making actual use of discord.py) # TODO: yt-dlp music support # TODO: Send messages only to heidispam channel # TODO: Print status messages to heidispam # TODO: Somehow upload voicelines more easily (from discord voice message?) # TODO: Reenable text/quote generation, allow uploading of training text files, allow switching "personalities" # TODO: Zalgo generator # IDs of the servers Heidi is used on LINUS_GUILD = discord.Object(id=431154792308408340) TEST_GUILD = discord.Object(id=821511861178204161) class HeidiClient(discord.Client): def __init__(self, *, intents: discord.Intents): super().__init__(status="Nur eine kann GNTM werden!", intents=intents) # Separate object that keeps all application command state self.tree = app_commands.CommandTree(self) # TODO: Replace with slash commands self.prefix = "Heidi, " self.prefix_regex = "^" + self.prefix # self.models = Models() # scraped model list # automatic actions on all messages # auto_triggers is a map with tuples of two functions: (predicate, action) # if the predicate is true the action is performed self.auto_triggers = { # lambda m: m.author.nick.lower() in self.models.get_in_names(): self.autoreact_to_girls, lambda m: "jeremy" in m.author.nick.lower(): self._autoreact_to_jeremy } # TODO: Replace these by slash commands # explicit commands self.matchers = { "Hilfe$": self.show_help, "Heidi!$": self.say_name, # GNTM stuff # "wer ist dabei\\?$": self.list_models_in, # "wer ist raus\\?$": self.list_models_out, # "gib Bild von .+$": self.show_model_picture, "gib Link$": self.show_link, # Fun stuff "welche Farbe .+\\?": self.random_color, ".+, ja oder nein\\?": self.magic_shell, "wähle: (.+,?)+$": self.choose, "sprechen": self.list_voicelines, "sag .+$": self.say_voiceline } # Synchronize commands to guilds async def setup_hook(self): self.tree.copy_global_to(guild=LINUS_GUILD) await self.tree.sync(guild=LINUS_GUILD) self.tree.copy_global_to(guild=TEST_GUILD) await self.tree.sync(guild=TEST_GUILD) # Helpers ------------------------------------------------------------------------------------ def _help_text(self): """ Generate help-string from docstrings of matchers and triggers """ docstrings_triggers = [ " - " + str(func.__doc__).strip() for func in self.auto_triggers.values() ] docstrings_matchers = [ " - " + str(func.__doc__).strip() for func in self.matchers.values() ] response = 'Präfix: "' + self.prefix + '" (mit Leerzeichen)\n' response += "--------------------------------------------------\n" response += "Automatisch:\n" response += "\n".join(docstrings_triggers) response += "\n\nCommands:\n" response += "\n".join(docstrings_matchers) return response def _match(self, matcher, message): """ Check if a string matches against prefix + matcher (case-insensitive) """ return re.match(self.prefix_regex + matcher, message.content, re.IGNORECASE) # Commands ----------------------------------------------------------------------------------- async def show_help(self, message): """ Hilfe (Senpai UwU) """ await message.channel.send(self._help_text()) @staticmethod async def say_name(message): """ Heidi! """ await message.channel.send("HEIDI!") # async def list_models_in(self, message): # """ # wer ist dabei? # """ # await message.channel.send("\n".join(self.models.get_in_names())) # async def list_models_out(self, message): # """ # wer ist raus? (Liste der Keks welche ge*ickt wurden) # """ # await message.channel.send("\n".join(self.models.get_out_names())) # async def show_model_picture(self, message): # """ # gib Bild von # """ # name = message.content.split()[-1] # picture = discord.Embed() # picture.set_image(url=self.models.get_image(name)) # picture.set_footer(text=name) # await message.channel.send(embed=picture) @staticmethod async def magic_shell(message): """ , ja oder nein? """ choices = [ "Ja!", "Jo.", "Total!", "Natürlich.", "Nein!", "Nö.", "Nä.", "Niemals!", ] await message.channel.send(random.choice(choices)) # TODO: Accept multi-word inputs: "Heidi, wähle: Ipp ist dumm, ich bin dumm" @staticmethod async def choose(message): """ wähle: