mirror of
https://github.com/RafaelSolVargas/Vulkan.git
synced 2025-10-29 16:57:23 +00:00
Merge pull request #26 from RafaelSolVargas/jumpMusic
Upgrading Song Queue message
This commit is contained in:
commit
5f60c12179
Binary file not shown.
|
Before Width: | Height: | Size: 34 KiB |
BIN
Assets/playermenu.jpg
Normal file
BIN
Assets/playermenu.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 33 KiB |
BIN
Assets/queuemessage.jpg
Normal file
BIN
Assets/queuemessage.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 111 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 75 KiB |
BIN
Assets/vulkancommands.jpg
Normal file
BIN
Assets/vulkancommands.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 72 KiB |
@ -19,12 +19,14 @@ class VConfigs(Singleton):
|
||||
|
||||
self.CLEANER_MESSAGES_QUANT = 5
|
||||
self.ACQUIRE_LOCK_TIMEOUT = 10
|
||||
self.QUEUE_VIEW_TIMEOUT = 120
|
||||
self.COMMANDS_FOLDER_NAME = 'DiscordCogs'
|
||||
self.COMMANDS_PATH = f'{Folder().rootFolder}{self.COMMANDS_FOLDER_NAME}'
|
||||
self.VC_TIMEOUT = 300
|
||||
|
||||
self.MAX_PLAYLIST_LENGTH = 50
|
||||
self.MAX_PLAYLIST_FORCED_LENGTH = 5
|
||||
self.MAX_SONGS_IN_PAGE = 10
|
||||
self.MAX_PRELOAD_SONGS = 15
|
||||
self.MAX_SONGS_HISTORY = 15
|
||||
|
||||
|
||||
@ -34,6 +34,14 @@ class VEmbeds:
|
||||
)
|
||||
return embed
|
||||
|
||||
def INVALID_INDEX(self) -> Embed:
|
||||
embed = Embed(
|
||||
title=self.__messages.BAD_COMMAND_TITLE,
|
||||
description=self.__messages.INVALID_INDEX,
|
||||
colour=self.__colors.BLACK
|
||||
)
|
||||
return embed
|
||||
|
||||
def SONG_ADDED_TWO(self, info: dict, pos: int) -> Embed:
|
||||
embed = self.SONG_INFO(info, self.__messages.SONG_ADDED_TWO, pos)
|
||||
return embed
|
||||
@ -162,6 +170,14 @@ class VEmbeds:
|
||||
)
|
||||
return embed
|
||||
|
||||
def INVALID_ARGUMENTS(self):
|
||||
embed = Embed(
|
||||
title=self.__messages.BAD_COMMAND_TITLE,
|
||||
description=self.__messages.INVALID_ARGUMENTS,
|
||||
colour=self.__colors.BLACK
|
||||
)
|
||||
return embed
|
||||
|
||||
def COMMAND_NOT_FOUND(self) -> Embed:
|
||||
embed = Embed(
|
||||
title=self.__messages.COMMAND_NOT_FOUND_TITLE,
|
||||
@ -261,6 +277,41 @@ class VEmbeds:
|
||||
)
|
||||
return embed
|
||||
|
||||
def PLAYER_RESUMED(self) -> Embed:
|
||||
embed = Embed(
|
||||
title=self.__messages.SONG_RESUMED,
|
||||
colour=self.__colors.BLUE
|
||||
)
|
||||
return embed
|
||||
|
||||
def SKIPPING_SONG(self) -> Embed:
|
||||
embed = Embed(
|
||||
title=self.__messages.SONG_SKIPPED,
|
||||
colour=self.__colors.BLUE
|
||||
)
|
||||
return embed
|
||||
|
||||
def STOPPING_PLAYER(self) -> Embed:
|
||||
embed = Embed(
|
||||
title=self.__messages.STOPPING,
|
||||
colour=self.__colors.BLUE
|
||||
)
|
||||
return embed
|
||||
|
||||
def RETURNING_SONG(self) -> Embed:
|
||||
embed = Embed(
|
||||
title=self.__messages.RETURNING_SONG,
|
||||
colour=self.__colors.BLUE
|
||||
)
|
||||
return embed
|
||||
|
||||
def PLAYER_PAUSED(self) -> Embed:
|
||||
embed = Embed(
|
||||
title=self.__messages.SONG_PAUSED,
|
||||
colour=self.__colors.BLUE
|
||||
)
|
||||
return embed
|
||||
|
||||
def NOT_PREVIOUS_SONG(self) -> Embed:
|
||||
embed = Embed(
|
||||
title=self.__messages.SONG_PLAYER,
|
||||
|
||||
@ -79,6 +79,11 @@ class ErrorRemoving(VulkanError):
|
||||
super().__init__(message, title, *args)
|
||||
|
||||
|
||||
class InvalidIndex(VulkanError):
|
||||
def __init__(self, message='', title='', *args: object) -> None:
|
||||
super().__init__(message, title, *args)
|
||||
|
||||
|
||||
class NumberRequired(VulkanError):
|
||||
def __init__(self, message='', title='', *args: object) -> None:
|
||||
super().__init__(message, title, *args)
|
||||
|
||||
@ -26,6 +26,9 @@ class Messages(Singleton):
|
||||
self.ALL_SONGS_LOOPING = f'{self.__emojis.MUSIC} Looping All Songs'
|
||||
self.SONG_PAUSED = f'{self.__emojis.PAUSE} Song paused'
|
||||
self.SONG_RESUMED = f'{self.__emojis.PLAY} Song playing'
|
||||
self.SONG_SKIPPED = f'{self.__emojis.SKIP} Song skipped'
|
||||
self.RETURNING_SONG = f'{self.__emojis.BACK} Playing previous song'
|
||||
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...'
|
||||
|
||||
@ -64,6 +67,8 @@ class Messages(Singleton):
|
||||
self.NO_CHANNEL = 'To play some music, connect to any voice channel first.'
|
||||
self.NO_GUILD = f'This server does not has a Player, try {configs.BOT_PREFIX}reset'
|
||||
self.INVALID_INPUT = f'This URL was too strange, try something better or type {configs.BOT_PREFIX}help play'
|
||||
self.INVALID_INDEX = f'Invalid index passed as argument.'
|
||||
self.INVALID_ARGUMENTS = f'Invalid arguments passed to command.'
|
||||
self.DOWNLOADING_ERROR = f"{self.__emojis.ERROR} It's impossible to download and play this video"
|
||||
self.EXTRACTING_ERROR = f'{self.__emojis.ERROR} An error ocurred while searching for the songs'
|
||||
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
from discord.ext.commands import Context, command, Cog
|
||||
from Config.Exceptions import InvalidInput
|
||||
from Config.Helper import Helper
|
||||
from Handlers.ClearHandler import ClearHandler
|
||||
from Handlers.HandlerResponse import HandlerResponse
|
||||
from Handlers.MoveHandler import MoveHandler
|
||||
from Handlers.NowPlayingHandler import NowPlayingHandler
|
||||
from Handlers.PlayHandler import PlayHandler
|
||||
@ -15,10 +17,12 @@ from Handlers.ResumeHandler import ResumeHandler
|
||||
from Handlers.HistoryHandler import HistoryHandler
|
||||
from Handlers.QueueHandler import QueueHandler
|
||||
from Handlers.LoopHandler import LoopHandler
|
||||
from UI.Responses.EmoteCogResponse import EmoteCommandResponse
|
||||
from UI.Responses.EmbedCogResponse import EmbedCommandResponse
|
||||
from Messages.MessagesCategory import MessagesCategory
|
||||
from Messages.Responses.EmoteCogResponse import EmoteCommandResponse
|
||||
from Messages.Responses.EmbedCogResponse import EmbedCommandResponse
|
||||
from Music.VulkanBot import VulkanBot
|
||||
from Config.Configs import VConfigs
|
||||
from Config.Embeds import VEmbeds
|
||||
from Parallelism.ProcessManager import ProcessManager
|
||||
|
||||
helper = Helper()
|
||||
@ -33,6 +37,7 @@ class MusicCog(Cog):
|
||||
|
||||
def __init__(self, bot: VulkanBot) -> None:
|
||||
self.__bot: VulkanBot = bot
|
||||
self.__embeds = VEmbeds()
|
||||
VConfigs().setProcessManager(ProcessManager(bot))
|
||||
|
||||
@command(name="play", help=helper.HELP_PLAY, description=helper.HELP_PLAY_LONG, aliases=['p', 'tocar'])
|
||||
@ -42,21 +47,37 @@ class MusicCog(Cog):
|
||||
|
||||
response = await controller.run(args)
|
||||
if response is not None:
|
||||
view1 = EmbedCommandResponse(response)
|
||||
view2 = EmoteCommandResponse(response)
|
||||
await view1.run()
|
||||
await view2.run()
|
||||
cogResponser1 = EmbedCommandResponse(response, MessagesCategory.PLAYER)
|
||||
cogResponser2 = EmoteCommandResponse(response, MessagesCategory.PLAYER)
|
||||
await cogResponser1.run()
|
||||
await cogResponser2.run()
|
||||
except Exception as e:
|
||||
print(f'[ERROR IN COG] -> {e}')
|
||||
|
||||
@command(name="queue", help=helper.HELP_QUEUE, description=helper.HELP_QUEUE_LONG, aliases=['q', 'fila', 'musicas'])
|
||||
async def queue(self, ctx: Context) -> None:
|
||||
async def queue(self, ctx: Context, *args) -> None:
|
||||
try:
|
||||
pageNumber = " ".join(args)
|
||||
|
||||
controller = QueueHandler(ctx, self.__bot)
|
||||
|
||||
response = await controller.run()
|
||||
view2 = EmbedCommandResponse(response)
|
||||
await view2.run()
|
||||
if pageNumber == "":
|
||||
response = await controller.run()
|
||||
else:
|
||||
pageNumber = int(pageNumber)
|
||||
pageNumber -= 1 # Change index 1 to 0
|
||||
response = await controller.run(pageNumber)
|
||||
|
||||
cogResponser = EmbedCommandResponse(response, MessagesCategory.QUEUE)
|
||||
await cogResponser.run()
|
||||
except ValueError as e:
|
||||
# Draft a Handler Response to pass to cogResponser
|
||||
error = InvalidInput()
|
||||
embed = self.__embeds.INVALID_ARGUMENTS()
|
||||
response = HandlerResponse(ctx, embed, error)
|
||||
|
||||
cogResponser = EmbedCommandResponse(response, MessagesCategory.QUEUE)
|
||||
await cogResponser.run(deleteLast=False)
|
||||
except Exception as e:
|
||||
print(f'[ERROR IN COG] -> {e}')
|
||||
|
||||
@ -66,12 +87,10 @@ class MusicCog(Cog):
|
||||
controller = SkipHandler(ctx, self.__bot)
|
||||
|
||||
response = await controller.run()
|
||||
if response.success:
|
||||
view = EmoteCommandResponse(response)
|
||||
else:
|
||||
view = EmbedCommandResponse(response)
|
||||
|
||||
await view.run()
|
||||
cogResponser1 = EmbedCommandResponse(response, MessagesCategory.PLAYER)
|
||||
cogResponser2 = EmoteCommandResponse(response, MessagesCategory.PLAYER)
|
||||
await cogResponser1.run()
|
||||
await cogResponser2.run()
|
||||
except Exception as e:
|
||||
print(f'[ERROR IN COG] -> {e}')
|
||||
|
||||
@ -81,12 +100,10 @@ class MusicCog(Cog):
|
||||
controller = StopHandler(ctx, self.__bot)
|
||||
|
||||
response = await controller.run()
|
||||
if response.success:
|
||||
view = EmoteCommandResponse(response)
|
||||
else:
|
||||
view = EmbedCommandResponse(response)
|
||||
|
||||
await view.run()
|
||||
cogResponser1 = EmbedCommandResponse(response, MessagesCategory.PLAYER)
|
||||
cogResponser2 = EmoteCommandResponse(response, MessagesCategory.PLAYER)
|
||||
await cogResponser1.run()
|
||||
await cogResponser2.run()
|
||||
except Exception as e:
|
||||
print(f'[ERROR IN COG] -> {e}')
|
||||
|
||||
@ -96,10 +113,10 @@ class MusicCog(Cog):
|
||||
controller = PauseHandler(ctx, self.__bot)
|
||||
|
||||
response = await controller.run()
|
||||
view1 = EmoteCommandResponse(response)
|
||||
view2 = EmbedCommandResponse(response)
|
||||
await view1.run()
|
||||
await view2.run()
|
||||
cogResponser1 = EmoteCommandResponse(response, MessagesCategory.PLAYER)
|
||||
cogResponser2 = EmbedCommandResponse(response, MessagesCategory.PLAYER)
|
||||
await cogResponser1.run()
|
||||
await cogResponser2.run()
|
||||
except Exception as e:
|
||||
print(f'[ERROR IN COG] -> {e}')
|
||||
|
||||
@ -109,10 +126,10 @@ class MusicCog(Cog):
|
||||
controller = ResumeHandler(ctx, self.__bot)
|
||||
|
||||
response = await controller.run()
|
||||
view1 = EmoteCommandResponse(response)
|
||||
view2 = EmbedCommandResponse(response)
|
||||
await view1.run()
|
||||
await view2.run()
|
||||
cogResponser1 = EmoteCommandResponse(response, MessagesCategory.PLAYER)
|
||||
cogResponser2 = EmbedCommandResponse(response, MessagesCategory.PLAYER)
|
||||
await cogResponser1.run()
|
||||
await cogResponser2.run()
|
||||
except Exception as e:
|
||||
print(f'[ERROR IN COG] -> {e}')
|
||||
|
||||
@ -123,10 +140,10 @@ class MusicCog(Cog):
|
||||
|
||||
response = await controller.run()
|
||||
if response is not None:
|
||||
view1 = EmbedCommandResponse(response)
|
||||
view2 = EmoteCommandResponse(response)
|
||||
await view1.run()
|
||||
await view2.run()
|
||||
cogResponser1 = EmbedCommandResponse(response, MessagesCategory.PLAYER)
|
||||
cogResponser2 = EmoteCommandResponse(response, MessagesCategory.PLAYER)
|
||||
await cogResponser1.run()
|
||||
await cogResponser2.run()
|
||||
except Exception as e:
|
||||
print(f'[ERROR IN COG] -> {e}')
|
||||
|
||||
@ -136,10 +153,10 @@ class MusicCog(Cog):
|
||||
controller = HistoryHandler(ctx, self.__bot)
|
||||
|
||||
response = await controller.run()
|
||||
view1 = EmbedCommandResponse(response)
|
||||
view2 = EmoteCommandResponse(response)
|
||||
await view1.run()
|
||||
await view2.run()
|
||||
cogResponser1 = EmbedCommandResponse(response, MessagesCategory.HISTORY)
|
||||
cogResponser2 = EmoteCommandResponse(response, MessagesCategory.HISTORY)
|
||||
await cogResponser1.run()
|
||||
await cogResponser2.run()
|
||||
except Exception as e:
|
||||
print(f'[ERROR IN COG] -> {e}')
|
||||
|
||||
@ -149,10 +166,10 @@ class MusicCog(Cog):
|
||||
controller = LoopHandler(ctx, self.__bot)
|
||||
|
||||
response = await controller.run(args)
|
||||
view1 = EmoteCommandResponse(response)
|
||||
view2 = EmbedCommandResponse(response)
|
||||
await view1.run()
|
||||
await view2.run()
|
||||
cogResponser1 = EmoteCommandResponse(response, MessagesCategory.LOOP)
|
||||
cogResponser2 = EmbedCommandResponse(response, MessagesCategory.LOOP)
|
||||
await cogResponser1.run()
|
||||
await cogResponser2.run()
|
||||
except Exception as e:
|
||||
print(f'[ERROR IN COG] -> {e}')
|
||||
|
||||
@ -162,8 +179,10 @@ class MusicCog(Cog):
|
||||
controller = ClearHandler(ctx, self.__bot)
|
||||
|
||||
response = await controller.run()
|
||||
view = EmoteCommandResponse(response)
|
||||
await view.run()
|
||||
cogResponser1 = EmbedCommandResponse(response, MessagesCategory.PLAYER)
|
||||
cogResponser2 = EmoteCommandResponse(response, MessagesCategory.PLAYER)
|
||||
await cogResponser1.run()
|
||||
await cogResponser2.run()
|
||||
except Exception as e:
|
||||
print(f'[ERROR IN COG] -> {e}')
|
||||
|
||||
@ -173,10 +192,10 @@ class MusicCog(Cog):
|
||||
controller = NowPlayingHandler(ctx, self.__bot)
|
||||
|
||||
response = await controller.run()
|
||||
view1 = EmbedCommandResponse(response)
|
||||
view2 = EmoteCommandResponse(response)
|
||||
await view1.run()
|
||||
await view2.run()
|
||||
cogResponser1 = EmbedCommandResponse(response, MessagesCategory.NOW_PLAYING)
|
||||
cogResponser2 = EmoteCommandResponse(response, MessagesCategory.NOW_PLAYING)
|
||||
await cogResponser1.run()
|
||||
await cogResponser2.run()
|
||||
except Exception as e:
|
||||
print(f'[ERROR IN COG] -> {e}')
|
||||
|
||||
@ -186,10 +205,10 @@ class MusicCog(Cog):
|
||||
controller = ShuffleHandler(ctx, self.__bot)
|
||||
|
||||
response = await controller.run()
|
||||
view1 = EmbedCommandResponse(response)
|
||||
view2 = EmoteCommandResponse(response)
|
||||
await view1.run()
|
||||
await view2.run()
|
||||
cogResponser1 = EmbedCommandResponse(response, MessagesCategory.PLAYER)
|
||||
cogResponser2 = EmoteCommandResponse(response, MessagesCategory.PLAYER)
|
||||
await cogResponser1.run()
|
||||
await cogResponser2.run()
|
||||
except Exception as e:
|
||||
print(f'[ERROR IN COG] -> {e}')
|
||||
|
||||
@ -199,10 +218,10 @@ class MusicCog(Cog):
|
||||
controller = MoveHandler(ctx, self.__bot)
|
||||
|
||||
response = await controller.run(pos1, pos2)
|
||||
view1 = EmbedCommandResponse(response)
|
||||
view2 = EmoteCommandResponse(response)
|
||||
await view1.run()
|
||||
await view2.run()
|
||||
cogResponser1 = EmbedCommandResponse(response, MessagesCategory.MANAGING_QUEUE)
|
||||
cogResponser2 = EmoteCommandResponse(response, MessagesCategory.MANAGING_QUEUE)
|
||||
await cogResponser1.run()
|
||||
await cogResponser2.run()
|
||||
except Exception as e:
|
||||
print(f'[ERROR IN COG] -> {e}')
|
||||
|
||||
@ -212,10 +231,10 @@ class MusicCog(Cog):
|
||||
controller = RemoveHandler(ctx, self.__bot)
|
||||
|
||||
response = await controller.run(position)
|
||||
view1 = EmbedCommandResponse(response)
|
||||
view2 = EmoteCommandResponse(response)
|
||||
await view1.run()
|
||||
await view2.run()
|
||||
cogResponser1 = EmbedCommandResponse(response, MessagesCategory.MANAGING_QUEUE)
|
||||
cogResponser2 = EmoteCommandResponse(response, MessagesCategory.MANAGING_QUEUE)
|
||||
await cogResponser1.run()
|
||||
await cogResponser2.run()
|
||||
except Exception as e:
|
||||
print(f'[ERROR IN COG] -> {e}')
|
||||
|
||||
@ -225,10 +244,10 @@ class MusicCog(Cog):
|
||||
controller = ResetHandler(ctx, self.__bot)
|
||||
|
||||
response = await controller.run()
|
||||
view1 = EmbedCommandResponse(response)
|
||||
view2 = EmoteCommandResponse(response)
|
||||
await view1.run()
|
||||
await view2.run()
|
||||
cogResponser1 = EmbedCommandResponse(response, MessagesCategory.PLAYER)
|
||||
cogResponser2 = EmoteCommandResponse(response, MessagesCategory.PLAYER)
|
||||
await cogResponser1.run()
|
||||
await cogResponser2.run()
|
||||
except Exception as e:
|
||||
print(f'[ERROR IN COG] -> {e}')
|
||||
|
||||
|
||||
@ -2,14 +2,16 @@ from typing import Union
|
||||
from discord.ext.commands import Context
|
||||
from Config.Exceptions import VulkanError
|
||||
from discord import Embed, Interaction
|
||||
from UI.Views.AbstractView import AbstractView
|
||||
|
||||
|
||||
class HandlerResponse:
|
||||
def __init__(self, ctx: Union[Context, Interaction], embed: Embed = None, error: VulkanError = None) -> None:
|
||||
def __init__(self, ctx: Union[Context, Interaction], embed: Embed = None, error: VulkanError = None, view=None) -> None:
|
||||
self.__ctx: Context = ctx
|
||||
self.__error: VulkanError = error
|
||||
self.__embed: Embed = embed
|
||||
self.__success = False if error else True
|
||||
self.__view = view
|
||||
|
||||
@property
|
||||
def ctx(self) -> Union[Context, Interaction]:
|
||||
@ -19,6 +21,10 @@ class HandlerResponse:
|
||||
def embed(self) -> Union[Embed, None]:
|
||||
return self.__embed
|
||||
|
||||
@property
|
||||
def view(self) -> AbstractView:
|
||||
return self.__view
|
||||
|
||||
def error(self) -> Union[VulkanError, None]:
|
||||
return self.__error
|
||||
|
||||
|
||||
80
Handlers/JumpMusicHandler.py
Normal file
80
Handlers/JumpMusicHandler.py
Normal file
@ -0,0 +1,80 @@
|
||||
from typing import Union
|
||||
from Config.Exceptions import BadCommandUsage, InvalidInput, NumberRequired, UnknownError, VulkanError
|
||||
from Handlers.AbstractHandler import AbstractHandler
|
||||
from discord.ext.commands import Context
|
||||
from discord import Interaction
|
||||
from Handlers.HandlerResponse import HandlerResponse
|
||||
from Music.Playlist import Playlist
|
||||
from Music.VulkanBot import VulkanBot
|
||||
from Parallelism.Commands import VCommands, VCommandsType
|
||||
|
||||
|
||||
class JumpMusicHandler(AbstractHandler):
|
||||
"""Move a music from a specific position and play it directly"""
|
||||
|
||||
def __init__(self, ctx: Union[Context, Interaction], bot: VulkanBot) -> None:
|
||||
super().__init__(ctx, bot)
|
||||
|
||||
async def run(self, musicPos: str) -> HandlerResponse:
|
||||
processManager = self.config.getProcessManager()
|
||||
processInfo = processManager.getRunningPlayerInfo(self.guild)
|
||||
if not processInfo:
|
||||
embed = self.embeds.NOT_PLAYING()
|
||||
error = BadCommandUsage()
|
||||
return HandlerResponse(self.ctx, embed, error)
|
||||
|
||||
processLock = processInfo.getLock()
|
||||
acquired = processLock.acquire(timeout=self.config.ACQUIRE_LOCK_TIMEOUT)
|
||||
if acquired:
|
||||
# Try to convert input to int
|
||||
error = self.__validateInput(musicPos)
|
||||
if error:
|
||||
embed = self.embeds.ERROR_EMBED(error.message)
|
||||
processLock.release()
|
||||
return HandlerResponse(self.ctx, embed, error)
|
||||
|
||||
# Sanitize the input
|
||||
playlist: Playlist = processInfo.getPlaylist()
|
||||
musicPos = self.__sanitizeInput(playlist, musicPos)
|
||||
|
||||
# Validate the position
|
||||
if not playlist.validate_position(musicPos):
|
||||
error = InvalidInput()
|
||||
embed = self.embeds.PLAYLIST_RANGE_ERROR()
|
||||
processLock.release()
|
||||
return HandlerResponse(self.ctx, embed, error)
|
||||
try:
|
||||
# Move the selected song
|
||||
playlist.move_songs(musicPos, 1)
|
||||
|
||||
# Send a command to the player to skip the music
|
||||
command = VCommands(VCommandsType.SKIP, None)
|
||||
queue = processInfo.getQueueToPlayer()
|
||||
queue.put(command)
|
||||
|
||||
processLock.release()
|
||||
return HandlerResponse(self.ctx)
|
||||
except:
|
||||
# Release the acquired Lock
|
||||
processLock.release()
|
||||
embed = self.embeds.ERROR_MOVING()
|
||||
error = UnknownError()
|
||||
return HandlerResponse(self.ctx, embed, error)
|
||||
else:
|
||||
processManager.resetProcess(self.guild, self.ctx)
|
||||
embed = self.embeds.PLAYER_RESTARTED()
|
||||
return HandlerResponse(self.ctx, embed)
|
||||
|
||||
def __validateInput(self, position: str) -> Union[VulkanError, None]:
|
||||
try:
|
||||
position = int(position)
|
||||
except:
|
||||
return NumberRequired(self.messages.ERROR_NUMBER)
|
||||
|
||||
def __sanitizeInput(self, playlist: Playlist, position: int) -> int:
|
||||
position = int(position)
|
||||
|
||||
if position == -1:
|
||||
position = len(playlist.getSongs())
|
||||
|
||||
return position
|
||||
@ -25,7 +25,8 @@ class PauseHandler(AbstractHandler):
|
||||
queue = processInfo.getQueueToPlayer()
|
||||
queue.put(command)
|
||||
|
||||
return HandlerResponse(self.ctx)
|
||||
embed = self.embeds.PLAYER_PAUSED()
|
||||
return HandlerResponse(self.ctx, embed)
|
||||
else:
|
||||
embed = self.embeds.NOT_PLAYING()
|
||||
return HandlerResponse(self.ctx, embed)
|
||||
|
||||
@ -45,7 +45,9 @@ class PrevHandler(AbstractHandler):
|
||||
prevCommand = VCommands(VCommandsType.PREV, self.author.voice.channel.id)
|
||||
queue = processInfo.getQueueToPlayer()
|
||||
queue.put(prevCommand)
|
||||
return HandlerResponse(self.ctx)
|
||||
|
||||
embed = self.embeds.RETURNING_SONG()
|
||||
return HandlerResponse(self.ctx, embed)
|
||||
|
||||
def __user_connected(self) -> bool:
|
||||
if self.author.voice:
|
||||
|
||||
@ -1,19 +1,26 @@
|
||||
from discord.ext.commands import Context
|
||||
from Config.Exceptions import InvalidIndex
|
||||
from Handlers.AbstractHandler import AbstractHandler
|
||||
from Handlers.HandlerResponse import HandlerResponse
|
||||
from Music.Downloader import Downloader
|
||||
from Handlers.JumpMusicHandler import JumpMusicHandler
|
||||
from Messages.MessagesCategory import MessagesCategory
|
||||
from UI.Views.BasicView import BasicView
|
||||
from Utils.Utils import Utils
|
||||
from Music.VulkanBot import VulkanBot
|
||||
from typing import Union
|
||||
from discord import Interaction
|
||||
from Music.Song import Song
|
||||
from Music.Playlist import Playlist
|
||||
from typing import List, Union
|
||||
from discord import Button, Interaction
|
||||
from UI.Buttons.CallbackButton import CallbackButton
|
||||
from UI.Buttons.PlaylistDropdown import PlaylistDropdown
|
||||
from Config.Emojis import VEmojis
|
||||
|
||||
|
||||
class QueueHandler(AbstractHandler):
|
||||
def __init__(self, ctx: Union[Context, Interaction], bot: VulkanBot) -> None:
|
||||
super().__init__(ctx, bot)
|
||||
self.__down = Downloader()
|
||||
|
||||
async def run(self) -> HandlerResponse:
|
||||
async def run(self, pageNumber=0) -> HandlerResponse:
|
||||
# Retrieve the process of the guild
|
||||
processManager = self.config.getProcessManager()
|
||||
processInfo = processManager.getRunningPlayerInfo(self.guild)
|
||||
@ -25,7 +32,7 @@ class QueueHandler(AbstractHandler):
|
||||
processLock = processInfo.getLock()
|
||||
acquired = processLock.acquire(timeout=self.config.ACQUIRE_LOCK_TIMEOUT)
|
||||
if acquired:
|
||||
playlist = processInfo.getPlaylist()
|
||||
playlist: Playlist = processInfo.getPlaylist()
|
||||
|
||||
if playlist.isLoopingOne():
|
||||
song = playlist.getCurrentSong()
|
||||
@ -33,13 +40,26 @@ class QueueHandler(AbstractHandler):
|
||||
processLock.release() # Release the Lock
|
||||
return HandlerResponse(self.ctx, embed)
|
||||
|
||||
songs_preload = playlist.getSongsToPreload()
|
||||
allSongs = playlist.getSongs()
|
||||
if len(songs_preload) == 0:
|
||||
if len(allSongs) == 0:
|
||||
embed = self.embeds.EMPTY_QUEUE()
|
||||
processLock.release() # Release the Lock
|
||||
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)
|
||||
|
||||
# Select the page in queue to be printed
|
||||
songs = songsPages[pageNumber]
|
||||
# Create view for this embed
|
||||
buttons = self.__createViewButtons(songsPages, pageNumber)
|
||||
buttons.extend(self.__createViewJumpButtons(playlist))
|
||||
queueView = BasicView(self.bot, buttons, self.config.QUEUE_VIEW_TIMEOUT)
|
||||
|
||||
if playlist.isLoopingAll():
|
||||
title = self.messages.ALL_SONGS_LOOPING
|
||||
else:
|
||||
@ -49,17 +69,36 @@ class QueueHandler(AbstractHandler):
|
||||
for song in allSongs]))
|
||||
total_songs = len(playlist.getSongs())
|
||||
|
||||
text = f'📜 Queue length: {total_songs} | ⌛ Duration: `{total_time}` downloaded \n\n'
|
||||
text = f'📜 Queue length: {total_songs} | Page Number: {pageNumber+1}/{len(songsPages)} | ⌛ Duration: `{total_time}` downloaded \n\n'
|
||||
|
||||
for pos, song in enumerate(songs_preload, start=1):
|
||||
# To work get the correct index of all songs
|
||||
startIndex = (pageNumber * self.config.MAX_SONGS_IN_PAGE) + 1
|
||||
for pos, song in enumerate(songs, start=startIndex):
|
||||
song_name = song.title if song.title else self.messages.SONG_DOWNLOADING
|
||||
text += f"**`{pos}` - ** {song_name} - `{Utils.format_time(song.duration)}`\n"
|
||||
|
||||
embed = self.embeds.QUEUE(title, text)
|
||||
# Release the acquired Lock
|
||||
processLock.release()
|
||||
return HandlerResponse(self.ctx, embed)
|
||||
return HandlerResponse(self.ctx, embed, view=queueView)
|
||||
else:
|
||||
processManager.resetProcess(self.guild, self.ctx)
|
||||
embed = self.embeds.PLAYER_RESTARTED()
|
||||
return HandlerResponse(self.ctx, embed)
|
||||
|
||||
def __createViewButtons(self, songsPages: List[List[Song]], pageNumber: int) -> List[Button]:
|
||||
buttons = []
|
||||
if pageNumber > 0:
|
||||
prevPageNumber = pageNumber - 1
|
||||
buttons.append(CallbackButton(self.bot, self.run, VEmojis().BACK, self.ctx.channel,
|
||||
self.guild.id, MessagesCategory.QUEUE, "Prev Page", pageNumber=prevPageNumber))
|
||||
|
||||
if pageNumber < len(songsPages) - 1:
|
||||
nextPageNumber = pageNumber + 1
|
||||
buttons.append(CallbackButton(self.bot, self.run, VEmojis().SKIP, self.ctx.channel,
|
||||
self.guild.id, MessagesCategory.QUEUE, "Next Page", pageNumber=nextPageNumber))
|
||||
|
||||
return buttons
|
||||
|
||||
def __createViewJumpButtons(self, playlist: Playlist) -> List[Button]:
|
||||
return [PlaylistDropdown(self.bot, JumpMusicHandler, playlist, self.ctx.channel, self.guild.id, MessagesCategory.PLAYER)]
|
||||
|
||||
@ -25,7 +25,8 @@ class ResumeHandler(AbstractHandler):
|
||||
queue = processInfo.getQueueToPlayer()
|
||||
queue.put(command)
|
||||
|
||||
return HandlerResponse(self.ctx)
|
||||
embed = self.embeds.PLAYER_RESUMED()
|
||||
return HandlerResponse(self.ctx, embed)
|
||||
else:
|
||||
embed = self.embeds.NOT_PLAYING()
|
||||
return HandlerResponse(self.ctx, embed)
|
||||
|
||||
@ -26,18 +26,13 @@ class SkipHandler(AbstractHandler):
|
||||
embed = self.embeds.NOT_PLAYING()
|
||||
return HandlerResponse(self.ctx, embed)
|
||||
|
||||
playlist = processInfo.getPlaylist()
|
||||
if playlist.isLoopingOne():
|
||||
embed = self.embeds.ERROR_DUE_LOOP_ONE_ON()
|
||||
error = BadCommandUsage()
|
||||
return HandlerResponse(self.ctx, embed, error)
|
||||
|
||||
# Send a command to the player process to skip the music
|
||||
command = VCommands(VCommandsType.SKIP, None)
|
||||
queue = processInfo.getQueueToPlayer()
|
||||
queue.put(command)
|
||||
|
||||
return HandlerResponse(self.ctx)
|
||||
embed = self.embeds.SKIPPING_SONG()
|
||||
return HandlerResponse(self.ctx, embed)
|
||||
else:
|
||||
embed = self.embeds.NOT_PLAYING()
|
||||
return HandlerResponse(self.ctx, embed)
|
||||
|
||||
@ -25,7 +25,8 @@ class StopHandler(AbstractHandler):
|
||||
queue = processInfo.getQueueToPlayer()
|
||||
queue.put(command)
|
||||
|
||||
return HandlerResponse(self.ctx)
|
||||
embed = self.embeds.STOPPING_PLAYER()
|
||||
return HandlerResponse(self.ctx, embed)
|
||||
else:
|
||||
embed = self.embeds.NOT_PLAYING()
|
||||
return HandlerResponse(self.ctx, embed)
|
||||
|
||||
11
Messages/MessagesCategory.py
Normal file
11
Messages/MessagesCategory.py
Normal file
@ -0,0 +1,11 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class MessagesCategory(Enum):
|
||||
QUEUE = 1
|
||||
HISTORY = 2
|
||||
LOOP = 3
|
||||
NOW_PLAYING = 4
|
||||
PLAYER = 5
|
||||
MANAGING_QUEUE = 6
|
||||
OTHERS = 7
|
||||
80
Messages/MessagesManager.py
Normal file
80
Messages/MessagesManager.py
Normal file
@ -0,0 +1,80 @@
|
||||
from typing import Dict, List
|
||||
from discord import Message
|
||||
from Config.Singleton import Singleton
|
||||
from UI.Views.AbstractView import AbstractView
|
||||
from Messages.MessagesCategory import MessagesCategory
|
||||
|
||||
|
||||
class MessagesManager(Singleton):
|
||||
def __init__(self) -> None:
|
||||
if not super().created:
|
||||
# For each guild, and for each category, there will be a list of messages
|
||||
self.__guildsMessages: Dict[int, Dict[MessagesCategory, List[Message]]] = {}
|
||||
# Will, for each message, store the AbstractView that controls it
|
||||
self.__messagesViews: Dict[Message, AbstractView] = {}
|
||||
|
||||
def addMessage(self, guildID: int, category: MessagesCategory, message: Message, view: AbstractView = None) -> None:
|
||||
if message is None:
|
||||
return
|
||||
|
||||
# If guild not exists create Dict
|
||||
if guildID not in self.__guildsMessages.keys():
|
||||
self.__guildsMessages[guildID] = {}
|
||||
# If category not in guild yet, add
|
||||
if category not in self.__guildsMessages[guildID].keys():
|
||||
self.__guildsMessages[guildID][category] = []
|
||||
|
||||
sendedMessages = self.__guildsMessages[guildID][category]
|
||||
if view is not None and isinstance(view, AbstractView):
|
||||
self.__messagesViews[message] = view
|
||||
sendedMessages.append(message)
|
||||
|
||||
async def addMessageAndClearPrevious(self, guildID: int, category: MessagesCategory, message: Message, view: AbstractView = None) -> None:
|
||||
if message is None:
|
||||
return
|
||||
|
||||
# If guild not exists create Dict
|
||||
if guildID not in self.__guildsMessages.keys():
|
||||
self.__guildsMessages[guildID] = {}
|
||||
# If category not in guild yet, add
|
||||
if category not in self.__guildsMessages[guildID].keys():
|
||||
self.__guildsMessages[guildID][category] = []
|
||||
|
||||
sendedMessages = self.__guildsMessages[guildID][category]
|
||||
|
||||
# Delete sended all messages of this category
|
||||
for previousMessage in sendedMessages:
|
||||
await self.__deleteMessage(previousMessage)
|
||||
|
||||
# Create a new list with only the new message
|
||||
self.__guildsMessages[guildID][category] = [message]
|
||||
|
||||
# Store the view of this message
|
||||
if view is not None and isinstance(view, AbstractView):
|
||||
self.__messagesViews[message] = view
|
||||
|
||||
async def clearMessagesOfCategory(self, guildID: int, category: MessagesCategory) -> None:
|
||||
sendedMessages = self.__guildsMessages[guildID][category]
|
||||
|
||||
for message in sendedMessages:
|
||||
self.__deleteMessage(message)
|
||||
|
||||
async def clearMessagesOfGuild(self, guildID: int) -> None:
|
||||
categoriesMessages = self.__guildsMessages[guildID]
|
||||
|
||||
for category in categoriesMessages.keys():
|
||||
for message in categoriesMessages[category]:
|
||||
self.__deleteMessage(message)
|
||||
|
||||
async def __deleteMessage(self, message: Message) -> None:
|
||||
try:
|
||||
# If there is a view for this message delete the key
|
||||
if message in self.__messagesViews.keys():
|
||||
messageView = self.__messagesViews.pop(message)
|
||||
messageView.stopView()
|
||||
del messageView
|
||||
|
||||
await message.delete()
|
||||
except Exception as e:
|
||||
print(f'[ERROR DELETING MESSAGE] -> {e}')
|
||||
pass
|
||||
@ -2,12 +2,16 @@ from abc import ABC, abstractmethod
|
||||
from Handlers.HandlerResponse import HandlerResponse
|
||||
from discord.ext.commands import Context
|
||||
from discord import Message
|
||||
from Messages.MessagesCategory import MessagesCategory
|
||||
from Messages.MessagesManager import MessagesManager
|
||||
from Music.VulkanBot import VulkanBot
|
||||
|
||||
|
||||
class AbstractCommandResponse(ABC):
|
||||
def __init__(self, response: HandlerResponse) -> None:
|
||||
def __init__(self, response: HandlerResponse, category: MessagesCategory) -> None:
|
||||
self.__messagesManager = MessagesManager()
|
||||
self.__response: HandlerResponse = response
|
||||
self.__category: MessagesCategory = category
|
||||
self.__context: Context = response.ctx
|
||||
self.__message: Message = response.ctx.message
|
||||
self.__bot: VulkanBot = response.ctx.bot
|
||||
@ -16,6 +20,10 @@ class AbstractCommandResponse(ABC):
|
||||
def response(self) -> HandlerResponse:
|
||||
return self.__response
|
||||
|
||||
@property
|
||||
def category(self) -> MessagesCategory:
|
||||
return self.__category
|
||||
|
||||
@property
|
||||
def bot(self) -> VulkanBot:
|
||||
return self.__bot
|
||||
@ -28,6 +36,10 @@ class AbstractCommandResponse(ABC):
|
||||
def context(self) -> Context:
|
||||
return self.__context
|
||||
|
||||
@property
|
||||
def manager(self) -> MessagesManager:
|
||||
return self.__messagesManager
|
||||
|
||||
@abstractmethod
|
||||
async def run(self) -> None:
|
||||
async def run(self, deleteLast: bool = True) -> None:
|
||||
pass
|
||||
24
Messages/Responses/EmbedCogResponse.py
Normal file
24
Messages/Responses/EmbedCogResponse.py
Normal file
@ -0,0 +1,24 @@
|
||||
from Messages.Responses.AbstractCogResponse import AbstractCommandResponse
|
||||
from Handlers.HandlerResponse import HandlerResponse
|
||||
from Messages.MessagesCategory import MessagesCategory
|
||||
|
||||
|
||||
class EmbedCommandResponse(AbstractCommandResponse):
|
||||
def __init__(self, response: HandlerResponse, category: MessagesCategory) -> None:
|
||||
super().__init__(response, category)
|
||||
|
||||
async def run(self, deleteLast: bool = True) -> None:
|
||||
message = None
|
||||
if self.response.embed and self.response.view:
|
||||
message = await self.context.send(embed=self.response.embed, view=self.response.view)
|
||||
# Set the view to contain the sended message
|
||||
self.response.view.set_message(message)
|
||||
elif self.response.embed:
|
||||
message = await self.context.send(embed=self.response.embed)
|
||||
|
||||
if message:
|
||||
# Only delete the previous message if this is not error and not forbidden by method caller
|
||||
if deleteLast and self.response.success:
|
||||
await self.manager.addMessageAndClearPrevious(self.context.guild.id, self.category, message, self.response.view)
|
||||
else:
|
||||
self.manager.addMessage(self.context.guild.id, self.category, message)
|
||||
@ -1,15 +1,16 @@
|
||||
from Config.Emojis import VEmojis
|
||||
from UI.Responses.AbstractCogResponse import AbstractCommandResponse
|
||||
from Messages.Responses.AbstractCogResponse import AbstractCommandResponse
|
||||
from Handlers.HandlerResponse import HandlerResponse
|
||||
from Messages.MessagesCategory import MessagesCategory
|
||||
|
||||
|
||||
class EmoteCommandResponse(AbstractCommandResponse):
|
||||
|
||||
def __init__(self, response: HandlerResponse) -> None:
|
||||
super().__init__(response)
|
||||
def __init__(self, response: HandlerResponse, category: MessagesCategory) -> None:
|
||||
super().__init__(response, category)
|
||||
self.__emojis = VEmojis()
|
||||
|
||||
async def run(self) -> None:
|
||||
async def run(self, deleteLast: bool = True) -> None:
|
||||
if self.response.success:
|
||||
await self.message.add_reaction(self.__emojis.SUCCESS)
|
||||
else:
|
||||
@ -1,65 +0,0 @@
|
||||
from typing import List
|
||||
from discord import Embed, Message, TextChannel
|
||||
from Music.VulkanBot import VulkanBot
|
||||
from Parallelism.ProcessInfo import ProcessInfo
|
||||
from Config.Configs import VConfigs
|
||||
from Config.Messages import Messages
|
||||
from Music.Song import Song
|
||||
from Config.Embeds import VEmbeds
|
||||
from UI.Views.PlayerView import PlayerView
|
||||
|
||||
|
||||
class MessagesController:
|
||||
def __init__(self, bot: VulkanBot) -> None:
|
||||
self.__bot = bot
|
||||
self.__previousMessages = []
|
||||
self.__configs = VConfigs()
|
||||
self.__messages = Messages()
|
||||
self.__embeds = VEmbeds()
|
||||
|
||||
async def sendNowPlaying(self, processInfo: ProcessInfo, song: Song) -> None:
|
||||
# Get the lock of the playlist
|
||||
playlist = processInfo.getPlaylist()
|
||||
if playlist.isLoopingOne():
|
||||
title = self.__messages.ONE_SONG_LOOPING
|
||||
else:
|
||||
title = self.__messages.SONG_PLAYING
|
||||
|
||||
# Create View and Embed
|
||||
embed = self.__embeds.SONG_INFO(song.info, title)
|
||||
view = PlayerView(self.__bot)
|
||||
channel = processInfo.getTextChannel()
|
||||
# Delete the previous and send the message
|
||||
await self.__deletePreviousNPMessages()
|
||||
await channel.send(embed=embed, view=view)
|
||||
|
||||
# Get the sended message
|
||||
sendedMessage = await self.__getSendedMessage(channel)
|
||||
# Set the message witch contains the view
|
||||
view.set_message(message=sendedMessage)
|
||||
self.__previousMessages.append(sendedMessage)
|
||||
|
||||
async def __deletePreviousNPMessages(self) -> None:
|
||||
for message in self.__previousMessages:
|
||||
try:
|
||||
await message.delete()
|
||||
except:
|
||||
pass
|
||||
self.__previousMessages.clear()
|
||||
|
||||
async def __getSendedMessage(self, channel: TextChannel) -> Message:
|
||||
stringToIdentify = 'Uploader:'
|
||||
last_messages: List[Message] = await channel.history(limit=5).flatten()
|
||||
|
||||
for message in last_messages:
|
||||
try:
|
||||
if message.author == self.__bot.user:
|
||||
if len(message.embeds) > 0:
|
||||
embed: Embed = message.embeds[0]
|
||||
if len(embed.fields) > 0:
|
||||
if embed.fields[0].name == stringToIdentify:
|
||||
return message
|
||||
|
||||
except Exception as e:
|
||||
print(f'DEVELOPER NOTE -> Error cleaning messages {e}')
|
||||
continue
|
||||
@ -50,6 +50,15 @@ class Playlist:
|
||||
def getSongsToPreload(self) -> List[Song]:
|
||||
return list(self.__queue)[:self.__configs.MAX_PRELOAD_SONGS]
|
||||
|
||||
def getSongsPages(self) -> List[List[Song]]:
|
||||
songsPages = []
|
||||
for x in range(0, len(self.__queue), self.__configs.MAX_SONGS_IN_PAGE):
|
||||
endIndex = x + self.__configs.MAX_SONGS_IN_PAGE
|
||||
startIndex = x
|
||||
songsPages.append(list(self.__queue)[startIndex:endIndex])
|
||||
|
||||
return songsPages
|
||||
|
||||
def __len__(self) -> int:
|
||||
return len(self.__queue)
|
||||
|
||||
@ -79,7 +88,7 @@ class Playlist:
|
||||
self.__current = None
|
||||
return None
|
||||
|
||||
self.__current = self.__queue.popleft()
|
||||
self.__current: Song = self.__queue.popleft()
|
||||
return self.__current
|
||||
|
||||
def prev_song(self) -> Song:
|
||||
|
||||
@ -42,6 +42,7 @@ class VulkanInitializer:
|
||||
cogsStatus.append(bot.load_extension(cogPath, store=True))
|
||||
|
||||
if len(bot.cogs.keys()) != self.__getTotalCogs():
|
||||
print(cogsStatus)
|
||||
raise VulkanError(message='Failed to load some Cog')
|
||||
|
||||
except VulkanError as e:
|
||||
|
||||
79
Parallelism/ProcessExecutor.py
Normal file
79
Parallelism/ProcessExecutor.py
Normal file
@ -0,0 +1,79 @@
|
||||
from typing import List
|
||||
from discord import Button, TextChannel
|
||||
from discord.ui import View
|
||||
from Config.Emojis import VEmojis
|
||||
from Messages.MessagesCategory import MessagesCategory
|
||||
from Music.VulkanBot import VulkanBot
|
||||
from Parallelism.ProcessInfo import ProcessInfo
|
||||
from Config.Messages import Messages
|
||||
from Music.Song import Song
|
||||
from Config.Embeds import VEmbeds
|
||||
from UI.Buttons.HandlerButton import HandlerButton
|
||||
from UI.Views.BasicView import BasicView
|
||||
from Messages.MessagesManager import MessagesManager
|
||||
from Handlers.PrevHandler import PrevHandler
|
||||
from Handlers.PauseHandler import PauseHandler
|
||||
from Handlers.SkipHandler import SkipHandler
|
||||
from Handlers.StopHandler import StopHandler
|
||||
from Handlers.ResumeHandler import ResumeHandler
|
||||
from Handlers.LoopHandler import LoopHandler
|
||||
from Handlers.QueueHandler import QueueHandler
|
||||
|
||||
|
||||
class ProcessCommandsExecutor:
|
||||
def __init__(self, bot: VulkanBot, guildID: int) -> None:
|
||||
self.__bot = bot
|
||||
self.__guildID = guildID
|
||||
self.__messagesManager = MessagesManager()
|
||||
self.__messages = Messages()
|
||||
self.__embeds = VEmbeds()
|
||||
self.__emojis = VEmojis()
|
||||
|
||||
async def sendNowPlaying(self, processInfo: ProcessInfo, song: Song) -> None:
|
||||
# Get the lock of the playlist
|
||||
playlist = processInfo.getPlaylist()
|
||||
if playlist.isLoopingOne():
|
||||
title = self.__messages.ONE_SONG_LOOPING
|
||||
else:
|
||||
title = self.__messages.SONG_PLAYING
|
||||
|
||||
# Create View and Embed
|
||||
embed = self.__embeds.SONG_INFO(song.info, title)
|
||||
channel = processInfo.getTextChannel()
|
||||
view = self.__getPlayerView(channel)
|
||||
# Send Message and add to the MessagesManager
|
||||
message = await channel.send(embed=embed, view=view)
|
||||
await self.__messagesManager.addMessageAndClearPrevious(self.__guildID, MessagesCategory.NOW_PLAYING, message, view)
|
||||
|
||||
# Set in the view the message witch contains the view
|
||||
view.set_message(message=message)
|
||||
|
||||
def __getPlayerView(self, channel: TextChannel) -> View:
|
||||
buttons = self.__getPlayerButtons(channel)
|
||||
view = BasicView(self.__bot, buttons)
|
||||
return view
|
||||
|
||||
def __getPlayerButtons(self, textChannel: TextChannel) -> List[Button]:
|
||||
"""Create the Buttons to be inserted in the Player View"""
|
||||
buttons: List[Button] = []
|
||||
|
||||
buttons.append(HandlerButton(self.__bot, PrevHandler, self.__emojis.BACK,
|
||||
textChannel, self.__guildID, MessagesCategory.PLAYER, "Back"))
|
||||
buttons.append(HandlerButton(self.__bot, PauseHandler, self.__emojis.PAUSE,
|
||||
textChannel, self.__guildID, MessagesCategory.PLAYER, "Pause"))
|
||||
buttons.append(HandlerButton(self.__bot, ResumeHandler, self.__emojis.PLAY,
|
||||
textChannel, self.__guildID, MessagesCategory.PLAYER, "Play"))
|
||||
buttons.append(HandlerButton(self.__bot, StopHandler, self.__emojis.STOP,
|
||||
textChannel, self.__guildID, MessagesCategory.PLAYER, "Stop"))
|
||||
buttons.append(HandlerButton(self.__bot, SkipHandler, self.__emojis.SKIP,
|
||||
textChannel, self.__guildID, MessagesCategory.PLAYER, "Skip"))
|
||||
buttons.append(HandlerButton(self.__bot, QueueHandler, self.__emojis.QUEUE,
|
||||
textChannel, self.__guildID, MessagesCategory.QUEUE, "Songs"))
|
||||
buttons.append(HandlerButton(self.__bot, LoopHandler, self.__emojis.LOOP_ONE,
|
||||
textChannel, self.__guildID, MessagesCategory.LOOP, "Loop One", 'One'))
|
||||
buttons.append(HandlerButton(self.__bot, LoopHandler, self.__emojis.LOOP_OFF,
|
||||
textChannel, self.__guildID, MessagesCategory.LOOP, "Loop Off", 'Off'))
|
||||
buttons.append(HandlerButton(self.__bot, LoopHandler, self.__emojis.LOOP_ALL,
|
||||
textChannel, self.__guildID, MessagesCategory.LOOP, "Loop All", 'All'))
|
||||
|
||||
return buttons
|
||||
@ -7,7 +7,7 @@ from typing import Dict, Tuple, Union
|
||||
from Config.Singleton import Singleton
|
||||
from discord import Guild, Interaction
|
||||
from discord.ext.commands import Context
|
||||
from Music.MessagesController import MessagesController
|
||||
from Parallelism.ProcessExecutor import ProcessCommandsExecutor
|
||||
from Music.Song import Song
|
||||
from Parallelism.PlayerProcess import PlayerProcess
|
||||
from Music.Playlist import Playlist
|
||||
@ -30,7 +30,7 @@ class ProcessManager(Singleton):
|
||||
self.__manager.start()
|
||||
self.__playersProcess: Dict[Guild, ProcessInfo] = {}
|
||||
self.__playersListeners: Dict[Guild, Tuple[Thread, bool]] = {}
|
||||
self.__playersMessages: Dict[Guild, MessagesController] = {}
|
||||
self.__playersCommandsExecutor: Dict[Guild, ProcessCommandsExecutor] = {}
|
||||
|
||||
def setPlayerInfo(self, guild: Guild, info: ProcessInfo):
|
||||
self.__playersProcess[guild.id] = info
|
||||
@ -91,7 +91,7 @@ class ProcessManager(Singleton):
|
||||
thread.start()
|
||||
|
||||
# Create a Message Controller for this player
|
||||
self.__playersMessages[guildID] = MessagesController(self.__bot)
|
||||
self.__playersCommandsExecutor[guildID] = ProcessCommandsExecutor(self.__bot, guildID)
|
||||
|
||||
return processInfo
|
||||
|
||||
@ -157,7 +157,7 @@ class ProcessManager(Singleton):
|
||||
def __terminateProcess(self, guildID: int) -> None:
|
||||
# Delete all structures associated with the Player
|
||||
del self.__playersProcess[guildID]
|
||||
del self.__playersMessages[guildID]
|
||||
del self.__playersCommandsExecutor[guildID]
|
||||
threadListening = self.__playersListeners[guildID]
|
||||
threadListening._stop()
|
||||
del self.__playersListeners[guildID]
|
||||
@ -174,9 +174,9 @@ class ProcessManager(Singleton):
|
||||
self.__playersProcess[guildID].setStatus(ProcessStatus.SLEEPING)
|
||||
|
||||
async def showNowPlaying(self, guildID: int, song: Song) -> None:
|
||||
messagesController = self.__playersMessages[guildID]
|
||||
commandExecutor = self.__playersCommandsExecutor[guildID]
|
||||
processInfo = self.__playersProcess[guildID]
|
||||
await messagesController.sendNowPlaying(processInfo, song)
|
||||
await commandExecutor.sendNowPlaying(processInfo, song)
|
||||
|
||||
|
||||
class VManager(BaseManager):
|
||||
|
||||
10
README.md
10
README.md
@ -7,7 +7,7 @@ Vulkan uses multiprocessing and asynchronous Python modules to maximize Music Pl
|
||||
|
||||
|
||||
<p align="center">
|
||||
<img src="./Assets/playermenu.jfif" />
|
||||
<img src="./Assets/playermenu.jpg" />
|
||||
</p>
|
||||
|
||||
|
||||
@ -15,14 +15,20 @@ Vulkan uses multiprocessing and asynchronous Python modules to maximize Music Pl
|
||||
- Play musics from Youtube, Spotify and Deezer links (Albums, Artists, Playlists and Tracks).
|
||||
- Play musics in multiple discord server at the same time.
|
||||
- The player contains buttons to shortcut some commands.
|
||||
- Search for all musics in Queue using buttons
|
||||
- Shortcut the playing of one song using dropdown menu.
|
||||
- Manage the loop of one or all playing musics.
|
||||
- Manage the order and remove musics from the queue.
|
||||
- Shuffle the musics queue order.
|
||||
|
||||
|
||||
<p align="center">
|
||||
<img src="./Assets/vulkancommands.jpg" />
|
||||
</p>
|
||||
|
||||
|
||||
<p align="center">
|
||||
<img src="./Assets/vulkancommands.jfif" />
|
||||
<img src="./Assets/queuemessage.jpg" />
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
12
UI/Buttons/AbstractItem.py
Normal file
12
UI/Buttons/AbstractItem.py
Normal file
@ -0,0 +1,12 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from discord.ui import Item, View
|
||||
|
||||
|
||||
class AbstractItem(ABC, Item):
|
||||
@abstractmethod
|
||||
def set_view(self, view: View):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_view(self) -> View:
|
||||
pass
|
||||
@ -1,22 +0,0 @@
|
||||
from discord import ButtonStyle, Interaction
|
||||
from discord.ui import Button
|
||||
from Config.Emojis import VEmojis
|
||||
from Handlers.PrevHandler import PrevHandler
|
||||
from Music.VulkanBot import VulkanBot
|
||||
|
||||
|
||||
class BackButton(Button):
|
||||
def __init__(self, bot: VulkanBot):
|
||||
super().__init__(label="Back", style=ButtonStyle.secondary, emoji=VEmojis().BACK)
|
||||
self.__bot = bot
|
||||
|
||||
async def callback(self, interaction: Interaction) -> None:
|
||||
"""Callback to when Button is clicked"""
|
||||
# Return to Discord that this command is being processed
|
||||
await interaction.response.defer()
|
||||
|
||||
handler = PrevHandler(interaction, self.__bot)
|
||||
response = await handler.run()
|
||||
|
||||
if response.embed:
|
||||
await interaction.followup.send(embed=response.embed)
|
||||
48
UI/Buttons/CallbackButton.py
Normal file
48
UI/Buttons/CallbackButton.py
Normal file
@ -0,0 +1,48 @@
|
||||
from typing import Awaitable
|
||||
from Config.Emojis import VEmojis
|
||||
from discord import ButtonStyle, Interaction, Message, TextChannel
|
||||
from discord.ui import Button, View
|
||||
from Handlers.HandlerResponse import HandlerResponse
|
||||
from Messages.MessagesCategory import MessagesCategory
|
||||
from Messages.MessagesManager import MessagesManager
|
||||
from Music.VulkanBot import VulkanBot
|
||||
|
||||
|
||||
class CallbackButton(Button):
|
||||
"""When clicked execute an callback passing the args and kwargs"""
|
||||
|
||||
def __init__(self, bot: VulkanBot, cb: Awaitable, emoji: VEmojis, textChannel: TextChannel, guildID: int, category: MessagesCategory, label=None, *args, **kwargs):
|
||||
super().__init__(label=label, style=ButtonStyle.secondary, emoji=emoji)
|
||||
self.__channel = textChannel
|
||||
self.__guildID = guildID
|
||||
self.__category = category
|
||||
self.__messagesManager = MessagesManager()
|
||||
self.__bot = bot
|
||||
self.__args = args
|
||||
self.__kwargs = kwargs
|
||||
self.__callback = cb
|
||||
self.__view: View = None
|
||||
|
||||
async def callback(self, interaction: Interaction) -> None:
|
||||
"""Callback to when Button is clicked"""
|
||||
# Return to Discord that this command is being processed
|
||||
await interaction.response.defer()
|
||||
|
||||
response: HandlerResponse = await self.__callback(*self.__args, **self.__kwargs)
|
||||
|
||||
message = None
|
||||
if response and response.view is not None:
|
||||
message: Message = await self.__channel.send(embed=response.embed, view=response.view)
|
||||
response.view.set_message(message)
|
||||
elif response.embed:
|
||||
message: Message = await self.__channel.send(embed=response.embed)
|
||||
|
||||
# Clear the last sended message in this category and add the new one
|
||||
if message:
|
||||
await self.__messagesManager.addMessageAndClearPrevious(self.__guildID, self.__category, message, response.view)
|
||||
|
||||
def set_view(self, view: View):
|
||||
self.__view = view
|
||||
|
||||
def get_view(self) -> View:
|
||||
return self.__view
|
||||
50
UI/Buttons/HandlerButton.py
Normal file
50
UI/Buttons/HandlerButton.py
Normal file
@ -0,0 +1,50 @@
|
||||
from Config.Emojis import VEmojis
|
||||
from discord import ButtonStyle, Interaction, Message, TextChannel
|
||||
from discord.ui import Button, View
|
||||
from Handlers.HandlerResponse import HandlerResponse
|
||||
from Messages.MessagesCategory import MessagesCategory
|
||||
from Music.VulkanBot import VulkanBot
|
||||
from Handlers.AbstractHandler import AbstractHandler
|
||||
from Messages.MessagesManager import MessagesManager
|
||||
|
||||
|
||||
class HandlerButton(Button):
|
||||
"""Button that will create and execute a Handler Object when clicked"""
|
||||
|
||||
def __init__(self, bot: VulkanBot, handler: type[AbstractHandler], emoji: VEmojis, textChannel: TextChannel, guildID: int, category: MessagesCategory, label=None, *args, **kwargs):
|
||||
super().__init__(label=label, style=ButtonStyle.secondary, emoji=emoji)
|
||||
self.__messagesManager = MessagesManager()
|
||||
self.__category = category
|
||||
self.__guildID = guildID
|
||||
self.__channel = textChannel
|
||||
self.__bot = bot
|
||||
self.__args = args
|
||||
self.__kwargs = kwargs
|
||||
self.__handlerClass = handler
|
||||
self.__view: View = None
|
||||
|
||||
async def callback(self, interaction: Interaction) -> None:
|
||||
"""Callback to when Button is clicked"""
|
||||
# Return to Discord that this command is being processed
|
||||
await interaction.response.defer()
|
||||
|
||||
# Create the handler object
|
||||
handler = self.__handlerClass(interaction, self.__bot)
|
||||
response: HandlerResponse = await handler.run(*self.__args, **self.__kwargs)
|
||||
|
||||
message = None
|
||||
if response and response.view is not None:
|
||||
message: Message = await self.__channel.send(embed=response.embed, view=response.view)
|
||||
response.view.set_message(message)
|
||||
elif response.embed:
|
||||
message: Message = await self.__channel.send(embed=response.embed)
|
||||
|
||||
# Clear the last category sended message and add the new one
|
||||
if message:
|
||||
await self.__messagesManager.addMessageAndClearPrevious(self.__guildID, self.__category, message, response.view)
|
||||
|
||||
def set_view(self, view: View):
|
||||
self.__view = view
|
||||
|
||||
def get_view(self) -> View:
|
||||
return self.__view
|
||||
@ -1,20 +0,0 @@
|
||||
from discord import ButtonStyle, Interaction
|
||||
from discord.ui import Button
|
||||
from Config.Emojis import VEmojis
|
||||
from Handlers.LoopHandler import LoopHandler
|
||||
from Music.VulkanBot import VulkanBot
|
||||
|
||||
|
||||
class LoopAllButton(Button):
|
||||
def __init__(self, bot: VulkanBot):
|
||||
super().__init__(label="Loop All", style=ButtonStyle.secondary, emoji=VEmojis().LOOP_ALL)
|
||||
self.__bot = bot
|
||||
|
||||
async def callback(self, interaction: Interaction) -> None:
|
||||
await interaction.response.defer()
|
||||
|
||||
handler = LoopHandler(interaction, self.__bot)
|
||||
response = await handler.run('all')
|
||||
|
||||
if response.embed:
|
||||
await interaction.followup.send(embed=response.embed)
|
||||
@ -1,20 +0,0 @@
|
||||
from discord import ButtonStyle, Interaction
|
||||
from discord.ui import Button
|
||||
from Config.Emojis import VEmojis
|
||||
from Handlers.LoopHandler import LoopHandler
|
||||
from Music.VulkanBot import VulkanBot
|
||||
|
||||
|
||||
class LoopOffButton(Button):
|
||||
def __init__(self, bot: VulkanBot):
|
||||
super().__init__(label="Loop Off", style=ButtonStyle.secondary, emoji=VEmojis().LOOP_OFF)
|
||||
self.__bot = bot
|
||||
|
||||
async def callback(self, interaction: Interaction) -> None:
|
||||
await interaction.response.defer()
|
||||
|
||||
handler = LoopHandler(interaction, self.__bot)
|
||||
response = await handler.run('off')
|
||||
|
||||
if response.embed:
|
||||
await interaction.followup.send(embed=response.embed)
|
||||
@ -1,20 +0,0 @@
|
||||
from discord import ButtonStyle, Interaction
|
||||
from discord.ui import Button
|
||||
from Config.Emojis import VEmojis
|
||||
from Handlers.LoopHandler import LoopHandler
|
||||
from Music.VulkanBot import VulkanBot
|
||||
|
||||
|
||||
class LoopOneButton(Button):
|
||||
def __init__(self, bot: VulkanBot):
|
||||
super().__init__(label="Loop One", style=ButtonStyle.secondary, emoji=VEmojis().LOOP_ONE)
|
||||
self.__bot = bot
|
||||
|
||||
async def callback(self, interaction: Interaction) -> None:
|
||||
await interaction.response.defer()
|
||||
|
||||
handler = LoopHandler(interaction, self.__bot)
|
||||
response = await handler.run('one')
|
||||
|
||||
if response.embed:
|
||||
await interaction.followup.send(embed=response.embed)
|
||||
@ -1,20 +0,0 @@
|
||||
from discord import ButtonStyle, Interaction
|
||||
from discord.ui import Button
|
||||
from Config.Emojis import VEmojis
|
||||
from Handlers.PauseHandler import PauseHandler
|
||||
from Music.VulkanBot import VulkanBot
|
||||
|
||||
|
||||
class PauseButton(Button):
|
||||
def __init__(self, bot: VulkanBot):
|
||||
super().__init__(label="Pause", style=ButtonStyle.secondary, emoji=VEmojis().PAUSE)
|
||||
self.__bot = bot
|
||||
|
||||
async def callback(self, interaction: Interaction) -> None:
|
||||
await interaction.response.defer()
|
||||
|
||||
handler = PauseHandler(interaction, self.__bot)
|
||||
response = await handler.run()
|
||||
|
||||
if response.embed:
|
||||
await interaction.followup.send(embed=response.embed)
|
||||
@ -1,20 +0,0 @@
|
||||
from discord import ButtonStyle, Interaction
|
||||
from discord.ui import Button
|
||||
from Config.Emojis import VEmojis
|
||||
from Music.VulkanBot import VulkanBot
|
||||
from Handlers.ResumeHandler import ResumeHandler
|
||||
|
||||
|
||||
class PlayButton(Button):
|
||||
def __init__(self, bot: VulkanBot):
|
||||
super().__init__(label="Play", style=ButtonStyle.secondary, emoji=VEmojis().PLAY)
|
||||
self.__bot = bot
|
||||
|
||||
async def callback(self, interaction: Interaction) -> None:
|
||||
await interaction.response.defer()
|
||||
|
||||
handler = ResumeHandler(interaction, self.__bot)
|
||||
response = await handler.run()
|
||||
|
||||
if response.embed:
|
||||
await interaction.followup.send(embed=response.embed)
|
||||
88
UI/Buttons/PlaylistDropdown.py
Normal file
88
UI/Buttons/PlaylistDropdown.py
Normal file
@ -0,0 +1,88 @@
|
||||
import asyncio
|
||||
from typing import List
|
||||
from discord import Interaction, Message, TextChannel, SelectOption
|
||||
from discord.ui import Select, View
|
||||
from Handlers.HandlerResponse import HandlerResponse
|
||||
from Messages.MessagesCategory import MessagesCategory
|
||||
from Messages.MessagesManager import MessagesManager
|
||||
from Music.VulkanBot import VulkanBot
|
||||
from Handlers.AbstractHandler import AbstractHandler
|
||||
from UI.Buttons.AbstractItem import AbstractItem
|
||||
from UI.Views.AbstractView import AbstractView
|
||||
from Music.Playlist import Playlist
|
||||
|
||||
|
||||
class PlaylistDropdown(Select, AbstractItem):
|
||||
"""Receives n elements to put in drop down and return the selected, pass the index value to a handler"""
|
||||
|
||||
def __init__(self, bot: VulkanBot, handler: type[AbstractHandler], playlist: Playlist, textChannel: TextChannel, guildID: int, category: MessagesCategory):
|
||||
songs = list(playlist.getSongs())
|
||||
|
||||
values = [str(x) for x in range(1, len(songs) + 1)]
|
||||
# Get the title of each of the 20 first songs, the pycord library doesn't accept more
|
||||
songsNames: List[str] = []
|
||||
for x in range(20):
|
||||
songsNames.append(f'{x + 1} - {songs[x].title[:80]}')
|
||||
|
||||
selectOptions: List[SelectOption] = []
|
||||
|
||||
for x in range(len(songsNames)):
|
||||
selectOptions.append(SelectOption(label=songsNames[x], value=values[x]))
|
||||
|
||||
super().__init__(placeholder="Select one music to play now, may be outdated",
|
||||
min_values=1, max_values=1, options=selectOptions)
|
||||
|
||||
self.__playlist = playlist
|
||||
self.__channel = textChannel
|
||||
self.__guildID = guildID
|
||||
self.__category = category
|
||||
self.__handlerClass = handler
|
||||
self.__messagesManager = MessagesManager()
|
||||
self.__bot = bot
|
||||
self.__view: AbstractView = None
|
||||
|
||||
async def callback(self, interaction: Interaction) -> None:
|
||||
"""Callback to when the selection is selected"""
|
||||
await interaction.response.defer()
|
||||
|
||||
# Execute the handler passing the value selected
|
||||
handler = self.__handlerClass(interaction, self.__bot)
|
||||
response: HandlerResponse = await handler.run(self.values[0])
|
||||
|
||||
message = None
|
||||
if response and response.view is not None:
|
||||
message: Message = await self.__channel.send(embed=response.embed, view=response.view)
|
||||
elif response.embed:
|
||||
message: Message = await self.__channel.send(embed=response.embed)
|
||||
|
||||
# Clear the last sended message in this category and add the new one
|
||||
if message:
|
||||
await self.__messagesManager.addMessageAndClearPrevious(self.__guildID, self.__category, message, response.view)
|
||||
|
||||
# Extreme ugly way to wait for the player process to actually retrieve the next song
|
||||
await asyncio.sleep(2)
|
||||
|
||||
await self.__update()
|
||||
|
||||
async def __update(self):
|
||||
songs = list(self.__playlist.getSongs())
|
||||
|
||||
values = [str(x) for x in range(1, len(songs) + 1)]
|
||||
# Get the title of each of the 20 first songs, library doesn't accept more
|
||||
songsNames = [song.title[:80] for song in songs[:20]]
|
||||
|
||||
selectOptions: List[SelectOption] = []
|
||||
|
||||
for x in range(len(songsNames)):
|
||||
selectOptions.append(SelectOption(label=songsNames[x], value=values[x]))
|
||||
|
||||
self.options = selectOptions
|
||||
|
||||
if self.__view is not None:
|
||||
await self.__view.update()
|
||||
|
||||
def set_view(self, view: View):
|
||||
self.__view = view
|
||||
|
||||
def get_view(self) -> View:
|
||||
return self.__view
|
||||
@ -1,20 +0,0 @@
|
||||
from discord import ButtonStyle, Interaction
|
||||
from discord.ui import Button
|
||||
from Config.Emojis import VEmojis
|
||||
from Music.VulkanBot import VulkanBot
|
||||
from Handlers.SkipHandler import SkipHandler
|
||||
|
||||
|
||||
class SkipButton(Button):
|
||||
def __init__(self, bot: VulkanBot):
|
||||
super().__init__(label="Skip", style=ButtonStyle.secondary, emoji=VEmojis().SKIP)
|
||||
self.__bot = bot
|
||||
|
||||
async def callback(self, interaction: Interaction) -> None:
|
||||
await interaction.response.defer()
|
||||
|
||||
handler = SkipHandler(interaction, self.__bot)
|
||||
response = await handler.run()
|
||||
|
||||
if response.embed:
|
||||
await interaction.followup.send(embed=response.embed)
|
||||
@ -1,20 +0,0 @@
|
||||
from Handlers.QueueHandler import QueueHandler
|
||||
from discord import ButtonStyle, Interaction
|
||||
from discord.ui import Button
|
||||
from Config.Emojis import VEmojis
|
||||
from Music.VulkanBot import VulkanBot
|
||||
|
||||
|
||||
class SongsButton(Button):
|
||||
def __init__(self, bot: VulkanBot):
|
||||
super().__init__(label="Songs", style=ButtonStyle.secondary, emoji=VEmojis().QUEUE)
|
||||
self.__bot = bot
|
||||
|
||||
async def callback(self, interaction: Interaction) -> None:
|
||||
await interaction.response.defer()
|
||||
|
||||
handler = QueueHandler(interaction, self.__bot)
|
||||
response = await handler.run()
|
||||
|
||||
if response.embed:
|
||||
await interaction.followup.send(embed=response.embed)
|
||||
@ -1,20 +0,0 @@
|
||||
from discord import ButtonStyle, Interaction
|
||||
from discord.ui import Button
|
||||
from Config.Emojis import VEmojis
|
||||
from Music.VulkanBot import VulkanBot
|
||||
from Handlers.StopHandler import StopHandler
|
||||
|
||||
|
||||
class StopButton(Button):
|
||||
def __init__(self, bot: VulkanBot):
|
||||
super().__init__(label="Stop", style=ButtonStyle.secondary, emoji=VEmojis().STOP)
|
||||
self.__bot = bot
|
||||
|
||||
async def callback(self, interaction: Interaction) -> None:
|
||||
await interaction.response.defer()
|
||||
|
||||
handler = StopHandler(interaction, self.__bot)
|
||||
response = await handler.run()
|
||||
|
||||
if response.embed:
|
||||
await interaction.followup.send(embed=response.embed)
|
||||
@ -1,11 +0,0 @@
|
||||
from UI.Responses.AbstractCogResponse import AbstractCommandResponse
|
||||
from Handlers.HandlerResponse import HandlerResponse
|
||||
|
||||
|
||||
class EmbedCommandResponse(AbstractCommandResponse):
|
||||
def __init__(self, response: HandlerResponse) -> None:
|
||||
super().__init__(response)
|
||||
|
||||
async def run(self) -> None:
|
||||
if self.response.embed:
|
||||
await self.context.send(embed=self.response.embed)
|
||||
14
UI/Views/AbstractView.py
Normal file
14
UI/Views/AbstractView.py
Normal file
@ -0,0 +1,14 @@
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
|
||||
class AbstractView(ABC):
|
||||
@abstractmethod
|
||||
async def update(self) -> None:
|
||||
pass
|
||||
|
||||
def set_message(self, message) -> None:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def stopView(self) -> None:
|
||||
pass
|
||||
52
UI/Views/BasicView.py
Normal file
52
UI/Views/BasicView.py
Normal file
@ -0,0 +1,52 @@
|
||||
from typing import List
|
||||
from discord import Message
|
||||
from discord.ui import View
|
||||
from Config.Emojis import VEmojis
|
||||
from Music.VulkanBot import VulkanBot
|
||||
from UI.Views.AbstractView import AbstractView
|
||||
from UI.Buttons.AbstractItem import AbstractItem
|
||||
|
||||
emojis = VEmojis()
|
||||
|
||||
|
||||
class BasicView(View, AbstractView):
|
||||
"""View that receives buttons to hold, in timeout disable buttons"""
|
||||
|
||||
def __init__(self, bot: VulkanBot, buttons: List[AbstractItem], timeout: float = 6000):
|
||||
super().__init__(timeout=timeout)
|
||||
self.__bot = bot
|
||||
self.__message: Message = None
|
||||
self.__working = True
|
||||
|
||||
for button in buttons:
|
||||
# Set the buttons to have a instance of the view that contains them
|
||||
button.set_view(self)
|
||||
self.add_item(button)
|
||||
|
||||
def stopView(self):
|
||||
self.__working = False
|
||||
|
||||
async def on_timeout(self) -> None:
|
||||
# Disable all itens and, if has the message, edit it
|
||||
try:
|
||||
if not self.__working:
|
||||
return
|
||||
|
||||
self.disable_all_items()
|
||||
if self.__message is not None and isinstance(self.__message, Message):
|
||||
await self.__message.edit(f"{emojis.MUSIC} - The buttons in this message have been disabled due timeout", view=self)
|
||||
except Exception as e:
|
||||
print(f'[ERROR EDITING MESSAGE] -> {e}')
|
||||
|
||||
def set_message(self, message: Message) -> None:
|
||||
self.__message = message
|
||||
|
||||
async def update(self):
|
||||
try:
|
||||
if not self.__working:
|
||||
return
|
||||
|
||||
if self.__message is not None:
|
||||
await self.__message.edit(view=self)
|
||||
except Exception as e:
|
||||
print(f'[ERROR UPDATING MESSAGE] -> {e}')
|
||||
@ -1,43 +0,0 @@
|
||||
from discord import Message
|
||||
from discord.ui import View
|
||||
from Config.Emojis import VEmojis
|
||||
from UI.Buttons.PauseButton import PauseButton
|
||||
from UI.Buttons.BackButton import BackButton
|
||||
from UI.Buttons.SkipButton import SkipButton
|
||||
from UI.Buttons.StopButton import StopButton
|
||||
from UI.Buttons.SongsButton import SongsButton
|
||||
from UI.Buttons.PlayButton import PlayButton
|
||||
from UI.Buttons.LoopAllButton import LoopAllButton
|
||||
from UI.Buttons.LoopOneButton import LoopOneButton
|
||||
from UI.Buttons.LoopOffButton import LoopOffButton
|
||||
from Music.VulkanBot import VulkanBot
|
||||
|
||||
emojis = VEmojis()
|
||||
|
||||
|
||||
class PlayerView(View):
|
||||
def __init__(self, bot: VulkanBot, timeout: float = 6000):
|
||||
super().__init__(timeout=timeout)
|
||||
self.__bot = bot
|
||||
self.__message: Message = None
|
||||
self.add_item(BackButton(self.__bot))
|
||||
self.add_item(PauseButton(self.__bot))
|
||||
self.add_item(PlayButton(self.__bot))
|
||||
self.add_item(StopButton(self.__bot))
|
||||
self.add_item(SkipButton(self.__bot))
|
||||
self.add_item(SongsButton(self.__bot))
|
||||
self.add_item(LoopOneButton(self.__bot))
|
||||
self.add_item(LoopOffButton(self.__bot))
|
||||
self.add_item(LoopAllButton(self.__bot))
|
||||
|
||||
async def on_timeout(self) -> None:
|
||||
# Disable all itens and, if has the message, edit it
|
||||
try:
|
||||
self.disable_all_items()
|
||||
if self.__message is not None and isinstance(self.__message, Message):
|
||||
await self.__message.edit(view=self)
|
||||
except Exception as e:
|
||||
print(f'[ERROR EDITING MESSAGE] -> {e}')
|
||||
|
||||
def set_message(self, message: Message) -> None:
|
||||
self.__message = message
|
||||
Loading…
x
Reference in New Issue
Block a user