mirror of
https://github.com/Matthww/TuneBot.git
synced 2026-09-21 23:37:47 +00:00
Merge pull request #17 from strNophix/player-control-ui
Bot UX/UI improvements
This commit is contained in:
+62
-18
@@ -1,8 +1,12 @@
|
||||
import asyncio
|
||||
import datetime
|
||||
import re
|
||||
from typing import Optional
|
||||
|
||||
import discord
|
||||
from discord.channel import TextChannel
|
||||
from discord.ext.commands.context import Context
|
||||
from discord.ext.commands.errors import CommandError
|
||||
import lavalink
|
||||
from discord import Embed
|
||||
from discord.channel import TextChannel
|
||||
@@ -16,6 +20,7 @@ from utils.classes import BaseCog
|
||||
from context import CustomContext
|
||||
from utils.database import AutoJoin
|
||||
from utils.database import Playlist
|
||||
from utils.exceptions import EmbeddedCommandException
|
||||
from utils.EmbedGenerator import EmbedGenerator
|
||||
|
||||
url_rx = re.compile(r"https?://(?:www\.)?.+")
|
||||
@@ -119,6 +124,26 @@ class Music(BaseCog):
|
||||
)
|
||||
player.add(requester=self.bot.user.id, track=track)
|
||||
|
||||
async def create_track_embed(self, track: AudioTrack) -> Embed:
|
||||
embed_color = self.bot.colors["embed"]
|
||||
embed = discord.Embed(
|
||||
title=f"Now playing...",
|
||||
colour=embed_color,
|
||||
)
|
||||
embed.description = f"[{track.title}]({track.uri})"
|
||||
embed.set_thumbnail(
|
||||
url=f"https://i3.ytimg.com/vi/{track.identifier}/mqdefault.jpg"
|
||||
)
|
||||
|
||||
try:
|
||||
duration = str(datetime.timedelta(milliseconds=int(track.duration)))
|
||||
except OverflowError:
|
||||
duration = "🔴 LIVE"
|
||||
|
||||
embed.add_field(name="Duration", value=duration)
|
||||
embed.add_field(name="Author", value=track.author)
|
||||
return embed
|
||||
|
||||
def cog_unload(self):
|
||||
"""Cog unload handler. This removes any event hooks that were registered."""
|
||||
self.bot.lavalink._event_hooks.clear()
|
||||
@@ -139,13 +164,15 @@ class Music(BaseCog):
|
||||
|
||||
return guild_check
|
||||
|
||||
async def cog_command_error(self, ctx, error):
|
||||
async def cog_command_error(self, ctx: CustomContext, error: CommandError):
|
||||
if isinstance(error, commands.CommandInvokeError):
|
||||
await ctx.send(error.original)
|
||||
# The above handles errors thrown in this cog and shows them to the user.
|
||||
# This shouldn't be a problem as the only errors thrown in this cog are from `ensure_voice`
|
||||
# which contain a reason string, such as "Join a voicechannel" etc. You can modify the above
|
||||
# if you want to do things differently.
|
||||
elif isinstance(error, EmbeddedCommandException):
|
||||
await error.send(ctx)
|
||||
|
||||
async def ensure_voice(self, ctx):
|
||||
"""This check ensures that the bot and command author are in the same voicechannel."""
|
||||
@@ -170,7 +197,14 @@ class Music(BaseCog):
|
||||
|
||||
if not player.is_connected:
|
||||
if not should_connect:
|
||||
raise commands.CommandInvokeError("Not connected.")
|
||||
bot_name = self.bot.config["info"]["name"]
|
||||
embed = await EmbedGenerator.Message(
|
||||
ctx,
|
||||
f"{bot_name} is not connected",
|
||||
"However you can start playing music using `/connect`",
|
||||
no_send=True,
|
||||
)
|
||||
raise EmbeddedCommandException(embed)
|
||||
|
||||
permissions = ctx.author.voice.channel.permissions_for(ctx.me)
|
||||
|
||||
@@ -198,14 +232,7 @@ class Music(BaseCog):
|
||||
elif isinstance(event, lavalink.events.TrackStartEvent):
|
||||
channel_id = int(event.player.fetch("channel"))
|
||||
channel: TextChannel = self.bot.get_channel(channel_id)
|
||||
|
||||
color = self.bot.colors["embed"]
|
||||
current_track: AudioTrack = event.player.current
|
||||
embed = Embed(
|
||||
title="Now playing:",
|
||||
description=f"[{current_track.title}]({current_track.uri})",
|
||||
color=color,
|
||||
)
|
||||
embed = await self.create_track_embed(event.player.current)
|
||||
await channel.send(embed=embed)
|
||||
elif isinstance(event, lavalink.events.TrackEndEvent):
|
||||
await self.fill_player_queue(event.player, 1)
|
||||
@@ -215,17 +242,17 @@ class Music(BaseCog):
|
||||
"""Start the radio"""
|
||||
# Get the player for this guild from cache.
|
||||
player: DefaultPlayer = self.bot.lavalink.player_manager.get(ctx.guild.id)
|
||||
|
||||
if player.is_connected:
|
||||
await ctx.send("Already connected")
|
||||
return
|
||||
|
||||
await self.fill_player_queue(player, self.bot.config["queue_buffer_size"])
|
||||
await self.fill_player_queue(player, self.bot.config["queue_buffer_size"]
|
||||
|
||||
if not player.is_playing:
|
||||
await player.play()
|
||||
|
||||
await ctx.send("Started playing")
|
||||
await EmbedGenerator.Title(ctx, "*⃣ | Connected.")
|
||||
return
|
||||
|
||||
@commands.command(name="skip", aliases=["next"])
|
||||
async def skip(self, ctx: Context):
|
||||
@@ -238,23 +265,33 @@ class Music(BaseCog):
|
||||
async def queue(self, ctx: Context):
|
||||
"""Display the current radio queue"""
|
||||
player: DefaultPlayer = self.bot.lavalink.player_manager.get(ctx.guild.id)
|
||||
await EmbedGenerator.Message(ctx, "Queue:", player.queue)
|
||||
|
||||
embed_color = self.bot.colors["embed"]
|
||||
embed = Embed(title="Coming Up...", colour=embed_color)
|
||||
|
||||
if len(player.queue) > 0:
|
||||
embed.description = "\n".join(
|
||||
f"{index}. [{track.title}]({track.uri})"
|
||||
for index, track in enumerate(player.queue, 1)
|
||||
)
|
||||
else:
|
||||
embed.description = "We are still determining a playlist"
|
||||
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@commands.command(name="disconnect", aliases=["dc", "stop"])
|
||||
async def disconnect(self, ctx: Context):
|
||||
"""Disconnects the radio from the channel"""
|
||||
player: DefaultPlayer = self.bot.lavalink.player_manager.get(ctx.guild.id)
|
||||
|
||||
if not player.is_connected:
|
||||
return await EmbedGenerator.Title(ctx, "Not connected.")
|
||||
|
||||
if not ctx.author.voice or (
|
||||
player.is_connected
|
||||
and ctx.author.voice.channel.id != int(player.channel_id)
|
||||
):
|
||||
# Abuse prevention. Users not in voice channels, or not in the same voice channel as the bot
|
||||
# may not disconnect the bot.
|
||||
return await EmbedGenerator.Title(ctx, "You're not in my voicechannel!")
|
||||
await EmbedGenerator.Title(ctx, "You're not in my voicechannel!")
|
||||
return
|
||||
|
||||
# Clear the queue to ensure old tracks don't start playing
|
||||
# when someone else queues something.
|
||||
@@ -265,6 +302,13 @@ class Music(BaseCog):
|
||||
await ctx.voice_client.disconnect(force=True)
|
||||
await EmbedGenerator.Title(ctx, "*⃣ | Disconnected.")
|
||||
|
||||
@commands.command(name="now")
|
||||
async def now_playing(self, ctx: CustomContext):
|
||||
player: DefaultPlayer = self.bot.lavalink.player_manager.get(ctx.guild.id)
|
||||
track = player.current
|
||||
embed = await self.create_track_embed(track)
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
|
||||
def setup(bot: ChristmasBot):
|
||||
bot.add_cog(Music(bot))
|
||||
|
||||
+10
-6
@@ -1,8 +1,8 @@
|
||||
from typing import Optional
|
||||
from typing import Optional, Union
|
||||
|
||||
import discord
|
||||
from discord import Embed
|
||||
from discord.ext.commands import Context
|
||||
from discord import Embed
|
||||
|
||||
|
||||
class EmbedGenerator:
|
||||
@@ -13,7 +13,9 @@ class EmbedGenerator:
|
||||
return await EmbedGenerator.SendWithFooter(ctx, em, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
async def Message(ctx: Context, title: str, message: Optional[str] = "", **kwargs):
|
||||
async def Message(
|
||||
ctx: Context, title: str, message: Optional[str] = "", **kwargs
|
||||
) -> Embed:
|
||||
color = ctx.bot.colors["embed"]
|
||||
em = Embed(title=title, description=message, color=color)
|
||||
return await EmbedGenerator.SendWithFooter(ctx, em, **kwargs)
|
||||
@@ -21,20 +23,22 @@ class EmbedGenerator:
|
||||
@staticmethod
|
||||
async def Image(
|
||||
ctx: Context, title: str, url: str, message: Optional[str] = "", **kwargs
|
||||
):
|
||||
) -> Embed:
|
||||
color = ctx.bot.colors["embed"]
|
||||
em = Embed(title=title, description=message, url=url, color=color)
|
||||
em.set_image(url=url)
|
||||
return await EmbedGenerator.SendWithFooter(ctx, em, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
async def Title(ctx: Context, title: str, **kwargs):
|
||||
async def Title(ctx: Context, title: str, **kwargs) -> Embed:
|
||||
color = ctx.bot.colors["embed"]
|
||||
em = Embed(title=title, color=color)
|
||||
return await EmbedGenerator.SendWithFooter(ctx, em, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
async def SendWithFooter(ctx: Context, em: Embed, **kwargs) -> discord.Message:
|
||||
async def SendWithFooter(
|
||||
ctx: Context, em: Embed, **kwargs
|
||||
) -> Union[discord.Message, Embed]:
|
||||
avatar = ctx.author.avatar.with_static_format("jpeg")
|
||||
em.set_footer(text=f"Requested by: {ctx.author}", icon_url=avatar)
|
||||
if kwargs.get("no_send", False):
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
from discord.embeds import Embed
|
||||
from context import CustomContext
|
||||
from discord.ext.commands import CommandError
|
||||
|
||||
|
||||
class EmbeddedCommandException(CommandError):
|
||||
def __init__(self, embed: Embed) -> None:
|
||||
self.embed = embed
|
||||
|
||||
async def send(self, ctx: CustomContext):
|
||||
await ctx.send(embed=self.embed)
|
||||
Reference in New Issue
Block a user