mirror of
https://github.com/RafaelSolVargas/Vulkan.git
synced 2025-10-29 16:57:23 +00:00
Fixing erros with buttons handlers and updating README
This commit is contained in:
parent
c5885f3093
commit
7f1ffb6b23
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,5 +1,4 @@
|
|||||||
.vscode
|
.vscode
|
||||||
assets/
|
|
||||||
__pycache__
|
__pycache__
|
||||||
.env
|
.env
|
||||||
.cache
|
.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 |
@ -17,7 +17,6 @@ from Handlers.QueueHandler import QueueHandler
|
|||||||
from Handlers.LoopHandler import LoopHandler
|
from Handlers.LoopHandler import LoopHandler
|
||||||
from UI.Responses.EmoteCogResponse import EmoteCommandResponse
|
from UI.Responses.EmoteCogResponse import EmoteCommandResponse
|
||||||
from UI.Responses.EmbedCogResponse import EmbedCommandResponse
|
from UI.Responses.EmbedCogResponse import EmbedCommandResponse
|
||||||
from UI.Views.PlayerView import PlayerView
|
|
||||||
from Music.VulkanBot import VulkanBot
|
from Music.VulkanBot import VulkanBot
|
||||||
from Config.Configs import VConfigs
|
from Config.Configs import VConfigs
|
||||||
from Parallelism.ProcessManager import ProcessManager
|
from Parallelism.ProcessManager import ProcessManager
|
||||||
@ -233,11 +232,6 @@ class MusicCog(Cog):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f'[ERROR IN COG] -> {e}')
|
print(f'[ERROR IN COG] -> {e}')
|
||||||
|
|
||||||
@command(name='rafael')
|
|
||||||
async def rafael(self, ctx: Context) -> None:
|
|
||||||
view = PlayerView(self.__bot)
|
|
||||||
await ctx.send(view=view)
|
|
||||||
|
|
||||||
|
|
||||||
def setup(bot):
|
def setup(bot):
|
||||||
bot.add_cog(MusicCog(bot))
|
bot.add_cog(MusicCog(bot))
|
||||||
|
|||||||
@ -38,7 +38,7 @@ class PlayHandler(AbstractHandler):
|
|||||||
|
|
||||||
# Get the process context for the current guild
|
# Get the process context for the current guild
|
||||||
processManager = self.config.getProcessManager()
|
processManager = self.config.getProcessManager()
|
||||||
processInfo = processManager.getPlayerInfo(self.guild, self.ctx)
|
processInfo = processManager.getOrCreatePlayerInfo(self.guild, self.ctx)
|
||||||
playlist = processInfo.getPlaylist()
|
playlist = processInfo.getPlaylist()
|
||||||
process = processInfo.getProcess()
|
process = processInfo.getProcess()
|
||||||
if not process.is_alive(): # If process has not yet started, start
|
if not process.is_alive(): # If process has not yet started, start
|
||||||
@ -119,7 +119,7 @@ class PlayHandler(AbstractHandler):
|
|||||||
await task
|
await task
|
||||||
song = songs[index]
|
song = songs[index]
|
||||||
if not song.problematic: # If downloaded add to the playlist and send play command
|
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()
|
processLock = processInfo.getLock()
|
||||||
acquired = processLock.acquire(timeout=self.config.ACQUIRE_LOCK_TIMEOUT)
|
acquired = processLock.acquire(timeout=self.config.ACQUIRE_LOCK_TIMEOUT)
|
||||||
if acquired:
|
if acquired:
|
||||||
|
|||||||
@ -13,8 +13,13 @@ class PrevHandler(AbstractHandler):
|
|||||||
super().__init__(ctx, bot)
|
super().__init__(ctx, bot)
|
||||||
|
|
||||||
async def run(self) -> HandlerResponse:
|
async def run(self) -> HandlerResponse:
|
||||||
|
if not self.__user_connected():
|
||||||
|
error = ImpossibleMove()
|
||||||
|
embed = self.embeds.NO_CHANNEL()
|
||||||
|
return HandlerResponse(self.ctx, embed, error)
|
||||||
|
|
||||||
processManager = self.config.getProcessManager()
|
processManager = self.config.getProcessManager()
|
||||||
processInfo = processManager.getPlayerInfo(self.guild, self.ctx)
|
processInfo = processManager.getOrCreatePlayerInfo(self.guild, self.ctx)
|
||||||
if not processInfo:
|
if not processInfo:
|
||||||
embed = self.embeds.NOT_PLAYING()
|
embed = self.embeds.NOT_PLAYING()
|
||||||
error = BadCommandUsage()
|
error = BadCommandUsage()
|
||||||
@ -26,11 +31,6 @@ class PrevHandler(AbstractHandler):
|
|||||||
embed = self.embeds.NOT_PREVIOUS_SONG()
|
embed = self.embeds.NOT_PREVIOUS_SONG()
|
||||||
return HandlerResponse(self.ctx, embed, error)
|
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():
|
if playlist.isLoopingAll() or playlist.isLoopingOne():
|
||||||
error = BadCommandUsage()
|
error = BadCommandUsage()
|
||||||
embed = self.embeds.FAIL_DUE_TO_LOOP_ON()
|
embed = self.embeds.FAIL_DUE_TO_LOOP_ON()
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
from discord.ext.commands import Context
|
from discord.ext.commands import Context
|
||||||
from Handlers.AbstractHandler import AbstractHandler
|
from Handlers.AbstractHandler import AbstractHandler
|
||||||
from Config.Exceptions import BadCommandUsage
|
from Config.Exceptions import BadCommandUsage, ImpossibleMove
|
||||||
from Handlers.HandlerResponse import HandlerResponse
|
from Handlers.HandlerResponse import HandlerResponse
|
||||||
from Music.VulkanBot import VulkanBot
|
from Music.VulkanBot import VulkanBot
|
||||||
from Parallelism.Commands import VCommands, VCommandsType
|
from Parallelism.Commands import VCommands, VCommandsType
|
||||||
@ -13,6 +13,11 @@ class SkipHandler(AbstractHandler):
|
|||||||
super().__init__(ctx, bot)
|
super().__init__(ctx, bot)
|
||||||
|
|
||||||
async def run(self) -> HandlerResponse:
|
async def run(self) -> HandlerResponse:
|
||||||
|
if not self.__user_connected():
|
||||||
|
error = ImpossibleMove()
|
||||||
|
embed = self.embeds.NO_CHANNEL()
|
||||||
|
return HandlerResponse(self.ctx, embed, error)
|
||||||
|
|
||||||
processManager = self.config.getProcessManager()
|
processManager = self.config.getProcessManager()
|
||||||
processInfo = processManager.getRunningPlayerInfo(self.guild)
|
processInfo = processManager.getRunningPlayerInfo(self.guild)
|
||||||
if processInfo: # Verify if there is a running process
|
if processInfo: # Verify if there is a running process
|
||||||
@ -31,3 +36,9 @@ class SkipHandler(AbstractHandler):
|
|||||||
else:
|
else:
|
||||||
embed = self.embeds.NOT_PLAYING()
|
embed = self.embeds.NOT_PLAYING()
|
||||||
return HandlerResponse(self.ctx, embed)
|
return HandlerResponse(self.ctx, embed)
|
||||||
|
|
||||||
|
def __user_connected(self) -> bool:
|
||||||
|
if self.author.voice:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|||||||
@ -35,16 +35,9 @@ class ProcessManager(Singleton):
|
|||||||
def setPlayerInfo(self, guild: Guild, info: ProcessInfo):
|
def setPlayerInfo(self, guild: Guild, info: ProcessInfo):
|
||||||
self.__playersProcess[guild.id] = info
|
self.__playersProcess[guild.id] = info
|
||||||
|
|
||||||
def getPlayerInfo(self, guild: Guild, context: Union[Context, Interaction]) -> ProcessInfo:
|
def getOrCreatePlayerInfo(self, guild: Guild, context: Union[Context, Interaction]) -> ProcessInfo:
|
||||||
"""Return the process info for the guild, if not and context is a instance
|
"""Return the process info for the guild, the user in context must be connected to a voice_channel"""
|
||||||
of discord.Context then create one, else return None"""
|
|
||||||
try:
|
try:
|
||||||
if isinstance(context, Interaction):
|
|
||||||
if guild.id not in self.__playersProcess.keys():
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
return self.__playersProcess[guild.id]
|
|
||||||
|
|
||||||
if guild.id not in self.__playersProcess.keys():
|
if guild.id not in self.__playersProcess.keys():
|
||||||
self.__playersProcess[guild.id] = self.__createProcessInfo(guild, context)
|
self.__playersProcess[guild.id] = self.__createProcessInfo(guild, context)
|
||||||
else:
|
else:
|
||||||
@ -102,12 +95,16 @@ class ProcessManager(Singleton):
|
|||||||
|
|
||||||
return processInfo
|
return processInfo
|
||||||
|
|
||||||
def __recreateProcess(self, guild: Guild, context: Context) -> ProcessInfo:
|
def __recreateProcess(self, guild: Guild, context: Union[Context, Interaction]) -> ProcessInfo:
|
||||||
"""Create a new process info using previous playlist"""
|
"""Create a new process info using previous playlist"""
|
||||||
guildID: int = context.guild.id
|
guildID: int = context.guild.id
|
||||||
textID: int = context.channel.id
|
textID: int = context.channel.id
|
||||||
voiceID: int = context.author.voice.channel.id
|
if isinstance(context, Interaction):
|
||||||
authorID: int = context.author.id
|
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()
|
playlist: Playlist = self.__playersProcess[guildID].getPlaylist()
|
||||||
lock = Lock()
|
lock = Lock()
|
||||||
|
|||||||
97
README.md
97
README.md
@ -1,68 +1,48 @@
|
|||||||
# **Vulkan**
|
<h1 align="center"> Vulkan</h1>
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
|
|
||||||
# **Music**
|
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.
|
||||||
- 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
|
|
||||||
|
|
||||||
### Commands
|
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.
|
||||||
```!play [title, spotify_url, youtube_url, deezer_url]``` - Start playing song
|
|
||||||
|
|
||||||
```!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
|
# **Music 🎧**
|
||||||
|
- Play musics from Youtube, Spotify and Deezer links (Albums, Artists, Playlists and Tracks).
|
||||||
```!stop``` - Stop the playing of musics
|
- Play musics in multiple discord server at the same time.
|
||||||
|
- The player contain buttons to shortcut some commands.
|
||||||
```!queue``` - Show the musics list in queue
|
- Manage the loop of one or all playing musics.
|
||||||
|
- Manage the order and remove musics from the queue.
|
||||||
```!history``` - Show the played songs list
|
- Shuffle the musics queue order.
|
||||||
|
|
||||||
```!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
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# **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)
|
* Your Discord Application - [Discord](https://discord.com/developers)
|
||||||
* You own Spotify Keys - [Spotify](https://developer.spotify.com/dashboard/applications)
|
* You own Spotify Keys - [Spotify](https://developer.spotify.com/dashboard/applications)
|
||||||
|
|
||||||
- This information must be stored in an .env file, explained further.
|
- This information must be stored in an .env file, explained further.
|
||||||
|
|
||||||
### **Requirements**
|
### **Installation of FFMPEG**<br>
|
||||||
- Installation of Python 3.8+ and the dependencies in the requirements.txt file.
|
|
||||||
```
|
|
||||||
pip install -r requirements.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
- **Installation of FFMPEG**<br>
|
|
||||||
FFMPEG is a module that will be used to play music, you must have this configured in your machine
|
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>
|
*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.
|
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**
|
### **⚙️ Configs**
|
||||||
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.
|
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**
|
### **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
|
- Run ```python main.py``` in console to start
|
||||||
|
|
||||||
|
|
||||||
## **Heroku**
|
## **🚀 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:
|
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/jonathanong/heroku-buildpack-ffmpeg-latest.git
|
||||||
|
|
||||||
- https://github.com/xrisk/heroku-opus.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>
|
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>
|
`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).
|
- 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.
|
- 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.
|
|
||||||
@ -32,9 +32,12 @@ class PlayerView(View):
|
|||||||
|
|
||||||
async def on_timeout(self) -> None:
|
async def on_timeout(self) -> None:
|
||||||
# Disable all itens and, if has the message, edit it
|
# Disable all itens and, if has the message, edit it
|
||||||
self.disable_all_items()
|
try:
|
||||||
if self.__message is not None and isinstance(self.__message, Message):
|
self.disable_all_items()
|
||||||
await self.__message.edit(view=self)
|
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:
|
def set_message(self, message: Message) -> None:
|
||||||
self.__message = message
|
self.__message = message
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user