Merge branch 'dev' into player-context

This commit is contained in:
2021-11-06 15:30:42 +01:00
committed by GitHub
3 changed files with 82 additions and 23 deletions
+61 -17
View File
@@ -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)
@@ -219,12 +246,13 @@ class Music(BaseCog):
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"]+1)
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: CustomContext):
@@ -237,23 +265,32 @@ class Music(BaseCog):
async def queue(self, ctx: CustomContext):
"""Display the current radio queue"""
player = ctx.get_player()
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: CustomContext):
"""Disconnects the radio from the channel"""
player = ctx.get_player()
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.
@@ -264,6 +301,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
View File
@@ -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):
+11
View File
@@ -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)