new help command, fixed queue and loop display, thumbnails and urls added to database
This commit is contained in:
@@ -107,72 +107,160 @@ def update_activity(guild_id):
|
||||
# Interactive buttons for queue control
|
||||
class QueueControls(View):
|
||||
def __init__(self, ctx):
|
||||
super().__init__(timeout=300) # 5 minute timeout
|
||||
super().__init__(timeout=None) # No timeout allows buttons to stay active longer
|
||||
self.ctx = ctx
|
||||
|
||||
async def refresh_message(self, interaction: discord.Interaction):
|
||||
"""Helper to regenerate the embed and edit the message"""
|
||||
try:
|
||||
# Generate new embed
|
||||
embed, view = await generate_queue_ui(self.ctx)
|
||||
await interaction.response.edit_message(embed=embed, view=view)
|
||||
except Exception as e:
|
||||
# Fallback if edit fails
|
||||
if not interaction.response.is_done():
|
||||
await interaction.response.send_message("Refreshed, but something went wrong updating the display.", ephemeral=True)
|
||||
|
||||
@discord.ui.button(label="⏭️ Skip", style=discord.ButtonStyle.primary)
|
||||
async def skip_button(self, interaction: discord.Interaction, button: Button):
|
||||
if interaction.user != self.ctx.author:
|
||||
await interaction.response.send_message("❌ Only the person who requested the queue can use these buttons!", ephemeral=True)
|
||||
if interaction.user not in self.ctx.voice_client.channel.members:
|
||||
await interaction.response.send_message("❌ You must be in the voice channel!", ephemeral=True)
|
||||
return
|
||||
|
||||
if self.ctx.voice_client and self.ctx.voice_client.is_playing():
|
||||
# Loop logic check
|
||||
loop_mode = await queue.get_loop_mode(self.ctx.guild.id)
|
||||
|
||||
# Logic mimics the command
|
||||
if loop_mode == 'song':
|
||||
# Just restart current song effectively but here we assume standard skip behavior for button
|
||||
pass
|
||||
|
||||
# Perform the skip
|
||||
await queue.pop(self.ctx.guild.id, True, skip_mode=True)
|
||||
if self.ctx.voice_client:
|
||||
self.ctx.voice_client.stop()
|
||||
await interaction.response.send_message("⏭️ Skipped!", ephemeral=True)
|
||||
else:
|
||||
await interaction.response.send_message("❌ Nothing is playing!", ephemeral=True)
|
||||
|
||||
# Refresh UI
|
||||
await self.refresh_message(interaction)
|
||||
|
||||
@discord.ui.button(label="🔀 Shuffle", style=discord.ButtonStyle.secondary)
|
||||
async def shuffle_button(self, interaction: discord.Interaction, button: Button):
|
||||
if interaction.user != self.ctx.author:
|
||||
await interaction.response.send_message("❌ Only the person who requested the queue can use these buttons!", ephemeral=True)
|
||||
return
|
||||
|
||||
success = await queue.shuffle_queue(self.ctx.guild.id)
|
||||
if success:
|
||||
await interaction.response.send_message("🔀 Queue shuffled!", ephemeral=True)
|
||||
else:
|
||||
await interaction.response.send_message("❌ Not enough songs to shuffle!", ephemeral=True)
|
||||
await queue.shuffle_queue(self.ctx.guild.id)
|
||||
await self.refresh_message(interaction)
|
||||
|
||||
@discord.ui.button(label="🔁 Loop", style=discord.ButtonStyle.secondary)
|
||||
async def loop_button(self, interaction: discord.Interaction, button: Button):
|
||||
if interaction.user != self.ctx.author:
|
||||
await interaction.response.send_message("❌ Only the person who requested the queue can use these buttons!", ephemeral=True)
|
||||
return
|
||||
|
||||
current_mode = await queue.get_loop_mode(self.ctx.guild.id)
|
||||
|
||||
# Cycle through modes
|
||||
if current_mode == 'off':
|
||||
new_mode = 'song'
|
||||
elif current_mode == 'song':
|
||||
new_mode = 'queue'
|
||||
else:
|
||||
new_mode = 'off'
|
||||
|
||||
new_mode = 'song' if current_mode == 'off' else ('queue' if current_mode == 'song' else 'off')
|
||||
await queue.set_loop_mode(self.ctx.guild.id, new_mode)
|
||||
|
||||
emojis = {'off': '⏹️', 'song': '🔂', 'queue': '🔁'}
|
||||
messages = {
|
||||
'off': 'Loop disabled',
|
||||
'song': 'Looping current song 🔂',
|
||||
'queue': 'Looping entire queue 🔁'
|
||||
}
|
||||
|
||||
await interaction.response.send_message(f"{emojis[new_mode]} {messages[new_mode]}", ephemeral=True)
|
||||
await self.refresh_message(interaction)
|
||||
|
||||
@discord.ui.button(label="🗑️ Clear", style=discord.ButtonStyle.danger)
|
||||
async def clear_button(self, interaction: discord.Interaction, button: Button):
|
||||
if interaction.user != self.ctx.author:
|
||||
await interaction.response.send_message("❌ Only the person who requested the queue can use these buttons!", ephemeral=True)
|
||||
return
|
||||
|
||||
await queue.clear(self.ctx.guild.id)
|
||||
if self.ctx.voice_client and self.ctx.voice_client.is_playing():
|
||||
self.ctx.voice_client.stop()
|
||||
await self.refresh_message(interaction)
|
||||
|
||||
await interaction.response.send_message("🗑️ Queue cleared!", ephemeral=True)
|
||||
@discord.ui.button(label="🔄 Refresh", style=discord.ButtonStyle.gray)
|
||||
async def refresh_button(self, interaction: discord.Interaction, button: Button):
|
||||
await self.refresh_message(interaction)
|
||||
|
||||
async def generate_queue_ui(ctx: Context):
|
||||
guild_id = ctx.guild.id
|
||||
server = ctx.guild
|
||||
|
||||
# Fetch all data
|
||||
n, songs = await queue.grab_songs(guild_id)
|
||||
current = await queue.get_current_song(guild_id) # Returns title, thumbnail, url
|
||||
loop_mode = await queue.get_loop_mode(guild_id)
|
||||
volume = await queue.get_volume(guild_id)
|
||||
effect = await queue.get_effect(guild_id)
|
||||
elapsed, duration, percentage = await queue.get_current_progress(guild_id)
|
||||
|
||||
# Configs
|
||||
effect_emoji = queue.get_effect_emoji(effect)
|
||||
|
||||
# Map loop mode to nicer text
|
||||
loop_map = {
|
||||
'off': {'emoji': '⏹️', 'text': 'Off'},
|
||||
'song': {'emoji': '🔂', 'text': 'Song'},
|
||||
'queue': {'emoji': '🔁', 'text': 'Queue'}
|
||||
}
|
||||
loop_info = loop_map.get(loop_mode, loop_map['off'])
|
||||
loop_emoji = loop_info['emoji']
|
||||
loop_text = loop_info['text']
|
||||
|
||||
# Build Embed
|
||||
embed = discord.Embed(color=discord.Color.from_rgb(43, 45, 49))
|
||||
embed.set_author(name=f"{server.name}'s Queue", icon_url=server.icon.url if server.icon else None)
|
||||
|
||||
# Progress Bar Logic
|
||||
progress_bar = ""
|
||||
# Only show bar if duration > 0 (prevents weird 00:00 bars)
|
||||
if duration > 0:
|
||||
bar_length = 16
|
||||
filled = int((percentage / 100) * bar_length)
|
||||
# Ensure filled isn't bigger than length
|
||||
filled = min(filled, bar_length)
|
||||
bar_str = '▬' * filled + '🔘' + '▬' * (bar_length - filled)
|
||||
progress_bar = f"\n`{format_time(elapsed)}` {bar_str} `{format_time(duration)}`"
|
||||
|
||||
# Now Playing Header
|
||||
title = current.get('title', 'Nothing Playing')
|
||||
thumb = current.get('thumbnail')
|
||||
url = current.get('url', '')
|
||||
|
||||
if title == 'Nothing':
|
||||
description = "## 💤 Nothing is playing\nUse `/play` to start the party!"
|
||||
else:
|
||||
# Create Hyperlink [Title](URL)
|
||||
# If no URL exists, link to Discord homepage as fallback or just bold
|
||||
if url and url.startswith("http"):
|
||||
song_link = f"[{title}]({url})"
|
||||
else:
|
||||
song_link = f"**{title}**"
|
||||
|
||||
# CLEARER STATUS LINE:
|
||||
# Loop: Mode | Effect: Name | Vol: %
|
||||
description = (
|
||||
f"## 💿 Now Playing\n"
|
||||
f"### {song_link}\n"
|
||||
f"{loop_emoji} **Loop: {loop_text}** | {effect_emoji} **Effect: {effect}** | 🔊 **{volume}%**"
|
||||
f"{progress_bar}"
|
||||
)
|
||||
|
||||
embed.description = description
|
||||
|
||||
# Queue List
|
||||
if len(songs) > 0:
|
||||
queue_text = ""
|
||||
for i, song in enumerate(songs[:10]):
|
||||
dur = '' if isinstance(song[1], str) else f" | `{format_time(song[1])}`"
|
||||
queue_text += f"**{i+1}.** {song[0]}{dur}\n"
|
||||
|
||||
embed.add_field(name="⏳ Up Next", value=queue_text, inline=False)
|
||||
|
||||
remaining = (n) - 9 # Approx calculation based on your grabbing logic
|
||||
if remaining > 0:
|
||||
embed.set_footer(text=f"Waitlist: {remaining} more songs...")
|
||||
else:
|
||||
embed.add_field(name="⏳ Up Next", value="*The queue is empty.*")
|
||||
|
||||
# Set Thumbnail safely
|
||||
if thumb and isinstance(thumb, str) and thumb.startswith("http"):
|
||||
embed.set_thumbnail(url=thumb)
|
||||
elif server.icon:
|
||||
# Fallback to server icon
|
||||
embed.set_thumbnail(url=server.icon.url)
|
||||
|
||||
view = QueueControls(ctx)
|
||||
return embed, view
|
||||
|
||||
# The command entry point calls this
|
||||
async def display_server_queue(ctx: Context, songs, n):
|
||||
embed, view = await generate_queue_ui(ctx)
|
||||
await ctx.send(embed=embed, view=view)
|
||||
|
||||
# Build a display message for queuing a new song
|
||||
async def queue_message(ctx: Context, data: dict):
|
||||
@@ -188,68 +276,6 @@ async def queue_message(ctx: Context, data: dict):
|
||||
|
||||
await ctx.send(embed=msg)
|
||||
|
||||
|
||||
# Build an embed message that shows the queue
|
||||
async def display_server_queue(ctx: Context, songs, n):
|
||||
server = ctx.guild
|
||||
|
||||
# Get current settings
|
||||
current_song = await queue.get_current_song(ctx.guild.id)
|
||||
loop_mode = await queue.get_loop_mode(ctx.guild.id)
|
||||
volume = await queue.get_volume(ctx.guild.id)
|
||||
effect = await queue.get_effect(ctx.guild.id)
|
||||
elapsed, duration, percentage = await queue.get_current_progress(ctx.guild.id)
|
||||
|
||||
# Build a beautiful embed
|
||||
embed = discord.Embed(
|
||||
title=f"🎵 {server.name}'s Queue",
|
||||
color=discord.Color.blue()
|
||||
)
|
||||
|
||||
# Add loop emoji based on mode
|
||||
loop_emojis = {'off': '', 'song': '🔂', 'queue': '🔁'}
|
||||
loop_emoji = loop_emojis.get(loop_mode, '')
|
||||
effect_emoji = queue.get_effect_emoji(effect)
|
||||
|
||||
# Progress bar - using Unicode block characters for smooth look
|
||||
progress_bar = ""
|
||||
if duration > 0:
|
||||
bar_length = 20 # Increased from 15 for smoother display
|
||||
filled = int((percentage / 100) * bar_length)
|
||||
|
||||
# Use block characters: █ for filled, ░ for empty
|
||||
progress_bar = f"\n{'█' * filled}{'░' * (bar_length - filled)} `{format_time(elapsed)} / {format_time(duration)}`"
|
||||
|
||||
# Now playing section
|
||||
now_playing = f"### 🔊 Now Playing\n**{current_song}** {loop_emoji}{progress_bar}\n"
|
||||
embed.add_field(name="", value=now_playing, inline=False)
|
||||
|
||||
# Settings section
|
||||
settings = f"🔊 Volume: **{volume}%** | 🔁 Loop: **{loop_mode}** | {effect_emoji} Effect: **{effect}**"
|
||||
embed.add_field(name="⚙️ Settings", value=settings, inline=False)
|
||||
|
||||
# Queue section
|
||||
if len(songs) > 0:
|
||||
queue_text = ""
|
||||
for i, song in enumerate(songs[:10]): # Show max 10
|
||||
time = '' if isinstance(song[1], str) else format_time(song[1])
|
||||
queue_text += f"`{i + 1}.` **{song[0]}**\n└ ⏱️ {time} • Queued by {song[2]}\n"
|
||||
|
||||
embed.add_field(name="📜 Up Next", value=queue_text, inline=False)
|
||||
|
||||
if n > 10:
|
||||
embed.set_footer(text=f"...and {n - 10} more songs in queue")
|
||||
else:
|
||||
embed.add_field(name="📜 Queue", value="*Queue is empty*", inline=False)
|
||||
|
||||
# Add thumbnail
|
||||
embed.set_thumbnail(url=server.icon.url if server.icon else None)
|
||||
|
||||
# Send with interactive buttons
|
||||
view = QueueControls(ctx)
|
||||
await ctx.send(embed=embed, view=view)
|
||||
|
||||
|
||||
# Converts seconds into more readable format
|
||||
def format_time(seconds):
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user