Implement channel name management in ExtendedAudio cog. Add functionality to store and reset original channel names when enabling/disabling voice channel status updates. Enhance status format configuration with additional variables and validation. Introduce cleanup tasks on cog unload and voice state updates for improved user experience.
Some checks are pending
Run pre-commit / Run pre-commit (push) Waiting to run
Some checks are pending
Run pre-commit / Run pre-commit (push) Waiting to run
This commit is contained in:
parent
8d79407cb4
commit
bddbd49106
1 changed files with 164 additions and 11 deletions
|
@ -5,10 +5,17 @@ from typing import Optional
|
|||
import discord
|
||||
from redbot.core import Config, commands
|
||||
from redbot.core.bot import Red
|
||||
from redbot.core.utils.chat_formatting import box
|
||||
from redbot.core.utils.chat_formatting import box, humanize_list
|
||||
from redbot.core.utils.predicates import MessagePredicate
|
||||
|
||||
log = logging.getLogger("red.valerie.extendedaudio")
|
||||
|
||||
SUPPORTED_VARIABLES = {
|
||||
"title": "Song title",
|
||||
"requester": "User who requested the song",
|
||||
"duration": "Duration of the song"
|
||||
}
|
||||
|
||||
class ExtendedAudio(commands.Cog):
|
||||
"""Extends Red's core Audio cog with additional features"""
|
||||
|
||||
|
@ -18,6 +25,7 @@ class ExtendedAudio(commands.Cog):
|
|||
default_guild = {
|
||||
"channel_status": True, # Whether to update voice channel name with current song
|
||||
"status_format": "🎵 {title}", # Format for the channel name
|
||||
"original_name": None, # Store the original channel name
|
||||
}
|
||||
self.config.register_guild(**default_guild)
|
||||
self.task = self.bot.loop.create_task(self.initialize())
|
||||
|
@ -37,13 +45,47 @@ class ExtendedAudio(commands.Cog):
|
|||
"""Cleanup when cog unloads"""
|
||||
if self.task:
|
||||
self.task.cancel()
|
||||
# Reset all modified channel names
|
||||
asyncio.create_task(self._cleanup_on_unload())
|
||||
|
||||
async def _cleanup_on_unload(self):
|
||||
"""Reset all modified channel names when cog unloads"""
|
||||
for guild in self.bot.guilds:
|
||||
try:
|
||||
original_name = await self.config.guild(guild).original_name()
|
||||
if original_name and guild.voice_client and guild.voice_client.channel:
|
||||
await guild.voice_client.channel.edit(name=original_name)
|
||||
await self.config.guild(guild).original_name.set(None)
|
||||
except:
|
||||
continue
|
||||
|
||||
async def cog_check(self, ctx: commands.Context):
|
||||
"""Check if Audio cog is loaded"""
|
||||
if not self.audio:
|
||||
self.audio = self.bot.get_cog("Audio")
|
||||
if not self.audio:
|
||||
await ctx.send("The Audio cog is not loaded. Please load it first with `[p]load audio`")
|
||||
return False
|
||||
return True
|
||||
|
||||
@commands.group(aliases=["eaudioset"])
|
||||
@commands.guild_only()
|
||||
@commands.admin_or_permissions(manage_guild=True)
|
||||
async def extendedaudioset(self, ctx: commands.Context):
|
||||
"""Configure ExtendedAudio settings"""
|
||||
pass
|
||||
if not ctx.invoked_subcommand:
|
||||
guild = ctx.guild
|
||||
conf = await self.config.guild(guild).all()
|
||||
enabled = conf["channel_status"]
|
||||
format_str = conf["status_format"]
|
||||
msg = (
|
||||
f"**Current Settings**\n"
|
||||
f"Channel Status: {'Enabled' if enabled else 'Disabled'}\n"
|
||||
f"Status Format: {format_str}\n\n"
|
||||
f"Available Variables: {humanize_list([f'{{' + k + '}}' for k in SUPPORTED_VARIABLES.keys()])}\n"
|
||||
f"Use `{ctx.prefix}extendedaudioset statusformat` to change the format."
|
||||
)
|
||||
await ctx.send(box(msg))
|
||||
|
||||
@extendedaudioset.command(name="channelstatus")
|
||||
async def set_channel_status(self, ctx: commands.Context, enabled: bool):
|
||||
|
@ -53,21 +95,73 @@ class ExtendedAudio(commands.Cog):
|
|||
|
||||
Example: [p]extendedaudioset channelstatus true
|
||||
"""
|
||||
await self.config.guild(ctx.guild).channel_status.set(enabled)
|
||||
guild = ctx.guild
|
||||
|
||||
# Check if bot has required permissions
|
||||
if not guild.me.guild_permissions.manage_channels:
|
||||
await ctx.send("I need the `Manage Channels` permission to update channel names.")
|
||||
return
|
||||
|
||||
# Store original channel name if enabling and not stored
|
||||
if enabled:
|
||||
voice_client = guild.voice_client
|
||||
if voice_client and voice_client.channel:
|
||||
current_name = voice_client.channel.name
|
||||
if not await self.config.guild(guild).original_name():
|
||||
await self.config.guild(guild).original_name.set(current_name)
|
||||
|
||||
await self.config.guild(guild).channel_status.set(enabled)
|
||||
state = "enabled" if enabled else "disabled"
|
||||
await ctx.send(f"Voice channel status updates {state}.")
|
||||
|
||||
# Reset channel name if disabling
|
||||
if not enabled:
|
||||
try:
|
||||
voice_client = guild.voice_client
|
||||
if voice_client and voice_client.channel:
|
||||
original_name = await self.config.guild(guild).original_name()
|
||||
if original_name:
|
||||
await voice_client.channel.edit(name=original_name)
|
||||
await self.config.guild(guild).original_name.set(None)
|
||||
except discord.Forbidden:
|
||||
await ctx.send("I don't have permission to edit the channel name.")
|
||||
except Exception as e:
|
||||
log.error(f"Error resetting channel name: {e}")
|
||||
|
||||
@extendedaudioset.command(name="statusformat")
|
||||
async def set_status_format(self, ctx: commands.Context, *, format_str: str):
|
||||
"""Set the format for voice channel status updates
|
||||
|
||||
Available variables:
|
||||
{title} - Song title
|
||||
{requester} - User who requested the song
|
||||
{duration} - Duration of the song
|
||||
|
||||
Example: [p]extendedaudioset statusformat 🎵 {title}
|
||||
"""
|
||||
# Validate format string
|
||||
try:
|
||||
# Test with sample data
|
||||
test_data = {
|
||||
"title": "Test Song",
|
||||
"requester": "Test User",
|
||||
"duration": "3:45"
|
||||
}
|
||||
format_str.format(**test_data)
|
||||
except KeyError as e:
|
||||
invalid_var = str(e).strip("'")
|
||||
supported = humanize_list([f"{{" + k + "}}" for k in SUPPORTED_VARIABLES.keys()])
|
||||
await ctx.send(
|
||||
f"Invalid variable `{invalid_var}` in format string.\n"
|
||||
f"Supported variables are: {supported}"
|
||||
)
|
||||
return
|
||||
except Exception as e:
|
||||
await ctx.send(f"Invalid format string: {e}")
|
||||
return
|
||||
|
||||
await self.config.guild(ctx.guild).status_format.set(format_str)
|
||||
example = format_str.format(title="Never Gonna Give You Up")
|
||||
example = format_str.format(title="Never Gonna Give You Up", requester="Rick Astley", duration="3:32")
|
||||
await ctx.send(
|
||||
f"Status format set! Example:\n"
|
||||
f"{box(example)}"
|
||||
|
@ -91,12 +185,31 @@ class ExtendedAudio(commands.Cog):
|
|||
|
||||
channel = voice_client.channel
|
||||
|
||||
# Store original name if not stored
|
||||
if not await self.config.guild(guild).original_name():
|
||||
await self.config.guild(guild).original_name.set(channel.name)
|
||||
|
||||
# Get the format and create the new name
|
||||
format_str = await self.config.guild(guild).status_format()
|
||||
new_name = format_str.format(title=track.get("title", "Unknown"))
|
||||
|
||||
# Update channel name if different
|
||||
if channel.name != new_name:
|
||||
# Prepare variables
|
||||
duration = track.get("length", 0)
|
||||
minutes = duration // 60
|
||||
seconds = duration % 60
|
||||
duration_str = f"{minutes}:{seconds:02d}"
|
||||
|
||||
new_name = format_str.format(
|
||||
title=track.get("title", "Unknown"),
|
||||
requester=requester.display_name,
|
||||
duration=duration_str
|
||||
)
|
||||
|
||||
# Ensure name length is valid (Discord limit is 100 characters)
|
||||
if len(new_name) > 100:
|
||||
new_name = new_name[:97] + "..."
|
||||
|
||||
# Update channel name if different and we have permissions
|
||||
if channel.name != new_name and guild.me.guild_permissions.manage_channels:
|
||||
await channel.edit(name=new_name)
|
||||
|
||||
except discord.Forbidden:
|
||||
|
@ -122,12 +235,52 @@ class ExtendedAudio(commands.Cog):
|
|||
|
||||
channel = voice_client.channel
|
||||
|
||||
# Reset channel name if it was modified (contains 🎵)
|
||||
if "🎵" in channel.name:
|
||||
original_name = channel.name.split("🎵")[-1].strip()
|
||||
# Reset to original name if stored and we have permissions
|
||||
original_name = await self.config.guild(guild).original_name()
|
||||
if original_name and guild.me.guild_permissions.manage_channels:
|
||||
await channel.edit(name=original_name)
|
||||
|
||||
except discord.Forbidden:
|
||||
log.warning(f"Missing permissions to edit channel name in {guild.name}")
|
||||
except Exception as e:
|
||||
log.error(f"Error resetting channel status in {guild.name}: {e}")
|
||||
log.error(f"Error resetting channel status in {guild.name}: {e}")
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_voice_state_update(self, member: discord.Member, before: discord.VoiceState, after: discord.VoiceState):
|
||||
"""Reset channel name when bot leaves voice channel"""
|
||||
if not member.guild:
|
||||
return
|
||||
|
||||
# Check if this is the bot disconnecting
|
||||
if member.id == self.bot.user.id and before.channel and not after.channel:
|
||||
try:
|
||||
# Reset channel name if we have the original stored and permissions
|
||||
guild = member.guild
|
||||
if not guild.me.guild_permissions.manage_channels:
|
||||
return
|
||||
|
||||
original_name = await self.config.guild(guild).original_name()
|
||||
if original_name and before.channel:
|
||||
await before.channel.edit(name=original_name)
|
||||
await self.config.guild(guild).original_name.set(None)
|
||||
except Exception as e:
|
||||
log.error(f"Error resetting channel name on disconnect: {e}")
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_red_audio_player_auto_disconnect(self, guild: discord.Guild):
|
||||
"""Handle auto-disconnect cleanup"""
|
||||
try:
|
||||
if guild.me.guild_permissions.manage_channels:
|
||||
original_name = await self.config.guild(guild).original_name()
|
||||
if original_name:
|
||||
voice_client = guild.voice_client
|
||||
if voice_client and voice_client.channel:
|
||||
await voice_client.channel.edit(name=original_name)
|
||||
await self.config.guild(guild).original_name.set(None)
|
||||
except Exception as e:
|
||||
log.error(f"Error handling auto-disconnect cleanup: {e}")
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_red_audio_player_auto_pause(self, guild: discord.Guild):
|
||||
"""Handle auto-pause"""
|
||||
# We don't change the channel name on pause to maintain consistency
|
Loading…
Add table
Reference in a new issue