mirror of
https://github.com/RafaelSolVargas/Vulkan.git
synced 2025-10-29 16:57:23 +00:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c5885f3093 | ||
|
|
60a36425ee | ||
|
|
5902a0dc72 | ||
|
|
ca754c6f62 | ||
|
|
4f11506c2b | ||
|
|
beb0bc085d | ||
|
|
fededdbb8c | ||
|
|
4a22b43ce9 | ||
|
|
48d7166386 |
@@ -1,7 +1,7 @@
|
||||
from Config.Singleton import Singleton
|
||||
|
||||
|
||||
class Colors(Singleton):
|
||||
class VColors(Singleton):
|
||||
def __init__(self) -> None:
|
||||
self.__red = 0xDC143C
|
||||
self.__green = 0x1F8B4C
|
||||
|
||||
@@ -2,7 +2,7 @@ from decouple import config
|
||||
from Config.Singleton import Singleton
|
||||
|
||||
|
||||
class Configs(Singleton):
|
||||
class VConfigs(Singleton):
|
||||
def __init__(self) -> None:
|
||||
if not super().created:
|
||||
self.BOT_PREFIX = '!'
|
||||
@@ -18,7 +18,7 @@ class Configs(Singleton):
|
||||
self.CLEANER_MESSAGES_QUANT = 5
|
||||
self.ACQUIRE_LOCK_TIMEOUT = 10
|
||||
self.COMMANDS_PATH = 'DiscordCogs'
|
||||
self.VC_TIMEOUT = 600
|
||||
self.VC_TIMEOUT = 300
|
||||
|
||||
self.MAX_PLAYLIST_LENGTH = 50
|
||||
self.MAX_PLAYLIST_FORCED_LENGTH = 5
|
||||
@@ -30,3 +30,9 @@ class Configs(Singleton):
|
||||
|
||||
self.MY_ERROR_BAD_COMMAND = 'This string serves to verify if some error was raised by myself on purpose'
|
||||
self.INVITE_URL = 'https://discordapp.com/oauth2/authorize?client_id={}&scope=bot'
|
||||
|
||||
def getProcessManager(self):
|
||||
return self.__manager
|
||||
|
||||
def setProcessManager(self, newManager):
|
||||
self.__manager = newManager
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
from Config.Messages import Messages
|
||||
from Config.Exceptions import VulkanError
|
||||
from discord import Embed
|
||||
from Config.Configs import Configs
|
||||
from Config.Colors import Colors
|
||||
from Config.Configs import VConfigs
|
||||
from Config.Colors import VColors
|
||||
from datetime import timedelta
|
||||
|
||||
|
||||
class Embeds:
|
||||
class VEmbeds:
|
||||
def __init__(self) -> None:
|
||||
self.__config = Configs()
|
||||
self.__config = VConfigs()
|
||||
self.__messages = Messages()
|
||||
self.__colors = Colors()
|
||||
self.__colors = VColors()
|
||||
|
||||
def ONE_SONG_LOOPING(self, info: dict) -> Embed:
|
||||
title = self.__messages.ONE_SONG_LOOPING
|
||||
@@ -334,7 +334,7 @@ class Embeds:
|
||||
|
||||
def CARA_COROA(self, result: str) -> Embed:
|
||||
embed = Embed(
|
||||
title='Cara Cora',
|
||||
title='Cara Coroa',
|
||||
description=f'Result: {result}',
|
||||
colour=self.__colors.GREEN
|
||||
)
|
||||
20
Config/Emojis.py
Normal file
20
Config/Emojis.py
Normal file
@@ -0,0 +1,20 @@
|
||||
from Config.Singleton import Singleton
|
||||
|
||||
|
||||
class VEmojis(Singleton):
|
||||
def __init__(self) -> None:
|
||||
if not super().created:
|
||||
self.SKIP = "⏩"
|
||||
self.BACK = "⏪"
|
||||
self.PAUSE = "⏸️"
|
||||
self.PLAY = "▶️"
|
||||
self.STOP = "⏹️"
|
||||
self.LOOP_ONE = "🔂"
|
||||
self.LOOP_OFF = "➡️"
|
||||
self.LOOP_ALL = "🔁"
|
||||
self.SHUFFLE = "🔀"
|
||||
self.QUEUE = "📜"
|
||||
self.MUSIC = "🎧"
|
||||
self.ERROR = "❌"
|
||||
self.DOWNLOADING = "📥"
|
||||
self.SUCCESS = "✅"
|
||||
@@ -1,11 +1,11 @@
|
||||
from Config.Singleton import Singleton
|
||||
from Config.Configs import Configs
|
||||
from Config.Configs import VConfigs
|
||||
|
||||
|
||||
class Helper(Singleton):
|
||||
def __init__(self) -> None:
|
||||
if not super().created:
|
||||
config = Configs()
|
||||
config = VConfigs()
|
||||
self.HELP_SKIP = 'Skip the current playing song.'
|
||||
self.HELP_SKIP_LONG = 'Skip the playing of the current song, does not work if loop one is activated. \n\nArguments: None.'
|
||||
self.HELP_RESUME = 'Resumes the song player.'
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
from Config.Singleton import Singleton
|
||||
from Config.Configs import Configs
|
||||
from Config.Configs import VConfigs
|
||||
from Config.Emojis import VEmojis
|
||||
|
||||
|
||||
class Messages(Singleton):
|
||||
def __init__(self) -> None:
|
||||
if not super().created:
|
||||
configs = Configs()
|
||||
self.__emojis = VEmojis()
|
||||
configs = VConfigs()
|
||||
self.STARTUP_MESSAGE = 'Starting Vulkan...'
|
||||
self.STARTUP_COMPLETE_MESSAGE = 'Vulkan is now operating.'
|
||||
|
||||
@@ -16,67 +18,67 @@ class Messages(Singleton):
|
||||
|
||||
self.SONGS_ADDED = 'Downloading `{}` songs to add to the queue'
|
||||
self.SONG_ADDED = 'Downloading the song `{}` to add to the queue'
|
||||
self.SONG_ADDED_TWO = '🎧 Song added to the queue'
|
||||
self.SONG_PLAYING = '🎧 Song playing now'
|
||||
self.SONG_PLAYER = '🎧 Song Player'
|
||||
self.QUEUE_TITLE = '🎧 Songs in Queue'
|
||||
self.ONE_SONG_LOOPING = '🎧 Looping One Song'
|
||||
self.ALL_SONGS_LOOPING = '🎧 Looping All Songs'
|
||||
self.SONG_PAUSED = '⏸️ Song paused'
|
||||
self.SONG_RESUMED = '▶️ Song playing'
|
||||
self.EMPTY_QUEUE = f'📜 Song queue is empty, use {configs.BOT_PREFIX}play to add new songs'
|
||||
self.SONG_DOWNLOADING = '📥 Downloading...'
|
||||
self.SONG_ADDED_TWO = f'{self.__emojis.MUSIC} Song added to the queue'
|
||||
self.SONG_PLAYING = f'{self.__emojis.MUSIC} Song playing now'
|
||||
self.SONG_PLAYER = f'{self.__emojis.MUSIC} Song Player'
|
||||
self.QUEUE_TITLE = f'{self.__emojis.MUSIC} Songs in Queue'
|
||||
self.ONE_SONG_LOOPING = f'{self.__emojis.MUSIC} Looping One Song'
|
||||
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.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.HISTORY_TITLE = '🎧 Played Songs'
|
||||
self.HISTORY_EMPTY = '📜 There is no musics in history'
|
||||
self.HISTORY_TITLE = f'{self.__emojis.MUSIC} Played Songs'
|
||||
self.HISTORY_EMPTY = f'{self.__emojis.QUEUE} There is no musics in history'
|
||||
|
||||
self.SONG_MOVED_SUCCESSFULLY = 'Song `{}` in position `{}` moved to the position `{}` successfully'
|
||||
self.SONG_REMOVED_SUCCESSFULLY = 'Song `{}` removed successfully'
|
||||
|
||||
self.LOOP_ALL_ON = f'❌ Vulkan is looping all songs, use {configs.BOT_PREFIX}loop off to disable this loop first'
|
||||
self.LOOP_ONE_ON = f'❌ Vulkan is looping one song, use {configs.BOT_PREFIX}loop off to disable this loop first'
|
||||
self.LOOP_ALL_ALREADY_ON = '🔁 Vulkan is already looping all songs'
|
||||
self.LOOP_ONE_ALREADY_ON = '🔂 Vulkan is already looping the current song'
|
||||
self.LOOP_ALL_ACTIVATE = '🔁 Looping all songs'
|
||||
self.LOOP_ONE_ACTIVATE = '🔂 Looping the current song'
|
||||
self.LOOP_DISABLE = '➡️ Loop disabled'
|
||||
self.LOOP_ALREADY_DISABLE = '❌ Loop is already disabled'
|
||||
self.LOOP_ON = f'❌ This command cannot be invoked with any loop activated. Use {configs.BOT_PREFIX}loop off to disable loop'
|
||||
self.BAD_USE_OF_LOOP = f"""❌ Invalid arguments of Loop command. Use {configs.BOT_PREFIX}help loop to more information.
|
||||
-> Available Arguments: ["all", "off", "one", ""]"""
|
||||
self.LOOP_ALL_ON = f'{self.__emojis.ERROR} Vulkan is looping all songs, use {configs.BOT_PREFIX}loop off to disable this loop first'
|
||||
self.LOOP_ONE_ON = f'{self.__emojis.ERROR} Vulkan is looping one song, use {configs.BOT_PREFIX}loop off to disable this loop first'
|
||||
self.LOOP_ALL_ALREADY_ON = f'{self.__emojis.LOOP_ALL} Vulkan is already looping all songs'
|
||||
self.LOOP_ONE_ALREADY_ON = f'{self.__emojis.LOOP_ONE} Vulkan is already looping the current song'
|
||||
self.LOOP_ALL_ACTIVATE = f'{self.__emojis.LOOP_ALL} Looping all songs'
|
||||
self.LOOP_ONE_ACTIVATE = f'{self.__emojis.LOOP_ONE} Looping the current song'
|
||||
self.LOOP_DISABLE = f'{self.__emojis.LOOP_OFF} Loop disabled'
|
||||
self.LOOP_ALREADY_DISABLE = f'{self.__emojis.ERROR} Loop is already disabled'
|
||||
self.LOOP_ON = f'{self.__emojis.ERROR} This command cannot be invoked with any loop activated. Use {configs.BOT_PREFIX}loop off to disable loop'
|
||||
self.BAD_USE_OF_LOOP = f"""{self.__emojis.ERROR} Invalid arguments of Loop command. Use {configs.BOT_PREFIX}help loop to more information.
|
||||
-> Available Arguments: ["all", "off", "one", ""]"""
|
||||
|
||||
self.SONGS_SHUFFLED = '🔀 Songs shuffled successfully'
|
||||
self.ERROR_SHUFFLING = '❌ Error while shuffling the songs'
|
||||
self.ERROR_MOVING = '❌ Error while moving the songs'
|
||||
self.LENGTH_ERROR = '❌ Numbers must be between 1 and queue length, use -1 for the last song'
|
||||
self.ERROR_NUMBER = '❌ This command require a number'
|
||||
self.ERROR_PLAYING = '❌ Error while playing songs'
|
||||
self.COMMAND_NOT_FOUND = f'❌ Command not found, type {configs.BOT_PREFIX}help to see all commands'
|
||||
self.UNKNOWN_ERROR = f'❌ Unknown Error, if needed, use {configs.BOT_PREFIX}reset to reset the player of your server'
|
||||
self.ERROR_MISSING_ARGUMENTS = f'❌ Missing arguments in this command. Type {configs.BOT_PREFIX}help "command" to see more info about this command'
|
||||
self.NOT_PREVIOUS = '❌ There is none previous song to play'
|
||||
self.PLAYER_NOT_PLAYING = f'❌ No song playing. Use {configs.BOT_PREFIX}play to start the player'
|
||||
self.SONGS_SHUFFLED = f'{self.__emojis.SHUFFLE} Songs shuffled successfully'
|
||||
self.ERROR_SHUFFLING = f'{self.__emojis.ERROR} Error while shuffling the songs'
|
||||
self.ERROR_MOVING = f'{self.__emojis.ERROR} Error while moving the songs'
|
||||
self.LENGTH_ERROR = f'{self.__emojis.ERROR} Numbers must be between 1 and queue length, use -1 for the last song'
|
||||
self.ERROR_NUMBER = f'{self.__emojis.ERROR} This command require a number'
|
||||
self.ERROR_PLAYING = f'{self.__emojis.ERROR} Error while playing songs'
|
||||
self.COMMAND_NOT_FOUND = f'{self.__emojis.ERROR} Command not found, type {configs.BOT_PREFIX}help to see all commands'
|
||||
self.UNKNOWN_ERROR = f'{self.__emojis.ERROR} Unknown Error, if needed, use {configs.BOT_PREFIX}reset to reset the player of your server'
|
||||
self.ERROR_MISSING_ARGUMENTS = f'{self.__emojis.ERROR} Missing arguments in this command. Type {configs.BOT_PREFIX}help "command" to see more info about this command'
|
||||
self.NOT_PREVIOUS = f'{self.__emojis.ERROR} There is none previous song to play'
|
||||
self.PLAYER_NOT_PLAYING = f'{self.__emojis.ERROR} No song playing. Use {configs.BOT_PREFIX}play to start the player'
|
||||
self.IMPOSSIBLE_MOVE = 'That is impossible :('
|
||||
self.ERROR_TITLE = 'Error :-('
|
||||
self.COMMAND_NOT_FOUND_TITLE = 'This is strange :-('
|
||||
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.DOWNLOADING_ERROR = "❌ It's impossible to download and play this video"
|
||||
self.EXTRACTING_ERROR = '❌ An error ocurred while searching for the songs'
|
||||
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'
|
||||
|
||||
self.ERROR_IN_PROCESS = "❌ Due to a internal error your player was restarted, skipping the song."
|
||||
self.ERROR_IN_PROCESS = f"{self.__emojis.ERROR} Due to a internal error your player was restarted, skipping the song."
|
||||
self.MY_ERROR_BAD_COMMAND = 'This string serves to verify if some error was raised by myself on purpose'
|
||||
self.BAD_COMMAND_TITLE = 'Misuse of command'
|
||||
self.BAD_COMMAND = f'❌ Bad usage of this command, type {configs.BOT_PREFIX}help "command" to understand the command better'
|
||||
self.VIDEO_UNAVAILABLE = '❌ Sorry. This video is unavailable for download.'
|
||||
self.ERROR_DUE_LOOP_ONE_ON = f'❌ This command cannot be executed with loop one activated. Use {configs.BOT_PREFIX}loop off to disable loop.'
|
||||
self.BAD_COMMAND = f'{self.__emojis.ERROR} Bad usage of this command, type {configs.BOT_PREFIX}help "command" to understand the command better'
|
||||
self.VIDEO_UNAVAILABLE = f'{self.__emojis.ERROR} Sorry. This video is unavailable for download.'
|
||||
self.ERROR_DUE_LOOP_ONE_ON = f'{self.__emojis.ERROR} This command cannot be executed with loop one activated. Use {configs.BOT_PREFIX}loop off to disable loop.'
|
||||
|
||||
|
||||
class SearchMessages(Singleton):
|
||||
def __init__(self) -> None:
|
||||
if not super().created:
|
||||
config = Configs()
|
||||
config = VConfigs()
|
||||
self.UNKNOWN_INPUT = f'This type of input was too strange, try something else or type {config.BOT_PREFIX}help play'
|
||||
self.UNKNOWN_INPUT_TITLE = 'Nothing Found'
|
||||
self.GENERIC_TITLE = 'URL could not be processed'
|
||||
|
||||
@@ -1,24 +1,22 @@
|
||||
from discord import Client, Game, Status, Embed
|
||||
from discord.ext.commands.errors import CommandNotFound, MissingRequiredArgument
|
||||
from discord.ext import commands
|
||||
from Config.Configs import Configs
|
||||
from discord import Embed
|
||||
from discord.ext.commands import Cog, command
|
||||
from Config.Configs import VConfigs
|
||||
from Config.Helper import Helper
|
||||
from Config.Messages import Messages
|
||||
from Config.Colors import Colors
|
||||
from Views.Embeds import Embeds
|
||||
from Config.Colors import VColors
|
||||
from Music.VulkanBot import VulkanBot
|
||||
from Config.Embeds import VEmbeds
|
||||
|
||||
helper = Helper()
|
||||
|
||||
|
||||
class ControlCog(commands.Cog):
|
||||
class ControlCog(Cog):
|
||||
"""Class to handle discord events"""
|
||||
|
||||
def __init__(self, bot: Client):
|
||||
def __init__(self, bot: VulkanBot):
|
||||
self.__bot = bot
|
||||
self.__config = Configs()
|
||||
self.__messages = Messages()
|
||||
self.__colors = Colors()
|
||||
self.__embeds = Embeds()
|
||||
self.__config = VConfigs()
|
||||
self.__colors = VColors()
|
||||
self.__embeds = VEmbeds()
|
||||
self.__commands = {
|
||||
'MUSIC': ['resume', 'pause', 'loop', 'stop',
|
||||
'skip', 'play', 'queue', 'clear',
|
||||
@@ -28,28 +26,7 @@ class ControlCog(commands.Cog):
|
||||
|
||||
}
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_ready(self):
|
||||
print(self.__messages.STARTUP_MESSAGE)
|
||||
await self.__bot.change_presence(status=Status.online, activity=Game(name=f"Vulkan | {self.__config.BOT_PREFIX}help"))
|
||||
print(self.__messages.STARTUP_COMPLETE_MESSAGE)
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_command_error(self, ctx, error):
|
||||
if isinstance(error, MissingRequiredArgument):
|
||||
embed = self.__embeds.MISSING_ARGUMENTS()
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
elif isinstance(error, CommandNotFound):
|
||||
embed = self.__embeds.COMMAND_NOT_FOUND()
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
else:
|
||||
print(f'DEVELOPER NOTE -> Command Error: {error}')
|
||||
embed = self.__embeds.UNKNOWN_ERROR()
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@commands.command(name="help", help=helper.HELP_HELP, description=helper.HELP_HELP_LONG, aliases=['h', 'ajuda'])
|
||||
@command(name="help", help=helper.HELP_HELP, description=helper.HELP_HELP_LONG, aliases=['h', 'ajuda'])
|
||||
async def help_msg(self, ctx, command_help=''):
|
||||
if command_help != '':
|
||||
for command in self.__bot.commands:
|
||||
@@ -97,10 +74,10 @@ class ControlCog(commands.Cog):
|
||||
colour=self.__colors.BLUE
|
||||
)
|
||||
|
||||
embedhelp.set_thumbnail(url=self.__bot.user.avatar_url)
|
||||
embedhelp.set_thumbnail(url=self.__bot.user.avatar)
|
||||
await ctx.send(embed=embedhelp)
|
||||
|
||||
@commands.command(name='invite', help=helper.HELP_INVITE, description=helper.HELP_INVITE_LONG, aliases=['convite', 'inv', 'convidar'])
|
||||
@command(name='invite', help=helper.HELP_INVITE, description=helper.HELP_INVITE_LONG, aliases=['convite', 'inv', 'convidar'])
|
||||
async def invite_bot(self, ctx):
|
||||
invite_url = self.__config.INVITE_URL.format(self.__bot.user.id)
|
||||
txt = self.__config.INVITE_MESSAGE.format(invite_url, invite_url)
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
from discord import Guild, Client
|
||||
from discord.ext import commands
|
||||
from discord.ext.commands import Context
|
||||
from discord.ext.commands import Context, command, Cog
|
||||
from Config.Helper import Helper
|
||||
from Handlers.ClearHandler import ClearHandler
|
||||
from Handlers.MoveHandler import MoveHandler
|
||||
@@ -17,219 +15,229 @@ from Handlers.ResumeHandler import ResumeHandler
|
||||
from Handlers.HistoryHandler import HistoryHandler
|
||||
from Handlers.QueueHandler import QueueHandler
|
||||
from Handlers.LoopHandler import LoopHandler
|
||||
from Views.EmoteView import EmoteView
|
||||
from Views.EmbedView import EmbedView
|
||||
from UI.Responses.EmoteCogResponse import EmoteCommandResponse
|
||||
from UI.Responses.EmbedCogResponse import EmbedCommandResponse
|
||||
from UI.Views.PlayerView import PlayerView
|
||||
from Music.VulkanBot import VulkanBot
|
||||
from Config.Configs import VConfigs
|
||||
from Parallelism.ProcessManager import ProcessManager
|
||||
|
||||
helper = Helper()
|
||||
|
||||
|
||||
class MusicCog(commands.Cog):
|
||||
class MusicCog(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) -> None:
|
||||
self.__bot: Client = bot
|
||||
def __init__(self, bot: VulkanBot) -> None:
|
||||
self.__bot: VulkanBot = bot
|
||||
VConfigs().setProcessManager(ProcessManager(bot))
|
||||
|
||||
@commands.command(name="play", help=helper.HELP_PLAY, description=helper.HELP_PLAY_LONG, aliases=['p', 'tocar'])
|
||||
@command(name="play", help=helper.HELP_PLAY, description=helper.HELP_PLAY_LONG, aliases=['p', 'tocar'])
|
||||
async def play(self, ctx: Context, *args) -> None:
|
||||
try:
|
||||
controller = PlayHandler(ctx, self.__bot)
|
||||
|
||||
response = await controller.run(args)
|
||||
if response is not None:
|
||||
view1 = EmbedView(response)
|
||||
view2 = EmoteView(response)
|
||||
view1 = EmbedCommandResponse(response)
|
||||
view2 = EmoteCommandResponse(response)
|
||||
await view1.run()
|
||||
await view2.run()
|
||||
except Exception as e:
|
||||
print(f'[ERROR IN COG] -> {e}')
|
||||
|
||||
@commands.command(name="queue", help=helper.HELP_QUEUE, description=helper.HELP_QUEUE_LONG, aliases=['q', 'fila', 'musicas'])
|
||||
@command(name="queue", help=helper.HELP_QUEUE, description=helper.HELP_QUEUE_LONG, aliases=['q', 'fila', 'musicas'])
|
||||
async def queue(self, ctx: Context) -> None:
|
||||
try:
|
||||
controller = QueueHandler(ctx, self.__bot)
|
||||
|
||||
response = await controller.run()
|
||||
view2 = EmbedView(response)
|
||||
view2 = EmbedCommandResponse(response)
|
||||
await view2.run()
|
||||
except Exception as e:
|
||||
print(f'[ERROR IN COG] -> {e}')
|
||||
|
||||
@commands.command(name="skip", help=helper.HELP_SKIP, description=helper.HELP_SKIP_LONG, aliases=['s', 'pular', 'next'])
|
||||
@command(name="skip", help=helper.HELP_SKIP, description=helper.HELP_SKIP_LONG, aliases=['s', 'pular', 'next'])
|
||||
async def skip(self, ctx: Context) -> None:
|
||||
try:
|
||||
controller = SkipHandler(ctx, self.__bot)
|
||||
|
||||
response = await controller.run()
|
||||
if response.success:
|
||||
view = EmoteView(response)
|
||||
view = EmoteCommandResponse(response)
|
||||
else:
|
||||
view = EmbedView(response)
|
||||
view = EmbedCommandResponse(response)
|
||||
|
||||
await view.run()
|
||||
except Exception as e:
|
||||
print(f'[ERROR IN COG] -> {e}')
|
||||
|
||||
@commands.command(name='stop', help=helper.HELP_STOP, description=helper.HELP_STOP_LONG, aliases=['parar'])
|
||||
@command(name='stop', help=helper.HELP_STOP, description=helper.HELP_STOP_LONG, aliases=['parar'])
|
||||
async def stop(self, ctx: Context) -> None:
|
||||
try:
|
||||
controller = StopHandler(ctx, self.__bot)
|
||||
|
||||
response = await controller.run()
|
||||
if response.success:
|
||||
view = EmoteView(response)
|
||||
view = EmoteCommandResponse(response)
|
||||
else:
|
||||
view = EmbedView(response)
|
||||
view = EmbedCommandResponse(response)
|
||||
|
||||
await view.run()
|
||||
except Exception as e:
|
||||
print(f'[ERROR IN COG] -> {e}')
|
||||
|
||||
@commands.command(name='pause', help=helper.HELP_PAUSE, description=helper.HELP_PAUSE_LONG, aliases=['pausar', 'pare'])
|
||||
@command(name='pause', help=helper.HELP_PAUSE, description=helper.HELP_PAUSE_LONG, aliases=['pausar', 'pare'])
|
||||
async def pause(self, ctx: Context) -> None:
|
||||
try:
|
||||
controller = PauseHandler(ctx, self.__bot)
|
||||
|
||||
response = await controller.run()
|
||||
view1 = EmoteView(response)
|
||||
view2 = EmbedView(response)
|
||||
view1 = EmoteCommandResponse(response)
|
||||
view2 = EmbedCommandResponse(response)
|
||||
await view1.run()
|
||||
await view2.run()
|
||||
except Exception as e:
|
||||
print(f'[ERROR IN COG] -> {e}')
|
||||
|
||||
@commands.command(name='resume', help=helper.HELP_RESUME, description=helper.HELP_RESUME_LONG, aliases=['soltar', 'despausar'])
|
||||
@command(name='resume', help=helper.HELP_RESUME, description=helper.HELP_RESUME_LONG, aliases=['soltar', 'despausar'])
|
||||
async def resume(self, ctx: Context) -> None:
|
||||
try:
|
||||
controller = ResumeHandler(ctx, self.__bot)
|
||||
|
||||
response = await controller.run()
|
||||
view1 = EmoteView(response)
|
||||
view2 = EmbedView(response)
|
||||
view1 = EmoteCommandResponse(response)
|
||||
view2 = EmbedCommandResponse(response)
|
||||
await view1.run()
|
||||
await view2.run()
|
||||
except Exception as e:
|
||||
print(f'[ERROR IN COG] -> {e}')
|
||||
|
||||
@commands.command(name='prev', help=helper.HELP_PREV, description=helper.HELP_PREV_LONG, aliases=['anterior', 'return', 'previous', 'back'])
|
||||
@command(name='prev', help=helper.HELP_PREV, description=helper.HELP_PREV_LONG, aliases=['anterior', 'return', 'previous', 'back'])
|
||||
async def prev(self, ctx: Context) -> None:
|
||||
try:
|
||||
controller = PrevHandler(ctx, self.__bot)
|
||||
|
||||
response = await controller.run()
|
||||
if response is not None:
|
||||
view1 = EmbedView(response)
|
||||
view2 = EmoteView(response)
|
||||
view1 = EmbedCommandResponse(response)
|
||||
view2 = EmoteCommandResponse(response)
|
||||
await view1.run()
|
||||
await view2.run()
|
||||
except Exception as e:
|
||||
print(f'[ERROR IN COG] -> {e}')
|
||||
|
||||
@commands.command(name='history', help=helper.HELP_HISTORY, description=helper.HELP_HISTORY_LONG, aliases=['historico', 'anteriores', 'hist'])
|
||||
@command(name='history', help=helper.HELP_HISTORY, description=helper.HELP_HISTORY_LONG, aliases=['historico', 'anteriores', 'hist'])
|
||||
async def history(self, ctx: Context) -> None:
|
||||
try:
|
||||
controller = HistoryHandler(ctx, self.__bot)
|
||||
|
||||
response = await controller.run()
|
||||
view1 = EmbedView(response)
|
||||
view2 = EmoteView(response)
|
||||
view1 = EmbedCommandResponse(response)
|
||||
view2 = EmoteCommandResponse(response)
|
||||
await view1.run()
|
||||
await view2.run()
|
||||
except Exception as e:
|
||||
print(f'[ERROR IN COG] -> {e}')
|
||||
|
||||
@commands.command(name='loop', help=helper.HELP_LOOP, description=helper.HELP_LOOP_LONG, aliases=['l', 'repeat'])
|
||||
@command(name='loop', help=helper.HELP_LOOP, description=helper.HELP_LOOP_LONG, aliases=['l', 'repeat'])
|
||||
async def loop(self, ctx: Context, args='') -> None:
|
||||
try:
|
||||
controller = LoopHandler(ctx, self.__bot)
|
||||
|
||||
response = await controller.run(args)
|
||||
view1 = EmoteView(response)
|
||||
view2 = EmbedView(response)
|
||||
view1 = EmoteCommandResponse(response)
|
||||
view2 = EmbedCommandResponse(response)
|
||||
await view1.run()
|
||||
await view2.run()
|
||||
except Exception as e:
|
||||
print(f'[ERROR IN COG] -> {e}')
|
||||
|
||||
@commands.command(name='clear', help=helper.HELP_CLEAR, description=helper.HELP_CLEAR_LONG, aliases=['c', 'limpar'])
|
||||
@command(name='clear', help=helper.HELP_CLEAR, description=helper.HELP_CLEAR_LONG, aliases=['c', 'limpar'])
|
||||
async def clear(self, ctx: Context) -> None:
|
||||
try:
|
||||
controller = ClearHandler(ctx, self.__bot)
|
||||
|
||||
response = await controller.run()
|
||||
view = EmoteView(response)
|
||||
view = EmoteCommandResponse(response)
|
||||
await view.run()
|
||||
except Exception as e:
|
||||
print(f'[ERROR IN COG] -> {e}')
|
||||
|
||||
@commands.command(name='np', help=helper.HELP_NP, description=helper.HELP_NP_LONG, aliases=['playing', 'now', 'this'])
|
||||
@command(name='np', help=helper.HELP_NP, description=helper.HELP_NP_LONG, aliases=['playing', 'now', 'this'])
|
||||
async def now_playing(self, ctx: Context) -> None:
|
||||
try:
|
||||
controller = NowPlayingHandler(ctx, self.__bot)
|
||||
|
||||
response = await controller.run()
|
||||
view1 = EmbedView(response)
|
||||
view2 = EmoteView(response)
|
||||
view1 = EmbedCommandResponse(response)
|
||||
view2 = EmoteCommandResponse(response)
|
||||
await view1.run()
|
||||
await view2.run()
|
||||
except Exception as e:
|
||||
print(f'[ERROR IN COG] -> {e}')
|
||||
|
||||
@commands.command(name='shuffle', help=helper.HELP_SHUFFLE, description=helper.HELP_SHUFFLE_LONG, aliases=['aleatorio', 'misturar'])
|
||||
@command(name='shuffle', help=helper.HELP_SHUFFLE, description=helper.HELP_SHUFFLE_LONG, aliases=['aleatorio', 'misturar'])
|
||||
async def shuffle(self, ctx: Context) -> None:
|
||||
try:
|
||||
controller = ShuffleHandler(ctx, self.__bot)
|
||||
|
||||
response = await controller.run()
|
||||
view1 = EmbedView(response)
|
||||
view2 = EmoteView(response)
|
||||
view1 = EmbedCommandResponse(response)
|
||||
view2 = EmoteCommandResponse(response)
|
||||
await view1.run()
|
||||
await view2.run()
|
||||
except Exception as e:
|
||||
print(f'[ERROR IN COG] -> {e}')
|
||||
|
||||
@commands.command(name='move', help=helper.HELP_MOVE, description=helper.HELP_MOVE_LONG, aliases=['m', 'mover'])
|
||||
@command(name='move', help=helper.HELP_MOVE, description=helper.HELP_MOVE_LONG, aliases=['m', 'mover'])
|
||||
async def move(self, ctx: Context, pos1, pos2='1') -> None:
|
||||
try:
|
||||
controller = MoveHandler(ctx, self.__bot)
|
||||
|
||||
response = await controller.run(pos1, pos2)
|
||||
view1 = EmbedView(response)
|
||||
view2 = EmoteView(response)
|
||||
view1 = EmbedCommandResponse(response)
|
||||
view2 = EmoteCommandResponse(response)
|
||||
await view1.run()
|
||||
await view2.run()
|
||||
except Exception as e:
|
||||
print(f'[ERROR IN COG] -> {e}')
|
||||
|
||||
@commands.command(name='remove', help=helper.HELP_REMOVE, description=helper.HELP_REMOVE_LONG, aliases=['remover'])
|
||||
@command(name='remove', help=helper.HELP_REMOVE, description=helper.HELP_REMOVE_LONG, aliases=['remover'])
|
||||
async def remove(self, ctx: Context, position) -> None:
|
||||
try:
|
||||
controller = RemoveHandler(ctx, self.__bot)
|
||||
|
||||
response = await controller.run(position)
|
||||
view1 = EmbedView(response)
|
||||
view2 = EmoteView(response)
|
||||
view1 = EmbedCommandResponse(response)
|
||||
view2 = EmoteCommandResponse(response)
|
||||
await view1.run()
|
||||
await view2.run()
|
||||
except Exception as e:
|
||||
print(f'[ERROR IN COG] -> {e}')
|
||||
|
||||
@commands.command(name='reset', help=helper.HELP_RESET, description=helper.HELP_RESET_LONG, aliases=['resetar'])
|
||||
@command(name='reset', help=helper.HELP_RESET, description=helper.HELP_RESET_LONG, aliases=['resetar'])
|
||||
async def reset(self, ctx: Context) -> None:
|
||||
try:
|
||||
controller = ResetHandler(ctx, self.__bot)
|
||||
|
||||
response = await controller.run()
|
||||
view1 = EmbedView(response)
|
||||
view2 = EmoteView(response)
|
||||
view1 = EmbedCommandResponse(response)
|
||||
view2 = EmoteCommandResponse(response)
|
||||
await view1.run()
|
||||
await view2.run()
|
||||
except Exception as e:
|
||||
print(f'[ERROR IN COG] -> {e}')
|
||||
|
||||
@command(name='rafael')
|
||||
async def rafael(self, ctx: Context) -> None:
|
||||
view = PlayerView(self.__bot)
|
||||
await ctx.send(view=view)
|
||||
|
||||
|
||||
def setup(bot):
|
||||
bot.add_cog(MusicCog(bot))
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
from random import randint, random
|
||||
from discord import Client
|
||||
from Music.VulkanBot import VulkanBot
|
||||
from discord.ext.commands import Context, command, Cog
|
||||
from Config.Helper import Helper
|
||||
from Views.Embeds import Embeds
|
||||
from Config.Embeds import VEmbeds
|
||||
|
||||
helper = Helper()
|
||||
|
||||
@@ -10,8 +10,8 @@ helper = Helper()
|
||||
class RandomCog(Cog):
|
||||
"""Class to listen to commands of type Random"""
|
||||
|
||||
def __init__(self, bot: Client):
|
||||
self.__embeds = Embeds()
|
||||
def __init__(self, bot: VulkanBot):
|
||||
self.__embeds = VEmbeds()
|
||||
|
||||
@command(name='random', help=helper.HELP_RANDOM, description=helper.HELP_RANDOM_LONG, aliases=['rand'])
|
||||
async def random(self, ctx: Context, arg: str) -> None:
|
||||
|
||||
@@ -1,26 +1,31 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import List
|
||||
from typing import List, Union
|
||||
from discord.ext.commands import Context
|
||||
from discord import Client, Guild, ClientUser, Member
|
||||
from discord import Client, Guild, ClientUser, Interaction, Member, User
|
||||
from Config.Messages import Messages
|
||||
from Music.VulkanBot import VulkanBot
|
||||
from Handlers.HandlerResponse import HandlerResponse
|
||||
from Config.Configs import Configs
|
||||
from Config.Configs import VConfigs
|
||||
from Config.Helper import Helper
|
||||
from Views.Embeds import Embeds
|
||||
from Config.Embeds import VEmbeds
|
||||
|
||||
|
||||
class AbstractHandler(ABC):
|
||||
def __init__(self, ctx: Context, bot: Client) -> None:
|
||||
self.__bot: Client = bot
|
||||
def __init__(self, ctx: Union[Context, Interaction], bot: VulkanBot) -> None:
|
||||
self.__bot: VulkanBot = bot
|
||||
self.__guild: Guild = ctx.guild
|
||||
self.__ctx: Context = ctx
|
||||
self.__bot_user: ClientUser = self.__bot.user
|
||||
self.__id = self.__bot_user.id
|
||||
self.__messages = Messages()
|
||||
self.__config = Configs()
|
||||
self.__config = VConfigs()
|
||||
self.__helper = Helper()
|
||||
self.__embeds = Embeds()
|
||||
self.__embeds = VEmbeds()
|
||||
self.__bot_member: Member = self.__get_member()
|
||||
if isinstance(ctx, Context):
|
||||
self.__author = ctx.author
|
||||
else:
|
||||
self.__author = ctx.user
|
||||
|
||||
@abstractmethod
|
||||
async def run(self) -> HandlerResponse:
|
||||
@@ -38,6 +43,10 @@ class AbstractHandler(ABC):
|
||||
def bot_user(self) -> ClientUser:
|
||||
return self.__bot_user
|
||||
|
||||
@property
|
||||
def author(self) -> User:
|
||||
return self.__author
|
||||
|
||||
@property
|
||||
def guild(self) -> Guild:
|
||||
return self.__guild
|
||||
@@ -47,7 +56,7 @@ class AbstractHandler(ABC):
|
||||
return self.__bot
|
||||
|
||||
@property
|
||||
def config(self) -> Configs:
|
||||
def config(self) -> VConfigs:
|
||||
return self.__config
|
||||
|
||||
@property
|
||||
@@ -59,11 +68,11 @@ class AbstractHandler(ABC):
|
||||
return self.__helper
|
||||
|
||||
@property
|
||||
def ctx(self) -> Context:
|
||||
def ctx(self) -> Union[Context, Interaction]:
|
||||
return self.__ctx
|
||||
|
||||
@property
|
||||
def embeds(self) -> Embeds:
|
||||
def embeds(self) -> VEmbeds:
|
||||
return self.__embeds
|
||||
|
||||
def __get_member(self) -> Member:
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
from typing import Union
|
||||
from discord import Interaction
|
||||
from discord.ext.commands import Context
|
||||
from discord import Client
|
||||
from Music.VulkanBot import VulkanBot
|
||||
from Handlers.AbstractHandler import AbstractHandler
|
||||
from Handlers.HandlerResponse import HandlerResponse
|
||||
from Parallelism.ProcessManager import ProcessManager
|
||||
|
||||
|
||||
class ClearHandler(AbstractHandler):
|
||||
def __init__(self, ctx: Context, bot: Client) -> None:
|
||||
def __init__(self, ctx: Union[Context, Interaction], bot: VulkanBot) -> None:
|
||||
super().__init__(ctx, bot)
|
||||
|
||||
async def run(self) -> HandlerResponse:
|
||||
# Get the current process of the guild
|
||||
processManager = ProcessManager()
|
||||
processManager = self.config.getProcessManager()
|
||||
processInfo = processManager.getRunningPlayerInfo(self.guild)
|
||||
if processInfo:
|
||||
# Clear the playlist
|
||||
@@ -21,7 +22,6 @@ class ClearHandler(AbstractHandler):
|
||||
if acquired:
|
||||
playlist.clear()
|
||||
processLock.release()
|
||||
processLock.release()
|
||||
return HandlerResponse(self.ctx)
|
||||
else:
|
||||
processManager.resetProcess(self.guild, self.ctx)
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
from typing import Union
|
||||
from discord.ext.commands import Context
|
||||
from Config.Exceptions import VulkanError
|
||||
from discord import Embed
|
||||
from discord import Embed, Interaction
|
||||
|
||||
|
||||
class HandlerResponse:
|
||||
def __init__(self, ctx: Context, embed: Embed = None, error: VulkanError = None) -> None:
|
||||
def __init__(self, ctx: Union[Context, Interaction], embed: Embed = None, error: VulkanError = None) -> None:
|
||||
self.__ctx: Context = ctx
|
||||
self.__error: VulkanError = error
|
||||
self.__embed: Embed = embed
|
||||
self.__success = False if error else True
|
||||
|
||||
@property
|
||||
def ctx(self) -> Context:
|
||||
def ctx(self) -> Union[Context, Interaction]:
|
||||
return self.__ctx
|
||||
|
||||
@property
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
from discord.ext.commands import Context
|
||||
from discord import Client
|
||||
from Music.VulkanBot import VulkanBot
|
||||
from Handlers.AbstractHandler import AbstractHandler
|
||||
from Handlers.HandlerResponse import HandlerResponse
|
||||
from Utils.Utils import Utils
|
||||
from Parallelism.ProcessManager import ProcessManager
|
||||
from typing import Union
|
||||
from discord import Interaction
|
||||
|
||||
|
||||
class HistoryHandler(AbstractHandler):
|
||||
def __init__(self, ctx: Context, bot: Client) -> None:
|
||||
def __init__(self, ctx: Union[Context, Interaction], bot: VulkanBot) -> None:
|
||||
super().__init__(ctx, bot)
|
||||
|
||||
async def run(self) -> HandlerResponse:
|
||||
# Get the current process of the guild
|
||||
processManager = ProcessManager()
|
||||
processManager = self.config.getProcessManager()
|
||||
processInfo = processManager.getRunningPlayerInfo(self.guild)
|
||||
if processInfo:
|
||||
processLock = processInfo.getLock()
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
from discord.ext.commands import Context
|
||||
from discord import Client
|
||||
from Music.VulkanBot import VulkanBot
|
||||
from Handlers.AbstractHandler import AbstractHandler
|
||||
from Handlers.HandlerResponse import HandlerResponse
|
||||
from Config.Exceptions import BadCommandUsage
|
||||
from Parallelism.ProcessManager import ProcessManager
|
||||
from typing import Union
|
||||
from discord import Interaction
|
||||
|
||||
|
||||
class LoopHandler(AbstractHandler):
|
||||
def __init__(self, ctx: Context, bot: Client) -> None:
|
||||
def __init__(self, ctx: Union[Context, Interaction], bot: VulkanBot) -> None:
|
||||
super().__init__(ctx, bot)
|
||||
|
||||
async def run(self, args: str) -> HandlerResponse:
|
||||
# Get the current process of the guild
|
||||
processManager = ProcessManager()
|
||||
processManager = self.config.getProcessManager()
|
||||
processInfo = processManager.getRunningPlayerInfo(self.guild)
|
||||
if not processInfo:
|
||||
embed = self.embeds.NOT_PLAYING()
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
from typing import Union
|
||||
from discord.ext.commands import Context
|
||||
from discord import Client
|
||||
from Music.VulkanBot import VulkanBot
|
||||
from Handlers.AbstractHandler import AbstractHandler
|
||||
from Handlers.HandlerResponse import HandlerResponse
|
||||
from Config.Exceptions import BadCommandUsage, VulkanError, InvalidInput, NumberRequired, UnknownError
|
||||
from Music.Playlist import Playlist
|
||||
from Parallelism.ProcessManager import ProcessManager
|
||||
from typing import Union
|
||||
from discord import Interaction
|
||||
|
||||
|
||||
class MoveHandler(AbstractHandler):
|
||||
def __init__(self, ctx: Context, bot: Client) -> None:
|
||||
def __init__(self, ctx: Union[Context, Interaction], bot: VulkanBot) -> None:
|
||||
super().__init__(ctx, bot)
|
||||
|
||||
async def run(self, pos1: str, pos2: str) -> HandlerResponse:
|
||||
processManager = ProcessManager()
|
||||
processManager = self.config.getProcessManager()
|
||||
processInfo = processManager.getRunningPlayerInfo(self.guild)
|
||||
if not processInfo:
|
||||
embed = self.embeds.NOT_PLAYING()
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
from discord.ext.commands import Context
|
||||
from discord import Client
|
||||
from Handlers.AbstractHandler import AbstractHandler
|
||||
from Handlers.HandlerResponse import HandlerResponse
|
||||
from Music.VulkanBot import VulkanBot
|
||||
from Utils.Cleaner import Cleaner
|
||||
from Parallelism.ProcessManager import ProcessManager
|
||||
from typing import Union
|
||||
from discord import Interaction
|
||||
|
||||
|
||||
class NowPlayingHandler(AbstractHandler):
|
||||
def __init__(self, ctx: Context, bot: Client) -> None:
|
||||
def __init__(self, ctx: Union[Context, Interaction], bot: VulkanBot) -> None:
|
||||
super().__init__(ctx, bot)
|
||||
self.__cleaner = Cleaner()
|
||||
|
||||
async def run(self) -> HandlerResponse:
|
||||
# Get the current process of the guild
|
||||
processManager = ProcessManager()
|
||||
processManager = self.config.getProcessManager()
|
||||
processInfo = processManager.getRunningPlayerInfo(self.guild)
|
||||
if not processInfo:
|
||||
embed = self.embeds.NOT_PLAYING()
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
from discord.ext.commands import Context
|
||||
from discord import Client
|
||||
from Handlers.AbstractHandler import AbstractHandler
|
||||
from Handlers.HandlerResponse import HandlerResponse
|
||||
from Parallelism.ProcessManager import ProcessManager
|
||||
from Parallelism.Commands import VCommands, VCommandsType
|
||||
from Music.VulkanBot import VulkanBot
|
||||
from typing import Union
|
||||
from discord import Interaction
|
||||
|
||||
|
||||
class PauseHandler(AbstractHandler):
|
||||
def __init__(self, ctx: Context, bot: Client) -> None:
|
||||
def __init__(self, ctx: Union[Context, Interaction], bot: VulkanBot) -> None:
|
||||
super().__init__(ctx, bot)
|
||||
|
||||
async def run(self) -> HandlerResponse:
|
||||
processManager = ProcessManager()
|
||||
processManager = self.config.getProcessManager()
|
||||
processInfo = processManager.getRunningPlayerInfo(self.guild)
|
||||
if processInfo:
|
||||
# Send Pause command to be execute by player process
|
||||
command = VCommands(VCommandsType.PAUSE, None)
|
||||
queue = processInfo.getQueue()
|
||||
queue = processInfo.getQueueToPlayer()
|
||||
queue.put(command)
|
||||
|
||||
return HandlerResponse(self.ctx)
|
||||
|
||||
@@ -2,20 +2,21 @@ import asyncio
|
||||
from typing import List
|
||||
from Config.Exceptions import DownloadingError, InvalidInput, VulkanError
|
||||
from discord.ext.commands import Context
|
||||
from discord import Client
|
||||
from Handlers.AbstractHandler import AbstractHandler
|
||||
from Config.Exceptions import ImpossibleMove, UnknownError
|
||||
from Handlers.HandlerResponse import HandlerResponse
|
||||
from Music.Downloader import Downloader
|
||||
from Music.Searcher import Searcher
|
||||
from Music.Song import Song
|
||||
from Parallelism.ProcessManager import ProcessManager
|
||||
from Parallelism.ProcessInfo import ProcessInfo
|
||||
from Parallelism.Commands import VCommands, VCommandsType
|
||||
from Music.VulkanBot import VulkanBot
|
||||
from typing import Union
|
||||
from discord import Interaction
|
||||
|
||||
|
||||
class PlayHandler(AbstractHandler):
|
||||
def __init__(self, ctx: Context, bot: Client) -> None:
|
||||
def __init__(self, ctx: Union[Context, Interaction], bot: VulkanBot) -> None:
|
||||
super().__init__(ctx, bot)
|
||||
self.__searcher = Searcher()
|
||||
self.__down = Downloader()
|
||||
@@ -36,7 +37,7 @@ class PlayHandler(AbstractHandler):
|
||||
raise InvalidInput(self.messages.INVALID_INPUT, self.messages.ERROR_TITLE)
|
||||
|
||||
# Get the process context for the current guild
|
||||
processManager = ProcessManager()
|
||||
processManager = self.config.getProcessManager()
|
||||
processInfo = processManager.getPlayerInfo(self.guild, self.ctx)
|
||||
playlist = processInfo.getPlaylist()
|
||||
process = processInfo.getProcess()
|
||||
@@ -72,7 +73,7 @@ class PlayHandler(AbstractHandler):
|
||||
playlist.add_song(song)
|
||||
# Release the acquired Lock
|
||||
processLock.release()
|
||||
queue = processInfo.getQueue()
|
||||
queue = processInfo.getQueueToPlayer()
|
||||
playCommand = VCommands(VCommandsType.PLAY, None)
|
||||
queue.put(playCommand)
|
||||
else:
|
||||
@@ -104,7 +105,7 @@ class PlayHandler(AbstractHandler):
|
||||
|
||||
async def __downloadSongsAndStore(self, songs: List[Song], processInfo: ProcessInfo) -> None:
|
||||
playlist = processInfo.getPlaylist()
|
||||
queue = processInfo.getQueue()
|
||||
queue = processInfo.getQueueToPlayer()
|
||||
playCommand = VCommands(VCommandsType.PLAY, None)
|
||||
# Trigger a task for each song to be downloaded
|
||||
tasks: List[asyncio.Task] = []
|
||||
@@ -113,7 +114,7 @@ class PlayHandler(AbstractHandler):
|
||||
tasks.append(task)
|
||||
|
||||
# In the original order, await for the task and then if successfully downloaded add in the playlist
|
||||
processManager = ProcessManager()
|
||||
processManager = self.config.getProcessManager()
|
||||
for index, task in enumerate(tasks):
|
||||
await task
|
||||
song = songs[index]
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
from discord.ext.commands import Context
|
||||
from discord import Client
|
||||
from Handlers.AbstractHandler import AbstractHandler
|
||||
from Config.Exceptions import BadCommandUsage, ImpossibleMove
|
||||
from Handlers.HandlerResponse import HandlerResponse
|
||||
from Parallelism.ProcessManager import ProcessManager
|
||||
from Parallelism.Commands import VCommands, VCommandsType
|
||||
from Music.VulkanBot import VulkanBot
|
||||
from typing import Union
|
||||
from discord import Interaction
|
||||
|
||||
|
||||
class PrevHandler(AbstractHandler):
|
||||
def __init__(self, ctx: Context, bot: Client) -> None:
|
||||
def __init__(self, ctx: Union[Context, Interaction], bot: VulkanBot) -> None:
|
||||
super().__init__(ctx, bot)
|
||||
|
||||
async def run(self) -> HandlerResponse:
|
||||
processManager = ProcessManager()
|
||||
processManager = self.config.getProcessManager()
|
||||
processInfo = processManager.getPlayerInfo(self.guild, self.ctx)
|
||||
if not processInfo:
|
||||
embed = self.embeds.NOT_PLAYING()
|
||||
@@ -41,13 +42,13 @@ class PrevHandler(AbstractHandler):
|
||||
process.start()
|
||||
|
||||
# Send a prev command, together with the user voice channel
|
||||
prevCommand = VCommands(VCommandsType.PREV, self.ctx.author.voice.channel.id)
|
||||
queue = processInfo.getQueue()
|
||||
prevCommand = VCommands(VCommandsType.PREV, self.author.voice.channel.id)
|
||||
queue = processInfo.getQueueToPlayer()
|
||||
queue.put(prevCommand)
|
||||
return HandlerResponse(self.ctx)
|
||||
|
||||
def __user_connected(self) -> bool:
|
||||
if self.ctx.author.voice:
|
||||
if self.author.voice:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
from discord.ext.commands import Context
|
||||
from discord import Client
|
||||
from Handlers.AbstractHandler import AbstractHandler
|
||||
from Handlers.HandlerResponse import HandlerResponse
|
||||
from Music.Downloader import Downloader
|
||||
from Utils.Utils import Utils
|
||||
from Parallelism.ProcessManager import ProcessManager
|
||||
from Music.VulkanBot import VulkanBot
|
||||
from typing import Union
|
||||
from discord import Interaction
|
||||
|
||||
|
||||
class QueueHandler(AbstractHandler):
|
||||
def __init__(self, ctx: Context, bot: Client) -> None:
|
||||
def __init__(self, ctx: Union[Context, Interaction], bot: VulkanBot) -> None:
|
||||
super().__init__(ctx, bot)
|
||||
self.__down = Downloader()
|
||||
|
||||
async def run(self) -> HandlerResponse:
|
||||
# Retrieve the process of the guild
|
||||
processManager = ProcessManager()
|
||||
processManager = self.config.getProcessManager()
|
||||
processInfo = processManager.getRunningPlayerInfo(self.guild)
|
||||
if not processInfo: # If no process return empty list
|
||||
embed = self.embeds.EMPTY_QUEUE()
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
from typing import Union
|
||||
from discord.ext.commands import Context
|
||||
from discord import Client
|
||||
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 Parallelism.ProcessManager import ProcessManager
|
||||
from Music.VulkanBot import VulkanBot
|
||||
from typing import Union
|
||||
from discord import Interaction
|
||||
|
||||
|
||||
class RemoveHandler(AbstractHandler):
|
||||
def __init__(self, ctx: Context, bot: Client) -> None:
|
||||
def __init__(self, ctx: Union[Context, Interaction], bot: VulkanBot) -> None:
|
||||
super().__init__(ctx, bot)
|
||||
|
||||
async def run(self, position: str) -> HandlerResponse:
|
||||
# Get the current process of the guild
|
||||
processManager = ProcessManager()
|
||||
processManager = self.config.getProcessManager()
|
||||
processInfo = processManager.getRunningPlayerInfo(self.guild)
|
||||
if not processInfo:
|
||||
# Clear the playlist
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
from discord.ext.commands import Context
|
||||
from discord import Client
|
||||
from Handlers.AbstractHandler import AbstractHandler
|
||||
from Handlers.HandlerResponse import HandlerResponse
|
||||
from Parallelism.ProcessManager import ProcessManager
|
||||
from Parallelism.Commands import VCommands, VCommandsType
|
||||
from Music.VulkanBot import VulkanBot
|
||||
from typing import Union
|
||||
from discord import Interaction
|
||||
|
||||
|
||||
class ResetHandler(AbstractHandler):
|
||||
def __init__(self, ctx: Context, bot: Client) -> None:
|
||||
def __init__(self, ctx: Union[Context, Interaction], bot: VulkanBot) -> None:
|
||||
super().__init__(ctx, bot)
|
||||
|
||||
async def run(self) -> HandlerResponse:
|
||||
# Get the current process of the guild
|
||||
processManager = ProcessManager()
|
||||
processManager = self.config.getProcessManager()
|
||||
processInfo = processManager.getRunningPlayerInfo(self.guild)
|
||||
if processInfo:
|
||||
command = VCommands(VCommandsType.RESET, None)
|
||||
queue = processInfo.getQueue()
|
||||
queue = processInfo.getQueueToPlayer()
|
||||
queue.put(command)
|
||||
|
||||
return HandlerResponse(self.ctx)
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
from discord.ext.commands import Context
|
||||
from discord import Client
|
||||
from Handlers.AbstractHandler import AbstractHandler
|
||||
from Handlers.HandlerResponse import HandlerResponse
|
||||
from Parallelism.ProcessManager import ProcessManager
|
||||
from Parallelism.Commands import VCommands, VCommandsType
|
||||
from Music.VulkanBot import VulkanBot
|
||||
from typing import Union
|
||||
from discord import Interaction
|
||||
|
||||
|
||||
class ResumeHandler(AbstractHandler):
|
||||
def __init__(self, ctx: Context, bot: Client) -> None:
|
||||
def __init__(self, ctx: Union[Context, Interaction], bot: VulkanBot) -> None:
|
||||
super().__init__(ctx, bot)
|
||||
|
||||
async def run(self) -> HandlerResponse:
|
||||
processManager = ProcessManager()
|
||||
processManager = self.config.getProcessManager()
|
||||
processInfo = processManager.getRunningPlayerInfo(self.guild)
|
||||
if processInfo:
|
||||
# Send Resume command to be execute by player process
|
||||
command = VCommands(VCommandsType.RESUME, None)
|
||||
queue = processInfo.getQueue()
|
||||
queue = processInfo.getQueueToPlayer()
|
||||
queue.put(command)
|
||||
|
||||
return HandlerResponse(self.ctx)
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
from discord.ext.commands import Context
|
||||
from discord import Client
|
||||
from Handlers.AbstractHandler import AbstractHandler
|
||||
from Handlers.HandlerResponse import HandlerResponse
|
||||
from Config.Exceptions import UnknownError
|
||||
from Parallelism.ProcessManager import ProcessManager
|
||||
from Music.VulkanBot import VulkanBot
|
||||
from typing import Union
|
||||
from discord import Interaction
|
||||
|
||||
|
||||
class ShuffleHandler(AbstractHandler):
|
||||
def __init__(self, ctx: Context, bot: Client) -> None:
|
||||
def __init__(self, ctx: Union[Context, Interaction], bot: VulkanBot) -> None:
|
||||
super().__init__(ctx, bot)
|
||||
|
||||
async def run(self) -> HandlerResponse:
|
||||
processManager = ProcessManager()
|
||||
processManager = self.config.getProcessManager()
|
||||
processInfo = processManager.getRunningPlayerInfo(self.guild)
|
||||
if processInfo:
|
||||
try:
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
from discord.ext.commands import Context
|
||||
from discord import Client
|
||||
from Handlers.AbstractHandler import AbstractHandler
|
||||
from Config.Exceptions import BadCommandUsage
|
||||
from Handlers.HandlerResponse import HandlerResponse
|
||||
from Parallelism.ProcessManager import ProcessManager
|
||||
from Music.VulkanBot import VulkanBot
|
||||
from Parallelism.Commands import VCommands, VCommandsType
|
||||
from typing import Union
|
||||
from discord import Interaction
|
||||
|
||||
|
||||
class SkipHandler(AbstractHandler):
|
||||
def __init__(self, ctx: Context, bot: Client) -> None:
|
||||
def __init__(self, ctx: Union[Context, Interaction], bot: VulkanBot) -> None:
|
||||
super().__init__(ctx, bot)
|
||||
|
||||
async def run(self) -> HandlerResponse:
|
||||
processManager = ProcessManager()
|
||||
processManager = self.config.getProcessManager()
|
||||
processInfo = processManager.getRunningPlayerInfo(self.guild)
|
||||
if processInfo: # Verify if there is a running process
|
||||
playlist = processInfo.getPlaylist()
|
||||
@@ -23,7 +24,7 @@ class SkipHandler(AbstractHandler):
|
||||
|
||||
# Send a command to the player process to skip the music
|
||||
command = VCommands(VCommandsType.SKIP, None)
|
||||
queue = processInfo.getQueue()
|
||||
queue = processInfo.getQueueToPlayer()
|
||||
queue.put(command)
|
||||
|
||||
return HandlerResponse(self.ctx)
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
from discord.ext.commands import Context
|
||||
from discord import Client
|
||||
from Handlers.AbstractHandler import AbstractHandler
|
||||
from Handlers.HandlerResponse import HandlerResponse
|
||||
from Parallelism.ProcessManager import ProcessManager
|
||||
from Music.VulkanBot import VulkanBot
|
||||
from Parallelism.Commands import VCommands, VCommandsType
|
||||
from typing import Union
|
||||
from discord import Interaction
|
||||
|
||||
|
||||
class StopHandler(AbstractHandler):
|
||||
def __init__(self, ctx: Context, bot: Client) -> None:
|
||||
def __init__(self, ctx: Union[Context, Interaction], bot: VulkanBot) -> None:
|
||||
super().__init__(ctx, bot)
|
||||
|
||||
async def run(self) -> HandlerResponse:
|
||||
processManager = ProcessManager()
|
||||
processManager = self.config.getProcessManager()
|
||||
processInfo = processManager.getRunningPlayerInfo(self.guild)
|
||||
if processInfo:
|
||||
# Send command to player process stop
|
||||
command = VCommands(VCommandsType.STOP, None)
|
||||
queue = processInfo.getQueue()
|
||||
queue = processInfo.getQueueToPlayer()
|
||||
queue.put(command)
|
||||
|
||||
return HandlerResponse(self.ctx)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import asyncio
|
||||
from typing import List
|
||||
from Config.Configs import Configs
|
||||
from Config.Configs import VConfigs
|
||||
from yt_dlp import YoutubeDL, DownloadError
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from Music.Song import Song
|
||||
@@ -9,7 +9,7 @@ from Config.Exceptions import DownloadingError
|
||||
|
||||
|
||||
class Downloader:
|
||||
config = Configs()
|
||||
config = VConfigs()
|
||||
__YDL_OPTIONS = {'format': 'bestaudio/best',
|
||||
'default_search': 'auto',
|
||||
'playliststart': 0,
|
||||
@@ -34,7 +34,7 @@ class Downloader:
|
||||
__BASE_URL = 'https://www.youtube.com/watch?v={}'
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.__config = Configs()
|
||||
self.__config = VConfigs()
|
||||
self.__music_keys_only = ['resolution', 'fps', 'quality']
|
||||
self.__not_extracted_keys_only = ['ie_key']
|
||||
self.__not_extracted_not_keys = ['entries']
|
||||
|
||||
65
Music/MessagesController.py
Normal file
65
Music/MessagesController.py
Normal file
@@ -0,0 +1,65 @@
|
||||
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
|
||||
@@ -1,6 +1,6 @@
|
||||
from collections import deque
|
||||
from typing import List
|
||||
from Config.Configs import Configs
|
||||
from Config.Configs import VConfigs
|
||||
from Music.Song import Song
|
||||
import random
|
||||
|
||||
@@ -8,7 +8,7 @@ import random
|
||||
class Playlist:
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.__configs = Configs()
|
||||
self.__configs = VConfigs()
|
||||
self.__queue = deque() # Store the musics to play
|
||||
self.__songs_history = deque() # Store the musics played
|
||||
|
||||
@@ -62,7 +62,7 @@ class Playlist:
|
||||
# Att played song info
|
||||
if played_song != None:
|
||||
if not self.__looping_one and not self.__looping_all:
|
||||
if played_song.problematic == False:
|
||||
if not played_song.problematic:
|
||||
self.__songs_history.appendleft(played_song)
|
||||
|
||||
if len(self.__songs_history) > self.__configs.MAX_SONGS_HISTORY:
|
||||
|
||||
@@ -2,14 +2,14 @@ from spotipy import Spotify
|
||||
from spotipy.oauth2 import SpotifyClientCredentials
|
||||
from spotipy.exceptions import SpotifyException
|
||||
from Config.Exceptions import SpotifyError
|
||||
from Config.Configs import Configs
|
||||
from Config.Configs import VConfigs
|
||||
from Config.Messages import SpotifyMessages
|
||||
|
||||
|
||||
class SpotifySearch():
|
||||
def __init__(self) -> None:
|
||||
self.__messages = SpotifyMessages()
|
||||
self.__config = Configs()
|
||||
self.__config = VConfigs()
|
||||
self.__connected = False
|
||||
self.__connect()
|
||||
|
||||
|
||||
73
Music/VulkanBot.py
Normal file
73
Music/VulkanBot.py
Normal file
@@ -0,0 +1,73 @@
|
||||
from asyncio import AbstractEventLoop
|
||||
from discord import Guild, Status, Game, Message
|
||||
from discord.ext.commands.errors import CommandNotFound, MissingRequiredArgument
|
||||
from Config.Configs import VConfigs
|
||||
from discord.ext.commands import Bot, Context
|
||||
from Config.Messages import Messages
|
||||
from Config.Embeds import VEmbeds
|
||||
|
||||
|
||||
class VulkanBot(Bot):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.__configs = VConfigs()
|
||||
self.__messages = Messages()
|
||||
self.__embeds = VEmbeds()
|
||||
self.remove_command("help")
|
||||
|
||||
def startBot(self) -> None:
|
||||
"""Blocking function that will start the bot"""
|
||||
if self.__configs.BOT_TOKEN == '':
|
||||
print('DEVELOPER NOTE -> Token not found')
|
||||
exit()
|
||||
|
||||
super().run(self.__configs.BOT_TOKEN, reconnect=True)
|
||||
|
||||
async def startBotCoro(self, loop: AbstractEventLoop) -> None:
|
||||
"""Start a bot coroutine, does not wait for connection to be established"""
|
||||
task = loop.create_task(self.__login())
|
||||
await task
|
||||
loop.create_task(self.__connect())
|
||||
|
||||
async def __login(self):
|
||||
"""Coroutine to login the Bot in discord"""
|
||||
await self.login(token=self.__configs.BOT_TOKEN)
|
||||
|
||||
async def __connect(self):
|
||||
"""Coroutine to connect the Bot in discord"""
|
||||
await self.connect(reconnect=True)
|
||||
|
||||
async def on_ready(self):
|
||||
print(self.__messages.STARTUP_MESSAGE)
|
||||
await self.change_presence(status=Status.online, activity=Game(name=f"Vulkan | {self.__configs.BOT_PREFIX}help"))
|
||||
print(self.__messages.STARTUP_COMPLETE_MESSAGE)
|
||||
|
||||
async def on_command_error(self, ctx, error):
|
||||
if isinstance(error, MissingRequiredArgument):
|
||||
embed = self.__embeds.MISSING_ARGUMENTS()
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
elif isinstance(error, CommandNotFound):
|
||||
embed = self.__embeds.COMMAND_NOT_FOUND()
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
else:
|
||||
print(f'DEVELOPER NOTE -> Command Error: {error}')
|
||||
embed = self.__embeds.UNKNOWN_ERROR()
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
async def process_commands(self, message: Message):
|
||||
if message.author.bot:
|
||||
return
|
||||
|
||||
ctx = await self.get_context(message, cls=Context)
|
||||
|
||||
if ctx.valid and not message.guild:
|
||||
return
|
||||
|
||||
await self.invoke(ctx)
|
||||
|
||||
|
||||
class Context(Context):
|
||||
bot: VulkanBot
|
||||
guild: Guild
|
||||
55
Music/VulkanInitializer.py
Normal file
55
Music/VulkanInitializer.py
Normal file
@@ -0,0 +1,55 @@
|
||||
from random import choices
|
||||
import string
|
||||
from discord.bot import Bot
|
||||
from discord import Intents
|
||||
from Music.VulkanBot import VulkanBot
|
||||
from os import listdir
|
||||
from Config.Configs import VConfigs
|
||||
from Config.Exceptions import VulkanError
|
||||
|
||||
|
||||
class VulkanInitializer:
|
||||
def __init__(self, willListen: bool) -> None:
|
||||
self.__config = VConfigs()
|
||||
self.__intents = Intents.default()
|
||||
self.__intents.message_content = True
|
||||
self.__intents.members = True
|
||||
self.__bot = self.__create_bot(willListen)
|
||||
self.__add_cogs(self.__bot)
|
||||
|
||||
def getBot(self) -> VulkanBot:
|
||||
return self.__bot
|
||||
|
||||
def __create_bot(self, willListen: bool) -> VulkanBot:
|
||||
if willListen:
|
||||
prefix = self.__config.BOT_PREFIX
|
||||
else:
|
||||
prefix = ''.join(choices(string.ascii_uppercase + string.digits, k=4))
|
||||
|
||||
bot = VulkanBot(command_prefix=prefix,
|
||||
pm_help=True,
|
||||
case_insensitive=True,
|
||||
intents=self.__intents)
|
||||
return bot
|
||||
|
||||
def __add_cogs(self, bot: Bot) -> None:
|
||||
try:
|
||||
cogsStatus = []
|
||||
for filename in listdir(f'./{self.__config.COMMANDS_PATH}'):
|
||||
if filename.endswith('.py'):
|
||||
cogPath = f'{self.__config.COMMANDS_PATH}.{filename[:-3]}'
|
||||
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:
|
||||
print(f'[Error Loading Vulkan] -> {e.message}')
|
||||
|
||||
def __getTotalCogs(self) -> int:
|
||||
quant = 0
|
||||
for filename in listdir(f'./{self.__config.COMMANDS_PATH}'):
|
||||
if filename.endswith('.py'):
|
||||
quant += 1
|
||||
return quant
|
||||
@@ -11,6 +11,9 @@ class VCommandsType(Enum):
|
||||
PLAY = 'Play'
|
||||
STOP = 'Stop'
|
||||
RESET = 'Reset'
|
||||
NOW_PLAYING = 'Now Playing'
|
||||
TERMINATE = 'Terminate'
|
||||
SLEEPING = 'Sleeping'
|
||||
|
||||
|
||||
class VCommands:
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import asyncio
|
||||
from os import listdir
|
||||
from discord import Intents, User, Member, Message, Embed
|
||||
from asyncio import AbstractEventLoop, Semaphore
|
||||
from multiprocessing import Process, Queue, RLock
|
||||
from threading import Lock, Thread
|
||||
from Music.VulkanInitializer import VulkanInitializer
|
||||
from discord import User, Member, Message
|
||||
from asyncio import AbstractEventLoop, Semaphore, Queue
|
||||
from multiprocessing import Process, RLock, Lock, Queue
|
||||
from threading import Thread
|
||||
from typing import Callable, List
|
||||
from discord import Client, Guild, FFmpegPCMAudio, VoiceChannel, TextChannel
|
||||
from discord import Guild, FFmpegPCMAudio, VoiceChannel, TextChannel
|
||||
from Music.Playlist import Playlist
|
||||
from Music.Song import Song
|
||||
from Config.Configs import Configs
|
||||
from Config.Configs import VConfigs
|
||||
from Config.Messages import Messages
|
||||
from discord.ext.commands import Bot
|
||||
from Views.Embeds import Embeds
|
||||
from Music.VulkanBot import VulkanBot
|
||||
from Config.Embeds import VEmbeds
|
||||
from Parallelism.Commands import VCommands, VCommandsType
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ class TimeoutClock:
|
||||
self.__task = loop.create_task(self.__executor())
|
||||
|
||||
async def __executor(self):
|
||||
await asyncio.sleep(Configs().VC_TIMEOUT)
|
||||
await asyncio.sleep(VConfigs().VC_TIMEOUT)
|
||||
await self.__callback()
|
||||
|
||||
def cancel(self):
|
||||
@@ -31,7 +31,7 @@ class TimeoutClock:
|
||||
class PlayerProcess(Process):
|
||||
"""Process that will play songs, receive commands from the main process by a Queue"""
|
||||
|
||||
def __init__(self, name: str, playlist: Playlist, lock: Lock, queue: Queue, guildID: int, textID: int, voiceID: int, authorID: int) -> None:
|
||||
def __init__(self, name: str, playlist: Playlist, lock: Lock, queueToReceive: Queue, queueToSend: Queue, guildID: int, textID: int, voiceID: int, authorID: int) -> None:
|
||||
"""
|
||||
Start a new process that will have his own bot instance
|
||||
Due to pickle serialization, no objects are stored, the values initialization are being made in the run method
|
||||
@@ -40,7 +40,8 @@ class PlayerProcess(Process):
|
||||
# Synchronization objects
|
||||
self.__playlist: Playlist = playlist
|
||||
self.__playlistLock: Lock = lock
|
||||
self.__queue: Queue = queue
|
||||
self.__queueReceive: Queue = queueToReceive
|
||||
self.__queueSend: Queue = queueToSend
|
||||
self.__semStopPlaying: Semaphore = None
|
||||
self.__loop: AbstractEventLoop = None
|
||||
# Discord context ID
|
||||
@@ -50,14 +51,14 @@ class PlayerProcess(Process):
|
||||
self.__authorID = authorID
|
||||
# All information of discord context will be retrieved directly with discord API
|
||||
self.__guild: Guild = None
|
||||
self.__bot: Client = None
|
||||
self.__bot: VulkanBot = None
|
||||
self.__voiceChannel: VoiceChannel = None
|
||||
self.__textChannel: TextChannel = None
|
||||
self.__author: User = None
|
||||
self.__botMember: Member = None
|
||||
|
||||
self.__configs: Configs = None
|
||||
self.__embeds: Embeds = None
|
||||
self.__configs: VConfigs = None
|
||||
self.__embeds: VEmbeds = None
|
||||
self.__messages: Messages = None
|
||||
self.__messagesToDelete: List[Message] = []
|
||||
self.__playing = False
|
||||
@@ -70,11 +71,12 @@ class PlayerProcess(Process):
|
||||
try:
|
||||
print(f'Starting Process {self.name}')
|
||||
self.__playerLock = RLock()
|
||||
self.__loop = asyncio.get_event_loop()
|
||||
self.__loop = asyncio.get_event_loop_policy().new_event_loop()
|
||||
asyncio.set_event_loop(self.__loop)
|
||||
|
||||
self.__configs = Configs()
|
||||
self.__configs = VConfigs()
|
||||
self.__messages = Messages()
|
||||
self.__embeds = Embeds()
|
||||
self.__embeds = VEmbeds()
|
||||
|
||||
self.__semStopPlaying = Semaphore(0)
|
||||
self.__loop.run_until_complete(self._run())
|
||||
@@ -107,9 +109,13 @@ class PlayerProcess(Process):
|
||||
self.__timer.cancel()
|
||||
|
||||
async def __playPlaylistSongs(self) -> None:
|
||||
"""If the player is not running trigger to play a new song"""
|
||||
if not self.__playing:
|
||||
song = None
|
||||
with self.__playlistLock:
|
||||
song = self.__playlist.next_song()
|
||||
with self.__playerLock:
|
||||
if not (self.__guild.voice_client.is_playing() or self.__guild.voice_client.is_paused()):
|
||||
song = self.__playlist.next_song()
|
||||
|
||||
if song is not None:
|
||||
self.__loop.create_task(self.__playSong(song), name=f'Song {song.identifier}')
|
||||
@@ -141,8 +147,8 @@ class PlayerProcess(Process):
|
||||
self.__timer.cancel()
|
||||
self.__timer = TimeoutClock(self.__timeoutHandler, self.__loop)
|
||||
|
||||
await self.__deletePrevNowPlaying()
|
||||
await self.__showNowPlaying()
|
||||
nowPlayingCommand = VCommands(VCommandsType.NOW_PLAYING, song)
|
||||
self.__queueSend.put(nowPlayingCommand)
|
||||
except Exception as e:
|
||||
print(f'[ERROR IN PLAY SONG] -> {e}, {type(e)}')
|
||||
self.__playNext(None)
|
||||
@@ -150,44 +156,49 @@ class PlayerProcess(Process):
|
||||
self.__playerLock.release()
|
||||
|
||||
def __playNext(self, error) -> None:
|
||||
with self.__playerLock:
|
||||
if self.__forceStop: # If it's forced to stop player
|
||||
self.__forceStop = False
|
||||
return None
|
||||
with self.__playlistLock:
|
||||
with self.__playerLock:
|
||||
if self.__forceStop: # If it's forced to stop player
|
||||
self.__forceStop = False
|
||||
return None
|
||||
|
||||
with self.__playlistLock:
|
||||
song = self.__playlist.next_song()
|
||||
|
||||
if song is not None:
|
||||
self.__loop.create_task(self.__playSong(song), name=f'Song {song.identifier}')
|
||||
else:
|
||||
with self.__playlistLock:
|
||||
if song is not None:
|
||||
self.__loop.create_task(self.__playSong(song), name=f'Song {song.identifier}')
|
||||
else:
|
||||
self.__playlist.loop_off()
|
||||
self.__playingSong = None
|
||||
self.__playing = False
|
||||
self.__playingSong = None
|
||||
self.__playing = False
|
||||
# Send a command to the main process put this one to sleep
|
||||
sleepCommand = VCommands(VCommandsType.SLEEPING)
|
||||
self.__queueSend.put(sleepCommand)
|
||||
# Release the semaphore to finish the process
|
||||
self.__semStopPlaying.release()
|
||||
|
||||
async def __playPrev(self, voiceChannelID: int) -> None:
|
||||
with self.__playlistLock:
|
||||
song = self.__playlist.prev_song()
|
||||
|
||||
if song is not None:
|
||||
if self.__guild.voice_client is None: # If not connect, connect to the user voice channel
|
||||
self.__voiceChannelID = voiceChannelID
|
||||
self.__voiceChannel = self.__guild.get_channel(self.__voiceChannelID)
|
||||
await self.__connectToVoiceChannel()
|
||||
with self.__playerLock:
|
||||
if song is not None:
|
||||
if self.__guild.voice_client is None: # If not connect, connect to the user voice channel
|
||||
self.__voiceChannelID = voiceChannelID
|
||||
self.__voiceChannel = self.__guild.get_channel(self.__voiceChannelID)
|
||||
await self.__connectToVoiceChannel()
|
||||
|
||||
# If already playing, stop the current play
|
||||
if self.__guild.voice_client.is_playing() or self.__guild.voice_client.is_paused():
|
||||
# Will forbidden next_song to execute after stopping current player
|
||||
self.__forceStop = True
|
||||
self.__guild.voice_client.stop()
|
||||
self.__playing = False
|
||||
# If already playing, stop the current play
|
||||
if self.__guild.voice_client.is_playing() or self.__guild.voice_client.is_paused():
|
||||
# Will forbidden next_song to execute after stopping current player
|
||||
self.__forceStop = True
|
||||
self.__guild.voice_client.stop()
|
||||
self.__playing = False
|
||||
|
||||
self.__loop.create_task(self.__playSong(song), name=f'Song {song.identifier}')
|
||||
self.__loop.create_task(self.__playSong(song), name=f'Song {song.identifier}')
|
||||
|
||||
def __commandsReceiver(self) -> None:
|
||||
while True:
|
||||
command: VCommands = self.__queue.get()
|
||||
command: VCommands = self.__queueReceive.get()
|
||||
type = command.getType()
|
||||
args = command.getArgs()
|
||||
|
||||
@@ -235,9 +246,11 @@ class PlayerProcess(Process):
|
||||
if self.__guild.voice_client is not None:
|
||||
if self.__guild.voice_client.is_connected():
|
||||
with self.__playlistLock:
|
||||
self.__playlist.clear()
|
||||
self.__playlist.loop_off()
|
||||
|
||||
# Send a command to the main process put this to sleep
|
||||
sleepCommand = VCommands(VCommandsType.SLEEPING)
|
||||
self.__queueSend.put(sleepCommand)
|
||||
self.__guild.voice_client.stop()
|
||||
self.__playingSong = None
|
||||
await self.__guild.voice_client.disconnect()
|
||||
@@ -269,30 +282,13 @@ class PlayerProcess(Process):
|
||||
self.__playlist.clear()
|
||||
self.__playlist.loop_off()
|
||||
|
||||
async def __createBotInstance(self) -> Client:
|
||||
"""Load a new bot instance that should not be directly called.
|
||||
Get the guild, voice and text Channel in discord API using IDs passed in constructor
|
||||
"""
|
||||
intents = Intents.default()
|
||||
intents.members = True
|
||||
bot = Bot(command_prefix='Rafael',
|
||||
pm_help=True,
|
||||
case_insensitive=True,
|
||||
intents=intents)
|
||||
bot.remove_command('help')
|
||||
async def __createBotInstance(self) -> VulkanBot:
|
||||
"""Load a new bot instance that should not be directly called."""
|
||||
initializer = VulkanInitializer(willListen=False)
|
||||
bot = initializer.getBot()
|
||||
|
||||
# Add the Cogs for this bot too
|
||||
for filename in listdir(f'./{self.__configs.COMMANDS_PATH}'):
|
||||
if filename.endswith('.py'):
|
||||
bot.load_extension(f'{self.__configs.COMMANDS_PATH}.{filename[:-3]}')
|
||||
|
||||
# Login and connect the bot instance to discord API
|
||||
task = self.__loop.create_task(bot.login(token=self.__configs.BOT_TOKEN, bot=True))
|
||||
await task
|
||||
self.__loop.create_task(bot.connect(reconnect=True))
|
||||
# Sleep to wait connection to be established
|
||||
await bot.startBotCoro(self.__loop)
|
||||
await self.__ensureDiscordConnection(bot)
|
||||
|
||||
return bot
|
||||
|
||||
async def __timeoutHandler(self) -> None:
|
||||
@@ -301,21 +297,36 @@ class PlayerProcess(Process):
|
||||
return
|
||||
|
||||
if self.__guild.voice_client.is_playing() or self.__guild.voice_client.is_paused():
|
||||
self.__timer = TimeoutClock(self.__timeoutHandler, self.__loop)
|
||||
if not self.__isBotAloneInChannel(): # If bot is not alone continue to play
|
||||
self.__timer = TimeoutClock(self.__timeoutHandler, self.__loop)
|
||||
return
|
||||
|
||||
elif self.__guild.voice_client.is_connected():
|
||||
# Finish the process
|
||||
if self.__guild.voice_client.is_connected():
|
||||
with self.__playerLock:
|
||||
with self.__playlistLock:
|
||||
self.__playlist.clear()
|
||||
self.__playlist.loop_off()
|
||||
self.__playing = False
|
||||
await self.__guild.voice_client.disconnect()
|
||||
# Send command to main process to finish this one
|
||||
sleepCommand = VCommands(VCommandsType.SLEEPING)
|
||||
self.__queueSend.put(sleepCommand)
|
||||
# Release semaphore to finish process
|
||||
self.__semStopPlaying.release()
|
||||
except Exception as e:
|
||||
print(f'[Error in Timeout] -> {e}')
|
||||
|
||||
async def __ensureDiscordConnection(self, bot: Client) -> None:
|
||||
def __isBotAloneInChannel(self) -> bool:
|
||||
try:
|
||||
if len(self.__guild.voice_client.channel.members) <= 1:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f'[ERROR IN CHECK BOT ALONE] -> {e}')
|
||||
return False
|
||||
|
||||
async def __ensureDiscordConnection(self, bot: VulkanBot) -> None:
|
||||
"""Await in this point until connection to discord is established"""
|
||||
guild = None
|
||||
while guild is None:
|
||||
@@ -335,46 +346,3 @@ class PlayerProcess(Process):
|
||||
for member in guild_members:
|
||||
if member.id == self.__bot.user.id:
|
||||
return member
|
||||
|
||||
async def __showNowPlaying(self) -> None:
|
||||
# Get the lock of the playlist
|
||||
with self.__playlistLock:
|
||||
if not self.__playing or self.__playingSong is None:
|
||||
embed = self.__embeds.NOT_PLAYING()
|
||||
await self.__textChannel.send(embed=embed)
|
||||
return
|
||||
|
||||
if self.__playlist.isLoopingOne():
|
||||
title = self.__messages.ONE_SONG_LOOPING
|
||||
else:
|
||||
title = self.__messages.SONG_PLAYING
|
||||
|
||||
info = self.__playingSong.info
|
||||
embed = self.__embeds.SONG_INFO(info, title)
|
||||
await self.__textChannel.send(embed=embed)
|
||||
self.__messagesToDelete.append(await self.__getSendedMessage())
|
||||
|
||||
async def __deletePrevNowPlaying(self) -> None:
|
||||
for message in self.__messagesToDelete:
|
||||
try:
|
||||
await message.delete()
|
||||
except:
|
||||
pass
|
||||
self.__messagesToDelete.clear()
|
||||
|
||||
async def __getSendedMessage(self) -> Message:
|
||||
stringToIdentify = 'Uploader:'
|
||||
last_messages: List[Message] = await self.__textChannel.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
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from multiprocessing import Process, Queue, Lock
|
||||
from discord import TextChannel
|
||||
from Music.Playlist import Playlist
|
||||
|
||||
|
||||
@@ -7,11 +8,13 @@ class ProcessInfo:
|
||||
Class to store the reference to all structures to maintain a player process
|
||||
"""
|
||||
|
||||
def __init__(self, process: Process, queue: Queue, playlist: Playlist, lock: Lock) -> None:
|
||||
def __init__(self, process: Process, queueToPlayer: Queue, queueToMain: Queue, playlist: Playlist, lock: Lock, textChannel: TextChannel) -> None:
|
||||
self.__process = process
|
||||
self.__queue = queue
|
||||
self.__queueToPlayer = queueToPlayer
|
||||
self.__queueToMain = queueToMain
|
||||
self.__playlist = playlist
|
||||
self.__lock = lock
|
||||
self.__textChannel = textChannel
|
||||
|
||||
def setProcess(self, newProcess: Process) -> None:
|
||||
self.__process = newProcess
|
||||
@@ -19,11 +22,17 @@ class ProcessInfo:
|
||||
def getProcess(self) -> Process:
|
||||
return self.__process
|
||||
|
||||
def getQueue(self) -> Queue:
|
||||
return self.__queue
|
||||
def getQueueToPlayer(self) -> Queue:
|
||||
return self.__queueToPlayer
|
||||
|
||||
def getQueueToMain(self) -> Queue:
|
||||
return self.__queueToMain
|
||||
|
||||
def getPlaylist(self) -> Playlist:
|
||||
return self.__playlist
|
||||
|
||||
def getLock(self) -> Lock:
|
||||
return self.__lock
|
||||
|
||||
def getTextChannel(self) -> TextChannel:
|
||||
return self.__textChannel
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
from multiprocessing import Queue, Lock
|
||||
import asyncio
|
||||
from multiprocessing import Lock, Queue
|
||||
from multiprocessing.managers import BaseManager, NamespaceProxy
|
||||
from typing import Dict
|
||||
from queue import Empty
|
||||
from threading import Thread
|
||||
from typing import Dict, Tuple, Union
|
||||
from Config.Singleton import Singleton
|
||||
from discord import Guild
|
||||
from discord import Guild, Interaction
|
||||
from discord.ext.commands import Context
|
||||
from Music.MessagesController import MessagesController
|
||||
from Music.Song import Song
|
||||
from Parallelism.PlayerProcess import PlayerProcess
|
||||
from Music.Playlist import Playlist
|
||||
from Parallelism.ProcessInfo import ProcessInfo
|
||||
from Parallelism.Commands import VCommands, VCommandsType
|
||||
from Music.VulkanBot import VulkanBot
|
||||
|
||||
|
||||
class ProcessManager(Singleton):
|
||||
@@ -16,25 +22,35 @@ class ProcessManager(Singleton):
|
||||
Deal with the creation of shared memory
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
def __init__(self, bot: VulkanBot = None) -> None:
|
||||
if not super().created:
|
||||
self.__bot = bot
|
||||
VManager.register('Playlist', Playlist)
|
||||
self.__manager = VManager()
|
||||
self.__manager.start()
|
||||
self.__playersProcess: Dict[Guild, ProcessInfo] = {}
|
||||
self.__playersListeners: Dict[Guild, Tuple[Thread, bool]] = {}
|
||||
self.__playersMessages: Dict[Guild, MessagesController] = {}
|
||||
|
||||
def setPlayerContext(self, guild: Guild, context: ProcessInfo):
|
||||
self.__playersProcess[guild.id] = context
|
||||
def setPlayerInfo(self, guild: Guild, info: ProcessInfo):
|
||||
self.__playersProcess[guild.id] = info
|
||||
|
||||
def getPlayerInfo(self, guild: Guild, context: Context) -> ProcessInfo:
|
||||
"""Return the process info for the guild, if not, create one"""
|
||||
def getPlayerInfo(self, guild: Guild, context: Union[Context, Interaction]) -> ProcessInfo:
|
||||
"""Return the process info for the guild, if not and context is a instance
|
||||
of discord.Context then create one, else return None"""
|
||||
try:
|
||||
if isinstance(context, Interaction):
|
||||
if guild.id not in self.__playersProcess.keys():
|
||||
return None
|
||||
else:
|
||||
return self.__playersProcess[guild.id]
|
||||
|
||||
if guild.id not in self.__playersProcess.keys():
|
||||
self.__playersProcess[guild.id] = self.__createProcessInfo(context)
|
||||
self.__playersProcess[guild.id] = self.__createProcessInfo(guild, context)
|
||||
else:
|
||||
# If the process has ended create a new one
|
||||
if not self.__playersProcess[guild.id].getProcess().is_alive():
|
||||
self.__playersProcess[guild.id] = self.__recreateProcess(context)
|
||||
self.__playersProcess[guild.id] = self.__recreateProcess(guild, context)
|
||||
|
||||
return self.__playersProcess[guild.id]
|
||||
except Exception as e:
|
||||
@@ -46,11 +62,11 @@ class ProcessManager(Singleton):
|
||||
return None
|
||||
|
||||
# Recreate the process keeping the playlist
|
||||
newProcessInfo = self.__recreateProcess(context)
|
||||
newProcessInfo = self.__recreateProcess(guild, context)
|
||||
newProcessInfo.getProcess().start() # Start the process
|
||||
# Send a command to start the play again
|
||||
playCommand = VCommands(VCommandsType.PLAY)
|
||||
newProcessInfo.getQueue().put(playCommand)
|
||||
newProcessInfo.getQueueToPlayer().put(playCommand)
|
||||
self.__playersProcess[guild.id] = newProcessInfo
|
||||
|
||||
def getRunningPlayerInfo(self, guild: Guild) -> ProcessInfo:
|
||||
@@ -60,7 +76,7 @@ class ProcessManager(Singleton):
|
||||
|
||||
return self.__playersProcess[guild.id]
|
||||
|
||||
def __createProcessInfo(self, context: Context) -> ProcessInfo:
|
||||
def __createProcessInfo(self, guild: Guild, context: Context) -> ProcessInfo:
|
||||
guildID: int = context.guild.id
|
||||
textID: int = context.channel.id
|
||||
voiceID: int = context.author.voice.channel.id
|
||||
@@ -68,14 +84,25 @@ class ProcessManager(Singleton):
|
||||
|
||||
playlist: Playlist = self.__manager.Playlist()
|
||||
lock = Lock()
|
||||
queue = Queue()
|
||||
process = PlayerProcess(context.guild.name, playlist, lock, queue,
|
||||
guildID, textID, voiceID, authorID)
|
||||
processInfo = ProcessInfo(process, queue, playlist, lock)
|
||||
queueToListen = Queue()
|
||||
queueToSend = Queue()
|
||||
process = PlayerProcess(context.guild.name, playlist, lock, queueToSend,
|
||||
queueToListen, guildID, textID, voiceID, authorID)
|
||||
processInfo = ProcessInfo(process, queueToSend, queueToListen,
|
||||
playlist, lock, context.channel)
|
||||
|
||||
# Create a Thread to listen for the queue coming from the Player Process, this will redirect the Queue to a async
|
||||
thread = Thread(target=self.__listenToCommands,
|
||||
args=(queueToListen, guild), daemon=True)
|
||||
self.__playersListeners[guildID] = (thread, False)
|
||||
thread.start()
|
||||
|
||||
# Create a Message Controller for this player
|
||||
self.__playersMessages[guildID] = MessagesController(self.__bot)
|
||||
|
||||
return processInfo
|
||||
|
||||
def __recreateProcess(self, context: Context) -> ProcessInfo:
|
||||
def __recreateProcess(self, guild: Guild, context: Context) -> ProcessInfo:
|
||||
"""Create a new process info using previous playlist"""
|
||||
guildID: int = context.guild.id
|
||||
textID: int = context.channel.id
|
||||
@@ -84,14 +111,74 @@ class ProcessManager(Singleton):
|
||||
|
||||
playlist: Playlist = self.__playersProcess[guildID].getPlaylist()
|
||||
lock = Lock()
|
||||
queue = Queue()
|
||||
queueToListen = Queue()
|
||||
queueToSend = Queue()
|
||||
process = PlayerProcess(context.guild.name, playlist, lock, queueToSend,
|
||||
queueToListen, guildID, textID, voiceID, authorID)
|
||||
processInfo = ProcessInfo(process, queueToSend, queueToListen,
|
||||
playlist, lock, context.channel)
|
||||
|
||||
process = PlayerProcess(context.guild.name, playlist, lock, queue,
|
||||
guildID, textID, voiceID, authorID)
|
||||
processInfo = ProcessInfo(process, queue, playlist, lock)
|
||||
# Create a Thread to listen for the queue coming from the Player Process, this will redirect the Queue to a async
|
||||
thread = Thread(target=self.__listenToCommands,
|
||||
args=(queueToListen, guild), daemon=True)
|
||||
self.__playersListeners[guildID] = (thread, False)
|
||||
thread.start()
|
||||
|
||||
return processInfo
|
||||
|
||||
def __listenToCommands(self, queue: Queue, guild: Guild) -> None:
|
||||
guildID = guild.id
|
||||
while True:
|
||||
shouldEnd = self.__playersListeners[guildID][1]
|
||||
if shouldEnd:
|
||||
break
|
||||
|
||||
try:
|
||||
command: VCommands = queue.get(timeout=5)
|
||||
commandType = command.getType()
|
||||
args = command.getArgs()
|
||||
|
||||
print(f'Process {guild.name} sended command {commandType}')
|
||||
if commandType == VCommandsType.NOW_PLAYING:
|
||||
asyncio.run_coroutine_threadsafe(self.showNowPlaying(
|
||||
guild.id, args), self.__bot.loop)
|
||||
elif commandType == VCommandsType.TERMINATE:
|
||||
# Delete the process elements and return, to finish task
|
||||
self.__terminateProcess(guildID)
|
||||
return
|
||||
elif commandType == VCommandsType.SLEEPING:
|
||||
# The process might be used again
|
||||
self.__sleepingProcess(guildID)
|
||||
return
|
||||
else:
|
||||
print(f'[ERROR] -> Unknown Command Received from Process: {commandType}')
|
||||
except Empty:
|
||||
continue
|
||||
except Exception as e:
|
||||
print(f'[ERROR IN LISTENING PROCESS] -> {guild.name} - {e}')
|
||||
|
||||
def __terminateProcess(self, guildID: int) -> None:
|
||||
# Delete all structures associated with the Player
|
||||
del self.__playersProcess[guildID]
|
||||
del self.__playersMessages[guildID]
|
||||
threadListening = self.__playersListeners[guildID]
|
||||
threadListening._stop()
|
||||
del self.__playersListeners[guildID]
|
||||
|
||||
def __sleepingProcess(self, guildID: int) -> None:
|
||||
# Disable all process structures, except Playlist
|
||||
queue1 = self.__playersProcess[guildID].getQueueToMain()
|
||||
queue2 = self.__playersProcess[guildID].getQueueToPlayer()
|
||||
queue1.close()
|
||||
queue1.join_thread()
|
||||
queue2.close()
|
||||
queue2.join_thread()
|
||||
|
||||
async def showNowPlaying(self, guildID: int, song: Song) -> None:
|
||||
messagesController = self.__playersMessages[guildID]
|
||||
processInfo = self.__playersProcess[guildID]
|
||||
await messagesController.sendNowPlaying(processInfo, song)
|
||||
|
||||
|
||||
class VManager(BaseManager):
|
||||
pass
|
||||
|
||||
22
UI/Buttons/BackButton.py
Normal file
22
UI/Buttons/BackButton.py
Normal file
@@ -0,0 +1,22 @@
|
||||
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)
|
||||
20
UI/Buttons/LoopAllButton.py
Normal file
20
UI/Buttons/LoopAllButton.py
Normal file
@@ -0,0 +1,20 @@
|
||||
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)
|
||||
20
UI/Buttons/LoopOffButton.py
Normal file
20
UI/Buttons/LoopOffButton.py
Normal file
@@ -0,0 +1,20 @@
|
||||
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)
|
||||
20
UI/Buttons/LoopOneButton.py
Normal file
20
UI/Buttons/LoopOneButton.py
Normal file
@@ -0,0 +1,20 @@
|
||||
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)
|
||||
20
UI/Buttons/PauseButton.py
Normal file
20
UI/Buttons/PauseButton.py
Normal file
@@ -0,0 +1,20 @@
|
||||
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)
|
||||
20
UI/Buttons/PlayButton.py
Normal file
20
UI/Buttons/PlayButton.py
Normal file
@@ -0,0 +1,20 @@
|
||||
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)
|
||||
20
UI/Buttons/SkipButton.py
Normal file
20
UI/Buttons/SkipButton.py
Normal file
@@ -0,0 +1,20 @@
|
||||
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)
|
||||
20
UI/Buttons/SongsButton.py
Normal file
20
UI/Buttons/SongsButton.py
Normal file
@@ -0,0 +1,20 @@
|
||||
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)
|
||||
20
UI/Buttons/StopButton.py
Normal file
20
UI/Buttons/StopButton.py
Normal file
@@ -0,0 +1,20 @@
|
||||
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,22 +1,23 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from Handlers.HandlerResponse import HandlerResponse
|
||||
from discord.ext.commands import Context
|
||||
from discord import Client, Message
|
||||
from discord import Message
|
||||
from Music.VulkanBot import VulkanBot
|
||||
|
||||
|
||||
class AbstractView(ABC):
|
||||
class AbstractCommandResponse(ABC):
|
||||
def __init__(self, response: HandlerResponse) -> None:
|
||||
self.__response: HandlerResponse = response
|
||||
self.__context: Context = response.ctx
|
||||
self.__message: Message = response.ctx.message
|
||||
self.__bot: Client = response.ctx.bot
|
||||
self.__bot: VulkanBot = response.ctx.bot
|
||||
|
||||
@property
|
||||
def response(self) -> HandlerResponse:
|
||||
return self.__response
|
||||
|
||||
@property
|
||||
def bot(self) -> Client:
|
||||
def bot(self) -> VulkanBot:
|
||||
return self.__bot
|
||||
|
||||
@property
|
||||
@@ -1,8 +1,8 @@
|
||||
from Views.AbstractView import AbstractView
|
||||
from UI.Responses.AbstractCogResponse import AbstractCommandResponse
|
||||
from Handlers.HandlerResponse import HandlerResponse
|
||||
|
||||
|
||||
class EmbedView(AbstractView):
|
||||
class EmbedCommandResponse(AbstractCommandResponse):
|
||||
def __init__(self, response: HandlerResponse) -> None:
|
||||
super().__init__(response)
|
||||
|
||||
16
UI/Responses/EmoteCogResponse.py
Normal file
16
UI/Responses/EmoteCogResponse.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from Config.Emojis import VEmojis
|
||||
from UI.Responses.AbstractCogResponse import AbstractCommandResponse
|
||||
from Handlers.HandlerResponse import HandlerResponse
|
||||
|
||||
|
||||
class EmoteCommandResponse(AbstractCommandResponse):
|
||||
|
||||
def __init__(self, response: HandlerResponse) -> None:
|
||||
super().__init__(response)
|
||||
self.__emojis = VEmojis()
|
||||
|
||||
async def run(self) -> None:
|
||||
if self.response.success:
|
||||
await self.message.add_reaction(self.__emojis.SUCCESS)
|
||||
else:
|
||||
await self.message.add_reaction(self.__emojis.ERROR)
|
||||
40
UI/Views/PlayerView.py
Normal file
40
UI/Views/PlayerView.py
Normal file
@@ -0,0 +1,40 @@
|
||||
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
|
||||
self.disable_all_items()
|
||||
if self.__message is not None and isinstance(self.__message, Message):
|
||||
await self.__message.edit(view=self)
|
||||
|
||||
def set_message(self, message: Message) -> None:
|
||||
self.__message = message
|
||||
@@ -1,16 +1,17 @@
|
||||
from typing import List
|
||||
from discord.ext.commands import Context
|
||||
from discord import Client, Message, Embed
|
||||
from discord import Message, Embed
|
||||
from Config.Singleton import Singleton
|
||||
from Music.VulkanBot import VulkanBot
|
||||
|
||||
|
||||
class Cleaner(Singleton):
|
||||
def __init__(self, bot: Client = None) -> None:
|
||||
def __init__(self, bot: VulkanBot = None) -> None:
|
||||
if not super().created:
|
||||
self.__bot = bot
|
||||
self.__clean_str = 'Uploader:'
|
||||
|
||||
def set_bot(self, bot: Client) -> None:
|
||||
def set_bot(self, bot: VulkanBot) -> None:
|
||||
self.__bot = bot
|
||||
|
||||
async def clean_messages(self, ctx: Context, quant: int) -> None:
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import re
|
||||
import asyncio
|
||||
from Config.Configs import Configs
|
||||
from Config.Configs import VConfigs
|
||||
from functools import wraps, partial
|
||||
config = Configs()
|
||||
config = VConfigs()
|
||||
|
||||
|
||||
class Utils:
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
from Views.AbstractView import AbstractView
|
||||
from Handlers.HandlerResponse import HandlerResponse
|
||||
|
||||
|
||||
class EmoteView(AbstractView):
|
||||
|
||||
def __init__(self, response: HandlerResponse) -> None:
|
||||
super().__init__(response)
|
||||
|
||||
async def run(self) -> None:
|
||||
if self.response.success:
|
||||
await self.message.add_reaction('✅')
|
||||
else:
|
||||
await self.message.add_reaction('❌')
|
||||
39
main.py
39
main.py
@@ -1,38 +1,7 @@
|
||||
from discord import Intents, Client
|
||||
from os import listdir
|
||||
from Config.Configs import Configs
|
||||
from discord.ext.commands import Bot
|
||||
|
||||
|
||||
class VulkanInitializer:
|
||||
def __init__(self) -> None:
|
||||
self.__config = Configs()
|
||||
self.__intents = Intents.default()
|
||||
self.__intents.members = True
|
||||
self.__bot = self.__create_bot()
|
||||
self.__add_cogs(self.__bot)
|
||||
|
||||
def __create_bot(self) -> Client:
|
||||
bot = Bot(command_prefix=self.__config.BOT_PREFIX,
|
||||
pm_help=True,
|
||||
case_insensitive=True,
|
||||
intents=self.__intents)
|
||||
bot.remove_command('help')
|
||||
return bot
|
||||
|
||||
def __add_cogs(self, bot: Client) -> None:
|
||||
for filename in listdir(f'./{self.__config.COMMANDS_PATH}'):
|
||||
if filename.endswith('.py'):
|
||||
bot.load_extension(f'{self.__config.COMMANDS_PATH}.{filename[:-3]}')
|
||||
|
||||
def run(self) -> None:
|
||||
if self.__config.BOT_TOKEN == '':
|
||||
print('DEVELOPER NOTE -> Token not found')
|
||||
exit()
|
||||
|
||||
self.__bot.run(self.__config.BOT_TOKEN, bot=True, reconnect=True)
|
||||
from Music.VulkanInitializer import VulkanInitializer
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
vulkan = VulkanInitializer()
|
||||
vulkan.run()
|
||||
initializer = VulkanInitializer(willListen=True)
|
||||
vulkanBot = initializer.getBot()
|
||||
vulkanBot.startBot()
|
||||
|
||||
BIN
requirements.txt
BIN
requirements.txt
Binary file not shown.
Reference in New Issue
Block a user