Skip to content

Commit

Permalink
Adding support to slash commands
Browse files Browse the repository at this point in the history
  • Loading branch information
RafaelSolVargas committed Sep 22, 2022
1 parent ef66bf8 commit 3b198cf
Show file tree
Hide file tree
Showing 18 changed files with 422 additions and 40 deletions.
5 changes: 5 additions & 0 deletions Config/Embeds.py
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,11 @@ def PLAYLIST_RANGE_ERROR(self) -> Embed:
)
return embed

def PLAYLIST_CLEAR(self) -> Embed:
return Embed(
description=self.__messages.PLAYLIST_CLEAR
)

def CARA_COROA(self, result: str) -> Embed:
embed = Embed(
title='Cara Coroa',
Expand Down
9 changes: 6 additions & 3 deletions Config/Helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ def __init__(self) -> None:
Off - Disable loop."""
self.HELP_NP = 'Show the info of the current song.'
self.HELP_NP_LONG = 'Show the information of the song being played.\n\nRequire: A song being played.\nArguments: None.'
self.HELP_QUEUE = f'Show the first {config.MAX_PRELOAD_SONGS} songs in queue.'
self.HELP_QUEUE_LONG = f'Show the first {config.MAX_PRELOAD_SONGS} song in the queue.\n\nArguments: None.'
self.HELP_QUEUE = f'Show the first {config.MAX_SONGS_IN_PAGE} songs in queue.'
self.HELP_QUEUE_LONG = f'Show the first {config.MAX_SONGS_IN_PAGE} song in the queue.\n\nArguments: None.'
self.HELP_PAUSE = 'Pauses the song player.'
self.HELP_PAUSE_LONG = 'If playing, pauses the song player.\n\nArguments: None'
self.HELP_PREV = 'Play the previous song.'
Expand All @@ -33,7 +33,7 @@ def __init__(self) -> None:
self.HELP_PLAY_LONG = 'Play a song in discord. \n\nRequire: You to be connected to a voice channel.\nArguments: Youtube, Spotify or Deezer song/playlist link or the title of the song to be searched in Youtube.'
self.HELP_HISTORY = f'Show the history of played songs.'
self.HELP_HISTORY_LONG = f'Show the last {config.MAX_SONGS_HISTORY} played songs'
self.HELP_MOVE = 'Moves a song from position x to y in queue.'
self.HELP_MOVE = 'Moves a song from position pos1 to pos2 in queue.'
self.HELP_MOVE_LONG = 'Moves a song from position x to position y in queue.\n\nRequire: Positions to be both valid numbers.\nArguments: 1º Number => Initial position, 2º Number => Destination position. Both numbers could be -1 to refer to the last song in queue.\nDefault: By default, if the second number is not passed, it will be 1, moving the selected song to 1º position.'
self.HELP_REMOVE = 'Remove a song in position x.'
self.HELP_REMOVE_LONG = 'Remove a song from queue in the position passed.\n\nRequire: Position to be a valid number.\nArguments: 1º self.Number => Position in queue of the song.'
Expand All @@ -49,3 +49,6 @@ def __init__(self) -> None:
self.HELP_CHOOSE_LONG = 'Choose randomly one item passed in this command.\n\nRequire: Itens to be separated by comma.\nArguments: As much as you want.'
self.HELP_CARA = 'Return cara or coroa.'
self.HELP_CARA_LONG = 'Return cara or coroa.'

self.SLASH_QUEUE_DESCRIPTION = f'Number of queue page, there is only {config.MAX_SONGS_IN_PAGE} musics by page'
self.SLASH_MOVE_HELP = 'Moves a song from position pos1 to pos2 in queue.'
1 change: 1 addition & 0 deletions Config/Messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ def __init__(self) -> None:
self.STOPPING = f'{self.__emojis.STOP} Player Stopped'
self.EMPTY_QUEUE = f'{self.__emojis.QUEUE} Song queue is empty, use {configs.BOT_PREFIX}play to add new songs'
self.SONG_DOWNLOADING = f'{self.__emojis.DOWNLOADING} Downloading...'
self.PLAYLIST_CLEAR = f'{self.__emojis.MUSIC} Playlist is now empty'

self.HISTORY_TITLE = f'{self.__emojis.MUSIC} Played Songs'
self.HISTORY_EMPTY = f'{self.__emojis.QUEUE} There is no musics in history'
Expand Down
7 changes: 6 additions & 1 deletion DiscordCogs/MusicCog.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,12 @@ async def play(self, ctx: Context, *args) -> None:
try:
controller = PlayHandler(ctx, self.__bot)

response = await controller.run(args)
if len(args) > 1:
track = " ".join(args)
else:
track = args

response = await controller.run(track)
if response is not None:
cogResponser1 = EmbedCommandResponse(response, MessagesCategory.PLAYER)
cogResponser2 = EmoteCommandResponse(response, MessagesCategory.PLAYER)
Expand Down
271 changes: 271 additions & 0 deletions DiscordCogs/SlashCog.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
from discord.ext.commands import slash_command, Cog
from discord import Option, ApplicationContext, OptionChoice
from Handlers.ClearHandler import ClearHandler
from Handlers.MoveHandler import MoveHandler
from Handlers.NowPlayingHandler import NowPlayingHandler
from Handlers.PlayHandler import PlayHandler
from Handlers.PrevHandler import PrevHandler
from Handlers.RemoveHandler import RemoveHandler
from Handlers.ResetHandler import ResetHandler
from Handlers.ShuffleHandler import ShuffleHandler
from Handlers.SkipHandler import SkipHandler
from Handlers.PauseHandler import PauseHandler
from Handlers.StopHandler import StopHandler
from Handlers.ResumeHandler import ResumeHandler
from Handlers.HistoryHandler import HistoryHandler
from Handlers.QueueHandler import QueueHandler
from Handlers.LoopHandler import LoopHandler
from Messages.MessagesCategory import MessagesCategory
from Messages.Responses.SlashEmbedResponse import SlashEmbedResponse
from Music.VulkanBot import VulkanBot
from Config.Embeds import VEmbeds
from Config.Helper import Helper
import traceback

helper = Helper()


class SlashCommands(Cog):
"""
Class to listen to Music commands
It'll listen for commands from discord, when triggered will create a specific Handler for the command
Execute the handler and then create a specific View to be showed in Discord
"""

def __init__(self, bot: VulkanBot) -> None:
self.__bot: VulkanBot = bot
self.__embeds = VEmbeds()

@slash_command(name="play", description=helper.HELP_PLAY)
async def play(self, ctx: ApplicationContext,
music: Option(str, "The music name or URL", required=True)) -> None:
# Due to the utilization of multiprocessing module in this Project, we have multiple instances of the Bot, and by using this flag
# we can control witch bot instance will listen to the commands that Discord send to our application
if not self.__bot.listingSlash:
return
try:
await ctx.defer()
controller = PlayHandler(ctx, self.__bot)

response = await controller.run(music)
if response is not None:
cogResponser1 = SlashEmbedResponse(response, ctx, MessagesCategory.PLAYER)
await cogResponser1.run()
except Exception:
print(f'[ERROR IN SLASH COMMAND] -> {traceback.format_exc()}')

@slash_command(name="queue", description=helper.HELP_QUEUE)
async def queue(self, ctx: ApplicationContext,
page_number: Option(int, helper.SLASH_QUEUE_DESCRIPTION, min_value=1, default=1)) -> None:
if not self.__bot.listingSlash:
return
try:
await ctx.defer()
controller = QueueHandler(ctx, self.__bot)

# Change index 1 to 0
page_number -= 1
response = await controller.run(page_number)

cogResponser = SlashEmbedResponse(response, ctx, MessagesCategory.QUEUE)
await cogResponser.run()
except Exception:
print(f'[ERROR IN SLASH COMMAND] -> {traceback.format_exc()}')

@slash_command(name="skip", description=helper.HELP_SKIP)
async def skip(self, ctx: ApplicationContext) -> None:
if not self.__bot.listingSlash:
return
try:
await ctx.defer()
controller = SkipHandler(ctx, self.__bot)

response = await controller.run()
cogResponser = SlashEmbedResponse(response, ctx, MessagesCategory.PLAYER)
await cogResponser.run()
except Exception:
print(f'[ERROR IN SLASH COMMAND] -> {traceback.format_exc()}')

@slash_command(name='stop', description=helper.HELP_STOP)
async def stop(self, ctx: ApplicationContext) -> None:
if not self.__bot.listingSlash:
return
try:
await ctx.defer()
controller = StopHandler(ctx, self.__bot)

response = await controller.run()
cogResponser = SlashEmbedResponse(response, ctx, MessagesCategory.PLAYER)
await cogResponser.run()
except Exception:
print(f'[ERROR IN SLASH COMMAND] -> {traceback.format_exc()}')

@slash_command(name='pause', description=helper.HELP_PAUSE)
async def pause(self, ctx: ApplicationContext) -> None:
if not self.__bot.listingSlash:
return
try:
await ctx.defer()
controller = PauseHandler(ctx, self.__bot)

response = await controller.run()
cogResponser = SlashEmbedResponse(response, ctx, MessagesCategory.PLAYER)
await cogResponser.run()
except Exception:
print(f'[ERROR IN SLASH COMMAND] -> {traceback.format_exc()}')

@slash_command(name='resume', description=helper.HELP_RESUME)
async def resume(self, ctx: ApplicationContext) -> None:
if not self.__bot.listingSlash:
return
try:
await ctx.defer()
controller = ResumeHandler(ctx, self.__bot)

response = await controller.run()
cogResponser = SlashEmbedResponse(response, ctx, MessagesCategory.PLAYER)
await cogResponser.run()
except Exception:
print(f'[ERROR IN SLASH COMMAND] -> {traceback.format_exc()}')

@slash_command(name='previous', description=helper.HELP_PREV)
async def previous(self, ctx: ApplicationContext) -> None:
if not self.__bot.listingSlash:
return
try:
await ctx.defer()
controller = PrevHandler(ctx, self.__bot)

response = await controller.run()
if response is not None:
cogResponser = SlashEmbedResponse(response, ctx, MessagesCategory.PLAYER)
await cogResponser.run()
except Exception:
print(f'[ERROR IN SLASH COMMAND] -> {traceback.format_exc()}')

@slash_command(name='history', description=helper.HELP_HISTORY)
async def history(self, ctx: ApplicationContext) -> None:
if not self.__bot.listingSlash:
return
try:
await ctx.defer()
controller = HistoryHandler(ctx, self.__bot)

response = await controller.run()
cogResponser = SlashEmbedResponse(response, ctx, MessagesCategory.HISTORY)
await cogResponser.run()
except Exception:
print(f'[ERROR IN SLASH COMMAND] -> {traceback.format_exc()}')

@slash_command(name='loop', description=helper.HELP_LOOP)
async def loop(self, ctx: ApplicationContext,
loop_type: Option(str, choices=[
OptionChoice(name='off', value='off'),
OptionChoice(name='one', value='one'),
OptionChoice(name='all', value='all')
])) -> None:
if not self.__bot.listingSlash:
return
try:
await ctx.defer()
controller = LoopHandler(ctx, self.__bot)

response = await controller.run(loop_type)
cogResponser = SlashEmbedResponse(response, ctx, MessagesCategory.LOOP)
await cogResponser.run()
except Exception:
print(f'[ERROR IN SLASH COMMAND] -> {traceback.format_exc()}')

@slash_command(name='clear', description=helper.HELP_CLEAR)
async def clear(self, ctx: ApplicationContext) -> None:
if not self.__bot.listingSlash:
return
try:
await ctx.defer()
controller = ClearHandler(ctx, self.__bot)

response = await controller.run()
cogResponser = SlashEmbedResponse(response, ctx, MessagesCategory.PLAYER)
await cogResponser.run()
except Exception:
print(f'[ERROR IN SLASH COMMAND] -> {traceback.format_exc()}')

@slash_command(name='now_playing', description=helper.HELP_NP)
async def now_playing(self, ctx: ApplicationContext) -> None:
if not self.__bot.listingSlash:
return
try:
await ctx.defer()
controller = NowPlayingHandler(ctx, self.__bot)

response = await controller.run()
cogResponser = SlashEmbedResponse(response, ctx, MessagesCategory.NOW_PLAYING)
await cogResponser.run()
except Exception:
print(f'[ERROR IN SLASH COMMAND] -> {traceback.format_exc()}')

@slash_command(name='shuffle_songs', description=helper.HELP_SHUFFLE)
async def shuffle(self, ctx: ApplicationContext) -> None:
if not self.__bot.listingSlash:
return
try:
await ctx.defer()
controller = ShuffleHandler(ctx, self.__bot)

response = await controller.run()
cogResponser = SlashEmbedResponse(response, ctx, MessagesCategory.PLAYER)
await cogResponser.run()
except Exception:
print(f'[ERROR IN SLASH COMMAND] -> {traceback.format_exc()}')

@slash_command(name='move_song', description=helper.SLASH_MOVE_HELP)
async def move(self, ctx: ApplicationContext,
from_pos: Option(int, "The position of song to move", min_value=1),
to_pos: Option(int, "The position to put the song, default 1", min_value=1, default=1)) -> None:
if not self.__bot.listingSlash:
return
try:
await ctx.defer()
if from_pos == 0:
from_pos = 1

controller = MoveHandler(ctx, self.__bot)

response = await controller.run(from_pos, to_pos)
cogResponser = SlashEmbedResponse(response, ctx, MessagesCategory.MANAGING_QUEUE)
await cogResponser.run()
except Exception:
print(f'[ERROR IN SLASH COMMAND] -> {traceback.format_exc()}')

@slash_command(name='remove', description=helper.HELP_REMOVE)
async def remove(self, ctx: ApplicationContext,
position: Option(int, "The song position to remove", min_value=1)) -> None:
if not self.__bot.listingSlash:
return
try:
await ctx.defer()
controller = RemoveHandler(ctx, self.__bot)

response = await controller.run(position)
cogResponser = SlashEmbedResponse(response, ctx, MessagesCategory.MANAGING_QUEUE)
await cogResponser.run()
except Exception:
print(f'[ERROR IN SLASH COMMAND] -> {traceback.format_exc()}')

@slash_command(name='reset', description=helper.HELP_RESET)
async def reset(self, ctx: ApplicationContext) -> None:
if not self.__bot.listingSlash:
return
try:
await ctx.defer()
controller = ResetHandler(ctx, self.__bot)

response = await controller.run()
cogResponser = SlashEmbedResponse(response, ctx, MessagesCategory.PLAYER)
await cogResponser.run()
except Exception:
print(f'[ERROR IN SLASH COMMAND] -> {traceback.format_exc()}')


def setup(bot):
bot.add_cog(SlashCommands(bot))
3 changes: 2 additions & 1 deletion Handlers/ClearHandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ async def run(self) -> HandlerResponse:
if acquired:
playlist.clear()
processLock.release()
return HandlerResponse(self.ctx)
embed = self.embeds.PLAYLIST_CLEAR()
return HandlerResponse(self.ctx, embed)
else:
processManager.resetProcess(self.guild, self.ctx)
embed = self.embeds.PLAYER_RESTARTED()
Expand Down
3 changes: 1 addition & 2 deletions Handlers/PlayHandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ def __init__(self, ctx: Union[Context, Interaction], bot: VulkanBot) -> None:
self.__searcher = Searcher()
self.__down = Downloader()

async def run(self, args: str) -> HandlerResponse:
track = " ".join(args)
async def run(self, track: str) -> HandlerResponse:
requester = self.ctx.author.name

if not self.__isUserConnected():
Expand Down
10 changes: 5 additions & 5 deletions Handlers/QueueHandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,11 @@ async def run(self, pageNumber=0) -> HandlerResponse:
return HandlerResponse(self.ctx, embed)

songsPages = playlist.getSongsPages()
if pageNumber < 0 or pageNumber >= len(songsPages):
embed = self.embeds.INVALID_INDEX()
error = InvalidIndex()
processLock.release() # Release the Lock
return HandlerResponse(self.ctx, embed, error)
# Truncate the pageNumber to the closest value
if pageNumber < 0:
pageNumber = 0
elif pageNumber >= len(songsPages):
pageNumber = len(songsPages) - 1

# Select the page in queue to be printed
songs = songsPages[pageNumber]
Expand Down
7 changes: 3 additions & 4 deletions Handlers/RemoveHandler.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from typing import Union
from discord.ext.commands import Context
from Handlers.AbstractHandler import AbstractHandler
from Handlers.HandlerResponse import HandlerResponse
from Config.Exceptions import BadCommandUsage, VulkanError, ErrorRemoving, InvalidInput, NumberRequired
from Music.Playlist import Playlist
from Music.VulkanBot import VulkanBot
from Parallelism.ProcessInfo import ProcessInfo
from typing import Union
from discord import Interaction

Expand All @@ -16,15 +16,14 @@ def __init__(self, ctx: Union[Context, Interaction], bot: VulkanBot) -> None:
async def run(self, position: str) -> HandlerResponse:
# Get the current process of the guild
processManager = self.config.getProcessManager()
processInfo = processManager.getRunningPlayerInfo(self.guild)
processInfo: ProcessInfo = processManager.getRunningPlayerInfo(self.guild)
if not processInfo:
# Clear the playlist
embed = self.embeds.NOT_PLAYING()
error = BadCommandUsage()
return HandlerResponse(self.ctx, embed, error)

playlist = processInfo.getPlaylist()
if playlist.getCurrentSong() is None:
if playlist is None:
embed = self.embeds.NOT_PLAYING()
error = BadCommandUsage()
return HandlerResponse(self.ctx, embed, error)
Expand Down
Loading

0 comments on commit 3b198cf

Please sign in to comment.