diff --git a/bot.py b/bot.py index 84fcd7c..dd97df8 100644 --- a/bot.py +++ b/bot.py @@ -9,6 +9,9 @@ load_dotenv() TOKEN = os.getenv("DISCORD_TOKEN") DATA_FILE = "data.json" +# Datenformat: +# { "guild_id": { "user_id": { "mic": , "deaf": } } } + def load_data() -> dict: if os.path.exists(DATA_FILE): @@ -22,16 +25,19 @@ def save_data(data: dict): json.dump(data, f, indent=2, ensure_ascii=False) -def get_mute_count(data: dict, guild_id: int, user_id: int) -> int: - return data.get(str(guild_id), {}).get(str(user_id), 0) +def get_user_entry(data: dict, guild_id: int, user_id: int) -> dict: + return data.get(str(guild_id), {}).get(str(user_id), {"mic": 0, "deaf": 0}) -def increment_mute(data: dict, guild_id: int, user_id: int): +def increment(data: dict, guild_id: int, user_id: int, kind: str): + """kind: 'mic' oder 'deaf'""" gid = str(guild_id) uid = str(user_id) if gid not in data: data[gid] = {} - data[gid][uid] = data[gid].get(uid, 0) + 1 + if uid not in data[gid]: + data[gid][uid] = {"mic": 0, "deaf": 0} + data[gid][uid][kind] += 1 intents = discord.Intents.default() @@ -58,29 +64,40 @@ async def on_voice_state_update( before: discord.VoiceState, after: discord.VoiceState, ): - # Bots ignorieren if member.bot: return guild = member.guild - - # AFK-Channel ausschließen: Ereignisse ignorieren, wenn Nutzer im AFK-Channel ist afk_channel = guild.afk_channel - if after.channel is not None and afk_channel is not None and after.channel.id == afk_channel.id: - return - if before.channel is not None and afk_channel is not None and before.channel.id == afk_channel.id: - return - # Erkennen: Nutzer hat sich gerade selbst gemutet (war vorher nicht gemutet) - just_muted = (not before.self_mute) and after.self_mute + # AFK-Channel ausschließen + if afk_channel is not None: + if (after.channel is not None and after.channel.id == afk_channel.id) or \ + (before.channel is not None and before.channel.id == afk_channel.id): + return - if just_muted: - increment_mute(mute_data, guild.id, member.id) + # Full Mute (Deafen): Nutzer hat sich gerade taubgestellt + just_deafened = (not before.self_deaf) and after.self_deaf + + # Nur Mikrofon gemutet: self_mute wurde aktiviert, aber NICHT deafen + just_mic_muted = (not before.self_mute) and after.self_mute and (not after.self_deaf) + + if just_deafened: + increment(mute_data, guild.id, member.id, "deaf") save_data(mute_data) + entry = get_user_entry(mute_data, guild.id, member.id) print( - f"{member.display_name} hat sich gemutet " - f"(Gesamt: {get_mute_count(mute_data, guild.id, member.id)}x) " - f"[Server: {guild.name}]" + f"[DEAF] {member.display_name} hat sich taubgestellt " + f"(deaf={entry['deaf']}x, mic={entry['mic']}x) [{guild.name}]" + ) + + elif just_mic_muted: + increment(mute_data, guild.id, member.id, "mic") + save_data(mute_data) + entry = get_user_entry(mute_data, guild.id, member.id) + print( + f"[MIC] {member.display_name} hat nur sein Mikrofon gemutet " + f"(mic={entry['mic']}x, deaf={entry['deaf']}x) [{guild.name}]" ) @@ -97,35 +114,55 @@ async def mutescore(interaction: discord.Interaction, limit: int = 10): ) return - sorted_entries = sorted(guild_data.items(), key=lambda x: x[1], reverse=True) - top = sorted_entries[:limit] + # Sortieren nach Gesamt-Mutes (mic + deaf) + def total(entry): + if isinstance(entry, dict): + return entry.get("mic", 0) + entry.get("deaf", 0) + return entry # Fallback für altes Format - embed = discord.Embed( - title="Mute-Leaderboard", - description="Wer mutet sich am häufigsten?", - color=discord.Color.blurple(), - ) + sorted_entries = sorted(guild_data.items(), key=lambda x: total(x[1]), reverse=True) + top = sorted_entries[:limit] medals = {1: "🥇", 2: "🥈", 3: "🥉"} lines = [] - for rank, (uid, count) in enumerate(top, start=1): + for rank, (uid, counts) in enumerate(top, start=1): member = guild.get_member(int(uid)) name = member.display_name if member else f"Unbekannt ({uid})" medal = medals.get(rank, f"**#{rank}**") - lines.append(f"{medal} {name} — **{count}x** gemutet") + if isinstance(counts, dict): + mic = counts.get("mic", 0) + deaf = counts.get("deaf", 0) + lines.append( + f"{medal} {name} — " + f"**{mic + deaf}x** gesamt " + f"*(🎙️ {mic}x Mikro / 🔇 {deaf}x Deaf)*" + ) + else: + lines.append(f"{medal} {name} — **{counts}x** gemutet") + + embed = discord.Embed( + title="Mute-Leaderboard", + color=discord.Color.blurple(), + ) embed.description = "\n".join(lines) - embed.set_footer(text=f"Top {len(top)} von {len(sorted_entries)} Nutzern") + embed.set_footer(text=f"Top {len(top)} von {len(sorted_entries)} Nutzern | 🎙️ = nur Mikro | 🔇 = Deaf") await interaction.response.send_message(embed=embed) -@bot.tree.command(name="mymutes", description="Zeigt deine eigene Mute-Anzahl.") +@bot.tree.command(name="mymutes", description="Zeigt deine eigenen Mute-Stats.") async def mymutes(interaction: discord.Interaction): - count = get_mute_count(mute_data, interaction.guild.id, interaction.user.id) + entry = get_user_entry(mute_data, interaction.guild.id, interaction.user.id) + mic = entry.get("mic", 0) + deaf = entry.get("deaf", 0) await interaction.response.send_message( - f"Du hast dich bisher **{count}x** gemutet.", ephemeral=True + f"Deine Mute-Stats:\n" + f"🎙️ Nur Mikrofon gemutet: **{mic}x**\n" + f"🔇 Taubgestellt (Deaf): **{deaf}x**\n" + f"📊 Gesamt: **{mic + deaf}x**", + ephemeral=True, )