mirror of
https://github.com/Matthww/TuneBot.git
synced 2026-09-21 22:57:48 +00:00
improved bot ux/ui
This commit is contained in:
+60
-17
@@ -1,10 +1,12 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
|
import datetime
|
||||||
import re
|
import re
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
from discord.channel import TextChannel
|
from discord.channel import TextChannel
|
||||||
from discord.ext.commands.context import Context
|
from discord.ext.commands.context import Context
|
||||||
|
from discord.ext.commands.errors import CommandError
|
||||||
import lavalink
|
import lavalink
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
from lavalink.models import AudioTrack, DefaultPlayer
|
from lavalink.models import AudioTrack, DefaultPlayer
|
||||||
@@ -16,6 +18,7 @@ from context import CustomContext
|
|||||||
from discord import Embed
|
from discord import Embed
|
||||||
|
|
||||||
from utils.database import Playlist
|
from utils.database import Playlist
|
||||||
|
from utils.exceptions import EmbeddedCommandException
|
||||||
|
|
||||||
url_rx = re.compile(r"https?://(?:www\.)?.+")
|
url_rx = re.compile(r"https?://(?:www\.)?.+")
|
||||||
|
|
||||||
@@ -122,6 +125,26 @@ class Music(commands.Cog):
|
|||||||
)
|
)
|
||||||
player.add(requester=self.bot.user.id, track=track)
|
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):
|
def cog_unload(self):
|
||||||
"""Cog unload handler. This removes any event hooks that were registered."""
|
"""Cog unload handler. This removes any event hooks that were registered."""
|
||||||
self.bot.lavalink._event_hooks.clear()
|
self.bot.lavalink._event_hooks.clear()
|
||||||
@@ -142,13 +165,15 @@ class Music(commands.Cog):
|
|||||||
|
|
||||||
return guild_check
|
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):
|
if isinstance(error, commands.CommandInvokeError):
|
||||||
await ctx.send(error.original)
|
await ctx.send(error.original)
|
||||||
# The above handles errors thrown in this cog and shows them to the user.
|
# 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`
|
# 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
|
# which contain a reason string, such as "Join a voicechannel" etc. You can modify the above
|
||||||
# if you want to do things differently.
|
# if you want to do things differently.
|
||||||
|
elif isinstance(error, EmbeddedCommandException):
|
||||||
|
await error.send(ctx)
|
||||||
|
|
||||||
async def ensure_voice(self, ctx):
|
async def ensure_voice(self, ctx):
|
||||||
"""This check ensures that the bot and command author are in the same voicechannel."""
|
"""This check ensures that the bot and command author are in the same voicechannel."""
|
||||||
@@ -173,7 +198,14 @@ class Music(commands.Cog):
|
|||||||
|
|
||||||
if not player.is_connected:
|
if not player.is_connected:
|
||||||
if not should_connect:
|
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)
|
permissions = ctx.author.voice.channel.permissions_for(ctx.me)
|
||||||
|
|
||||||
@@ -201,14 +233,7 @@ class Music(commands.Cog):
|
|||||||
elif isinstance(event, lavalink.events.TrackStartEvent):
|
elif isinstance(event, lavalink.events.TrackStartEvent):
|
||||||
channel_id = int(event.player.fetch("channel"))
|
channel_id = int(event.player.fetch("channel"))
|
||||||
channel: TextChannel = self.bot.get_channel(channel_id)
|
channel: TextChannel = self.bot.get_channel(channel_id)
|
||||||
|
embed = await self.create_track_embed(event.player.current)
|
||||||
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,
|
|
||||||
)
|
|
||||||
await channel.send(embed=embed)
|
await channel.send(embed=embed)
|
||||||
elif isinstance(event, lavalink.events.TrackEndEvent):
|
elif isinstance(event, lavalink.events.TrackEndEvent):
|
||||||
await self.fill_player_queue(event.player, 1)
|
await self.fill_player_queue(event.player, 1)
|
||||||
@@ -218,12 +243,13 @@ class Music(commands.Cog):
|
|||||||
"""Starts playing Christmas bangers"""
|
"""Starts playing Christmas bangers"""
|
||||||
# Get the player for this guild from cache.
|
# Get the player for this guild from cache.
|
||||||
player: DefaultPlayer = self.bot.lavalink.player_manager.get(ctx.guild.id)
|
player: DefaultPlayer = self.bot.lavalink.player_manager.get(ctx.guild.id)
|
||||||
await self.fill_player_queue(player, self.bot.config["queue_buffer_size"])
|
await self.fill_player_queue(player, self.bot.config["queue_buffer_size"] + 1)
|
||||||
|
|
||||||
if not player.is_playing:
|
if not player.is_playing:
|
||||||
await player.play()
|
await player.play()
|
||||||
|
|
||||||
await ctx.send("Started playing")
|
await EmbedGenerator.Title(ctx, "*⃣ | Connected.")
|
||||||
|
return
|
||||||
|
|
||||||
@commands.command(name="skip", aliases=["next"])
|
@commands.command(name="skip", aliases=["next"])
|
||||||
async def skip(self, ctx: Context):
|
async def skip(self, ctx: Context):
|
||||||
@@ -236,23 +262,33 @@ class Music(commands.Cog):
|
|||||||
async def queue(self, ctx: Context):
|
async def queue(self, ctx: Context):
|
||||||
"""Ghetto queue"""
|
"""Ghetto queue"""
|
||||||
player: DefaultPlayer = self.bot.lavalink.player_manager.get(ctx.guild.id)
|
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"])
|
@commands.command(name="disconnect", aliases=["dc", "stop"])
|
||||||
async def disconnect(self, ctx: Context):
|
async def disconnect(self, ctx: Context):
|
||||||
"""Disconnects ChristmasBot"""
|
"""Disconnects ChristmasBot"""
|
||||||
player: DefaultPlayer = self.bot.lavalink.player_manager.get(ctx.guild.id)
|
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 (
|
if not ctx.author.voice or (
|
||||||
player.is_connected
|
player.is_connected
|
||||||
and ctx.author.voice.channel.id != int(player.channel_id)
|
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
|
# Abuse prevention. Users not in voice channels, or not in the same voice channel as the bot
|
||||||
# may not disconnect 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
|
# Clear the queue to ensure old tracks don't start playing
|
||||||
# when someone else queues something.
|
# when someone else queues something.
|
||||||
@@ -263,6 +299,13 @@ class Music(commands.Cog):
|
|||||||
await ctx.voice_client.disconnect(force=True)
|
await ctx.voice_client.disconnect(force=True)
|
||||||
await EmbedGenerator.Title(ctx, "*⃣ | Disconnected.")
|
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):
|
def setup(bot: ChristmasBot):
|
||||||
bot.add_cog(Music(bot))
|
bot.add_cog(Music(bot))
|
||||||
|
|||||||
+11
-7
@@ -1,8 +1,8 @@
|
|||||||
from typing import Optional
|
from typing import Optional, Union
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
from discord import Embed
|
|
||||||
from discord.ext.commands import Context
|
from discord.ext.commands import Context
|
||||||
|
from discord import Embed
|
||||||
|
|
||||||
|
|
||||||
class EmbedGenerator:
|
class EmbedGenerator:
|
||||||
@@ -13,7 +13,9 @@ class EmbedGenerator:
|
|||||||
return await EmbedGenerator.SendWithFooter(ctx, em, **kwargs)
|
return await EmbedGenerator.SendWithFooter(ctx, em, **kwargs)
|
||||||
|
|
||||||
@staticmethod
|
@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"]
|
color = ctx.bot.colors["embed"]
|
||||||
em = Embed(title=title, description=message, color=color)
|
em = Embed(title=title, description=message, color=color)
|
||||||
return await EmbedGenerator.SendWithFooter(ctx, em, **kwargs)
|
return await EmbedGenerator.SendWithFooter(ctx, em, **kwargs)
|
||||||
@@ -21,22 +23,24 @@ class EmbedGenerator:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
async def Image(
|
async def Image(
|
||||||
ctx: Context, title: str, url: str, message: Optional[str] = "", **kwargs
|
ctx: Context, title: str, url: str, message: Optional[str] = "", **kwargs
|
||||||
):
|
) -> Embed:
|
||||||
color = ctx.bot.colors["embed"]
|
color = ctx.bot.colors["embed"]
|
||||||
em = Embed(title=title, description=message, url=url, color=color)
|
em = Embed(title=title, description=message, url=url, color=color)
|
||||||
em.set_image(url=url)
|
em.set_image(url=url)
|
||||||
return await EmbedGenerator.SendWithFooter(ctx, em, **kwargs)
|
return await EmbedGenerator.SendWithFooter(ctx, em, **kwargs)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def Title(ctx: Context, title: str, **kwargs):
|
async def Title(ctx: Context, title: str, **kwargs) -> Embed:
|
||||||
color = ctx.bot.colors["embed"]
|
color = ctx.bot.colors["embed"]
|
||||||
em = Embed(title=title, color=color)
|
em = Embed(title=title, color=color)
|
||||||
return await EmbedGenerator.SendWithFooter(ctx, em, **kwargs)
|
return await EmbedGenerator.SendWithFooter(ctx, em, **kwargs)
|
||||||
|
|
||||||
@staticmethod
|
@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")
|
avatar = ctx.author.avatar.with_static_format("jpeg")
|
||||||
em.set_footer(text=f"Requested by: {ctx.author}", icon_url=avatar)
|
em.set_footer(text=f"Requested by: {ctx.author}", icon_url=avatar)
|
||||||
if kwargs.get("no_send", False):
|
if kwargs.get("no_send", False):
|
||||||
return em
|
return em
|
||||||
return await ctx.send(embed=em, **kwargs)
|
return await ctx.send(embed=em, **kwargs)
|
||||||
|
|||||||
@@ -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