From 1ea6a387e4ec9f6c4c327ff90a86141c48b277a0 Mon Sep 17 00:00:00 2001 From: Medicopter117 Date: Fri, 24 Oct 2025 19:45:46 +0200 Subject: [PATCH 01/10] UPDATE: V2 Components for Weather Command --- cogs/Servermanament/welcome.py | 2 +- cogs/fun/weather.py | 72 ++++++++++++++++++++-------- cogs/fun/wikipedia.py | 14 ++++-- docs/todo.md | 0 main.py | 5 +- req.txt | 2 +- translation/command.yaml | 86 ++++++++++++++++++++++++++++++++++ version.txt | 2 +- 8 files changed, 156 insertions(+), 27 deletions(-) create mode 100644 docs/todo.md create mode 100644 translation/command.yaml diff --git a/cogs/Servermanament/welcome.py b/cogs/Servermanament/welcome.py index e6872f2..d27da92 100644 --- a/cogs/Servermanament/welcome.py +++ b/cogs/Servermanament/welcome.py @@ -1,6 +1,6 @@ import discord from discord.ext import commands -from FastCoding import WelcomeDatabase # Korrigierter Import +from DevTools import WelcomeDatabase # Korrigierter Import import asyncio import json import io diff --git a/cogs/fun/weather.py b/cogs/fun/weather.py index 6c9b48b..134f682 100644 --- a/cogs/fun/weather.py +++ b/cogs/fun/weather.py @@ -2,38 +2,72 @@ import requests from DevTools.backend import discord, slash_command, ezcord from DevTools.backend import WEATHER_API +import discord +from discord import slash_command +from discord.ui import Container +import ezcord from DevTools import DEFLAUT_COLOR + + class Weather(ezcord.Cog, group="fun"): def __init__(self, bot: ezcord.Bot): self.bot = bot - @slash_command(name="weather", description="Get the weather for a city") + @slash_command(name="weather", description="Erhalte das Wetter für eine Stadt") async def weather(self, ctx: discord.ApplicationContext, city: str): """Get the weather for a city""" url = f"http://api.weatherapi.com/v1/current.json?key={WEATHER_API}&q={city}&lang=de" - response = requests.get(url) - data = response.json() + + try: + response = requests.get(url, timeout=10) + response.raise_for_status() + data = response.json() + except requests.RequestException: + await ctx.respond("⚠️ Es gab ein Problem beim Abrufen der Wetterdaten. Bitte versuche es später erneut.") + return if "error" in data: - await ctx.respond(f"Error: {data['error']['message']}") + await ctx.respond(f"⚠️ Fehler: {data['error']['message']}") return - data = response.json() - ort = data['location']['name'] - land = data['location']['country'] - temp = data['current']['temp_c'] - zustand = data['current']['condition']['text'] - icon = data['current']['condition']['icon'] - wind = data['current']['wind_kph'] - - embed = discord.Embed(title=f"Wetter in {ort}, {land}", color=DEFLAUT_COLOR) - embed.add_field(name="🌡️ Temperatur", value=f"{temp}°C", inline=True) - embed.add_field(name="🌬️ Wind", value=f"{wind} km/h", inline=True) - embed.add_field(name="☁️ Zustand", value=zustand, inline=False) + location = data['location'] + current = data['current'] + + embed = discord.Embed( + title=f"Wetter in {location['name']}, {location['country']}", + description=f"Zeitzone: {location['tz_id']}\nLetzte Aktualisierung: {current['last_updated']}", + color=DEFLAUT_COLOR + ) + + embed.add_field(name="🌡️ Temperatur", value=f"{current['temp_c']}°C", inline=True) + embed.add_field(name="💧 Luftfeuchtigkeit", value=f"{current['humidity']}%", inline=True) + embed.add_field(name="🌬️ Wind", value=f"{current['wind_kph']} km/h ({current['wind_dir']})", inline=True) + embed.add_field(name="☁️ Zustand", value=current['condition']['text'], inline=False) + embed.add_field(name="🌫️ Sichtweite", value=f"{current['vis_km']} km", inline=True) + embed.add_field(name="🌡️ Luftdruck", value=f"{current['pressure_mb']} hPa", inline=True) + embed.add_field(name="🌅 Sonnenauf-/untergang", value=f"{current.get('astro', {}).get('sunrise', 'N/A')} / {current.get('astro', {}).get('sunset', 'N/A')}", inline=False) + + embed.set_thumbnail(url="http:" + current['condition']['icon']) embed.set_footer(text="Weather data provided by WeatherAPI") - embed.set_thumbnail(url="http:" + icon) - await ctx.respond(embed=embed) + container = Container() + container.add_text( + f"## Wetter in {location['name']}, {location['country']} \n" + f"**Zeitzone:** {location['tz_id']}\n**Letzte Aktualisierung:** {current['last_updated']}" + ) + container.add_separator() + container.add_text( + + f"**🌡️ Temperatur:** {current['temp_c']}°C \n" + f"**💧 Luftfeuchtigkeit:** {current['humidity']}% \n" + f"**🌬️ Wind:** {current['wind_kph']} km/h ({current['wind_dir']}) \n " + f"**☁️ Zustand:** {current['condition']['text']} \n" + f"**🌫️ Sichtweite:** {current['vis_km']} km \n" + f"**🌡️ Luftdruck:** {current['pressure_mb']} hPa" + ) + + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view) def setup(bot: ezcord.Bot): - bot.add_cog(Weather(bot)) \ No newline at end of file + bot.add_cog(Weather(bot)) diff --git a/cogs/fun/wikipedia.py b/cogs/fun/wikipedia.py index ba8f1b4..1b54ca6 100644 --- a/cogs/fun/wikipedia.py +++ b/cogs/fun/wikipedia.py @@ -5,9 +5,11 @@ import wikipedia import asyncio import re +import discord from datetime import datetime, timedelta from typing import Optional, List, Dict, Any -from DevTools import discord, ezcord, SlashCommandGroup +from discord import SlashCommandGroup, InteractionContextType, IntegrationType, slash_command +import ezcord # Fallback für Farben falls nicht in FastCoding definiert try: @@ -606,8 +608,14 @@ def cog_unload(self): if hasattr(self, 'cleanup_task') and self.cleanup_task: self.cleanup_task.cancel() - wiki = SlashCommandGroup("wikipedia", "Wikipedia-Funktionen") - @wiki.command(name="search", description="🔍 Durchsuche Wikipedia nach Artikeln und Informationen") + wiki = SlashCommandGroup( + "wikipedia", + "Wikipedia-Funktionen" + ) + @wiki.command( + name="search", + description="🔍 Durchsuche Wikipedia nach Artikeln und Informationen" + ) async def wikipedia_search( self, ctx: discord.ApplicationContext, diff --git a/docs/todo.md b/docs/todo.md new file mode 100644 index 0000000..e69de29 diff --git a/main.py b/main.py index 20bb1bb..708f9a8 100644 --- a/main.py +++ b/main.py @@ -44,12 +44,13 @@ language="auto", default_language="de", logging_level=logging.DEBUG, error_webhook_url=os.getenv("ERROR_WEBHOOK_URL"), - ready_event=None + ready_event=None, + debug_guild=1428835818792947884 ) # ============================================================================= # BOT VERSION # ============================================================================= -BOT_VERSION = "1.7.0" +BOT_VERSION = "1.7.1" VERSION_URL = "https://raw.githubusercontent.com/Oppro-net-Development/ManagerX/main/version.txt" async def check_for_update(): diff --git a/req.txt b/req.txt index 9ace0a6..8d7640e 100644 --- a/req.txt +++ b/req.txt @@ -18,7 +18,7 @@ Jinja2==3.1.6 MarkupSafe==3.0.2 multidict==6.4.3 propcache==0.3.1 -py-cord==2.6.1 +py-cord==2.7.0rc1 pydantic==2.11.7 pydantic_core==2.33.2 python-dotenv==1.1.0 diff --git a/translation/command.yaml b/translation/command.yaml new file mode 100644 index 0000000..f5fcd7f --- /dev/null +++ b/translation/command.yaml @@ -0,0 +1,86 @@ +de: +# Sever -- Welcome System -- + + welcome: + name: willkommen + + channel: + name: kanal + description: Setzt den Willkommenskanal + options: + channel: + name: kanal + description: Setzt den Willkommenskanal + + message: + name: nachricht + description: Setzt die Willkommensnachricht + + toggle: + name: toggle + description: Schaltet das Willkommensystem ein/aus + + embed: + name: embed + description: Aktiviert/Deaktiviert Embed Modus + + autorole: + name: autorole + description: Setzt eine Rolle die automatisch vergeben wird + options: + name: rolle + + dm: + name: dm + description: Aktiviert/Konfiguriert private Willkommensnachrichten + options: + message: + name: nachricht + + template: + name: vorlage + description: Lädt eine Vorlage + options: + template_name: + name: vorlage_name + + config: + name: config + description: Zeigt die aktuelle Konfiguration + + test: + name: text + description: Testet die Willkommensnachricht + + placeholders: + name: platzhalter + description: Zeigt alle verfügbaren Platzhalter + + export: + name: export + description: Exportiert die Willkommenskonfiguration + + stats: + name: stats + description: Zeigt Willkommensstatistiken + + reset: + name: reset + description: Setzt alle Willkommenseinstellungen zurück + +# Server -- TempVC -- + + tempvc: + name: tempvc + description: Verwalte temporäre Voice-Kanal Systeme + + create: + name: erstellen + description: Erstelle ein VC-Erstellungssystem + options: + creator_channel: + name: kanal + description: Kanal, den Mitglieder betreten, um ihren VC zu erstellen + category: + name: kategorie + description: Kategorie, in der die Temp-Channels erstellt werden \ No newline at end of file diff --git a/version.txt b/version.txt index 081af9a..0a182f2 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.7.1 \ No newline at end of file +1.7.2 \ No newline at end of file From 73f01a0d664f3248cb5943254555d58f4d4cfcf5 Mon Sep 17 00:00:00 2001 From: Medicopter117 Date: Sun, 26 Oct 2025 10:42:46 +0100 Subject: [PATCH 02/10] UPDATE: tempvc.py to the new Container --- cogs/Servermanament/tempvc.py | 444 +++++++++++++++++----------------- 1 file changed, 228 insertions(+), 216 deletions(-) diff --git a/cogs/Servermanament/tempvc.py b/cogs/Servermanament/tempvc.py index 95eb2ef..3e8fa82 100644 --- a/cogs/Servermanament/tempvc.py +++ b/cogs/Servermanament/tempvc.py @@ -2,6 +2,7 @@ from DevTools import TempVCDatabase from DevTools import discord, commands, option, slash_command, ezcord, SlashCommandGroup from DevTools import emoji_yes, emoji_no, ERROR_TITLE, ERROR_COLOR, SUCCESS_COLOR, AUTHOR, FLOOTER +from discord.ui import Container db = TempVCDatabase() @@ -21,8 +22,9 @@ def __init__(self, channel_owner_id: int, prefix: str = "🔧"): @discord.ui.button(label="🔧 Umbenennen", style=discord.ButtonStyle.primary, custom_id="tempvc_rename") async def rename_button(self, button: discord.ui.Button, interaction: discord.Interaction): if interaction.user.id != self.channel_owner_id: - await interaction.response.send_message("❌ Du bist nicht der Besitzer dieses Channels!", ephemeral=True) - return + container = Container() + container.add_text(f"{emoji_no} Keine Berechtigung\nDu bist nicht der Besitzer dieses Channels!") + return await interaction.response.send_message(view=container, ephemeral=True) modal = RenameChannelModal(interaction.channel) await interaction.response.send_modal(modal) @@ -30,8 +32,9 @@ async def rename_button(self, button: discord.ui.Button, interaction: discord.In @discord.ui.button(label="🔧 Limit", style=discord.ButtonStyle.primary, custom_id="tempvc_limit") async def limit_button(self, button: discord.ui.Button, interaction: discord.Interaction): if interaction.user.id != self.channel_owner_id: - await interaction.response.send_message("❌ Du bist nicht der Besitzer dieses Channels!", ephemeral=True) - return + container = Container() + container.add_text(f"{emoji_no} Keine Berechtigung\nDu bist nicht der Besitzer dieses Channels!") + return await interaction.response.send_message(view=container, ephemeral=True) modal = UserLimitModal(interaction.channel) await interaction.response.send_modal(modal) @@ -39,8 +42,9 @@ async def limit_button(self, button: discord.ui.Button, interaction: discord.Int @discord.ui.button(label="🔧 Sperren", style=discord.ButtonStyle.secondary, custom_id="tempvc_lock") async def lock_button(self, button: discord.ui.Button, interaction: discord.Interaction): if interaction.user.id != self.channel_owner_id: - await interaction.response.send_message("❌ Du bist nicht der Besitzer dieses Channels!", ephemeral=True) - return + container = Container() + container.add_text(f"{emoji_no} Keine Berechtigung\nDu bist nicht der Besitzer dieses Channels!") + return await interaction.response.send_message(view=container, ephemeral=True) channel = interaction.channel overwrites = channel.overwrites @@ -60,15 +64,21 @@ async def lock_button(self, button: discord.ui.Button, interaction: discord.Inte button.style = discord.ButtonStyle.danger if is_locked else discord.ButtonStyle.secondary await interaction.response.edit_message(view=self) - await interaction.followup.send(f"Channel wurde {status}!", ephemeral=True) + + container = Container() + container.add_text(f"Channel wurde {status}!") + await interaction.followup.send(view=container, ephemeral=True) except discord.Forbidden: - await interaction.response.send_message("❌ Fehlende Berechtigungen!", ephemeral=True) + container = Container() + container.add_text(f"{emoji_no} Fehler\nFehlende Berechtigungen!") + await interaction.response.send_message(view=container, ephemeral=True) @discord.ui.button(label="🔧 Kick", style=discord.ButtonStyle.danger, custom_id="tempvc_kick") async def kick_button(self, button: discord.ui.Button, interaction: discord.Interaction): if interaction.user.id != self.channel_owner_id: - await interaction.response.send_message("❌ Du bist nicht der Besitzer dieses Channels!", ephemeral=True) - return + container = Container() + container.add_text(f"{emoji_no} Keine Berechtigung\nDu bist nicht der Besitzer dieses Channels!") + return await interaction.response.send_message(view=container, ephemeral=True) modal = KickUserModal(interaction.channel) await interaction.response.send_modal(modal) @@ -93,30 +103,36 @@ async def callback(self, interaction: discord.Interaction): # Validate name if len(new_name) < 1: - await interaction.response.send_message("❌ Name darf nicht leer sein!", ephemeral=True) - return + container = Container() + container.add_text(f"{emoji_no} Ungültiger Name\nName darf nicht leer sein!") + return await interaction.response.send_message(view=container, ephemeral=True) # Check for forbidden characters forbidden_chars = ['@', '#', ':', '`', '```'] if any(char in new_name for char in forbidden_chars): - await interaction.response.send_message("❌ Name enthält ungültige Zeichen!", ephemeral=True) - return + container = Container() + container.add_text(f"{emoji_no} Ungültige Zeichen\nName enthält ungültige Zeichen!") + return await interaction.response.send_message(view=container, ephemeral=True) try: old_name = self.channel.name await self.channel.edit(name=new_name) - embed = discord.Embed( - title="✅ Channel umbenannt", - color=SUCCESS_COLOR, - description=f"**{old_name}** → **{new_name}**" + container = Container() + container.add_text( + f"{emoji_yes} Channel umbenannt\n" + f"**{old_name}** → **{new_name}**" ) - await interaction.response.send_message(embed=embed, ephemeral=True) + await interaction.response.send_message(view=container, ephemeral=True) except discord.Forbidden: - await interaction.response.send_message("❌ Fehlende Berechtigungen zum Umbenennen!", ephemeral=True) + container = Container() + container.add_text(f"{emoji_no} Fehler\nFehlende Berechtigungen zum Umbenennen!") + await interaction.response.send_message(view=container, ephemeral=True) except discord.HTTPException as e: - await interaction.response.send_message(f"❌ Fehler beim Umbenennen: {str(e)}", ephemeral=True) + container = Container() + container.add_text(f"{emoji_no} Fehler\nFehler beim Umbenennen: {str(e)}") + await interaction.response.send_message(view=container, ephemeral=True) class UserLimitModal(discord.ui.Modal): @@ -140,8 +156,9 @@ async def callback(self, interaction: discord.Interaction): limit = int(self.limit_input.value.strip()) if limit < 0 or limit > 99: - await interaction.response.send_message("❌ Limit muss zwischen 0 und 99 liegen!", ephemeral=True) - return + container = Container() + container.add_text(f"{emoji_no} Ungültiges Limit\nLimit muss zwischen 0 und 99 liegen!") + return await interaction.response.send_message(view=container, ephemeral=True) # 0 means no limit in Discord limit = None if limit == 0 else limit @@ -150,19 +167,25 @@ async def callback(self, interaction: discord.Interaction): limit_text = "Kein Limit" if limit is None else f"{limit} User" - embed = discord.Embed( - title="✅ User-Limit geändert", - color=SUCCESS_COLOR, - description=f"Neues Limit: **{limit_text}**" + container = Container() + container.add_text( + f"{emoji_yes} User-Limit geändert\n" + f"Neues Limit: **{limit_text}**" ) - await interaction.response.send_message(embed=embed, ephemeral=True) + await interaction.response.send_message(view=container, ephemeral=True) except ValueError: - await interaction.response.send_message("❌ Bitte gib eine gültige Zahl ein!", ephemeral=True) + container = Container() + container.add_text(f"{emoji_no} Ungültige Eingabe\nBitte gib eine gültige Zahl ein!") + await interaction.response.send_message(view=container, ephemeral=True) except discord.Forbidden: - await interaction.response.send_message("❌ Fehlende Berechtigungen!", ephemeral=True) + container = Container() + container.add_text(f"{emoji_no} Fehler\nFehlende Berechtigungen!") + await interaction.response.send_message(view=container, ephemeral=True) except discord.HTTPException as e: - await interaction.response.send_message(f"❌ Fehler beim Setzen des Limits: {str(e)}", ephemeral=True) + container = Container() + container.add_text(f"{emoji_no} Fehler\nFehler beim Setzen des Limits: {str(e)}") + await interaction.response.send_message(view=container, ephemeral=True) class KickUserModal(discord.ui.Modal): @@ -221,35 +244,43 @@ async def callback(self, interaction: discord.Interaction): break if not target_user: - await interaction.response.send_message("❌ User nicht gefunden!", ephemeral=True) - return + container = Container() + container.add_text(f"{emoji_no} Fehler\nUser nicht gefunden!") + return await interaction.response.send_message(view=container, ephemeral=True) if target_user not in self.channel.members: - await interaction.response.send_message("❌ User ist nicht in diesem Channel!", ephemeral=True) - return + container = Container() + container.add_text(f"{emoji_no} Fehler\nUser ist nicht in diesem Channel!") + return await interaction.response.send_message(view=container, ephemeral=True) if target_user.id == db.get_temp_channel_owner(self.channel.id): - await interaction.response.send_message("❌ Du kannst dich nicht selbst kicken!", ephemeral=True) - return + container = Container() + container.add_text(f"{emoji_no} Fehler\nDu kannst dich nicht selbst kicken!") + return await interaction.response.send_message(view=container, ephemeral=True) if target_user.bot: - await interaction.response.send_message("❌ Bots können nicht gekickt werden!", ephemeral=True) - return + container = Container() + container.add_text(f"{emoji_no} Fehler\nBots können nicht gekickt werden!") + return await interaction.response.send_message(view=container, ephemeral=True) try: await target_user.move_to(None) # Disconnect from voice - embed = discord.Embed( - title="✅ User gekickt", - color=SUCCESS_COLOR, - description=f"**{target_user.display_name}** wurde aus dem Channel gekickt." + container = Container() + container.add_text( + f"{emoji_yes} User gekickt\n" + f"**{target_user.display_name}** wurde aus dem Channel gekickt." ) - await interaction.response.send_message(embed=embed, ephemeral=True) + await interaction.response.send_message(view=container, ephemeral=True) except discord.Forbidden: - await interaction.response.send_message("❌ Fehlende Berechtigungen zum Kicken!", ephemeral=True) + container = Container() + container.add_text(f"{emoji_no} Fehler\nFehlende Berechtigungen zum Kicken!") + await interaction.response.send_message(view=container, ephemeral=True) except discord.HTTPException as e: - await interaction.response.send_message(f"❌ Fehler beim Kicken: {str(e)}", ephemeral=True) + container = Container() + container.add_text(f"{emoji_no} Fehler\nFehler beim Kicken: {str(e)}") + await interaction.response.send_message(view=container, ephemeral=True) class TempVC(ezcord.Cog): @@ -266,174 +297,151 @@ def __init__(self, bot): async def tempvc_create(self, ctx: discord.ApplicationContext, creator_channel: discord.VoiceChannel, category: discord.CategoryChannel): if not ctx.author.guild_permissions.administrator: - no_perm_embed = discord.Embed( - title=ERROR_TITLE, - color=ERROR_COLOR + container = Container() + container.add_text( + f"{emoji_no} Keine Berechtigung\n" + "Du brauchst Administratorrechte." ) - no_perm_embed.set_author(name=AUTHOR) - no_perm_embed.add_field(name=f"{emoji_no} Keine Berechtigung", value="Du brauchst Administratorrechte.", - inline=False) - no_perm_embed.set_footer(text=FLOOTER) - return await ctx.respond(embed=no_perm_embed, ephemeral=True) + return await ctx.respond(view=container, ephemeral=True) try: db.set_tempvc_settings(ctx.guild.id, creator_channel.id, category.id) - - success_embed = discord.Embed( - title=f"{emoji_yes} Temp-VC System aktiviert", - color=SUCCESS_COLOR, - description="Das temporäre Voice-Channel System wurde erfolgreich eingerichtet!" + + container = Container() + container.add_text( + f"{emoji_yes} Temp-VC System aktiviert\n" + "Das temporäre Voice-Channel System wurde erfolgreich eingerichtet!" + ) + container.add_separator() + container.add_text( + f"**🎤 Ersteller-Channel:** {creator_channel.mention}\n" + f"**📁 Kategorie:** {category.mention}\n" + "**ℹ️ Information:** Mitglieder können nun den Ersteller-Channel betreten, um automatisch einen eigenen temporären Voice-Channel zu erhalten." ) - success_embed.set_author(name=AUTHOR) - success_embed.add_field(name="🎤 Ersteller-Channel", value=creator_channel.mention, inline=True) - success_embed.add_field(name="📁 Kategorie", value=category.mention, inline=True) - success_embed.add_field(name="ℹ️ Information", - value="Mitglieder können nun den Ersteller-Channel betreten, um automatisch einen eigenen temporären Voice-Channel zu erhalten.", - inline=False) - success_embed.set_footer(text=FLOOTER) - - await ctx.respond(embed=success_embed, ephemeral=True) + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view, ephemeral=True) except Exception as e: - error_embed = discord.Embed( - title=ERROR_TITLE, - color=ERROR_COLOR + container = Container() + container.add_text( + f"{emoji_no} Fehler beim Erstellen\n" + f"```{str(e)}```" ) - error_embed.set_author(name=AUTHOR) - error_embed.add_field(name=f"{emoji_no} Fehler beim Erstellen", value=f"```{str(e)}```", inline=False) - error_embed.set_footer(text=FLOOTER) - await ctx.respond(embed=error_embed, ephemeral=True) + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view, ephemeral=True) @tempvc.command(name="remove", description="Entferne das VC-Erstellungssystem") async def tempvc_remove(self, ctx: discord.ApplicationContext): if not ctx.author.guild_permissions.administrator: - no_perm_embed = discord.Embed( - title=ERROR_TITLE, - color=ERROR_COLOR + container = Container() + container.add_text( + f"{emoji_no} Keine Berechtigung\n" + "Du brauchst Administratorrechte." ) - no_perm_embed.set_author(name=AUTHOR) - no_perm_embed.add_field(name=f"{emoji_no} Keine Berechtigung", value="Du brauchst Administratorrechte.", - inline=False) - no_perm_embed.set_footer(text=FLOOTER) - return await ctx.respond(embed=no_perm_embed, ephemeral=True) + view = discord.ui.View(container, timeout=None) + return await ctx.respond(view=view, ephemeral=True) try: settings = db.get_tempvc_settings(ctx.guild.id) if not settings: - no_system_embed = discord.Embed( - title=f"{emoji_no} Kein System aktiv", - color=ERROR_COLOR, - description="Es ist derzeit kein Temp-VC System auf diesem Server aktiv." + container = Container() + container.add_text( + f"{emoji_no} Kein System aktiv\n" + "Es ist derzeit kein Temp-VC System auf diesem Server aktiv." ) - no_system_embed.set_author(name=AUTHOR) - no_system_embed.set_footer(text=FLOOTER) - return await ctx.respond(embed=no_system_embed, ephemeral=True) + view = discord.ui.View(container, timeout=None) + return await ctx.respond(view=view, ephemeral=True) db.remove_tempvc_settings(ctx.guild.id) - removal_embed = discord.Embed( - title=f"{emoji_yes} System deaktiviert", - color=SUCCESS_COLOR, - description="Das Temp-VC System wurde erfolgreich deaktiviert!" + container = Container() + container.add_text( + f"{emoji_yes} System deaktiviert\n" + "Das Temp-VC System wurde erfolgreich deaktiviert!" ) - removal_embed.set_author(name=AUTHOR) - removal_embed.add_field(name="ℹ️ Information", - value="Bestehende temporäre Channels bleiben bestehen, aber es werden keine neuen mehr erstellt.", - inline=False) - removal_embed.set_footer(text=FLOOTER) - - await ctx.respond(embed=removal_embed, ephemeral=True) + container.add_separator() + container.add_text( + "**ℹ️ Information:** Bestehende temporäre Channels bleiben bestehen, aber es werden keine neuen mehr erstellt." + ) + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view, ephemeral=True) except Exception as e: - error_embed = discord.Embed( - title=ERROR_TITLE, - color=ERROR_COLOR + container = Container() + container.add_text( + f"{emoji_no} Fehler beim Entfernen\n" + f"```{str(e)}```" ) - error_embed.set_author(name=AUTHOR) - error_embed.add_field(name=f"{emoji_no} Fehler beim Entfernen", value=f"```{str(e)}```", inline=False) - error_embed.set_footer(text=FLOOTER) - await ctx.respond(embed=error_embed, ephemeral=True) + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view, ephemeral=True) @tempvc.command(name="settings", description="Zeige die aktuellen Temp-VC Einstellungen") async def tempvc_settings(self, ctx: discord.ApplicationContext): if not ctx.author.guild_permissions.administrator: - no_perm_embed = discord.Embed( - title=ERROR_TITLE, - color=ERROR_COLOR + container = Container() + container.add_text( + f"{emoji_no} Keine Berechtigung\n" + "Du brauchst Administratorrechte." ) - no_perm_embed.set_author(name=AUTHOR) - no_perm_embed.add_field(name=f"{emoji_no} Keine Berechtigung", value="Du brauchst Administratorrechte.", - inline=False) - no_perm_embed.set_footer(text=FLOOTER) - return await ctx.respond(embed=no_perm_embed, ephemeral=True) + view = discord.ui.View(container, timeout=None) + return await ctx.respond(view=view, ephemeral=True) settings = db.get_tempvc_settings(ctx.guild.id) if not settings: - no_system_embed = discord.Embed( - title=f"{emoji_no} Kein System aktiv", - color=ERROR_COLOR, - description="Es ist derzeit kein Temp-VC System auf diesem Server aktiv." + container = Container() + container.add_text( + f"{emoji_no} Kein System aktiv\n" + "Es ist derzeit kein Temp-VC System auf diesem Server aktiv." + ) + container.add_separator() + container.add_text( + "**💡 Tipp:** Verwende `/tempvc create` um ein Temp-VC System einzurichten." ) - no_system_embed.set_author(name=AUTHOR) - no_system_embed.add_field(name="💡 Tipp", value="Verwende `/tempvc create` um ein Temp-VC System einzurichten.", - inline=False) - no_system_embed.set_footer(text=FLOOTER) - return await ctx.respond(embed=no_system_embed, ephemeral=True) + view = discord.ui.View(container, timeout=None) + return await ctx.respond(view=view, ephemeral=True) creator_channel_id, category_id, auto_delete_time = settings creator_channel = ctx.guild.get_channel(creator_channel_id) category = ctx.guild.get_channel(category_id) - embed = discord.Embed( - title=f"{emoji_settings} Temp-VC Einstellungen", - color=discord.Color.blue(), - description="Aktuelle Konfiguration des temporären Voice-Channel Systems" - ) - embed.set_author(name=AUTHOR) - embed.add_field( - name="🎤 Ersteller-Channel", - value=creator_channel.mention if creator_channel else f"{emoji_no} Channel nicht gefunden (ID: {creator_channel_id})", - inline=True - ) - embed.add_field( - name="📁 Kategorie", - value=category.mention if category else f"{emoji_no} Kategorie nicht gefunden (ID: {category_id})", - inline=True + container = Container() + container.add_text("🎛️ **Temp-VC Einstellungen**\nAktuelle Konfiguration des temporären Voice-Channel Systems") + container.add_separator() + + container.add_text( + f"**🎤 Ersteller-Channel:**\n" + f"{creator_channel.mention if creator_channel else f'{emoji_no} Channel nicht gefunden (ID: {creator_channel_id})'}" ) - embed.add_field( - name="⏰ Auto-Löschzeit", - value=f"{auto_delete_time} Minuten", - inline=True + container.add_separator() + + container.add_text( + f"**📁 Kategorie:**\n" + f"{category.mention if category else f'{emoji_no} Kategorie nicht gefunden (ID: {category_id})'}" ) + container.add_separator() + + container.add_text(f"**⏰ Auto-Löschzeit:**\n{auto_delete_time} Minuten") + container.add_separator() # UI Settings ui_settings = db.get_ui_settings(ctx.guild.id) if ui_settings: ui_enabled, ui_prefix = ui_settings - embed.add_field( - name="🖥️ Control-UI", - value=f"{'✅ Aktiviert' if ui_enabled else '❌ Deaktiviert'}", - inline=True + container.add_text( + f"**🖥️ Control-UI:**\n" + f"{'✅ Aktiviert' if ui_enabled else '❌ Deaktiviert'}" ) if ui_enabled: - embed.add_field( - name="🏷️ UI-Prefix", - value=ui_prefix, - inline=True - ) + container.add_separator() + container.add_text(f"**🏷️ UI-Prefix:**\n{ui_prefix}") else: - embed.add_field( - name="🖥️ Control-UI", - value="❌ Deaktiviert", - inline=True - ) + container.add_text("**🖥️ Control-UI:**\n❌ Deaktiviert") - embed.add_field( - name="ℹ️ Status", - value=f"{emoji_yes} System aktiv" if creator_channel and category else f"{emoji_no} Fehlerhafte Konfiguration", - inline=False + container.add_separator() + container.add_text( + f"**ℹ️ Status:**\n" + f"{emoji_yes + ' System aktiv' if creator_channel and category else emoji_no + ' Fehlerhafte Konfiguration'}" ) - embed.set_footer(text=FLOOTER) - - await ctx.respond(embed=embed, ephemeral=True) + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view, ephemeral=True) @tempvc.command(name="ui", description="Konfiguriere das Control-UI für Temp-Channels") @option("enabled", description="Soll das UI aktiviert sein?", choices=[ @@ -443,64 +451,62 @@ async def tempvc_settings(self, ctx: discord.ApplicationContext): @option("prefix", description="Prefix für UI-Buttons (Emoji oder Text)", required=False, default="🔧") async def tempvc_ui(self, ctx: discord.ApplicationContext, enabled: str, prefix: str = "🔧"): if not ctx.author.guild_permissions.administrator: - no_perm_embed = discord.Embed( - title=ERROR_TITLE, - color=ERROR_COLOR + container = Container() + container.add_text( + f"{emoji_no} Keine Berechtigung\n" + "Du brauchst Administratorrechte." ) - no_perm_embed.set_author(name=AUTHOR) - no_perm_embed.add_field(name=f"{emoji_no} Keine Berechtigung", value="Du brauchst Administratorrechte.", - inline=False) - no_perm_embed.set_footer(text=FLOOTER) - return await ctx.respond(embed=no_perm_embed, ephemeral=True) + return await ctx.respond(view=container, ephemeral=True) # Check if TempVC system exists settings = db.get_tempvc_settings(ctx.guild.id) if not settings: - no_system_embed = discord.Embed( - title=f"{emoji_no} Kein System aktiv", - color=ERROR_COLOR, - description="Du musst zuerst ein Temp-VC System erstellen!" + container = Container() + container.add_text( + f"{emoji_no} Kein System aktiv\n" + "Du musst zuerst ein Temp-VC System erstellen!" ) - no_system_embed.set_author(name=AUTHOR) - no_system_embed.add_field(name="💡 Tipp", value="Verwende `/tempvc create` um ein Temp-VC System einzurichten.", - inline=False) - no_system_embed.set_footer(text=FLOOTER) - return await ctx.respond(embed=no_system_embed, ephemeral=True) + container.add_separator() + container.add_text( + "**💡 Tipp:** Verwende `/tempvc create` um ein Temp-VC System einzurichten." + ) + view = discord.ui.View(container, timeout=None) + return await ctx.respond(view=view, ephemeral=True) ui_enabled = enabled == "true" # Validate prefix if len(prefix) > 10: - await ctx.respond("❌ Prefix darf maximal 10 Zeichen lang sein!", ephemeral=True) - return + container = Container() + container.add_text(f"{emoji_no} Ungültiger Prefix\nPrefix darf maximal 10 Zeichen lang sein!") + return await ctx.respond(view=container, ephemeral=True) try: db.set_ui_settings(ctx.guild.id, ui_enabled, prefix) - embed = discord.Embed( - title=f"{emoji_yes} UI-Einstellungen gespeichert", - color=SUCCESS_COLOR + container = Container() + container.add_text(f"{emoji_yes} UI-Einstellungen gespeichert") + container.add_separator() + container.add_text( + f"**🖥️ Control-UI:** {'✅ Aktiviert' if ui_enabled else '❌ Deaktiviert'}" ) - embed.set_author(name=AUTHOR) - embed.add_field(name="🖥️ Control-UI", value="✅ Aktiviert" if ui_enabled else "❌ Deaktiviert", inline=True) if ui_enabled: - embed.add_field(name="🏷️ Prefix", value=prefix, inline=True) - embed.add_field(name="ℹ️ Information", - value="Das Control-UI wird nun in neu erstellten Temp-Channels angezeigt.", - inline=False) - embed.set_footer(text=FLOOTER) - - await ctx.respond(embed=embed, ephemeral=True) + container.add_separator() + container.add_text(f"**🏷️ Prefix:** {prefix}") + container.add_separator() + container.add_text( + "**ℹ️ Information:** Das Control-UI wird nun in neu erstellten Temp-Channels angezeigt." + ) + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view, ephemeral=True) except Exception as e: - error_embed = discord.Embed( - title=ERROR_TITLE, - color=ERROR_COLOR + container = Container() + container.add_text( + f"{emoji_no} Fehler beim Speichern\n" + f"```{str(e)}```" ) - error_embed.set_author(name=AUTHOR) - error_embed.add_field(name=f"{emoji_no} Fehler beim Speichern", value=f"```{str(e)}```", inline=False) - error_embed.set_footer(text=FLOOTER) - await ctx.respond(embed=error_embed, ephemeral=True) + await ctx.respond(view=container, ephemeral=True) @commands.Cog.listener() async def on_voice_state_update(self, member, before, after): @@ -552,21 +558,27 @@ async def handle_creator_channel_join(self, member: discord.Member, channel: dis if ui_settings and ui_settings[0]: # UI enabled ui_enabled, ui_prefix = ui_settings - embed = discord.Embed( - title=f"🎛️ Channel-Kontrolle", - color=discord.Color.blue(), - description=f"**{member.display_name}**, du bist der Besitzer dieses Channels!\nVerwende die Buttons unten, um deinen Channel zu verwalten." + container = Container() + container.add_text( + f"🎛️ **Channel-Kontrolle**\n" + f"**{member.display_name}**, du bist der Besitzer dieses Channels!\n" + "Verwende die Buttons unten, um deinen Channel zu verwalten." + ) + container.add_separator() + container.add_text( + "**🔧 Verfügbare Aktionen:**\n" + "• **Umbenennen** - Ändere den Channel-Namen\n" + "• **Limit** - Setze ein User-Limit\n" + "• **Sperren** - Sperre/Entsperre den Channel\n" + "• **Kick** - Kicke User aus dem Channel" ) - embed.add_field(name="🔧 Verfügbare Aktionen:", - value="• **Umbenennen** - Ändere den Channel-Namen\n" - "• **Limit** - Setze ein User-Limit\n" - "• **Sperren** - Sperre/Entsperre den Channel\n" - "• **Kick** - Kicke User aus dem Channel", - inline=False) - embed.set_footer(text="Diese Buttons funktionieren nur für den Channel-Besitzer.") + container.add_separator() + container.add_text("Diese Buttons funktionieren nur für den Channel-Besitzer.") - view = TempChannelControlView(member.id, ui_prefix) - await temp_channel.send(embed=embed, view=view) + control_view = TempChannelControlView(member.id, ui_prefix) + view = discord.ui.View(container, timeout=None) + view.add_view(control_view) + await temp_channel.send(view=view) except discord.Forbidden: print(f"Missing permissions to create voice channel in guild {guild.id}") From ed72ea5846c2a39ee2dd508b4cb50a5b6d02556c Mon Sep 17 00:00:00 2001 From: Medicopter117 Date: Sun, 26 Oct 2025 10:51:00 +0100 Subject: [PATCH 03/10] FIX: control_view --- cogs/Servermanament/tempvc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cogs/Servermanament/tempvc.py b/cogs/Servermanament/tempvc.py index 3e8fa82..50508d7 100644 --- a/cogs/Servermanament/tempvc.py +++ b/cogs/Servermanament/tempvc.py @@ -577,8 +577,8 @@ async def handle_creator_channel_join(self, member: discord.Member, channel: dis control_view = TempChannelControlView(member.id, ui_prefix) view = discord.ui.View(container, timeout=None) - view.add_view(control_view) await temp_channel.send(view=view) + await temp_channel.send(view=control_view) except discord.Forbidden: print(f"Missing permissions to create voice channel in guild {guild.id}") From 7f658f1478d9a5f0b6bc38bb6ca4b9d44f1b627b Mon Sep 17 00:00:00 2001 From: Medicopter117 Date: Sun, 26 Oct 2025 11:25:13 +0100 Subject: [PATCH 04/10] UPDATE: V2 Components for globalchat.py --- cogs/Servermanament/globalchat.py | 41 +++++++++++++++++++------------ 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/cogs/Servermanament/globalchat.py b/cogs/Servermanament/globalchat.py index b4cf125..9d08be2 100644 --- a/cogs/Servermanament/globalchat.py +++ b/cogs/Servermanament/globalchat.py @@ -11,6 +11,8 @@ import json from datetime import datetime, timedelta import ezcord + +from discord.ui import Container # Logger konfigurieren logger = logging.getLogger(__name__) @@ -378,18 +380,21 @@ async def setup_globalchat( self._channel_cache = [] self._cache_last_update = 0 - embed = discord.Embed( - title="🌍 GlobalChat eingerichtet!", - description=f"Der Channel {channel.mention} wurde als GlobalChat-Channel eingerichtet.\n\n" - "**Wie es funktioniert:**\n" - "• Nachrichten in diesem Channel werden an alle anderen GlobalChat-Server gesendet\n" - "• Die ursprüngliche Nachricht wird gelöscht und als Embed neu gesendet\n" - "• Rate-Limiting: 5 Nachrichten pro Minute pro User", - color=discord.Color.green() + container = Container() + container.add_text( + "## 🌍 GlobalChat eingerichtet!" ) - embed.set_footer(text="Nutze /globalchat_settings für weitere Einstellungen") - - await ctx.respond(embed=embed) + container.add_separator() + container.add_text( + f"Der Channel {channel.mention} wurde als GlobalChat-Channel eingerichtet.\n\n" + "**Wie es funktioniert:**\n" + "• Nachrichten in diesem Channel werden an alle anderen GlobalChat-Server gesendet\n" + "• Die ursprüngliche Nachricht wird gelöscht und als Embed neu gesendet\n" + "• Rate-Limiting: 5 Nachrichten pro Minute pro User\n" + "-# Nutze /globalchat_settings für weitere Einstellungen" + ) + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view) else: await ctx.respond("❌ Fehler beim Einrichten des GlobalChat-Channels!", ephemeral=True) @@ -410,12 +415,16 @@ async def remove_globalchat(self, ctx: discord.ApplicationContext): self._channel_cache = [] self._cache_last_update = 0 - embed = discord.Embed( - title="🗑️ GlobalChat entfernt", - description="Der GlobalChat-Channel wurde von diesem Server entfernt.", - color=discord.Color.red() + container = Container() + container.add_text( + "# 🗑️ GlobalChat entfernt\n" ) - await ctx.respond(embed=embed) + container.add_separator() + container.add_text( + "Der GlobalChat-Channel wurde von diesem Server entfernt." + ) + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view) else: await ctx.respond("❌ Kein GlobalChat-Channel auf diesem Server gefunden!", ephemeral=True) From f97f596b2131508c67fce18b932f00b1cf47c31f Mon Sep 17 00:00:00 2001 From: Medicopter117 Date: Tue, 28 Oct 2025 18:52:08 +0100 Subject: [PATCH 05/10] DOCS: INSTALLATION.md ADDED --- .gitignore | 2 +- cogs/Servermanament/globalchat.py | 38 +++---- cogs/Servermanament/levelsystem.py | 1 + cogs/Servermanament/stats.py | 1 + cogs/Servermanament/tempvc.py | 2 +- cogs/fun/weather.py | 17 --- cogs/moderation/moderation.py | 9 +- docs/INSTALLATION.md | 164 +++++++++++++++++++++++++++++ docs/todo.md | 0 9 files changed, 191 insertions(+), 43 deletions(-) create mode 100644 docs/INSTALLATION.md delete mode 100644 docs/todo.md diff --git a/.gitignore b/.gitignore index 7c72bb7..31d34dd 100644 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,4 @@ Thumbs.db *.bak *.tmp FastCoding/backend/utils/config.py -translations/command.yaml +command.yaml diff --git a/cogs/Servermanament/globalchat.py b/cogs/Servermanament/globalchat.py index 9d08be2..0913489 100644 --- a/cogs/Servermanament/globalchat.py +++ b/cogs/Servermanament/globalchat.py @@ -440,29 +440,26 @@ async def globalchat_stats(self, ctx: discord.ApplicationContext): await ctx.respond("❌ Fehler beim Abrufen der Statistiken!", ephemeral=True) return - embed = discord.Embed( - title="🌍 GlobalChat Statistiken", - color=discord.Color.blue() + container = Container() + container.add_text( + "# 🌍 GlobalChat Statistiken" ) - - embed.add_field( - name="📊 Server & Nachrichten", - value=f"**Aktive Server:** {stats.get('active_guilds', 0):,}\n" - f"**Nachrichten insgesamt:** {stats.get('total_messages', 0):,}\n" - f"**Nachrichten heute:** {stats.get('today_messages', 0):,}", - inline=False + container.add_separator() + container.add_text( + "### 📊 Server & Nachrichten:\n" + f"**Aktive Server:** {stats.get('active_guilds', 0):,}\n" + f"**Nachrichten insgesamt:** {stats.get('total_messages', 0):,}\n" + f"**Nachrichten heute:** {stats.get('today_messages', 0):,}" ) - - embed.add_field( - name="🚫 Moderation", - value=f"**Gesperrte User:** {stats.get('banned_users', 0):,}\n" - f"**Gesperrte Server:** {stats.get('banned_guilds', 0):,}", - inline=False + container.add_separator() + container.add_text( + "### 🚫 Moderation\n" + f"**Gesperrte User:** {stats.get('banned_users', 0):,}\n" + f"**Gesperrte Server:** {stats.get('banned_guilds', 0):,}\n" + f"Stand: {datetime.now().strftime('%d.%m.%Y %H:%M')}" ) - - embed.set_footer(text=f"Stand: {datetime.now().strftime('%d.%m.%Y %H:%M')}") - - await ctx.respond(embed=embed) + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view) @globalchat.command( name="settings", @@ -537,7 +534,6 @@ async def globalchat_settings( value=f"**Embed-Farbe:** {current_settings.get('embed_color', '#5865F2')}", inline=False ) - await ctx.respond(embed=embed) # --- Admin Commands (nur für Bot-Owner) --- diff --git a/cogs/Servermanament/levelsystem.py b/cogs/Servermanament/levelsystem.py index ab7e3be..e669b69 100644 --- a/cogs/Servermanament/levelsystem.py +++ b/cogs/Servermanament/levelsystem.py @@ -9,6 +9,7 @@ import io import csv from typing import Optional +from discord.ui import Container class PrestigeConfirmView(discord.ui.View): diff --git a/cogs/Servermanament/stats.py b/cogs/Servermanament/stats.py index 69f98a7..99c35a6 100644 --- a/cogs/Servermanament/stats.py +++ b/cogs/Servermanament/stats.py @@ -9,6 +9,7 @@ from datetime import datetime, timedelta import math + logger = logging.getLogger(__name__) diff --git a/cogs/Servermanament/tempvc.py b/cogs/Servermanament/tempvc.py index 50508d7..c1ec2c6 100644 --- a/cogs/Servermanament/tempvc.py +++ b/cogs/Servermanament/tempvc.py @@ -560,7 +560,7 @@ async def handle_creator_channel_join(self, member: discord.Member, channel: dis container = Container() container.add_text( - f"🎛️ **Channel-Kontrolle**\n" + f"## 🎛️ **Channel-Kontrolle**\n" f"**{member.display_name}**, du bist der Besitzer dieses Channels!\n" "Verwende die Buttons unten, um deinen Channel zu verwalten." ) diff --git a/cogs/fun/weather.py b/cogs/fun/weather.py index 134f682..ab8eea0 100644 --- a/cogs/fun/weather.py +++ b/cogs/fun/weather.py @@ -33,23 +33,6 @@ async def weather(self, ctx: discord.ApplicationContext, city: str): location = data['location'] current = data['current'] - embed = discord.Embed( - title=f"Wetter in {location['name']}, {location['country']}", - description=f"Zeitzone: {location['tz_id']}\nLetzte Aktualisierung: {current['last_updated']}", - color=DEFLAUT_COLOR - ) - - embed.add_field(name="🌡️ Temperatur", value=f"{current['temp_c']}°C", inline=True) - embed.add_field(name="💧 Luftfeuchtigkeit", value=f"{current['humidity']}%", inline=True) - embed.add_field(name="🌬️ Wind", value=f"{current['wind_kph']} km/h ({current['wind_dir']})", inline=True) - embed.add_field(name="☁️ Zustand", value=current['condition']['text'], inline=False) - embed.add_field(name="🌫️ Sichtweite", value=f"{current['vis_km']} km", inline=True) - embed.add_field(name="🌡️ Luftdruck", value=f"{current['pressure_mb']} hPa", inline=True) - embed.add_field(name="🌅 Sonnenauf-/untergang", value=f"{current.get('astro', {}).get('sunrise', 'N/A')} / {current.get('astro', {}).get('sunset', 'N/A')}", inline=False) - - embed.set_thumbnail(url="http:" + current['condition']['icon']) - embed.set_footer(text="Weather data provided by WeatherAPI") - container = Container() container.add_text( f"## Wetter in {location['name']}, {location['country']} \n" diff --git a/cogs/moderation/moderation.py b/cogs/moderation/moderation.py index e12d06d..fdadc44 100644 --- a/cogs/moderation/moderation.py +++ b/cogs/moderation/moderation.py @@ -2,8 +2,6 @@ # ─────────────────────────────────────────────── # >> Imports # ─────────────────────────────────────────────── -from DevTools.backend import discord, ezcord, slash_command, option, timedelta, SlashCommandGroup -from DevTools.backend import KICK, BAN, MODERATE from DevTools.ui import emoji_yes, emoji_no, emoji_member, emoji_warn, emoji_summary, emoji_staff, emoji_slowmode from DevTools.ui import ERROR_TITLE, ERROR_COLOR, SUCCESS_COLOR, AUTHOR, FLOOTER @@ -13,6 +11,11 @@ from typing import Optional, Dict, List import logging +import discord +import ezcord +from discord import slash_command, option, SlashCommandGroup +import timedelta +from discord.ui import Container # ─────────────────────────────────────────────── # >> Cogs # ─────────────────────────────────────────────── @@ -25,7 +28,7 @@ def __init__(self, bot): self._active_votes: Dict[int, Dict] = {} self.logger = logging.getLogger(__name__) - moderation = SlashCommandGroup("moderation", "Erweiterte Moderationsbefehle") + moderation = SlashCommandGroup("mod", "Erweiterte Moderationsbefehle") def _has_permission(self, member: discord.Member, permission: str) -> bool: """Überprüft ob ein Member eine bestimmte Berechtigung hat""" diff --git a/docs/INSTALLATION.md b/docs/INSTALLATION.md new file mode 100644 index 0000000..f5b6ca4 --- /dev/null +++ b/docs/INSTALLATION.md @@ -0,0 +1,164 @@ +# 🚀 Installation Guide - ManagerX + +Willkommen zur Installationsanleitung für ManagerX! Folge diesen Schritten, um den Bot erfolgreich einzurichten. + +--- + +## 📋 Voraussetzungen + +Bevor du mit der Installation beginnst, stelle sicher, dass folgende Komponenten installiert sind: + +- **Python 3.10+** ([Download](https://www.python.org/downloads/)) +- **Git** ([Download](https://git-scm.com/downloads)) +- **Discord Bot Token** ([Anleitung](#discord-bot-token-erstellen)) + +--- + +## ⚡ Quick Start + +### 1️⃣ Repository klonen + +```bash +git clone https://github.com/Oppro-net-Development/ManagerX.git +cd ManagerX +``` + +### 2️⃣ Abhängigkeiten installieren + +```bash +pip install -r requirements.txt +``` + +Oder mit einem Virtual Environment (empfohlen): + +```bash +# Virtual Environment erstellen +python -m venv venv + +# Aktivieren (Windows) +venv\Scripts\activate + +# Aktivieren (Linux/macOS) +source venv/bin/activate + +# Dependencies installieren +pip install -r requirements.txt +``` + +### 3️⃣ Umgebungsvariablen konfigurieren + +Erstelle eine `.env` Datei im Root-Verzeichnis des Projekts: + +```env +# Discord Bot Token (erforderlich) +TOKEN=dein_discord_bot_token_hier +``` + +> ⚠️ **Wichtig:** Füge die `.env` Datei niemals zu Git hinzu! Sie sollte bereits in der `.gitignore` stehen. + +> 💡 **Tipp:** Die Konfiguration des Bots erfolgt direkt über Discord-Commands nach dem Start. Weitere Einstellungen können in der Datenbank oder über Bot-Befehle vorgenommen werden. + +### 4️⃣ Version überprüfen + +Bevor du den Bot startest, überprüfe die Version: + +**In `main.py` (Zeile 53):** +```python +BOT_VERSION = "1.7.1" +``` + +**Auf GitHub in `version.txt`:** +```txt +1.7.1 +``` + +> 💡 **Tipp:** Stelle sicher, dass beide Versionen übereinstimmen, um Kompatibilitätsprobleme zu vermeiden. + +### 5️⃣ Bot starten + +```bash +python main.py +``` + +Wenn alles geklappt hat, solltest du folgende Ausgabe sehen: + +``` +[DEBUG] Custom language file loaded: ez_de.json +[18:50] [COGS LOADING] Loaded 19 cogs +[18:50] [BOT] Starting ManagerX... +[18:50] [STARTING UP] Logged in as ManagerX Test#5099 +[UP-TO-DATE] You have the latest Version: 1.7.1 +[18:50] [DATABASE] Spam database initialized successfully. +[18:50] [DATABASE] Notes database initialized successfully. +[18:50] [DATABASE] Warn database initialized successfully. +[18:50] [DATABASE] TempVC database initialized successfully. +[18:50] [DATABASE] Stats database initialized successfully. +[18:50] [DATABASE] Levelsystem database initialized successfully. +[18:50] [DATABASE] Globalchat database initialized successfully. +[18:50] [DATABASE] Logging database initialized successfully. +[18:50] [API] Weather API has Loaded. +[18:50] [DEVTOOLS] DevTools is ready to use! +``` + +--- + +## 🎯 Discord Bot Token erstellen + +Falls du noch keinen Discord Bot Token hast, folge diesen Schritten: + +1. **Gehe zum [Discord Developer Portal](https://discord.com/developers/applications)** +2. **Klicke auf "New Application"** und gib deinem Bot einen Namen +3. **Navigiere zu "Bot"** im linken Menü +4. **Klicke auf "Add Bot"** +5. **Kopiere den Token** unter "TOKEN" (einmal klicken auf "Reset Token" falls nötig) +6. **Aktiviere folgende Intents:** + - ✅ Presence Intent + - ✅ Server Members Intent + - ✅ Message Content Intent + +> ⚠️ **Sicherheitshinweis:** Teile deinen Token niemals mit anderen! Wenn dein Token kompromittiert wurde, setze ihn sofort im Developer Portal zurück. + +--- + +## 🔧 Erweiterte Konfiguration + +### Datenbank initialisieren + +Beim ersten Start wird automatisch mehrere SQLite-Datenbank erstellt: + + + +```bash +python main.py +``` + +--- + +## 📚 Weiterführende Dokumentation + +- 📖 [Befehle & Features](COMMANDS.md) +- ⚙️ [Konfiguration](CONFIG.md) +- 🔄 [Update-Anleitung](UPDATE.md) +- 🤝 [Contributing Guide](CONTRIBUTING.md) + +--- + +## 💬 Support + +Brauchst du Hilfe? Hier sind deine Optionen: + +- 💬 [Discord Support Server](https://discord.gg/tmz673WAnV) +- 🐛 [GitHub Issues](https://github.com/Oppro-net-Development/ManagerX/issues) +- 📧 [E-Mail Support](mailto:oppro.help@gmail.com) + +--- + +
+ +**🎉 Viel Erfolg mit ManagerX!** + +*Made with ❤️ by OPPRO.NET* + +[⬅️ Zurück zur Hauptseite](README.md) + +
\ No newline at end of file diff --git a/docs/todo.md b/docs/todo.md deleted file mode 100644 index e69de29..0000000 From c6d14102e5d33c0730dc86552aca3d288f873c23 Mon Sep 17 00:00:00 2001 From: Medicopter117 Date: Tue, 28 Oct 2025 18:57:30 +0100 Subject: [PATCH 06/10] DOCS: docs files added BETA --- docs/COMMANDS.md | 0 docs/UPDATE.md | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/COMMANDS.md create mode 100644 docs/UPDATE.md diff --git a/docs/COMMANDS.md b/docs/COMMANDS.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/UPDATE.md b/docs/UPDATE.md new file mode 100644 index 0000000..e69de29 From 8b87b6452b0207cfe688b4017c75f4380c42f284 Mon Sep 17 00:00:00 2001 From: Medicopter117 Date: Wed, 29 Oct 2025 14:56:41 +0100 Subject: [PATCH 07/10] FIX: main.py Versionchecker --- main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.py b/main.py index 708f9a8..6854402 100644 --- a/main.py +++ b/main.py @@ -50,7 +50,7 @@ # ============================================================================= # BOT VERSION # ============================================================================= -BOT_VERSION = "1.7.1" +BOT_VERSION = "1.7.2" VERSION_URL = "https://raw.githubusercontent.com/Oppro-net-Development/ManagerX/main/version.txt" async def check_for_update(): From b3b0a5edfc3361982fc6b33982de768659f9c5a8 Mon Sep 17 00:00:00 2001 From: Medicopter117 Date: Wed, 29 Oct 2025 15:05:30 +0100 Subject: [PATCH 08/10] FIX: req.txt failure ModuleNotFoundError --- req.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/req.txt b/req.txt index 8d7640e..b806111 100644 --- a/req.txt +++ b/req.txt @@ -33,3 +33,4 @@ typing-inspection==0.4.1 urllib3==2.4.0 wikipedia==1.4.0 yarl==1.20.0 +timedelta==2020.12.3 \ No newline at end of file From 11a2d985a1bab3d408989c9f6629cc9c5732ce33 Mon Sep 17 00:00:00 2001 From: Medicopter117 Date: Sun, 9 Nov 2025 10:48:59 +0100 Subject: [PATCH 09/10] edit: warinigsystem & welcome.py --- cogs/Servermanament/welcome.py | 306 ++++++++++++++++--------------- cogs/moderation/warningsystem.py | 2 + 2 files changed, 156 insertions(+), 152 deletions(-) diff --git a/cogs/Servermanament/welcome.py b/cogs/Servermanament/welcome.py index d27da92..21d0d23 100644 --- a/cogs/Servermanament/welcome.py +++ b/cogs/Servermanament/welcome.py @@ -9,6 +9,9 @@ import aiosqlite from datetime import datetime import ezcord +from discord.ui import Container +from DevTools import emoji_yes, emoji_no, emoji_add + # Logger Setup logger = logging.getLogger(__name__) @@ -303,19 +306,26 @@ async def set_welcome_channel(self, ctx, channel: discord.TextChannel): self.invalidate_cache(ctx.guild.id) if success: - embed = discord.Embed( - title="✅ Welcome Channel gesetzt", - description=f"Welcome Messages werden nun in {channel.mention} gesendet.", - color=discord.Color.green() + container = Container() + container.add_text( + f"{emoji_yes} Welcome Channel gesetzt" + ) + container.add_separator() + container.add_text( + f"Welcome Messages werden nun in {channel.mention} gesendet." ) + view = discord.ui.View(container, timeout=None) else: - embed = discord.Embed( - title="❌ Fehler", - description="Der Welcome Channel konnte nicht gesetzt werden.", - color=discord.Color.red() + container = Container() + container.add_text( + f"{emoji_no} Fehler" ) - - await ctx.respond(embed=embed) + container.add_separator() + container.add_text( + "Der Welcome Channel konnte nicht gesetzt werden." + ) + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view) @welcome.command(name="message", description="Setzt die Welcome Message über ein Modal") @commands.has_permissions(manage_guild=True) @@ -360,36 +370,29 @@ async def callback(self, interaction: discord.Interaction): # Vorschau erstellen preview = self.cog.replace_placeholders(message, interaction.user, interaction.guild) - embed = discord.Embed( - title="✅ Welcome Message gesetzt", - color=discord.Color.green() - ) - - embed.add_field( - name="💬 Neue Message", - value=f"```{message[:500]}{'...' if len(message) > 500 else ''}```", - inline=False + container = Container() + container.add_text( + "# ✅ Welcome Message gesetzt" ) - - embed.add_field( - name="👀 Vorschau (mit deinen Daten)", - value=preview[:500] + ("..." if len(preview) > 500 else ""), - inline=False + container.add_separator() + container.add_text( + "## 💬 Neue Message\n\n" + f"```{message[:500]}{'...' if len(message) > 500 else ''}```" ) - - embed.add_field( - name="💡 Tipp", - value="Verwende `/welcome test` für eine vollständige Vorschau oder `/welcome placeholders` für alle verfügbaren Optionen.", - inline=False + container.add_separator() + container.add_text( + "## 👀 Vorschau (mit deinen Daten)\n\n" + f"{preview[:500] + ("..." if len(preview) > 500 else "")}\n\n" + "-# 💡 Tipp Verwende `/welcome test` für eine vollständige Vorschau oder `/welcome placeholders` für alle verfügbaren Optionen." ) + view = discord.ui.View(container, timeout=None) else: - embed = discord.Embed( - title="❌ Fehler", - description="Die Welcome Message konnte nicht gesetzt werden.", - color=discord.Color.red() + container = Container() + container.add_text( + "# ❌ Fehler\nDie Welcome Message konnte nicht gesetzt werden." ) - - await interaction.response.send_message(embed=embed) + view = discord.ui.View(container, timeout=None) + await interaction.response.send_message(view=view) modal = WelcomeMessageModal(self, current_message) await ctx.send_modal(modal) @@ -402,20 +405,23 @@ async def toggle_welcome(self, ctx): self.invalidate_cache(ctx.guild.id) if new_state is None: - embed = discord.Embed( - title="❌ Fehler", - description="Es sind noch keine Welcome Einstellungen vorhanden. Setze zuerst einen Channel.", - color=discord.Color.red() + container = Container() + container.add_text( + "# ❌ Fehler\nEs sind noch keine Welcome Einstellungen vorhanden. Setze zuerst einen Channel." ) + view = discord.ui.View(container, timeout=None) else: status = "aktiviert" if new_state else "deaktiviert" - embed = discord.Embed( - title=f"✅ Welcome System {status}", - description=f"Das Welcome System wurde **{status}**.", - color=discord.Color.green() if new_state else discord.Color.orange() + container = Container() + container.add_text( + f"# ✅ Welcome System {status}" ) - - await ctx.respond(embed=embed) + container.add_separator() + container.add_text( + f"Das Welcome System wurde **{status}**." + ) + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view) @welcome.command(name="embed", description="Aktiviert/Deaktiviert Embed Modus") @commands.has_permissions(manage_guild=True) @@ -426,19 +432,21 @@ async def toggle_embed(self, ctx, enabled: bool): if success: status = "aktiviert" if enabled else "deaktiviert" - embed = discord.Embed( - title=f"✅ Embed Modus {status}", - description=f"Welcome Messages werden nun {'als Embed' if enabled else 'als normale Nachricht'} gesendet.", - color=discord.Color.green() + container = Container( + f"# ✅ Embed Modus {status}" ) + container.add_separator() + container.add_text( + f"Welcome Messages werden nun {'als Embed' if enabled else 'als normale Nachricht'} gesendet." + ) + view = discord.ui.View(container, timeout=None) else: - embed = discord.Embed( - title="❌ Fehler", - description="Der Embed Modus konnte nicht geändert werden.", - color=discord.Color.red() + container = Container() + container.add_text( + "# ❌ Fehler\nDer Embed Modus konnte nicht geändert werden." ) - - await ctx.respond(embed=embed) + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view) # Neue Commands @welcome.command(name="autorole", description="Setzt eine Rolle die automatisch vergeben wird") @@ -450,39 +458,47 @@ async def set_auto_role(self, ctx, role: discord.Role = None): success = await self.db.update_welcome_settings(ctx.guild.id, auto_role_id=None) self.invalidate_cache(ctx.guild.id) - embed = discord.Embed( - title="✅ Auto-Role entfernt", - description="Neue Mitglieder erhalten keine automatische Rolle mehr.", - color=discord.Color.orange() + container = Container() + container.add_text( + "# ✅ Auto-Role entfernt" + ) + container.add_separator() + container.add_text( + "Neue Mitglieder erhalten keine automatische Rolle mehr." ) + view = discord.ui.View(container, timeout=None) + else: # Rolle validieren if role >= ctx.guild.me.top_role: - embed = discord.Embed( - title="❌ Fehler", - description="Diese Rolle ist höher als meine höchste Rolle. Ich kann sie nicht vergeben.", - color=discord.Color.red() + container = Container() + container.add_text( + "# ❌ Fehler\nDiese Rolle ist höher als meine höchste Rolle. Ich kann sie nicht vergeben. " ) - await ctx.respond(embed=embed) + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view) return success = await self.db.update_welcome_settings(ctx.guild.id, auto_role_id=role.id) self.invalidate_cache(ctx.guild.id) if success: - embed = discord.Embed( - title="✅ Auto-Role gesetzt", - description=f"Neue Mitglieder erhalten automatisch die Rolle {role.mention}.", - color=discord.Color.green() + container = Container() + container.add_text( + "# ✅ Auto-Role gesetzt" ) + container.add_separator() + container.add_text( + f"Neue Mitglieder erhalten automatisch die Rolle {role.mention}." + ) + view = discord.ui.View(container, timeout=None) else: - embed = discord.Embed( - title="❌ Fehler", - description="Die Auto-Role konnte nicht gesetzt werden.", - color=discord.Color.red() + container = Container() + container.add_text( + "# ❌ Fehler\nDie Auto-Role konnte nicht gesetzt werden." ) - - await ctx.respond(embed=embed) + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view) @welcome.command(name="dm", description="Aktiviert/Konfiguriert private Willkommensnachrichten") @commands.has_permissions(manage_guild=True) @@ -504,19 +520,22 @@ async def setup_join_dm(self, ctx, enabled: bool, *, message: str = None): else: description = "Private Welcome Messages deaktiviert." - embed = discord.Embed( - title="✅ DM Einstellungen aktualisiert", - description=description, - color=discord.Color.green() + container = Container() + container.add_text( + "# ✅ DM Einstellungen aktualisiert" + ) + container.add_separator() + container.add_text( + f"{description}" ) + view = discord.ui.View(container, timeout=None) else: - embed = discord.Embed( - title="❌ Fehler", - description="Die DM Einstellungen konnten nicht aktualisiert werden.", - color=discord.Color.red() + container = Container() + container.add_text( + "# ❌ Fehler\nDie DM Einstellungen konnten nicht aktualisiert werden." ) - - await ctx.respond(embed=embed) + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view) @welcome.command(name="template", description="Lädt eine Vorlage") @commands.has_permissions(manage_guild=True) @@ -599,83 +618,67 @@ async def show_config(self, ctx): settings = await self.get_cached_settings(ctx.guild.id) if not settings: - embed = discord.Embed( - title="❌ Keine Konfiguration gefunden", - description="Es sind noch keine Welcome Einstellungen vorhanden.", - color=discord.Color.red() + container = Container() + container.add_text( + "# ❌ Keine Konfiguration gefunden\nEs sind noch keine Welcome Einstellungen vorhanden." ) - await ctx.respond(embed=embed) + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view) return channel = self.bot.get_channel(settings.get('channel_id')) if settings.get('channel_id') else None auto_role = ctx.guild.get_role(settings.get('auto_role_id')) if settings.get('auto_role_id') else None - - embed = discord.Embed( - title="⚙️ Welcome System Konfiguration", - color=discord.Color.blue() + container = Container() + container.add_text( + "# ⚙️ Welcome System Konfiguration" ) - - # Basis Einstellungen - embed.add_field( - name="📊 Status", - value="✅ Aktiviert" if settings.get('enabled') else "❌ Deaktiviert", - inline=True + container.add_separator() + container.add_text( + "## 📊 Status\n" + f"{'✅ Aktiviert' if settings.get('enabled') else '❌ Deaktiviert'}" ) - - embed.add_field( - name="📢 Channel", - value=channel.mention if channel else "❌ Nicht gesetzt", - inline=True + + container.add_text( + "## 📢 Channel\n" + f"{channel.mention if channel else '❌ Nicht gesetzt'}" ) - - embed.add_field( - name="🎨 Embed Modus", - value="✅ Aktiviert" if settings.get('embed_enabled') else "❌ Deaktiviert", - inline=True + + container.add_text( + "## 🎨 Embed Modus\n" + f"{'✅ Aktiviert' if settings.get('embed_enabled') else '❌ Deaktiviert'}" ) - - # Erweiterte Einstellungen (nur wenn verfügbar) - if settings.get('auto_role_id'): - embed.add_field( - name="🏷️ Auto-Role", - value=auto_role.mention if auto_role else "❌ Rolle nicht gefunden", - inline=True - ) - + + container.add_text( + "## 🏷️ Auto-Role\n" + f"{auto_role.mention if auto_role else '❌ Rolle nicht gefunden'}" + ) + if settings.get('join_dm_enabled'): - embed.add_field( - name="💌 Private Nachricht", - value="✅ Aktiviert", - inline=True + container.add_text( + "## 💌 Private Nachricht\n✅ Aktiviert" ) - + if settings.get('template_name'): - embed.add_field( - name="📋 Vorlage", - value=settings.get('template_name').title(), - inline=True + container.add_text( + "## 📋 Vorlage\n" + f"{settings.get('template_name').title()}" ) - - # Welcome Message + message = settings.get('welcome_message', 'Nicht gesetzt') - if message and len(message) > 100: + if len(message) > 100: message = message[:100] + "..." - - embed.add_field( - name="💬 Welcome Message", - value=f"```{message or 'Standard Embed'}```", - inline=False + container.add_text( + "## 💬 Welcome Message\n" + f"{message}" ) - - # Zusätzliche Info + if settings.get('delete_after', 0) > 0: - embed.add_field( - name="🗑️ Auto-Delete", - value=f"{settings.get('delete_after')} Sekunden", - inline=True + container.add_text( + "## 🗑️ Auto-Delete\n" + f"{settings.get('delete_after')} Sekunden" ) - - await ctx.respond(embed=embed) + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view) @welcome.command(name="test", description="Testet die Welcome Message") @commands.has_permissions(manage_messages=True) @@ -684,19 +687,18 @@ async def test_welcome(self, ctx): settings = await self.get_cached_settings(ctx.guild.id) if not settings: - embed = discord.Embed( - title="❌ Fehler", - description="Es sind noch keine Welcome Einstellungen vorhanden.", - color=discord.Color.red() + container = Container() + container.add_text( + "# ❌ Fehler\nEs sind noch keine Welcome Einstellungen vorhanden." ) - await ctx.respond(embed=embed, ephemeral=True) + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view, ephemeral=True) return if not settings.get('channel_id'): - embed = discord.Embed( - title="❌ Fehler", - description="Es ist kein Welcome Channel gesetzt.", - color=discord.Color.red() + container = Container() + container.add_text( + "# ❌ Fehler\nEs ist kein Welcome Channel gesetzt." ) await ctx.respond(embed=embed, ephemeral=True) return diff --git a/cogs/moderation/warningsystem.py b/cogs/moderation/warningsystem.py index c3bb2a5..5e1cc23 100644 --- a/cogs/moderation/warningsystem.py +++ b/cogs/moderation/warningsystem.py @@ -10,6 +10,8 @@ from DevTools.backend import discord, slash_command, Option, datetime, os, ezcord import asyncio from typing import Optional +from discord.ui import Container + # ─────────────────────────────────────────────── # >> Cogs From cbf6b4cf632940030ee59c8c3dd48743fddb713c Mon Sep 17 00:00:00 2001 From: Medicopter117 Date: Tue, 11 Nov 2025 17:53:36 +0100 Subject: [PATCH 10/10] UPDATE: main.py and the versioncheck --- main.py | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 76 insertions(+), 10 deletions(-) diff --git a/main.py b/main.py index 6854402..c12d36f 100644 --- a/main.py +++ b/main.py @@ -50,23 +50,77 @@ # ============================================================================= # BOT VERSION # ============================================================================= -BOT_VERSION = "1.7.2" +import aiohttp +from colorama import Fore, Style +import re + +BOT_VERSION = "1.7.2-dev" VERSION_URL = "https://raw.githubusercontent.com/Oppro-net-Development/ManagerX/main/version.txt" + +def parse_version(v: str): + """Zerlegt Version in (major, minor, patch, type)""" + match = re.match(r"(\d+)\.(\d+)\.(\d+)(?:[-_]?(dev|beta))?", v) + if match: + major, minor, patch, vtype = match.groups() + return int(major), int(minor), int(patch), vtype or "stable" + return 0, 0, 0, "unknown" + + async def check_for_update(): + """Überprüft, ob eine neuere Version verfügbar ist oder ob du eine Dev-/Beta-Version nutzt.""" try: async with aiohttp.ClientSession() as session: - async with session.get(VERSION_URL) as resp: - if resp.status == 200: - latest_version = (await resp.text()).strip() - if latest_version != BOT_VERSION: - print(f"[{Fore.YELLOW}UPDATE{Style.RESET_ALL}] Your Version {BOT_VERSION} is outdated! Latest Version: {latest_version}") - else: - print(f"[{Fore.GREEN}UP-TO-DATE{Style.RESET_ALL}] You have the latest Version: {BOT_VERSION}") + async with session.get(VERSION_URL, timeout=aiohttp.ClientTimeout(total=10)) as resp: + if resp.status != 200: + print(f"[{Fore.RED}ERROR{Style.RESET_ALL}] Update check failed (HTTP {resp.status})") + return None + + latest_version = (await resp.text()).strip() + if not latest_version: + print(f"[{Fore.RED}ERROR{Style.RESET_ALL}] Empty response from version server!") + return None + + # Versionen parsen + current = parse_version(BOT_VERSION) + latest = parse_version(latest_version) + + # --- Vergleich --- + if current[:3] == latest[:3] and current[3] == latest[3]: + print(f"[{Fore.GREEN}UP-TO-DATE{Style.RESET_ALL}] Running latest version: {BOT_VERSION}") + + elif current[:3] > latest[:3]: + print( + f"[{Fore.CYAN}DEV BUILD{Style.RESET_ALL}] " + f"Your version ({BOT_VERSION}) is newer than the latest public release ({latest_version})!" + ) + + elif current[:3] == latest[:3] and current[3] in ("dev", "beta"): + print( + f"[{Fore.MAGENTA}PRE-RELEASE{Style.RESET_ALL}] " + f"You are using a {current[3].upper()} version ({BOT_VERSION}) — " + f"latest stable: {latest_version}" + ) + else: - print(f"[{Fore.RED}ERROR{Style.RESET_ALL}] Could not retrieve version, Status: {resp.status}") + print( + f"[{Fore.YELLOW}UPDATE AVAILABLE{Style.RESET_ALL}] " + f"Installed: {BOT_VERSION} → Latest: {latest_version}\n" + f"Get the latest version here: {Fore.CYAN}https://github.com/Oppro-net-Development/ManagerX{Style.RESET_ALL}" + ) + + return latest_version + + except aiohttp.ClientConnectorError: + print(f"[{Fore.RED}ERROR{Style.RESET_ALL}] Could not connect to GitHub (network issue).") + except aiohttp.ServerTimeoutError: + print(f"[{Fore.RED}ERROR{Style.RESET_ALL}] Connection to version server timed out.") except Exception as e: - print(f"[{Fore.RED}ERROR{Style.RESET_ALL}] Error during update check: {e}") + print(f"[{Fore.RED}ERROR{Style.RESET_ALL}] Unexpected error: {e}") + + return None + + @bot.event @@ -130,6 +184,18 @@ async def on_message(message: discord.Message): except Exception as e: await message.channel.send(f"⚠️ Fehler: {e}", delete_after=5) return # wichtig für andere Befehle +# ============================================================================= +# Übersetzung +# ============================================================================= + +with open("translation/messages/de.yaml", encoding="utf-8") as file: + de = yaml.safe_load(file) + +with open("translation/messages/en.yaml", encoding="utf-8") as file: + en = yaml.safe_load(file) + +ezcord.I18N({"de": de, "en": en}, prefer_user_locale=True, fallback_locale="en") + # ============================================================================= # BOT START