Added slash-commands to reload all cogs aswell as print general information

This commit is contained in:
2024-10-12 23:44:42 +02:00
parent 57282d9c56
commit 709f5df4db
8 changed files with 154 additions and 1 deletions
+1
View File
@@ -1,2 +1,3 @@
[DISCORD]
TOKEN = <PLACE YOUR DISCORD TOKEN FROM THE DEV PORTAL HERE>
OWNER_ID = <PLACE THE USER ID OF THE OWNER HERE>
+45
View File
@@ -0,0 +1,45 @@
import discord
from discord import app_commands
from discord.ext import commands
from cogs.base_cog import Base_Cog
import logging
from utils.portal import Portal
class About_Command(Base_Cog):
def __init__(self, bot:commands.Bot):
self.__bot = bot
super().__init__(logging.getLogger("cmds.about"))
@app_commands.command(name = "about", description = "Provides general information about the bot")
async def about(self, ctx: discord.Interaction):
portal:Portal = Portal.instance()
embed = discord.Embed(title=f"POST IT - `{portal.PROGRAM_VERSION}`",
description="### Übersicht der Befehle\n- `/post` Veröffentlicht einen Post einer anderen Plattform, mit beliebigen Bildern als Anhang\n- `/help` Zeigt diese Übersicht an\n- `/settings` Persönliche Einstellungen für das verhalten des Bots\n- `/stats` Zeigt persönliche und globale Statistiken\n- `/debug` Erweiterte Informationen zum Betriebszustandes des Bots",
colour=0x5a5a5a)
embed.add_field(name="Status des Bots",
value="Fehlerfrei :green_circle:",
inline=True)
embed.add_field(name="Besitzer der Bot Instanz",
value=f"<@{portal.bot_config['DISCORD']['OWNER_ID']}>",
inline=True)
await ctx.response.send_message(embed = embed, ephemeral = True)
async def setup(bot:commands.Bot):
await bot.add_cog(About_Command(bot))
# class AddCog(commands.Cog):
# def __init__(self, bot):
# self.bot = bot
# @app_commands.command(name="add", description="Füge ein neues Wort zur Liste hinzu")
# async def add(self, interaction: discord.Interaction, new_word: str):
# if new_word.lower() not in self.bot.known_words:
# self.bot.known_words.append(new_word.lower())
# await interaction.response.send_message(f"Wort '{new_word}' wurde zur Liste hinzugefügt.")
# else:
# await interaction.response.send_message(f"Wort '{new_word}' existiert bereits.")
# async def setup(bot):
# await bot.add_cog(AddCog(bot))
+14
View File
@@ -0,0 +1,14 @@
import discord
from discord import app_commands
from discord.ext import commands
import logging
class Base_Cog(commands.Cog):
def __init__(self, logger:logging.Logger):
self._logger = logger
async def cog_load(self):
self._logger.debug(f"Cog for the '{self.__class__.__name__}' command got loaded")
async def cog_unload(self):
self._logger.debug(f"Cog for the '{self.__class__.__name__}' command got unloaded")
+25
View File
@@ -0,0 +1,25 @@
import discord
from discord import app_commands
from discord.ext import commands
from cogs.base_cog import Base_Cog
import logging
from datetime import datetime
class Reload_Command(Base_Cog):
def __init__(self, bot:commands.Bot):
self.__bot = bot
super().__init__(logging.getLogger("cmds.reload"))
@app_commands.command(name = "reload_all", description = "Reloads all cogs")
async def about(self, ctx: discord.Interaction):
self._logger.info("Reloading all cogs ...")
task_start = datetime.now().timestamp()
cog_names = list(self.__bot.extensions.keys())
for extension_name in cog_names:
await self.__bot.reload_extension(extension_name)
await ctx.response.send_message("Cogs successfully reloaded.")
async def setup(bot:commands.Bot):
await bot.add_cog(Reload_Command(bot))
+19
View File
@@ -14,6 +14,9 @@ import discord
from discord.ext import commands
from pathlib import Path
import re
import sys
import traceback
from utils.portal import Portal
source_path = Path(__file__).resolve()
base_path = source_path.parents[1]
@@ -26,6 +29,12 @@ class MyBot(commands.Bot):
def __init__(self):
super().__init__(command_prefix=None, help_command=None, intents=intents)
async def setup_hook(self):
# Register cogs to handle commands
for cog_name in ["about", "reload"]:
await self.load_extension(f"cogs.{cog_name}")
await self.tree.sync()
bot = MyBot()
bot_config = Advanced_ConfigParser(Path.joinpath(base_path, "config", "bot.ini"))
if re.match(r'[A-Za-z\d]{24}\.[\w-]{6}\.[\w-]{27}', bot_config["DISCORD"]["TOKEN"]):
@@ -41,6 +50,16 @@ else:
async def on_ready():
app_logger.info(f"Successfully logged in (after {get_elapsed_time_smal(datetime.now().timestamp() - startup)}) as {bot.user}")
@bot.tree.error
async def on_app_command_error(ctx, error):
# Traceback für mehr Informationen zum Fehler
print('Ignoring exception in command {}:'.format(ctx.command), file=sys.stderr)
traceback.print_exception(type(error), error, error.__traceback__)
# Execute some housekeeping actions
portal = Portal.instance()
portal.bot_config = bot_config
try:
bot.run(bot_config["DISCORD"]["TOKEN"], log_handler = None)
except discord.errors.LoginFailure:
+5
View File
@@ -28,5 +28,10 @@ class Custom_Logger:
utils_logger.addHandler(cls.console_handler)
utils_logger.setLevel(logging.DEBUG)
commands_logger = logging.getLogger("cmds")
commands_logger.addHandler(cls.console_handler)
commands_logger.setLevel(logging.DEBUG)
logging.getLogger('discord.app_commands.tree').setLevel(logging.DEBUG)
app_logger.debug("Logging successfully initialized")
+6
View File
@@ -0,0 +1,6 @@
from utils.singleton import Singleton
@Singleton
class Portal:
PROGRAM_VERSION = "0.1"
bot_config = None
+38
View File
@@ -0,0 +1,38 @@
class Singleton:
"""
A non-thread-safe helper class to ease implementing singletons.
This should be used as a decorator -- not a metaclass -- to the
class that should be a singleton.
The decorated class can define one `__init__` function that
takes only the `self` argument. Also, the decorated class cannot be
inherited from. Other than that, there are no restrictions that apply
to the decorated class.
To get the singleton instance, use the `instance` method. Trying
to use `__call__` will result in a `TypeError` being raised.
"""
# Source: https://stackoverflow.com/questions/31875/is-there-a-simple-elegant-way-to-define-singletons
def __init__(self, decorated):
self._decorated = decorated
def instance(self):
"""
Returns the singleton instance. Upon its first call, it creates a
new instance of the decorated class and calls its `__init__` method.
On all subsequent calls, the already created instance is returned.
"""
try:
return self._instance
except AttributeError:
self._instance = self._decorated()
return self._instance
def __call__(self):
raise TypeError('Singletons must be accessed through `instance()`.')
def __instancecheck__(self, inst):
return isinstance(inst, self._decorated)