From 3f6e41b0c0e14e24edd59d7ecee1652455ae3c4a Mon Sep 17 00:00:00 2001
From: "Edgar P. Burkhart" <git@edgarpierre.fr>
Date: Mon, 24 Mar 2025 10:46:58 +0100
Subject: [PATCH] Refactor VoiceBot to manage voice connections with a
 dictionary and improve channel handling logic

---
 botbotbot/voice.py | 47 ++++++++++++++++++++++++++++++++--------------
 1 file changed, 33 insertions(+), 14 deletions(-)

diff --git a/botbotbot/voice.py b/botbotbot/voice.py
index bc066ee..6cad996 100644
--- a/botbotbot/voice.py
+++ b/botbotbot/voice.py
@@ -26,6 +26,7 @@ class VoiceBot:
         self.shf = shuffler
         self.aibot = aibot
         self.guild_ids = guild_ids
+        self.vo: dict[int, discord.VoiceClient] = dict()
 
         self.mots = pathlib.Path("assets/mots.txt").read_text().split("\n")
 
@@ -59,7 +60,12 @@ class VoiceBot:
 
                 if random.random() < 50 / 100:
                     logger.info("Random connect.")
-                    voice_chan = random.choice(guild.voice_channels)
+                    voice_chan = random.choices(
+                        guild.voice_channels,
+                        weights=[
+                            10 * len(vc.members) + 1 for vc in guild.voice_channels
+                        ],
+                    )[0]
                     await self.connect_voice(voice_chan)
                     if not voice_chan.status and self.aibot is not None:
                         mot = random.choice(self.mots)
@@ -82,7 +88,7 @@ class VoiceBot:
 
         logger.info(f"Connecting to voice channel <{channel}>.")
         if len(channel.members) == 0:
-            vo = await self.connect_voice_chan(channel)
+            await self.connect_voice_chan(channel)
             return
         elif len(channel.members) == 1:
             member = self.rnd_name(channel.members[0])
@@ -121,13 +127,16 @@ class VoiceBot:
     async def connect_voice_chan(
         self, channel: discord.VoiceChannel | discord.StageChannel
     ) -> discord.VoiceClient:
-        await self.disconnect_voice(channel.guild)
-        return await channel.connect()
+        if channel.guild.id in self.vo:
+            await self.disconnect_voice(channel.guild)
+
+        vo: discord.VoiceClient = await channel.connect()
+        self.vo[channel.guild.id] = vo
+        return vo
 
     async def disconnect_voice(self, guild: discord.Guild) -> None:
-        for vc in self.bot.voice_clients:
-            if isinstance(vc, discord.VoiceClient) and vc.guild == guild:
-                await vc.disconnect()
+        if vo := self.vo.pop(guild.id, None):
+            await vo.disconnect()
 
     async def join_voice(self, ctx: discord.ApplicationContext) -> None:
         if ctx.user.voice:
@@ -157,14 +166,24 @@ class VoiceBot:
             logger.debug(after.channel.members)
 
         if (
-            self.cambai is not None
-            and before.channel is None
-            and after.channel is not None
-            and self.bot not in after.channel.members
-            and self.bot.user
-            and member.id != self.bot.user.id
-            and random.random() < 5 / 100
+            self.cambai is None
+            or after.channel is None
+            or before.channel == after.channel
+            or (self.bot.user and member == self.bot.user)
         ):
+            return
+
+        if self.bot.user in after.channel.members and (
+            vo := self.vo.get(after.channel.guild.id, None)
+        ):
+            m = self.rnd_name(member)
+            script = f"Salut {m}, ça va bien ?"
+            source = await discord.FFmpegOpusAudio.from_probe(self.cambai.tts(script))
+            await asyncio.sleep(10 * random.random())
+            await vo.play(source, wait_finish=True)
+            return
+
+        if random.random() < 5 / 100:
             await self.connect_voice(after.channel)
 
     async def shuffle(