mirror of
https://github.com/RafaelSolVargas/Vulkan.git
synced 2025-10-29 16:57:23 +00:00
Merge pull request #22 from RafaelSolVargas/upgradingUI
Creating Buttons for Commands
This commit is contained in:
commit
a5cecd85d4
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,5 +1,4 @@
|
||||
.vscode
|
||||
assets/
|
||||
__pycache__
|
||||
.env
|
||||
.cache
|
||||
|
||||
BIN
Assets/playermenu.jfif
Normal file
BIN
Assets/playermenu.jfif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
BIN
Assets/vulkan-logo.png
Normal file
BIN
Assets/vulkan-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.5 KiB |
BIN
Assets/vulkancommands.jfif
Normal file
BIN
Assets/vulkancommands.jfif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 75 KiB |
@ -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,214 +15,218 @@ 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 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:
|
||||
|
||||
@ -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,8 +37,8 @@ class PlayHandler(AbstractHandler):
|
||||
raise InvalidInput(self.messages.INVALID_INPUT, self.messages.ERROR_TITLE)
|
||||
|
||||
# Get the process context for the current guild
|
||||
processManager = ProcessManager()
|
||||
processInfo = processManager.getPlayerInfo(self.guild, self.ctx)
|
||||
processManager = self.config.getProcessManager()
|
||||
processInfo = processManager.getOrCreatePlayerInfo(self.guild, self.ctx)
|
||||
playlist = processInfo.getPlaylist()
|
||||
process = processInfo.getProcess()
|
||||
if not process.is_alive(): # If process has not yet started, start
|
||||
@ -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,12 +114,12 @@ 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]
|
||||
if not song.problematic: # If downloaded add to the playlist and send play command
|
||||
processInfo = processManager.getPlayerInfo(self.guild, self.ctx)
|
||||
processInfo = processManager.getOrCreatePlayerInfo(self.guild, self.ctx)
|
||||
processLock = processInfo.getLock()
|
||||
acquired = processLock.acquire(timeout=self.config.ACQUIRE_LOCK_TIMEOUT)
|
||||
if acquired:
|
||||
|
||||
@ -1,19 +1,25 @@
|
||||
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()
|
||||
processInfo = processManager.getPlayerInfo(self.guild, self.ctx)
|
||||
if not self.__user_connected():
|
||||
error = ImpossibleMove()
|
||||
embed = self.embeds.NO_CHANNEL()
|
||||
return HandlerResponse(self.ctx, embed, error)
|
||||
|
||||
processManager = self.config.getProcessManager()
|
||||
processInfo = processManager.getOrCreatePlayerInfo(self.guild, self.ctx)
|
||||
if not processInfo:
|
||||
embed = self.embeds.NOT_PLAYING()
|
||||
error = BadCommandUsage()
|
||||
@ -25,11 +31,6 @@ class PrevHandler(AbstractHandler):
|
||||
embed = self.embeds.NOT_PREVIOUS_SONG()
|
||||
return HandlerResponse(self.ctx, embed, error)
|
||||
|
||||
if not self.__user_connected():
|
||||
error = ImpossibleMove()
|
||||
embed = self.embeds.NO_CHANNEL()
|
||||
return HandlerResponse(self.ctx, embed, error)
|
||||
|
||||
if playlist.isLoopingAll() or playlist.isLoopingOne():
|
||||
error = BadCommandUsage()
|
||||
embed = self.embeds.FAIL_DUE_TO_LOOP_ON()
|
||||
@ -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,24 @@
|
||||
from discord.ext.commands import Context
|
||||
from discord import Client
|
||||
from Handlers.AbstractHandler import AbstractHandler
|
||||
from Config.Exceptions import BadCommandUsage
|
||||
from Config.Exceptions import BadCommandUsage, ImpossibleMove
|
||||
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()
|
||||
if not self.__user_connected():
|
||||
error = ImpossibleMove()
|
||||
embed = self.embeds.NO_CHANNEL()
|
||||
return HandlerResponse(self.ctx, embed, error)
|
||||
|
||||
processManager = self.config.getProcessManager()
|
||||
processInfo = processManager.getRunningPlayerInfo(self.guild)
|
||||
if processInfo: # Verify if there is a running process
|
||||
playlist = processInfo.getPlaylist()
|
||||
@ -23,10 +29,16 @@ 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)
|
||||
else:
|
||||
embed = self.embeds.NOT_PLAYING()
|
||||
return HandlerResponse(self.ctx, embed)
|
||||
|
||||
def __user_connected(self) -> bool:
|
||||
if self.author.voice:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
@ -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,28 @@ 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 getOrCreatePlayerInfo(self, guild: Guild, context: Union[Context, Interaction]) -> ProcessInfo:
|
||||
"""Return the process info for the guild, the user in context must be connected to a voice_channel"""
|
||||
try:
|
||||
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 +55,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 +69,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,30 +77,105 @@ 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: Union[Context, Interaction]) -> ProcessInfo:
|
||||
"""Create a new process info using previous playlist"""
|
||||
guildID: int = context.guild.id
|
||||
textID: int = context.channel.id
|
||||
voiceID: int = context.author.voice.channel.id
|
||||
authorID: int = context.author.id
|
||||
if isinstance(context, Interaction):
|
||||
authorID: int = context.user.id
|
||||
voiceID: int = context.user.voice.channel.id
|
||||
else:
|
||||
authorID: int = context.author.id
|
||||
voiceID: int = context.author.voice.channel.id
|
||||
|
||||
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
|
||||
|
||||
97
README.md
97
README.md
@ -1,68 +1,48 @@
|
||||
# **Vulkan**
|
||||
|
||||
A Music Discord bot, written in Python, that plays *Youtube*, *Spotify* and *Deezer* links. Vulkan was designed so that anyone can fork this project, follow the instructions and use it in their own way, Vulkan can also be configured in Heroku to work 24/7.
|
||||
<h1 align="center"> Vulkan</h1>
|
||||
|
||||
|
||||
# **Music**
|
||||
- Play musics from Youtube, Spotify and Deezer links (Albums, Artists, Playlists and Tracks)
|
||||
- Control loop of one or all musics
|
||||
- Allow moving and removing musics in the queue
|
||||
- Play musics in queue randomly
|
||||
- Store played songs and allow bidirectional flow
|
||||
A Music Discord Bot, that plays *Youtube*, *Spotify*, *Deezer* links or raw queries. Vulkan is open source, so everyone can fork this project, follow the instructions and use it in their own way, executing it in your own machine or hosting in others machines to work 24/7.
|
||||
|
||||
### Commands
|
||||
```!play [title, spotify_url, youtube_url, deezer_url]``` - Start playing song
|
||||
Vulkan uses multiprocessing and asynchronous Python modules to maximize Music Player response time, so the player doesn't lag when many commands are being processed and it can play in multiples discord serves at the same time without affecting the Music Player response time.
|
||||
|
||||
```!resume``` - Resume the song player
|
||||
|
||||
```!pause``` - Pause the song player
|
||||
<p align="center">
|
||||
<img src="./Assets/playermenu.jfif" />
|
||||
</p>
|
||||
|
||||
```!skip``` - Skip the currently playing song
|
||||
|
||||
```!prev``` - Return to play the previous song
|
||||
|
||||
```!stop``` - Stop the playing of musics
|
||||
|
||||
```!queue``` - Show the musics list in queue
|
||||
|
||||
```!history``` - Show the played songs list
|
||||
|
||||
```!loop [one, all, off]``` - Control the loop of songs
|
||||
|
||||
```!shuffle``` - Shuffle the songs in queue
|
||||
|
||||
```!remove [x]``` - Remove the song in position x
|
||||
|
||||
```!move [x, y]``` - Change the musics in position x and y in Queue
|
||||
|
||||
```!np``` - Show information of the currently song
|
||||
|
||||
```!clear``` - Clear the songs in queue, doesn't stop the player
|
||||
|
||||
```!reset``` - Reset the player, recommended if any error happen
|
||||
|
||||
```!invite``` - Send the URL to invite Vulkan to your server
|
||||
|
||||
```!help [command]``` - Show more info about the command selected
|
||||
# **Music 🎧**
|
||||
- Play musics from Youtube, Spotify and Deezer links (Albums, Artists, Playlists and Tracks).
|
||||
- Play musics in multiple discord server at the same time.
|
||||
- The player contain buttons to shortcut some commands.
|
||||
- Manage the loop of one or all playing musics.
|
||||
- Manage the order and remove musics from the queue.
|
||||
- Shuffle the musics queue order.
|
||||
|
||||
|
||||
|
||||
# **Usage:**
|
||||
<p align="center">
|
||||
<img src="./Assets/vulkancommands.jfif" />
|
||||
</p>
|
||||
|
||||
### **API Keys**
|
||||
|
||||
|
||||
# **How to use it**
|
||||
|
||||
|
||||
### **Requirements**
|
||||
Installation of Python 3.8+ and the dependencies in the requirements.txt file, creation of your own Bot in Discord and Spotify Keys.
|
||||
```
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
### **🔑 API Keys**
|
||||
You have to create your own discord Bot and store your Bot Token
|
||||
* Your Discord Application - [Discord](https://discord.com/developers)
|
||||
* You own Spotify Keys - [Spotify](https://developer.spotify.com/dashboard/applications)
|
||||
|
||||
- This information must be stored in an .env file, explained further.
|
||||
|
||||
### **Requirements**
|
||||
- Installation of Python 3.8+ and the dependencies in the requirements.txt file.
|
||||
```
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
|
||||
- **Installation of FFMPEG**<br>
|
||||
### **Installation of FFMPEG**<br>
|
||||
FFMPEG is a module that will be used to play music, you must have this configured in your machine
|
||||
*FFMPEG must be configured in the PATH for Windows users. Check this [YoutubeVideo](https://www.youtube.com/watch?v=r1AtmY-RMyQ&t=114s&ab_channel=TroubleChute).* <br><br>
|
||||
You can download the executables in this link `https://www.ffmpeg.org/download.html` and then put the .exe files inside a ffmpeg\bin folder in your C:\ folder. Do not forget to add 'ffmpeg\bin' to your PATH.
|
||||
@ -78,8 +58,8 @@ BOT_PREFIX=Your_Wanted_Prefix_For_Vulkan
|
||||
|
||||
```
|
||||
|
||||
### **Config File**
|
||||
The config file, located in ```./config``` folder doesn't require any change, but if you acquire the knowledged of how it works, you can change it to the way you want.
|
||||
### **⚙️ Configs**
|
||||
The config file is located at ```./config/Configs.py```, it doesn't require any change, but if you can change values to the way you want.
|
||||
|
||||
|
||||
### **Initialization**
|
||||
@ -87,25 +67,22 @@ The config file, located in ```./config``` folder doesn't require any change, bu
|
||||
- Run ```python main.py``` in console to start
|
||||
|
||||
|
||||
## **Heroku**
|
||||
To run your Bot in Heroku 24/7, you will need the Procfile located in root, then follow the instructions in this [video](https://www.youtube.com/watch?v=BPvg9bndP1U&ab_channel=TechWithTim). In addition, also add these two buildpacks to your Heroku Application:
|
||||
## **🚀 Heroku**
|
||||
To deploy and run your Bot in Heroku 24/7, you will need the Procfile located in root, then follow the instructions in this [video](https://www.youtube.com/watch?v=BPvg9bndP1U&ab_channel=TechWithTim). In addition, also add these two buildpacks to your Heroku Application:
|
||||
|
||||
- https://github.com/jonathanong/heroku-buildpack-ffmpeg-latest.git
|
||||
|
||||
- https://github.com/xrisk/heroku-opus.git
|
||||
|
||||
|
||||
## Testing
|
||||
|
||||
## 🧪 Tests
|
||||
The tests were written manually with no package due to problems with async function in other packages, to execute them type in root: <br>
|
||||
`python run_tests.py`<br>
|
||||
|
||||
## License
|
||||
## 📖 License
|
||||
- This program is free software: you can redistribute it and/or modify it under the terms of the [MIT License](https://github.com/RafaelSolVargas/Vulkan/blob/master/LICENSE).
|
||||
|
||||
|
||||
## Contributing
|
||||
## 🏗️ Contributing
|
||||
- If you are interested in upgrading this project i will be very happy to receive a PR or Issue from you. See TODO project to see if i'm working in some feature now.
|
||||
|
||||
|
||||
## Acknowledgment
|
||||
- See the DingoLingo [project](https://github.com/Raptor123471/DingoLingo) from Raptor123471, it helped me a lot to build Vulkan.
|
||||
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)
|
||||
43
UI/Views/PlayerView.py
Normal file
43
UI/Views/PlayerView.py
Normal file
@ -0,0 +1,43 @@
|
||||
from discord import Message
|
||||
from discord.ui import View
|
||||
from Config.Emojis import VEmojis
|
||||
from UI.Buttons.PauseButton import PauseButton
|
||||
from UI.Buttons.BackButton import BackButton
|
||||
from UI.Buttons.SkipButton import SkipButton
|
||||
from UI.Buttons.StopButton import StopButton
|
||||
from UI.Buttons.SongsButton import SongsButton
|
||||
from UI.Buttons.PlayButton import PlayButton
|
||||
from UI.Buttons.LoopAllButton import LoopAllButton
|
||||
from UI.Buttons.LoopOneButton import LoopOneButton
|
||||
from UI.Buttons.LoopOffButton import LoopOffButton
|
||||
from Music.VulkanBot import VulkanBot
|
||||
|
||||
emojis = VEmojis()
|
||||
|
||||
|
||||
class PlayerView(View):
|
||||
def __init__(self, bot: VulkanBot, timeout: float = 6000):
|
||||
super().__init__(timeout=timeout)
|
||||
self.__bot = bot
|
||||
self.__message: Message = None
|
||||
self.add_item(BackButton(self.__bot))
|
||||
self.add_item(PauseButton(self.__bot))
|
||||
self.add_item(PlayButton(self.__bot))
|
||||
self.add_item(StopButton(self.__bot))
|
||||
self.add_item(SkipButton(self.__bot))
|
||||
self.add_item(SongsButton(self.__bot))
|
||||
self.add_item(LoopOneButton(self.__bot))
|
||||
self.add_item(LoopOffButton(self.__bot))
|
||||
self.add_item(LoopAllButton(self.__bot))
|
||||
|
||||
async def on_timeout(self) -> None:
|
||||
# Disable all itens and, if has the message, edit it
|
||||
try:
|
||||
self.disable_all_items()
|
||||
if self.__message is not None and isinstance(self.__message, Message):
|
||||
await self.__message.edit(view=self)
|
||||
except Exception as e:
|
||||
print(f'[ERROR EDITING MESSAGE] -> {e}')
|
||||
|
||||
def set_message(self, message: Message) -> None:
|
||||
self.__message = message
|
||||
@ -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.
Loading…
x
Reference in New Issue
Block a user