diff --git a/config/Singleton.py b/config/Singleton.py new file mode 100644 index 0000000..d31909d --- /dev/null +++ b/config/Singleton.py @@ -0,0 +1,16 @@ +class Singleton(object): + __instance = None + __created = False + + def __new__(cls, *args, **kwargs): + if cls.__instance is None: + cls.__instance = object.__new__(cls) + return cls.__instance + + @property + def created(cls): + if cls.__created == False: + cls.__created = True + return False + else: + return True diff --git a/config/config.py b/config/config.py index cc7e6b2..36cc162 100644 --- a/config/config.py +++ b/config/config.py @@ -4,7 +4,7 @@ BOT_TOKEN = config('BOT_TOKEN') SPOTIFY_ID = config('SPOTIFY_ID') SPOTIFY_SECRET = config('SPOTIFY_SECRET') -BOT_PREFIX = '!' +BOT_PREFIX = '$' VC_TIMEOUT = 600 STARTUP_MESSAGE = 'Starting Vulkan...' diff --git a/vulkan/commands/Music.py b/vulkan/commands/Music.py index d7019d0..45e8ac4 100644 --- a/vulkan/commands/Music.py +++ b/vulkan/commands/Music.py @@ -6,6 +6,7 @@ from config import config from config import help from vulkan.music.Player import Player from vulkan.music.utils import is_connected +from vulkan.controllers.SkipController import SkipHandler class Music(commands.Cog): @@ -65,14 +66,15 @@ class Music(commands.Cog): @commands.command(name="skip", help=help.HELP_SKIP, description=help.HELP_SKIP_LONG, aliases=['s', 'pular']) async def skip(self, ctx: Context) -> None: - player = self.__get_player(ctx) - if player is None: - return - else: - await player.skip(ctx) + print(ctx.bot == self.__bot) + + handler = SkipHandler(ctx, self.__bot) + await handler.run() @commands.command(name='stop', help=help.HELP_STOP, description=help.HELP_STOP_LONG, aliases=['parar']) async def stop(self, ctx: Context) -> None: + print(ctx.bot == self.__bot) + player = self.__get_player(ctx) if player is None: return diff --git a/vulkan/controllers/AbstractHandler.py b/vulkan/controllers/AbstractHandler.py new file mode 100644 index 0000000..993ff28 --- /dev/null +++ b/vulkan/controllers/AbstractHandler.py @@ -0,0 +1,34 @@ +from abc import ABC, abstractmethod +from discord.ext.commands import Context +from discord import Client, Guild +from vulkan.controllers.PlayerController import PlayersController +from vulkan.music.Player import Player +from vulkan.results.AbstractResult import AbstractResult + + +class AbstractHandler(ABC): + def __init__(self, ctx: Context, bot: Client) -> None: + self.__bot: Client = bot + self.__controller = PlayersController(self.__bot) + self.__player: Player = self.__controller.get_player(ctx.guild) + self.__guild: Guild = ctx.guild + + @abstractmethod + async def run(self) -> AbstractResult: + pass + + @property + def guild(self) -> Guild: + return self.__guild + + @property + def player(self) -> Player: + return self.__player + + @property + def controller(self) -> PlayersController: + return self.__controller + + @property + def bot(self) -> Client: + return self.__bot diff --git a/vulkan/controllers/Exceptions.py b/vulkan/controllers/Exceptions.py new file mode 100644 index 0000000..7277eaa --- /dev/null +++ b/vulkan/controllers/Exceptions.py @@ -0,0 +1,26 @@ +from abc import ABC, abstractmethod + + +class Error(Exception, ABC): + @abstractmethod + def message(): + pass + + @abstractmethod + def title(): + pass + + +class MusicUnavailable(Error): + def __init__(self, message: str) -> None: + self.__message = message + super().__init__(message) + + def message(): + pass + + def title(): + pass + + def __str__(self) -> str: + return self.__message diff --git a/vulkan/controllers/PlayerController.py b/vulkan/controllers/PlayerController.py new file mode 100644 index 0000000..2b72fc6 --- /dev/null +++ b/vulkan/controllers/PlayerController.py @@ -0,0 +1,44 @@ +from typing import Dict, List, Union +from config.Singleton import Singleton +from discord import Guild, Client, VoiceClient +from vulkan.music.Player import Player + + +class PlayersController(Singleton): + def __init__(self, bot: Client = None) -> None: + if not super().created: + self.__bot: Client = bot + if bot is not None: + self.__players: Dict[Guild, Player] = self.__create_players() + + def set_bot(self, bot: Client) -> None: + self.__bot: Client = bot + self.__players: Dict[Guild, Player] = self.__create_players() + + def get_player(self, guild: Guild) -> Player: + if guild not in self.__players.keys(): + player = Player(self.__bot, guild) + self.__players[guild] = player + + return self.__players[guild] + + def reset_player(self, guild: Guild) -> None: + if isinstance(guild, Guild): + player = Player(self.__bot, guild) + self.__players[guild] == player + + def get_guild_voice(self, guild: Guild) -> Union[VoiceClient, None]: + if guild.voice_client is None: + return None + else: + return guild.voice_client + + def __create_players(self) -> Dict[Guild, Player]: + list_guilds: List[Guild] = self.__bot.guilds + players: Dict[Guild, Player] = {} + + for guild in list_guilds: + player = Player(self.__bot, guild) + players[guild] = player + + return players diff --git a/vulkan/controllers/SkipController.py b/vulkan/controllers/SkipController.py new file mode 100644 index 0000000..dabab0f --- /dev/null +++ b/vulkan/controllers/SkipController.py @@ -0,0 +1,26 @@ +from discord.ext.commands import Context +from discord import Client +from vulkan.controllers.AbstractHandler import AbstractHandler + + +class SkipHandler(AbstractHandler): + def __init__(self, ctx: Context, bot: Client) -> None: + super().__init__(ctx, bot) + + async def run(self) -> None: + if self.player.playlist.looping_one: + """ embed = Embed( + title=config.SONG_PLAYER, + description=config.LOOP_ON, + colour=config.COLOURS['blue'] + ) + await ctx.send(embed=embed) + return False + """ + return None + + voice = self.controller.get_guild_voice(self.guild) + if voice is None: + return None + else: + voice.stop() diff --git a/vulkan/music/Player.py b/vulkan/music/Player.py index 7551271..1bb3806 100644 --- a/vulkan/music/Player.py +++ b/vulkan/music/Player.py @@ -27,6 +27,10 @@ class Player(commands.Cog): self.FFMPEG_OPTIONS = {'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5', 'options': '-vn'} + @property + def playlist(self) -> Playlist: + return self.__playlist + async def connect(self, ctx: Context) -> bool: if not ctx.author.voice: return False diff --git a/vulkan/results/AbstractResult.py b/vulkan/results/AbstractResult.py new file mode 100644 index 0000000..6f26336 --- /dev/null +++ b/vulkan/results/AbstractResult.py @@ -0,0 +1,20 @@ +from typing import Union +from discord.ext.commands import Context +from vulkan.controllers.Exceptions import Error + + +class AbstractResult: + def __init__(self, ctx: Context, success: bool) -> None: + self.__success: bool = success + self.__ctx: Context = ctx + + @property + def ctx(self) -> Context: + return self.__ctx + + @property + def success(self) -> bool: + return self.__success + + def error(self) -> Union[Error, None]: + pass diff --git a/vulkan/results/SuccessResult.py b/vulkan/results/SuccessResult.py new file mode 100644 index 0000000..3f62f04 --- /dev/null +++ b/vulkan/results/SuccessResult.py @@ -0,0 +1,9 @@ +from vulkan.results import AbstractResult +from typing import Union +from discord.ext.commands import Context +from vulkan.controllers.Exceptions import Error + + +class SuccessResult(AbstractResult): + def __init__(self) -> None: + super().__init__() diff --git a/vulkan/views/AbstractView.py b/vulkan/views/AbstractView.py new file mode 100644 index 0000000..40df3ae --- /dev/null +++ b/vulkan/views/AbstractView.py @@ -0,0 +1,34 @@ +from abc import ABC, abstractmethod + +from numpy import result_type +from vulkan.results.AbstractResult import AbstractResult +from discord.ext.commands import Context +from discord import Client, Message + + +class AbstractView(ABC): + def __init__(self, result: AbstractResult) -> None: + self.__result: AbstractResult = result + self.__context: Context = result.ctx + self.__message: Message = result.ctx.message + self.__bot: Client = result.ctx.bot + + @property + def result(self) -> AbstractResult: + return self.__result + + @property + def bot(self) -> Client: + return self.__result.ctx.bot + + @property + def message(self) -> Message: + return self.__message + + @property + def context(self) -> Context: + return self.__context + + @abstractmethod + def run(self) -> None: + pass diff --git a/vulkan/views/EmoteView.py b/vulkan/views/EmoteView.py new file mode 100644 index 0000000..25d4acf --- /dev/null +++ b/vulkan/views/EmoteView.py @@ -0,0 +1,10 @@ +from vulkan.views.AbstractView import AbstractView +from vulkan.results import AbstractResult + + +class EmoteView(AbstractView): + def __init__(self, result: AbstractResult) -> None: + super().__init__(result) + + def run(self) -> None: + return super().run() diff --git a/vulkan/views/MessageView.py b/vulkan/views/MessageView.py new file mode 100644 index 0000000..7229560 --- /dev/null +++ b/vulkan/views/MessageView.py @@ -0,0 +1,10 @@ +from vulkan.views.AbstractView import AbstractView +from vulkan.results import AbstractResult + + +class MessageView(AbstractView): + def __init__(self, result: AbstractResult) -> None: + super().__init__(result) + + def run(self) -> None: + return super().run()