diff --git a/VocalMaisBot.py b/VocalMaisBot.py index a9af3eb..03018a8 100755 --- a/VocalMaisBot.py +++ b/VocalMaisBot.py @@ -52,6 +52,9 @@ class VocalMaisBot(discord.Client): else: return self.sorry_do_not_understand(message) + async def sorry_do_not_understand(self, message: discord.Message): + await message.channel.send(f"Sorry I did not understand this message. Try `@{self.user.display_name} help` for help") + async def print_help(self, channel: discord.TextChannel): me = self.user.display_name message = f""" @@ -83,18 +86,15 @@ class VocalMaisBot(discord.Client): "_name": message.guild.name, "watched_channels": [], } - watched_channel_for_this_guild = self.watched_channels[guild_id]["watched_channels"] + watched_channels_for_this_guild = self.watched_channels[guild_id]["watched_channels"] - if channel_id in watched_channel_for_this_guild: + if channel_id in watched_channels_for_this_guild: return await message.channel.send(":thumbsup: I was already watching this channel") else: - watched_channel_for_this_guild.append(channel_id) + watched_channels_for_this_guild.append(channel_id) self.loop.call_soon(self.write_watched_channels_file) return await message.channel.send(f":white_check_mark: I am now watching {channel.name}") - async def sorry_do_not_understand(self, message: discord.Message): - await message.channel.send(f"Sorry I did not understand this message. Try `@{self.user.display_name} help` for help") - def write_watched_channels_file(self): logger.debug("Writing watched channels information to file") self.watched_channels_file.seek(0) @@ -103,6 +103,61 @@ class VocalMaisBot(discord.Client): self.watched_channels_file.flush() logger.debug("Written watched channels information to file") + async def on_voice_state_update(self, member: discord.Member, before: discord.VoiceState, after: discord.VoiceState): + if member.bot: + return + if before.channel is not None: # They left a channel + await self.handle_user_left_voice(before.channel) + if after.channel is not None: # They joined a channel. Note that there is an if and not an elif, because they could leave a channel to join another + await self.handle_user_connected_to_voice(member, after.channel) + + async def handle_user_connected_to_voice(self, user: discord.Member, channel: discord.VoiceChannel): + guild_id = str(channel.guild.id) + if guild_id not in self.watched_channels: + return # We do not have an entry for this guild, so we surely do not have anything to do here + if channel.id not in self.watched_channels[guild_id]["watched_channels"]: + return # It's not one of our special watched join-to-create channel + + # The user connected to one of our special watched channels + category = channel.category + user_name = user.display_name + user_channel = await category.create_voice_channel(f"{user_name}'s channel", overwrites = {user: discord.PermissionOverwrite(manage_channels = True)}) + await user.move_to(user_channel) + logger.info(f"Created channel {user_channel.name}({user_channel.id}) for {user.display_name}({user.id})") + + # Updating channels information + guild_info = self.watched_channels[guild_id] + if "created_channels" not in guild_info: + guild_info["created_channels"] = [] + guild_info["created_channels"].append(user_channel.id) + self.loop.call_soon(self.write_watched_channels_file) + + async def handle_user_left_voice(self, channel: discord.VoiceChannel): + guild_id = str(channel.guild.id) + if guild_id not in self.watched_channels: + return # We do not have an entry for this guild, so we surely do not have anything to do here + guild_info = self.watched_channels[guild_id] + if "created_channels" not in guild_info: + return # We did not create any channel in this guild, so we do not have anything to do when a user disconnects + + if channel.id in guild_info["created_channels"]: # This is a temporary channel that we created + if len(channel.members) > 0: + return # There are still people inside it, nothing to do + try: + await channel.delete() + except discord.NotFound: + pass # The channel already does not exist, that's not a problem, that's what we want + logger.info(f"Deleted channel {channel.name}({channel.id}) because it was empty") + try: + guild_info["created_channels"].remove(channel.id) + except ValueError: + pass # For some reason the value was not in the list, that's not a problem, that's what we want + # We could update the json file, but we avoid it to limit the number of writes to disk. + # It is not critical if this information is lost, and it will probably be update properly anyway the next time the file is written + pass + else: + return + def _check_list_element(l: List, index: int, expected_value: Any) -> bool: try: